Deleted Added
full compact
pf_ioctl.c (126259) pf_ioctl.c (126261)
1/* $FreeBSD: head/sys/contrib/pf/net/pf_ioctl.c 126261 2004-02-26 02:34:12Z mlaier $ */
1/* $OpenBSD: pf_ioctl.c,v 1.81 2003/08/22 21:50:34 david Exp $ */
2
3/*
4 * Copyright (c) 2001 Daniel Hartmeier
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Effort sponsored in part by the Defense Advanced Research Projects
32 * Agency (DARPA) and Air Force Research Laboratory, Air Force
33 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
34 *
35 */
36
2/* $OpenBSD: pf_ioctl.c,v 1.81 2003/08/22 21:50:34 david Exp $ */
3
4/*
5 * Copyright (c) 2001 Daniel Hartmeier
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * - Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Effort sponsored in part by the Defense Advanced Research Projects
33 * Agency (DARPA) and Air Force Research Laboratory, Air Force
34 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35 *
36 */
37
38#if defined(__FreeBSD__)
39#include "opt_inet.h"
40#include "opt_inet6.h"
41#endif
42
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/mbuf.h>
40#include <sys/filio.h>
41#include <sys/fcntl.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/kernel.h>
45#include <sys/time.h>
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/mbuf.h>
46#include <sys/filio.h>
47#include <sys/fcntl.h>
48#include <sys/socket.h>
49#include <sys/socketvar.h>
50#include <sys/kernel.h>
51#include <sys/time.h>
52#include <sys/malloc.h>
53#if defined(__FreeBSD__)
54#include <sys/conf.h>
55#else
46#include <sys/timeout.h>
47#include <sys/pool.h>
56#include <sys/timeout.h>
57#include <sys/pool.h>
48#include <sys/malloc.h>
58#endif
49
50#include <net/if.h>
51#include <net/if_types.h>
52#include <net/route.h>
53
54#include <netinet/in.h>
55#include <netinet/in_var.h>
56#include <netinet/in_systm.h>
57#include <netinet/ip.h>
58#include <netinet/ip_var.h>
59#include <netinet/ip_icmp.h>
60
61#include <net/pfvar.h>
62
63#ifdef INET6
64#include <netinet/ip6.h>
65#include <netinet/in_pcb.h>
59
60#include <net/if.h>
61#include <net/if_types.h>
62#include <net/route.h>
63
64#include <netinet/in.h>
65#include <netinet/in_var.h>
66#include <netinet/in_systm.h>
67#include <netinet/ip.h>
68#include <netinet/ip_var.h>
69#include <netinet/ip_icmp.h>
70
71#include <net/pfvar.h>
72
73#ifdef INET6
74#include <netinet/ip6.h>
75#include <netinet/in_pcb.h>
76#if defined(__FreeBSD__) && (__FreeBSD_version < 501108)
77#include <netinet6/ip6protosw.h>
78#endif
66#endif /* INET6 */
67
68#ifdef ALTQ
69#include <altq/altq.h>
70#endif
71
79#endif /* INET6 */
80
81#ifdef ALTQ
82#include <altq/altq.h>
83#endif
84
85#if defined(__FreeBSD__)
86#if (__FreeBSD_version >= 500112)
87#include <sys/limits.h>
88#else
89#include <machine/limits.h>
90#endif
91#include <sys/lock.h>
92#include <sys/mutex.h>
93#if __FreeBSD_version < 501108
94#include <sys/protosw.h>
95#endif
96#include <net/pfil.h>
97#endif /* __FreeBSD__ */
98
99#if defined(__FreeBSD__)
100void init_zone_var(void);
101void cleanup_pf_zone(void);
102int pfattach(void);
103#else
72void pfattach(int);
73int pfopen(dev_t, int, int, struct proc *);
74int pfclose(dev_t, int, int, struct proc *);
104void pfattach(int);
105int pfopen(dev_t, int, int, struct proc *);
106int pfclose(dev_t, int, int, struct proc *);
107#endif
75struct pf_pool *pf_get_pool(char *, char *, u_int32_t,
76 u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t);
77int pf_get_ruleset_number(u_int8_t);
78void pf_init_ruleset(struct pf_ruleset *);
79void pf_mv_pool(struct pf_palist *, struct pf_palist *);
80void pf_empty_pool(struct pf_palist *);
108struct pf_pool *pf_get_pool(char *, char *, u_int32_t,
109 u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t);
110int pf_get_ruleset_number(u_int8_t);
111void pf_init_ruleset(struct pf_ruleset *);
112void pf_mv_pool(struct pf_palist *, struct pf_palist *);
113void pf_empty_pool(struct pf_palist *);
114#if defined(__FreeBSD__)
115int pfioctl(dev_t, u_long, caddr_t, int, struct thread *);
116#else
81int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
117int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
118#endif
82
119
120#if defined(__FreeBSD__)
121extern struct callout pf_expire_to;
122#if __FreeBSD_version < 501108
123extern struct protosw inetsw[];
124#endif
125#else
83extern struct timeout pf_expire_to;
126extern struct timeout pf_expire_to;
127#endif
84
85struct pf_rule pf_default_rule;
86
87#define TAGID_MAX 50000
88TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags);
89
90#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
91
128
129struct pf_rule pf_default_rule;
130
131#define TAGID_MAX 50000
132TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags);
133
134#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
135
136
137#if defined(__FreeBSD__)
138static dev_t pf_dev;
139
140/*
141 * XXX - These are new and need to be checked when moveing to a new version
142 */
143static int pf_beginrules(void *addr);
144static int pf_commitrules(void *addr);
145#if defined(ALTQ)
146static int pf_beginaltqs(void *addr);
147static int pf_commitaltqs(void *addr);
148static int pf_stopaltq(void);
149#endif
150static void pf_clearstates(void);
151static int pf_clear_tables(void *addr);
152/*
153 * XXX - These are new and need to be checked when moveing to a new version
154 */
155
156#if (__FreeBSD_version < 501108)
157static int pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir,
158 struct mbuf **m);
159static int pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir,
160 struct mbuf **m);
161#if defined(INET6)
162static int pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir,
163 struct mbuf **m);
164static int pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir,
165 struct mbuf **m);
166#endif
167#else /* (__FreeBSD_version >= 501108) */
168static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
169 int dir);
170static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
171 int dir);
172#if defined(INET6)
173static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
174 int dir);
175static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
176 int dir);
177#endif
178#endif /* (__FreeBSD_version >= 501108) */
179static int hook_pf(void);
180static int dehook_pf(void);
181static int shutdown_pf(void);
182static int pf_load(void);
183static int pf_unload(void);
184
185
186
187static struct cdevsw pf_cdevsw = {
188#if (__FreeBSD_version < 500105)
189 /* open */ noopen,
190 /* close */ noclose,
191 /* read */ noread,
192 /* write */ nowrite,
193 /* ioctl */ pfioctl,
194 /* poll */ nopoll,
195 /* mmap */ nommap,
196 /* strategy */ nostrategy,
197 /* name */ PF_NAME,
198 /* maj */ PF_CDEV_MAJOR,
199 /* dump */ nodump,
200 /* psize */ nopsize,
201 /* flags */ 0,
202 /* kqfilter */ nokqfilter,
203#elif (__FreeBSD_version < 501110)
204 .d_open = noopen,
205 .d_close = noclose,
206 .d_read = noread,
207 .d_write = nowrite,
208 .d_ioctl = pfioctl,
209 .d_poll = nopoll,
210 .d_mmap = nommap,
211 .d_strategy = nostrategy,
212 .d_name = PF_NAME,
213 .d_maj = MAJOR_AUTO, /* PF_CDEV_MAJOR */
214 .d_dump = nodump,
215 .d_flags = 0,
216 .d_kqfilter = nokqfilter,
217#else
218 .d_ioctl = pfioctl,
219 .d_name = PF_NAME,
220 .d_version = D_VERSION,
221#endif
222};
223#endif /* __FreeBSD__ */
224
225#if defined(__FreeBSD__)
226static volatile int pf_pfil_hooked = 0;
227struct mtx pf_task_mtx;
228
92void
229void
230init_pf_mutex(void)
231{
232 mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF);
233/*
234 * pf_altq_mtx is initialized at altq_subr.c.
235 *
236 * #if defined(ALTQ) && !defined(ALTQ3_COMPAT)
237 * mtx_init(&pf_altq_mtx, "pf altq mtx", NULL, MTX_DEF);
238 * #endif
239 */
240}
241
242void
243destroy_pf_mutex(void)
244{
245 mtx_destroy(&pf_task_mtx);
246/*
247 * pf_altq_mtx is initialized at altq_subr.c.
248 *
249 * #if defined(ALTQ) && !defined(ALTQ3_COMPAT)
250 * mtx_destroy(&pf_altq_mtx);
251 * #endif
252 */
253}
254
255void
256init_zone_var(void)
257{
258 pf_tree_pl = pf_rule_pl = pf_addr_pl = NULL;
259 pf_state_pl = pf_altq_pl = pf_pooladdr_pl = NULL;
260 pf_frent_pl = pf_frag_pl = pf_cache_pl = pf_cent_pl = NULL;
261 pf_state_scrub_pl = NULL;
262 pfr_ktable_pl = pfr_kentry_pl = NULL;
263}
264
265void
266cleanup_pf_zone(void)
267{
268 UMA_DESTROY(pf_tree_pl);
269 UMA_DESTROY(pf_rule_pl);
270 UMA_DESTROY(pf_addr_pl);
271 UMA_DESTROY(pf_state_pl);
272 UMA_DESTROY(pf_altq_pl);
273 UMA_DESTROY(pf_pooladdr_pl);
274 UMA_DESTROY(pf_frent_pl);
275 UMA_DESTROY(pf_frag_pl);
276 UMA_DESTROY(pf_cache_pl);
277 UMA_DESTROY(pf_cent_pl);
278 UMA_DESTROY(pfr_ktable_pl);
279 UMA_DESTROY(pfr_kentry_pl);
280 UMA_DESTROY(pf_state_scrub_pl);
281}
282#endif /* __FreeBSD__ */
283
284#if defined(__FreeBSD__)
285int
286pfattach(void)
287{
288 u_int32_t *my_timeout = pf_default_rule.timeout;
289 int error = 1;
290
291 do {
292 UMA_CREATE(pf_tree_pl, struct pf_tree_node, "pftrpl");
293 UMA_CREATE(pf_rule_pl, struct pf_rule, "pfrulepl");
294 UMA_CREATE(pf_addr_pl, struct pf_addr_dyn, "pfaddrpl");
295 UMA_CREATE(pf_state_pl, struct pf_state, "pfstatepl");
296 UMA_CREATE(pf_altq_pl, struct pf_altq, "pfaltqpl");
297 UMA_CREATE(pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl");
298 UMA_CREATE(pfr_ktable_pl, struct pfr_ktable, "pfrktable");
299 UMA_CREATE(pfr_kentry_pl, struct pfr_kentry, "pfrkentry");
300 UMA_CREATE(pf_frent_pl, struct pf_frent, "pffrent");
301 UMA_CREATE(pf_frag_pl, struct pf_fragment, "pffrag");
302 UMA_CREATE(pf_cache_pl, struct pf_fragment, "pffrcache");
303 UMA_CREATE(pf_cent_pl, struct pf_frcache, "pffrcent");
304 UMA_CREATE(pf_state_scrub_pl, struct pf_state_scrub,
305 "pfstatescrub");
306 error = 0;
307 } while(0);
308 if (error) {
309 cleanup_pf_zone();
310 return (error);
311 }
312 pfr_initialize();
313 if ( (error = pf_osfp_initialize()) ) {
314 cleanup_pf_zone();
315 pf_osfp_cleanup();
316 return (error);
317 }
318
319 pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl;
320 pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT;
321 pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl;
322 pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT;
323 uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp,
324 pf_pool_limits[PF_LIMIT_STATES].limit);
325
326 RB_INIT(&tree_lan_ext);
327 RB_INIT(&tree_ext_gwy);
328 TAILQ_INIT(&pf_anchors);
329 pf_init_ruleset(&pf_main_ruleset);
330 TAILQ_INIT(&pf_altqs[0]);
331 TAILQ_INIT(&pf_altqs[1]);
332 TAILQ_INIT(&pf_pabuf);
333 pf_altqs_active = &pf_altqs[0];
334 pf_altqs_inactive = &pf_altqs[1];
335
336 /* default rule should never be garbage collected */
337 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
338 pf_default_rule.action = PF_PASS;
339 pf_default_rule.nr = -1;
340
341 /* initialize default timeouts */
342 my_timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */
343 my_timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
344 my_timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */
345 my_timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */
346 my_timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */
347 my_timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */
348 my_timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */
349 my_timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */
350 my_timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */
351 my_timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */
352 my_timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */
353 my_timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */
354 my_timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */
355 my_timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */
356 my_timeout[PFTM_FRAG] = 30; /* Fragment expire */
357 my_timeout[PFTM_INTERVAL] = 10; /* Expire interval */
358
359 /*
360 * XXX
361 * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE
362 * if Gaint lock is removed from the network stack.
363 */
364 callout_init(&pf_expire_to, 0);
365 callout_reset(&pf_expire_to, my_timeout[PFTM_INTERVAL] * hz,
366 pf_purge_timeout, &pf_expire_to);
367
368 pf_normalize_init();
369 pf_status.debug = PF_DEBUG_URGENT;
370 pf_pfil_hooked = 0;
371 return (error);
372}
373#else /* !__FreeBSD__ */
374void
93pfattach(int num)
94{
95 u_int32_t *timeout = pf_default_rule.timeout;
96
97 pool_init(&pf_tree_pl, sizeof(struct pf_tree_node), 0, 0, 0, "pftrpl",
98 NULL);
99 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl",
100 &pool_allocator_nointr);
101 pool_init(&pf_addr_pl, sizeof(struct pf_addr_dyn), 0, 0, 0, "pfaddrpl",
102 &pool_allocator_nointr);
103 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
104 NULL);
105 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl",
106 NULL);
107 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
108 "pfpooladdrpl", NULL);
109 pfr_initialize();
110 pf_osfp_initialize();
111
112 pool_sethardlimit(&pf_state_pl, pf_pool_limits[PF_LIMIT_STATES].limit,
113 NULL, 0);
114
115 RB_INIT(&tree_lan_ext);
116 RB_INIT(&tree_ext_gwy);
117 TAILQ_INIT(&pf_anchors);
118 pf_init_ruleset(&pf_main_ruleset);
119 TAILQ_INIT(&pf_altqs[0]);
120 TAILQ_INIT(&pf_altqs[1]);
121 TAILQ_INIT(&pf_pabuf);
122 pf_altqs_active = &pf_altqs[0];
123 pf_altqs_inactive = &pf_altqs[1];
124
125 /* default rule should never be garbage collected */
126 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
127 pf_default_rule.action = PF_PASS;
128 pf_default_rule.nr = -1;
129
130 /* initialize default timeouts */
131 timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */
375pfattach(int num)
376{
377 u_int32_t *timeout = pf_default_rule.timeout;
378
379 pool_init(&pf_tree_pl, sizeof(struct pf_tree_node), 0, 0, 0, "pftrpl",
380 NULL);
381 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl",
382 &pool_allocator_nointr);
383 pool_init(&pf_addr_pl, sizeof(struct pf_addr_dyn), 0, 0, 0, "pfaddrpl",
384 &pool_allocator_nointr);
385 pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
386 NULL);
387 pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl",
388 NULL);
389 pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
390 "pfpooladdrpl", NULL);
391 pfr_initialize();
392 pf_osfp_initialize();
393
394 pool_sethardlimit(&pf_state_pl, pf_pool_limits[PF_LIMIT_STATES].limit,
395 NULL, 0);
396
397 RB_INIT(&tree_lan_ext);
398 RB_INIT(&tree_ext_gwy);
399 TAILQ_INIT(&pf_anchors);
400 pf_init_ruleset(&pf_main_ruleset);
401 TAILQ_INIT(&pf_altqs[0]);
402 TAILQ_INIT(&pf_altqs[1]);
403 TAILQ_INIT(&pf_pabuf);
404 pf_altqs_active = &pf_altqs[0];
405 pf_altqs_inactive = &pf_altqs[1];
406
407 /* default rule should never be garbage collected */
408 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
409 pf_default_rule.action = PF_PASS;
410 pf_default_rule.nr = -1;
411
412 /* initialize default timeouts */
413 timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */
132 timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
414 timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
133 timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */
134 timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */
135 timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */
136 timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */
137 timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */
138 timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */
139 timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */
140 timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */
141 timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */
142 timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */
143 timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */
144 timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */
145 timeout[PFTM_FRAG] = 30; /* Fragment expire */
146 timeout[PFTM_INTERVAL] = 10; /* Expire interval */
147
148 timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
149 timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
150
151 pf_normalize_init();
152 pf_status.debug = PF_DEBUG_URGENT;
153}
415 timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */
416 timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */
417 timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */
418 timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */
419 timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */
420 timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */
421 timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */
422 timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */
423 timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */
424 timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */
425 timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */
426 timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */
427 timeout[PFTM_FRAG] = 30; /* Fragment expire */
428 timeout[PFTM_INTERVAL] = 10; /* Expire interval */
429
430 timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
431 timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
432
433 pf_normalize_init();
434 pf_status.debug = PF_DEBUG_URGENT;
435}
436#endif /* __FreeBSD__ */
154
437
438#if !defined(__FreeBSD__)
155int
156pfopen(dev_t dev, int flags, int fmt, struct proc *p)
157{
158 if (minor(dev) >= 1)
159 return (ENXIO);
160 return (0);
161}
439int
440pfopen(dev_t dev, int flags, int fmt, struct proc *p)
441{
442 if (minor(dev) >= 1)
443 return (ENXIO);
444 return (0);
445}
446#endif
162
447
448#if !defined(__FreeBSD__)
163int
164pfclose(dev_t dev, int flags, int fmt, struct proc *p)
165{
166 if (minor(dev) >= 1)
167 return (ENXIO);
168 return (0);
169}
449int
450pfclose(dev_t dev, int flags, int fmt, struct proc *p)
451{
452 if (minor(dev) >= 1)
453 return (ENXIO);
454 return (0);
455}
456#endif
170
171struct pf_pool *
172pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket,
173 u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last,
174 u_int8_t active, u_int8_t check_ticket)
175{
176 struct pf_ruleset *ruleset;
177 struct pf_rule *rule;
178 int rs_num;
179
180 ruleset = pf_find_ruleset(anchorname, rulesetname);
181 if (ruleset == NULL)
182 return (NULL);
183 rs_num = pf_get_ruleset_number(rule_action);
184 if (rs_num >= PF_RULESET_MAX)
185 return (NULL);
186 if (active) {
187 if (check_ticket && ticket !=
188 ruleset->rules[rs_num].active.ticket)
189 return (NULL);
190 if (r_last)
191 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
192 pf_rulequeue);
193 else
194 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
195 } else {
196 if (check_ticket && ticket !=
197 ruleset->rules[rs_num].inactive.ticket)
198 return (NULL);
199 if (r_last)
200 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
201 pf_rulequeue);
202 else
203 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
204 }
205 if (!r_last) {
206 while ((rule != NULL) && (rule->nr != rule_number))
207 rule = TAILQ_NEXT(rule, entries);
208 }
209 if (rule == NULL)
210 return (NULL);
211
212 return (&rule->rpool);
213}
214
215int
216pf_get_ruleset_number(u_int8_t action)
217{
218 switch (action) {
219 case PF_SCRUB:
220 return (PF_RULESET_SCRUB);
221 break;
222 case PF_PASS:
223 case PF_DROP:
224 return (PF_RULESET_FILTER);
225 break;
226 case PF_NAT:
227 case PF_NONAT:
228 return (PF_RULESET_NAT);
229 break;
230 case PF_BINAT:
231 case PF_NOBINAT:
232 return (PF_RULESET_BINAT);
233 break;
234 case PF_RDR:
235 case PF_NORDR:
236 return (PF_RULESET_RDR);
237 break;
238 default:
239 return (PF_RULESET_MAX);
240 break;
241 }
242}
243
244void
245pf_init_ruleset(struct pf_ruleset *ruleset)
246{
247 int i;
248
249 memset(ruleset, 0, sizeof(struct pf_ruleset));
250 for (i = 0; i < PF_RULESET_MAX; i++) {
251 TAILQ_INIT(&ruleset->rules[i].queues[0]);
252 TAILQ_INIT(&ruleset->rules[i].queues[1]);
253 ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
254 ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
255 }
256}
257
258struct pf_anchor *
259pf_find_anchor(const char *anchorname)
260{
261 struct pf_anchor *anchor;
262 int n = -1;
263
264 anchor = TAILQ_FIRST(&pf_anchors);
265 while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0)
266 anchor = TAILQ_NEXT(anchor, entries);
267 if (n == 0)
268 return (anchor);
269 else
270 return (NULL);
271}
272
273struct pf_ruleset *
274pf_find_ruleset(char *anchorname, char *rulesetname)
275{
276 struct pf_anchor *anchor;
277 struct pf_ruleset *ruleset;
278
279 if (!anchorname[0] && !rulesetname[0])
280 return (&pf_main_ruleset);
281 if (!anchorname[0] || !rulesetname[0])
282 return (NULL);
283 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
284 rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
285 anchor = pf_find_anchor(anchorname);
286 if (anchor == NULL)
287 return (NULL);
288 ruleset = TAILQ_FIRST(&anchor->rulesets);
289 while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0)
290 ruleset = TAILQ_NEXT(ruleset, entries);
291 if (ruleset != NULL && !strcmp(ruleset->name, rulesetname))
292 return (ruleset);
293 else
294 return (NULL);
295}
296
297struct pf_ruleset *
298pf_find_or_create_ruleset(char *anchorname, char *rulesetname)
299{
300 struct pf_anchor *anchor, *a;
301 struct pf_ruleset *ruleset, *r;
302
303 if (!anchorname[0] && !rulesetname[0])
304 return (&pf_main_ruleset);
305 if (!anchorname[0] || !rulesetname[0])
306 return (NULL);
307 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
308 rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
309 a = TAILQ_FIRST(&pf_anchors);
310 while (a != NULL && strcmp(a->name, anchorname) < 0)
311 a = TAILQ_NEXT(a, entries);
312 if (a != NULL && !strcmp(a->name, anchorname))
313 anchor = a;
314 else {
315 anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor),
316 M_TEMP, M_NOWAIT);
317 if (anchor == NULL)
318 return (NULL);
319 memset(anchor, 0, sizeof(struct pf_anchor));
320 bcopy(anchorname, anchor->name, sizeof(anchor->name));
321 TAILQ_INIT(&anchor->rulesets);
322 if (a != NULL)
323 TAILQ_INSERT_BEFORE(a, anchor, entries);
324 else
325 TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries);
326 }
327 r = TAILQ_FIRST(&anchor->rulesets);
328 while (r != NULL && strcmp(r->name, rulesetname) < 0)
329 r = TAILQ_NEXT(r, entries);
330 if (r != NULL && !strcmp(r->name, rulesetname))
331 return (r);
332 ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset),
333 M_TEMP, M_NOWAIT);
334 if (ruleset != NULL) {
335 pf_init_ruleset(ruleset);
336 bcopy(rulesetname, ruleset->name, sizeof(ruleset->name));
337 ruleset->anchor = anchor;
338 if (r != NULL)
339 TAILQ_INSERT_BEFORE(r, ruleset, entries);
340 else
341 TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries);
342 }
343 return (ruleset);
344}
345
346void
347pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
348{
349 struct pf_anchor *anchor;
350 int i;
351
457
458struct pf_pool *
459pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket,
460 u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last,
461 u_int8_t active, u_int8_t check_ticket)
462{
463 struct pf_ruleset *ruleset;
464 struct pf_rule *rule;
465 int rs_num;
466
467 ruleset = pf_find_ruleset(anchorname, rulesetname);
468 if (ruleset == NULL)
469 return (NULL);
470 rs_num = pf_get_ruleset_number(rule_action);
471 if (rs_num >= PF_RULESET_MAX)
472 return (NULL);
473 if (active) {
474 if (check_ticket && ticket !=
475 ruleset->rules[rs_num].active.ticket)
476 return (NULL);
477 if (r_last)
478 rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
479 pf_rulequeue);
480 else
481 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
482 } else {
483 if (check_ticket && ticket !=
484 ruleset->rules[rs_num].inactive.ticket)
485 return (NULL);
486 if (r_last)
487 rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
488 pf_rulequeue);
489 else
490 rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
491 }
492 if (!r_last) {
493 while ((rule != NULL) && (rule->nr != rule_number))
494 rule = TAILQ_NEXT(rule, entries);
495 }
496 if (rule == NULL)
497 return (NULL);
498
499 return (&rule->rpool);
500}
501
502int
503pf_get_ruleset_number(u_int8_t action)
504{
505 switch (action) {
506 case PF_SCRUB:
507 return (PF_RULESET_SCRUB);
508 break;
509 case PF_PASS:
510 case PF_DROP:
511 return (PF_RULESET_FILTER);
512 break;
513 case PF_NAT:
514 case PF_NONAT:
515 return (PF_RULESET_NAT);
516 break;
517 case PF_BINAT:
518 case PF_NOBINAT:
519 return (PF_RULESET_BINAT);
520 break;
521 case PF_RDR:
522 case PF_NORDR:
523 return (PF_RULESET_RDR);
524 break;
525 default:
526 return (PF_RULESET_MAX);
527 break;
528 }
529}
530
531void
532pf_init_ruleset(struct pf_ruleset *ruleset)
533{
534 int i;
535
536 memset(ruleset, 0, sizeof(struct pf_ruleset));
537 for (i = 0; i < PF_RULESET_MAX; i++) {
538 TAILQ_INIT(&ruleset->rules[i].queues[0]);
539 TAILQ_INIT(&ruleset->rules[i].queues[1]);
540 ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
541 ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
542 }
543}
544
545struct pf_anchor *
546pf_find_anchor(const char *anchorname)
547{
548 struct pf_anchor *anchor;
549 int n = -1;
550
551 anchor = TAILQ_FIRST(&pf_anchors);
552 while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0)
553 anchor = TAILQ_NEXT(anchor, entries);
554 if (n == 0)
555 return (anchor);
556 else
557 return (NULL);
558}
559
560struct pf_ruleset *
561pf_find_ruleset(char *anchorname, char *rulesetname)
562{
563 struct pf_anchor *anchor;
564 struct pf_ruleset *ruleset;
565
566 if (!anchorname[0] && !rulesetname[0])
567 return (&pf_main_ruleset);
568 if (!anchorname[0] || !rulesetname[0])
569 return (NULL);
570 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
571 rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
572 anchor = pf_find_anchor(anchorname);
573 if (anchor == NULL)
574 return (NULL);
575 ruleset = TAILQ_FIRST(&anchor->rulesets);
576 while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0)
577 ruleset = TAILQ_NEXT(ruleset, entries);
578 if (ruleset != NULL && !strcmp(ruleset->name, rulesetname))
579 return (ruleset);
580 else
581 return (NULL);
582}
583
584struct pf_ruleset *
585pf_find_or_create_ruleset(char *anchorname, char *rulesetname)
586{
587 struct pf_anchor *anchor, *a;
588 struct pf_ruleset *ruleset, *r;
589
590 if (!anchorname[0] && !rulesetname[0])
591 return (&pf_main_ruleset);
592 if (!anchorname[0] || !rulesetname[0])
593 return (NULL);
594 anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
595 rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
596 a = TAILQ_FIRST(&pf_anchors);
597 while (a != NULL && strcmp(a->name, anchorname) < 0)
598 a = TAILQ_NEXT(a, entries);
599 if (a != NULL && !strcmp(a->name, anchorname))
600 anchor = a;
601 else {
602 anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor),
603 M_TEMP, M_NOWAIT);
604 if (anchor == NULL)
605 return (NULL);
606 memset(anchor, 0, sizeof(struct pf_anchor));
607 bcopy(anchorname, anchor->name, sizeof(anchor->name));
608 TAILQ_INIT(&anchor->rulesets);
609 if (a != NULL)
610 TAILQ_INSERT_BEFORE(a, anchor, entries);
611 else
612 TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries);
613 }
614 r = TAILQ_FIRST(&anchor->rulesets);
615 while (r != NULL && strcmp(r->name, rulesetname) < 0)
616 r = TAILQ_NEXT(r, entries);
617 if (r != NULL && !strcmp(r->name, rulesetname))
618 return (r);
619 ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset),
620 M_TEMP, M_NOWAIT);
621 if (ruleset != NULL) {
622 pf_init_ruleset(ruleset);
623 bcopy(rulesetname, ruleset->name, sizeof(ruleset->name));
624 ruleset->anchor = anchor;
625 if (r != NULL)
626 TAILQ_INSERT_BEFORE(r, ruleset, entries);
627 else
628 TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries);
629 }
630 return (ruleset);
631}
632
633void
634pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
635{
636 struct pf_anchor *anchor;
637 int i;
638
352 if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 || ruleset->topen)
639 if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 ||
640 ruleset->topen)
353 return;
354 for (i = 0; i < PF_RULESET_MAX; ++i)
355 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
356 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr))
357 return;
358
359 anchor = ruleset->anchor;
360 TAILQ_REMOVE(&anchor->rulesets, ruleset, entries);
361 free(ruleset, M_TEMP);
362
363 if (TAILQ_EMPTY(&anchor->rulesets)) {
364 TAILQ_REMOVE(&pf_anchors, anchor, entries);
365 free(anchor, M_TEMP);
366 }
367}
368
369void
370pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
371{
372 struct pf_pooladdr *mv_pool_pa;
373
374 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
375 TAILQ_REMOVE(poola, mv_pool_pa, entries);
376 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
377 }
378}
379
380void
381pf_empty_pool(struct pf_palist *poola)
382{
383 struct pf_pooladdr *empty_pool_pa;
384
385 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
386 pf_dynaddr_remove(&empty_pool_pa->addr);
387 pf_tbladdr_remove(&empty_pool_pa->addr);
388 TAILQ_REMOVE(poola, empty_pool_pa, entries);
389 pool_put(&pf_pooladdr_pl, empty_pool_pa);
390 }
391}
392
393void
394pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
395{
396 if (rulequeue != NULL) {
397 if (rule->states <= 0) {
398 /*
399 * XXX - we need to remove the table *before* detaching
400 * the rule to make sure the table code does not delete
401 * the anchor under our feet.
402 */
403 pf_tbladdr_remove(&rule->src.addr);
404 pf_tbladdr_remove(&rule->dst.addr);
405 }
406 TAILQ_REMOVE(rulequeue, rule, entries);
407 rule->entries.tqe_prev = NULL;
408 rule->nr = -1;
409 }
410 if (rule->states > 0 || rule->entries.tqe_prev != NULL)
411 return;
412 pf_tag_unref(rule->tag);
413 pf_tag_unref(rule->match_tag);
414 pf_dynaddr_remove(&rule->src.addr);
415 pf_dynaddr_remove(&rule->dst.addr);
416 if (rulequeue == NULL) {
417 pf_tbladdr_remove(&rule->src.addr);
418 pf_tbladdr_remove(&rule->dst.addr);
419 }
420 pf_empty_pool(&rule->rpool.list);
421 pool_put(&pf_rule_pl, rule);
422}
423
424u_int16_t
425pf_tagname2tag(char *tagname)
426{
427 struct pf_tagname *tag, *p = NULL;
428 u_int16_t new_tagid = 1;
429
430 TAILQ_FOREACH(tag, &pf_tags, entries)
431 if (strcmp(tagname, tag->name) == 0) {
432 tag->ref++;
433 return (tag->tag);
434 }
435
436 /*
437 * to avoid fragmentation, we do a linear search from the beginning
438 * and take the first free slot we find. if there is none or the list
439 * is empty, append a new entry at the end.
440 */
441
442 /* new entry */
443 if (!TAILQ_EMPTY(&pf_tags))
444 for (p = TAILQ_FIRST(&pf_tags); p != NULL &&
445 p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
446 new_tagid = p->tag + 1;
447
448 if (new_tagid > TAGID_MAX)
449 return (0);
450
451 /* allocate and fill new struct pf_tagname */
452 tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname),
453 M_TEMP, M_NOWAIT);
454 if (tag == NULL)
455 return (0);
456 bzero(tag, sizeof(struct pf_tagname));
457 strlcpy(tag->name, tagname, sizeof(tag->name));
458 tag->tag = new_tagid;
459 tag->ref++;
460
461 if (p != NULL) /* insert new entry before p */
462 TAILQ_INSERT_BEFORE(p, tag, entries);
463 else /* either list empty or no free slot in between */
464 TAILQ_INSERT_TAIL(&pf_tags, tag, entries);
465
466 return (tag->tag);
467}
468
469void
470pf_tag2tagname(u_int16_t tagid, char *p)
471{
472 struct pf_tagname *tag;
473
474 TAILQ_FOREACH(tag, &pf_tags, entries)
475 if (tag->tag == tagid) {
476 strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
477 return;
478 }
479}
480
481void
482pf_tag_unref(u_int16_t tag)
483{
484 struct pf_tagname *p, *next;
485
486 if (tag == 0)
487 return;
488
489 for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) {
490 next = TAILQ_NEXT(p, entries);
491 if (tag == p->tag) {
492 if (--p->ref == 0) {
493 TAILQ_REMOVE(&pf_tags, p, entries);
494 free(p, M_TEMP);
495 }
496 break;
497 }
498 }
499}
500
641 return;
642 for (i = 0; i < PF_RULESET_MAX; ++i)
643 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
644 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr))
645 return;
646
647 anchor = ruleset->anchor;
648 TAILQ_REMOVE(&anchor->rulesets, ruleset, entries);
649 free(ruleset, M_TEMP);
650
651 if (TAILQ_EMPTY(&anchor->rulesets)) {
652 TAILQ_REMOVE(&pf_anchors, anchor, entries);
653 free(anchor, M_TEMP);
654 }
655}
656
657void
658pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
659{
660 struct pf_pooladdr *mv_pool_pa;
661
662 while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
663 TAILQ_REMOVE(poola, mv_pool_pa, entries);
664 TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
665 }
666}
667
668void
669pf_empty_pool(struct pf_palist *poola)
670{
671 struct pf_pooladdr *empty_pool_pa;
672
673 while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
674 pf_dynaddr_remove(&empty_pool_pa->addr);
675 pf_tbladdr_remove(&empty_pool_pa->addr);
676 TAILQ_REMOVE(poola, empty_pool_pa, entries);
677 pool_put(&pf_pooladdr_pl, empty_pool_pa);
678 }
679}
680
681void
682pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
683{
684 if (rulequeue != NULL) {
685 if (rule->states <= 0) {
686 /*
687 * XXX - we need to remove the table *before* detaching
688 * the rule to make sure the table code does not delete
689 * the anchor under our feet.
690 */
691 pf_tbladdr_remove(&rule->src.addr);
692 pf_tbladdr_remove(&rule->dst.addr);
693 }
694 TAILQ_REMOVE(rulequeue, rule, entries);
695 rule->entries.tqe_prev = NULL;
696 rule->nr = -1;
697 }
698 if (rule->states > 0 || rule->entries.tqe_prev != NULL)
699 return;
700 pf_tag_unref(rule->tag);
701 pf_tag_unref(rule->match_tag);
702 pf_dynaddr_remove(&rule->src.addr);
703 pf_dynaddr_remove(&rule->dst.addr);
704 if (rulequeue == NULL) {
705 pf_tbladdr_remove(&rule->src.addr);
706 pf_tbladdr_remove(&rule->dst.addr);
707 }
708 pf_empty_pool(&rule->rpool.list);
709 pool_put(&pf_rule_pl, rule);
710}
711
712u_int16_t
713pf_tagname2tag(char *tagname)
714{
715 struct pf_tagname *tag, *p = NULL;
716 u_int16_t new_tagid = 1;
717
718 TAILQ_FOREACH(tag, &pf_tags, entries)
719 if (strcmp(tagname, tag->name) == 0) {
720 tag->ref++;
721 return (tag->tag);
722 }
723
724 /*
725 * to avoid fragmentation, we do a linear search from the beginning
726 * and take the first free slot we find. if there is none or the list
727 * is empty, append a new entry at the end.
728 */
729
730 /* new entry */
731 if (!TAILQ_EMPTY(&pf_tags))
732 for (p = TAILQ_FIRST(&pf_tags); p != NULL &&
733 p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
734 new_tagid = p->tag + 1;
735
736 if (new_tagid > TAGID_MAX)
737 return (0);
738
739 /* allocate and fill new struct pf_tagname */
740 tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname),
741 M_TEMP, M_NOWAIT);
742 if (tag == NULL)
743 return (0);
744 bzero(tag, sizeof(struct pf_tagname));
745 strlcpy(tag->name, tagname, sizeof(tag->name));
746 tag->tag = new_tagid;
747 tag->ref++;
748
749 if (p != NULL) /* insert new entry before p */
750 TAILQ_INSERT_BEFORE(p, tag, entries);
751 else /* either list empty or no free slot in between */
752 TAILQ_INSERT_TAIL(&pf_tags, tag, entries);
753
754 return (tag->tag);
755}
756
757void
758pf_tag2tagname(u_int16_t tagid, char *p)
759{
760 struct pf_tagname *tag;
761
762 TAILQ_FOREACH(tag, &pf_tags, entries)
763 if (tag->tag == tagid) {
764 strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
765 return;
766 }
767}
768
769void
770pf_tag_unref(u_int16_t tag)
771{
772 struct pf_tagname *p, *next;
773
774 if (tag == 0)
775 return;
776
777 for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) {
778 next = TAILQ_NEXT(p, entries);
779 if (tag == p->tag) {
780 if (--p->ref == 0) {
781 TAILQ_REMOVE(&pf_tags, p, entries);
782 free(p, M_TEMP);
783 }
784 break;
785 }
786 }
787}
788
789#if defined(__FreeBSD__)
501int
790int
791pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
792#else
793int
502pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
794pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
795#endif
503{
504 struct pf_pooladdr *pa = NULL;
505 struct pf_pool *pool = NULL;
506 int s;
507 int error = 0;
508
509 /* XXX keep in sync with switch() below */
510 if (securelevel > 1)
511 switch (cmd) {
512 case DIOCGETRULES:
513 case DIOCGETRULE:
514 case DIOCGETADDRS:
515 case DIOCGETADDR:
516 case DIOCGETSTATE:
517 case DIOCSETSTATUSIF:
518 case DIOCGETSTATUS:
519 case DIOCCLRSTATUS:
520 case DIOCNATLOOK:
521 case DIOCSETDEBUG:
522 case DIOCGETSTATES:
523 case DIOCGETTIMEOUT:
524 case DIOCCLRRULECTRS:
525 case DIOCGETLIMIT:
526 case DIOCGETALTQS:
527 case DIOCGETALTQ:
528 case DIOCGETQSTATS:
529 case DIOCGETANCHORS:
530 case DIOCGETANCHOR:
531 case DIOCGETRULESETS:
532 case DIOCGETRULESET:
533 case DIOCRGETTABLES:
534 case DIOCRGETTSTATS:
535 case DIOCRCLRTSTATS:
536 case DIOCRCLRADDRS:
537 case DIOCRADDADDRS:
538 case DIOCRDELADDRS:
539 case DIOCRSETADDRS:
540 case DIOCRGETADDRS:
541 case DIOCRGETASTATS:
542 case DIOCRCLRASTATS:
543 case DIOCRTSTADDRS:
544 case DIOCOSFPGET:
796{
797 struct pf_pooladdr *pa = NULL;
798 struct pf_pool *pool = NULL;
799 int s;
800 int error = 0;
801
802 /* XXX keep in sync with switch() below */
803 if (securelevel > 1)
804 switch (cmd) {
805 case DIOCGETRULES:
806 case DIOCGETRULE:
807 case DIOCGETADDRS:
808 case DIOCGETADDR:
809 case DIOCGETSTATE:
810 case DIOCSETSTATUSIF:
811 case DIOCGETSTATUS:
812 case DIOCCLRSTATUS:
813 case DIOCNATLOOK:
814 case DIOCSETDEBUG:
815 case DIOCGETSTATES:
816 case DIOCGETTIMEOUT:
817 case DIOCCLRRULECTRS:
818 case DIOCGETLIMIT:
819 case DIOCGETALTQS:
820 case DIOCGETALTQ:
821 case DIOCGETQSTATS:
822 case DIOCGETANCHORS:
823 case DIOCGETANCHOR:
824 case DIOCGETRULESETS:
825 case DIOCGETRULESET:
826 case DIOCRGETTABLES:
827 case DIOCRGETTSTATS:
828 case DIOCRCLRTSTATS:
829 case DIOCRCLRADDRS:
830 case DIOCRADDADDRS:
831 case DIOCRDELADDRS:
832 case DIOCRSETADDRS:
833 case DIOCRGETADDRS:
834 case DIOCRGETASTATS:
835 case DIOCRCLRASTATS:
836 case DIOCRTSTADDRS:
837 case DIOCOSFPGET:
838#if defined(__FreeBSD__)
839 case DIOCGIFSPEED:
840#endif
545 break;
546 default:
547 return (EPERM);
548 }
549
550 if (!(flags & FWRITE))
551 switch (cmd) {
552 case DIOCGETRULES:
553 case DIOCGETRULE:
554 case DIOCGETADDRS:
555 case DIOCGETADDR:
556 case DIOCGETSTATE:
557 case DIOCGETSTATUS:
558 case DIOCGETSTATES:
559 case DIOCGETTIMEOUT:
560 case DIOCGETLIMIT:
561 case DIOCGETALTQS:
562 case DIOCGETALTQ:
563 case DIOCGETQSTATS:
564 case DIOCGETANCHORS:
565 case DIOCGETANCHOR:
566 case DIOCGETRULESETS:
567 case DIOCGETRULESET:
568 case DIOCRGETTABLES:
569 case DIOCRGETTSTATS:
570 case DIOCRGETADDRS:
571 case DIOCRGETASTATS:
572 case DIOCRTSTADDRS:
573 case DIOCOSFPGET:
841 break;
842 default:
843 return (EPERM);
844 }
845
846 if (!(flags & FWRITE))
847 switch (cmd) {
848 case DIOCGETRULES:
849 case DIOCGETRULE:
850 case DIOCGETADDRS:
851 case DIOCGETADDR:
852 case DIOCGETSTATE:
853 case DIOCGETSTATUS:
854 case DIOCGETSTATES:
855 case DIOCGETTIMEOUT:
856 case DIOCGETLIMIT:
857 case DIOCGETALTQS:
858 case DIOCGETALTQ:
859 case DIOCGETQSTATS:
860 case DIOCGETANCHORS:
861 case DIOCGETANCHOR:
862 case DIOCGETRULESETS:
863 case DIOCGETRULESET:
864 case DIOCRGETTABLES:
865 case DIOCRGETTSTATS:
866 case DIOCRGETADDRS:
867 case DIOCRGETASTATS:
868 case DIOCRTSTADDRS:
869 case DIOCOSFPGET:
870#if defined(__FreeBSD__)
871 case DIOCGIFSPEED:
872#endif
574 break;
575 default:
576 return (EACCES);
577 }
578
873 break;
874 default:
875 return (EACCES);
876 }
877
878#if defined(__FreeBSD__)
879 PF_LOCK();
880#endif
881
579 switch (cmd) {
580
581 case DIOCSTART:
582 if (pf_status.running)
583 error = EEXIST;
584 else {
585 u_int32_t states = pf_status.states;
882 switch (cmd) {
883
884 case DIOCSTART:
885 if (pf_status.running)
886 error = EEXIST;
887 else {
888 u_int32_t states = pf_status.states;
889#if defined(__FreeBSD__)
890 PF_UNLOCK();
891 error = hook_pf();
892 PF_LOCK();
893 if (error) {
894 DPFPRINTF(PF_DEBUG_MISC,
895 ("pf: pfil registeration fail\n"));
896 break;
897 }
898#endif
586 bzero(&pf_status, sizeof(struct pf_status));
587 pf_status.running = 1;
588 pf_status.states = states;
899 bzero(&pf_status, sizeof(struct pf_status));
900 pf_status.running = 1;
901 pf_status.states = states;
902#if defined(__FreeBSD__)
903 pf_status.since = time_second;
904#else
589 pf_status.since = time.tv_sec;
905 pf_status.since = time.tv_sec;
906#endif
590 if (status_ifp != NULL)
907 if (status_ifp != NULL)
908#if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
909 snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
910 status_ifp->if_name, status_ifp->if_unit);
911#else
591 strlcpy(pf_status.ifname,
592 status_ifp->if_xname, IFNAMSIZ);
912 strlcpy(pf_status.ifname,
913 status_ifp->if_xname, IFNAMSIZ);
914#endif
593 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
594 }
595 break;
596
597 case DIOCSTOP:
598 if (!pf_status.running)
599 error = ENOENT;
600 else {
601 pf_status.running = 0;
915 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
916 }
917 break;
918
919 case DIOCSTOP:
920 if (!pf_status.running)
921 error = ENOENT;
922 else {
923 pf_status.running = 0;
924#if defined(__FreeBSD__)
925 PF_UNLOCK();
926 error = dehook_pf();
927 PF_LOCK();
928 if (error) {
929 pf_status.running = 1;
930 DPFPRINTF(PF_DEBUG_MISC,
931 ("pf: pfil unregisteration failed\n"));
932 }
933#endif
602 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
603 }
604 break;
605
606 case DIOCBEGINRULES: {
607 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
608 struct pf_ruleset *ruleset;
609 struct pf_rule *rule;
610 int rs_num;
611
612 ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
613 if (ruleset == NULL) {
614 error = EINVAL;
615 break;
616 }
617 rs_num = pf_get_ruleset_number(pr->rule.action);
618 if (rs_num >= PF_RULESET_MAX) {
619 error = EINVAL;
620 break;
621 }
622 while ((rule =
623 TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
624 pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
625 pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
626 break;
627 }
628
629 case DIOCADDRULE: {
630 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
631 struct pf_ruleset *ruleset;
632 struct pf_rule *rule, *tail;
633 struct pf_pooladdr *pa;
634 int rs_num;
635
636 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
637 if (ruleset == NULL) {
638 error = EINVAL;
639 break;
640 }
641 rs_num = pf_get_ruleset_number(pr->rule.action);
642 if (rs_num >= PF_RULESET_MAX) {
643 error = EINVAL;
644 break;
645 }
646 if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) {
647 error = EINVAL;
648 break;
649 }
650 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
651 error = EINVAL;
652 break;
653 }
654 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
655 error = EBUSY;
656 break;
657 }
658 if (pr->pool_ticket != ticket_pabuf) {
659 error = EBUSY;
660 break;
661 }
662 rule = pool_get(&pf_rule_pl, PR_NOWAIT);
663 if (rule == NULL) {
664 error = ENOMEM;
665 break;
666 }
667 bcopy(&pr->rule, rule, sizeof(struct pf_rule));
668 rule->anchor = NULL;
669 rule->ifp = NULL;
670 TAILQ_INIT(&rule->rpool.list);
671 /* initialize refcounting */
672 rule->states = 0;
673 rule->entries.tqe_prev = NULL;
674#ifndef INET
675 if (rule->af == AF_INET) {
676 pool_put(&pf_rule_pl, rule);
677 error = EAFNOSUPPORT;
678 break;
679 }
680#endif /* INET */
681#ifndef INET6
682 if (rule->af == AF_INET6) {
683 pool_put(&pf_rule_pl, rule);
684 error = EAFNOSUPPORT;
685 break;
686 }
687#endif /* INET6 */
688 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
689 pf_rulequeue);
690 if (tail)
691 rule->nr = tail->nr + 1;
692 else
693 rule->nr = 0;
694 if (rule->ifname[0]) {
695 rule->ifp = ifunit(rule->ifname);
696 if (rule->ifp == NULL) {
697 pool_put(&pf_rule_pl, rule);
698 error = EINVAL;
699 break;
700 }
701 }
702
703 if (rule->tagname[0])
704 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
705 error = EBUSY;
706 if (rule->match_tagname[0])
707 if ((rule->match_tag =
708 pf_tagname2tag(rule->match_tagname)) == 0)
709 error = EBUSY;
710 if (rule->rt && !rule->direction)
711 error = EINVAL;
712 if (pf_dynaddr_setup(&rule->src.addr, rule->af))
713 error = EINVAL;
714 if (pf_dynaddr_setup(&rule->dst.addr, rule->af))
715 error = EINVAL;
716 if (pf_tbladdr_setup(ruleset, &rule->src.addr))
717 error = EINVAL;
718 if (pf_tbladdr_setup(ruleset, &rule->dst.addr))
719 error = EINVAL;
720 TAILQ_FOREACH(pa, &pf_pabuf, entries)
721 if (pf_tbladdr_setup(ruleset, &pa->addr))
722 error = EINVAL;
723
724 pf_mv_pool(&pf_pabuf, &rule->rpool.list);
725 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
726 (rule->action == PF_BINAT)) && !rule->anchorname[0]) ||
727 (rule->rt > PF_FASTROUTE)) &&
728 (TAILQ_FIRST(&rule->rpool.list) == NULL))
729 error = EINVAL;
730
731 if (error) {
732 pf_rm_rule(NULL, rule);
733 break;
734 }
735 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
736 rule->evaluations = rule->packets = rule->bytes = 0;
737 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
738 rule, entries);
739 break;
740 }
741
742 case DIOCCOMMITRULES: {
743 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
744 struct pf_ruleset *ruleset;
745 struct pf_rulequeue *old_rules;
746 struct pf_rule *rule;
747 int rs_num;
748
749 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
750 if (ruleset == NULL) {
751 error = EINVAL;
752 break;
753 }
754 rs_num = pf_get_ruleset_number(pr->rule.action);
755 if (rs_num >= PF_RULESET_MAX) {
756 error = EINVAL;
757 break;
758 }
759 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
760 error = EBUSY;
761 break;
762 }
763
764#ifdef ALTQ
765 /* set queue IDs */
766 if (rs_num == PF_RULESET_FILTER)
767 pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
768#endif
769
770 /* Swap rules, keep the old. */
771 s = splsoftnet();
772 old_rules = ruleset->rules[rs_num].active.ptr;
773 ruleset->rules[rs_num].active.ptr =
774 ruleset->rules[rs_num].inactive.ptr;
775 ruleset->rules[rs_num].inactive.ptr = old_rules;
776 ruleset->rules[rs_num].active.ticket =
777 ruleset->rules[rs_num].inactive.ticket;
778 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
779
780 /* Purge the old rule list. */
781 while ((rule = TAILQ_FIRST(old_rules)) != NULL)
782 pf_rm_rule(old_rules, rule);
783 pf_remove_if_empty_ruleset(ruleset);
784 pf_update_anchor_rules();
785 splx(s);
786 break;
787 }
788
789 case DIOCGETRULES: {
790 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
791 struct pf_ruleset *ruleset;
792 struct pf_rule *tail;
793 int rs_num;
794
795 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
796 if (ruleset == NULL) {
797 error = EINVAL;
798 break;
799 }
800 rs_num = pf_get_ruleset_number(pr->rule.action);
801 if (rs_num >= PF_RULESET_MAX) {
802 error = EINVAL;
803 break;
804 }
805 s = splsoftnet();
806 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
807 pf_rulequeue);
808 if (tail)
809 pr->nr = tail->nr + 1;
810 else
811 pr->nr = 0;
812 pr->ticket = ruleset->rules[rs_num].active.ticket;
813 splx(s);
814 break;
815 }
816
817 case DIOCGETRULE: {
818 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
819 struct pf_ruleset *ruleset;
820 struct pf_rule *rule;
821 int rs_num, i;
822
823 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
824 if (ruleset == NULL) {
825 error = EINVAL;
826 break;
827 }
828 rs_num = pf_get_ruleset_number(pr->rule.action);
829 if (rs_num >= PF_RULESET_MAX) {
830 error = EINVAL;
831 break;
832 }
833 if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
834 error = EBUSY;
835 break;
836 }
837 s = splsoftnet();
838 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
839 while ((rule != NULL) && (rule->nr != pr->nr))
840 rule = TAILQ_NEXT(rule, entries);
841 if (rule == NULL) {
842 error = EBUSY;
843 splx(s);
844 break;
845 }
846 bcopy(rule, &pr->rule, sizeof(struct pf_rule));
847 pf_dynaddr_copyout(&pr->rule.src.addr);
848 pf_dynaddr_copyout(&pr->rule.dst.addr);
849 pf_tbladdr_copyout(&pr->rule.src.addr);
850 pf_tbladdr_copyout(&pr->rule.dst.addr);
851 for (i = 0; i < PF_SKIP_COUNT; ++i)
852 if (rule->skip[i].ptr == NULL)
853 pr->rule.skip[i].nr = -1;
854 else
855 pr->rule.skip[i].nr =
856 rule->skip[i].ptr->nr;
857 splx(s);
858 break;
859 }
860
861 case DIOCCHANGERULE: {
862 struct pfioc_rule *pcr = (struct pfioc_rule *)addr;
863 struct pf_ruleset *ruleset;
864 struct pf_rule *oldrule = NULL, *newrule = NULL;
865 u_int32_t nr = 0;
866 int rs_num;
867
868 if (!(pcr->action == PF_CHANGE_REMOVE ||
869 pcr->action == PF_CHANGE_GET_TICKET) &&
870 pcr->pool_ticket != ticket_pabuf) {
871 error = EBUSY;
872 break;
873 }
874
875 if (pcr->action < PF_CHANGE_ADD_HEAD ||
876 pcr->action > PF_CHANGE_GET_TICKET) {
877 error = EINVAL;
878 break;
879 }
880 ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset);
881 if (ruleset == NULL) {
882 error = EINVAL;
883 break;
884 }
885 rs_num = pf_get_ruleset_number(pcr->rule.action);
886 if (rs_num >= PF_RULESET_MAX) {
887 error = EINVAL;
888 break;
889 }
890
891 if (pcr->action == PF_CHANGE_GET_TICKET) {
892 pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
893 break;
894 } else {
895 if (pcr->ticket !=
896 ruleset->rules[rs_num].active.ticket) {
897 error = EINVAL;
898 break;
899 }
900 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
901 error = EINVAL;
902 break;
903 }
904 }
905
906 if (pcr->action != PF_CHANGE_REMOVE) {
907 newrule = pool_get(&pf_rule_pl, PR_NOWAIT);
908 if (newrule == NULL) {
909 error = ENOMEM;
910 break;
911 }
912 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
913 TAILQ_INIT(&newrule->rpool.list);
914 /* initialize refcounting */
915 newrule->states = 0;
916 newrule->entries.tqe_prev = NULL;
917#ifndef INET
918 if (newrule->af == AF_INET) {
919 pool_put(&pf_rule_pl, newrule);
920 error = EAFNOSUPPORT;
921 break;
922 }
923#endif /* INET */
924#ifndef INET6
925 if (newrule->af == AF_INET6) {
926 pool_put(&pf_rule_pl, newrule);
927 error = EAFNOSUPPORT;
928 break;
929 }
930#endif /* INET6 */
931 if (newrule->ifname[0]) {
932 newrule->ifp = ifunit(newrule->ifname);
933 if (newrule->ifp == NULL) {
934 pool_put(&pf_rule_pl, newrule);
935 error = EINVAL;
936 break;
937 }
938 } else
939 newrule->ifp = NULL;
940
941#ifdef ALTQ
942 /* set queue IDs */
943 if (newrule->qname[0] != 0) {
944 newrule->qid = pf_qname_to_qid(newrule->qname);
945 if (newrule->pqname[0] != 0)
946 newrule->pqid =
947 pf_qname_to_qid(newrule->pqname);
948 else
949 newrule->pqid = newrule->qid;
950 }
951#endif
952 if (newrule->tagname[0])
953 if ((newrule->tag =
954 pf_tagname2tag(newrule->tagname)) == 0)
955 error = EBUSY;
956 if (newrule->match_tagname[0])
957 if ((newrule->match_tag = pf_tagname2tag(
958 newrule->match_tagname)) == 0)
959 error = EBUSY;
960
961 if (newrule->rt && !newrule->direction)
962 error = EINVAL;
963 if (pf_dynaddr_setup(&newrule->src.addr, newrule->af))
964 error = EINVAL;
965 if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af))
966 error = EINVAL;
967 if (pf_tbladdr_setup(ruleset, &newrule->src.addr))
968 error = EINVAL;
969 if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))
970 error = EINVAL;
971
972 pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
973 if (((((newrule->action == PF_NAT) ||
974 (newrule->action == PF_RDR) ||
975 (newrule->action == PF_BINAT) ||
976 (newrule->rt > PF_FASTROUTE)) &&
977 !newrule->anchorname[0])) &&
978 (TAILQ_FIRST(&newrule->rpool.list) == NULL))
979 error = EINVAL;
980
981 if (error) {
982 pf_rm_rule(NULL, newrule);
983 break;
984 }
985 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
986 newrule->evaluations = newrule->packets = 0;
987 newrule->bytes = 0;
988 }
989 pf_empty_pool(&pf_pabuf);
990
991 s = splsoftnet();
992
993 if (pcr->action == PF_CHANGE_ADD_HEAD)
994 oldrule = TAILQ_FIRST(
995 ruleset->rules[rs_num].active.ptr);
996 else if (pcr->action == PF_CHANGE_ADD_TAIL)
997 oldrule = TAILQ_LAST(
998 ruleset->rules[rs_num].active.ptr, pf_rulequeue);
999 else {
1000 oldrule = TAILQ_FIRST(
1001 ruleset->rules[rs_num].active.ptr);
1002 while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
1003 oldrule = TAILQ_NEXT(oldrule, entries);
1004 if (oldrule == NULL) {
1005 pf_rm_rule(NULL, newrule);
1006 error = EINVAL;
1007 splx(s);
1008 break;
1009 }
1010 }
1011
1012 if (pcr->action == PF_CHANGE_REMOVE)
1013 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
1014 else {
1015 if (oldrule == NULL)
1016 TAILQ_INSERT_TAIL(
1017 ruleset->rules[rs_num].active.ptr,
1018 newrule, entries);
1019 else if (pcr->action == PF_CHANGE_ADD_HEAD ||
1020 pcr->action == PF_CHANGE_ADD_BEFORE)
1021 TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
1022 else
1023 TAILQ_INSERT_AFTER(
1024 ruleset->rules[rs_num].active.ptr,
1025 oldrule, newrule, entries);
1026 }
1027
1028 nr = 0;
1029 TAILQ_FOREACH(oldrule,
1030 ruleset->rules[rs_num].active.ptr, entries)
1031 oldrule->nr = nr++;
1032
1033 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1034 pf_remove_if_empty_ruleset(ruleset);
1035 pf_update_anchor_rules();
1036
1037 ruleset->rules[rs_num].active.ticket++;
1038 splx(s);
1039 break;
1040 }
1041
1042 case DIOCCLRSTATES: {
1043 struct pf_tree_node *n;
1044
1045 s = splsoftnet();
1046 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1047 n->state->timeout = PFTM_PURGE;
1048 pf_purge_expired_states();
1049 pf_status.states = 0;
1050 splx(s);
1051 break;
1052 }
1053
1054 case DIOCKILLSTATES: {
1055 struct pf_tree_node *n;
1056 struct pf_state *st;
1057 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
1058 int killed = 0;
1059
1060 s = splsoftnet();
1061 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1062 st = n->state;
1063 if ((!psk->psk_af || st->af == psk->psk_af) &&
1064 (!psk->psk_proto || psk->psk_proto == st->proto) &&
1065 PF_MATCHA(psk->psk_src.not,
1066 &psk->psk_src.addr.v.a.addr,
1067 &psk->psk_src.addr.v.a.mask, &st->lan.addr,
1068 st->af) &&
1069 PF_MATCHA(psk->psk_dst.not,
1070 &psk->psk_dst.addr.v.a.addr,
1071 &psk->psk_dst.addr.v.a.mask, &st->ext.addr,
1072 st->af) &&
1073 (psk->psk_src.port_op == 0 ||
1074 pf_match_port(psk->psk_src.port_op,
1075 psk->psk_src.port[0], psk->psk_src.port[1],
1076 st->lan.port)) &&
1077 (psk->psk_dst.port_op == 0 ||
1078 pf_match_port(psk->psk_dst.port_op,
1079 psk->psk_dst.port[0], psk->psk_dst.port[1],
1080 st->ext.port))) {
1081 st->timeout = PFTM_PURGE;
1082 killed++;
1083 }
1084 }
1085 pf_purge_expired_states();
1086 splx(s);
1087 psk->psk_af = killed;
1088 break;
1089 }
1090
1091 case DIOCADDSTATE: {
1092 struct pfioc_state *ps = (struct pfioc_state *)addr;
1093 struct pf_state *state;
1094
1095 if (ps->state.timeout >= PFTM_MAX &&
1096 ps->state.timeout != PFTM_UNTIL_PACKET) {
1097 error = EINVAL;
1098 break;
1099 }
1100 state = pool_get(&pf_state_pl, PR_NOWAIT);
1101 if (state == NULL) {
1102 error = ENOMEM;
1103 break;
1104 }
1105 s = splsoftnet();
1106 bcopy(&ps->state, state, sizeof(struct pf_state));
1107 state->rule.ptr = NULL;
1108 state->nat_rule.ptr = NULL;
1109 state->anchor.ptr = NULL;
1110 state->rt_ifp = NULL;
934 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
935 }
936 break;
937
938 case DIOCBEGINRULES: {
939 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
940 struct pf_ruleset *ruleset;
941 struct pf_rule *rule;
942 int rs_num;
943
944 ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
945 if (ruleset == NULL) {
946 error = EINVAL;
947 break;
948 }
949 rs_num = pf_get_ruleset_number(pr->rule.action);
950 if (rs_num >= PF_RULESET_MAX) {
951 error = EINVAL;
952 break;
953 }
954 while ((rule =
955 TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
956 pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
957 pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
958 break;
959 }
960
961 case DIOCADDRULE: {
962 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
963 struct pf_ruleset *ruleset;
964 struct pf_rule *rule, *tail;
965 struct pf_pooladdr *pa;
966 int rs_num;
967
968 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
969 if (ruleset == NULL) {
970 error = EINVAL;
971 break;
972 }
973 rs_num = pf_get_ruleset_number(pr->rule.action);
974 if (rs_num >= PF_RULESET_MAX) {
975 error = EINVAL;
976 break;
977 }
978 if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) {
979 error = EINVAL;
980 break;
981 }
982 if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
983 error = EINVAL;
984 break;
985 }
986 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
987 error = EBUSY;
988 break;
989 }
990 if (pr->pool_ticket != ticket_pabuf) {
991 error = EBUSY;
992 break;
993 }
994 rule = pool_get(&pf_rule_pl, PR_NOWAIT);
995 if (rule == NULL) {
996 error = ENOMEM;
997 break;
998 }
999 bcopy(&pr->rule, rule, sizeof(struct pf_rule));
1000 rule->anchor = NULL;
1001 rule->ifp = NULL;
1002 TAILQ_INIT(&rule->rpool.list);
1003 /* initialize refcounting */
1004 rule->states = 0;
1005 rule->entries.tqe_prev = NULL;
1006#ifndef INET
1007 if (rule->af == AF_INET) {
1008 pool_put(&pf_rule_pl, rule);
1009 error = EAFNOSUPPORT;
1010 break;
1011 }
1012#endif /* INET */
1013#ifndef INET6
1014 if (rule->af == AF_INET6) {
1015 pool_put(&pf_rule_pl, rule);
1016 error = EAFNOSUPPORT;
1017 break;
1018 }
1019#endif /* INET6 */
1020 tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
1021 pf_rulequeue);
1022 if (tail)
1023 rule->nr = tail->nr + 1;
1024 else
1025 rule->nr = 0;
1026 if (rule->ifname[0]) {
1027 rule->ifp = ifunit(rule->ifname);
1028 if (rule->ifp == NULL) {
1029 pool_put(&pf_rule_pl, rule);
1030 error = EINVAL;
1031 break;
1032 }
1033 }
1034
1035 if (rule->tagname[0])
1036 if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
1037 error = EBUSY;
1038 if (rule->match_tagname[0])
1039 if ((rule->match_tag =
1040 pf_tagname2tag(rule->match_tagname)) == 0)
1041 error = EBUSY;
1042 if (rule->rt && !rule->direction)
1043 error = EINVAL;
1044 if (pf_dynaddr_setup(&rule->src.addr, rule->af))
1045 error = EINVAL;
1046 if (pf_dynaddr_setup(&rule->dst.addr, rule->af))
1047 error = EINVAL;
1048 if (pf_tbladdr_setup(ruleset, &rule->src.addr))
1049 error = EINVAL;
1050 if (pf_tbladdr_setup(ruleset, &rule->dst.addr))
1051 error = EINVAL;
1052 TAILQ_FOREACH(pa, &pf_pabuf, entries)
1053 if (pf_tbladdr_setup(ruleset, &pa->addr))
1054 error = EINVAL;
1055
1056 pf_mv_pool(&pf_pabuf, &rule->rpool.list);
1057 if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
1058 (rule->action == PF_BINAT)) && !rule->anchorname[0]) ||
1059 (rule->rt > PF_FASTROUTE)) &&
1060 (TAILQ_FIRST(&rule->rpool.list) == NULL))
1061 error = EINVAL;
1062
1063 if (error) {
1064 pf_rm_rule(NULL, rule);
1065 break;
1066 }
1067 rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
1068 rule->evaluations = rule->packets = rule->bytes = 0;
1069 TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
1070 rule, entries);
1071 break;
1072 }
1073
1074 case DIOCCOMMITRULES: {
1075 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
1076 struct pf_ruleset *ruleset;
1077 struct pf_rulequeue *old_rules;
1078 struct pf_rule *rule;
1079 int rs_num;
1080
1081 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
1082 if (ruleset == NULL) {
1083 error = EINVAL;
1084 break;
1085 }
1086 rs_num = pf_get_ruleset_number(pr->rule.action);
1087 if (rs_num >= PF_RULESET_MAX) {
1088 error = EINVAL;
1089 break;
1090 }
1091 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
1092 error = EBUSY;
1093 break;
1094 }
1095
1096#ifdef ALTQ
1097 /* set queue IDs */
1098 if (rs_num == PF_RULESET_FILTER)
1099 pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
1100#endif
1101
1102 /* Swap rules, keep the old. */
1103 s = splsoftnet();
1104 old_rules = ruleset->rules[rs_num].active.ptr;
1105 ruleset->rules[rs_num].active.ptr =
1106 ruleset->rules[rs_num].inactive.ptr;
1107 ruleset->rules[rs_num].inactive.ptr = old_rules;
1108 ruleset->rules[rs_num].active.ticket =
1109 ruleset->rules[rs_num].inactive.ticket;
1110 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1111
1112 /* Purge the old rule list. */
1113 while ((rule = TAILQ_FIRST(old_rules)) != NULL)
1114 pf_rm_rule(old_rules, rule);
1115 pf_remove_if_empty_ruleset(ruleset);
1116 pf_update_anchor_rules();
1117 splx(s);
1118 break;
1119 }
1120
1121 case DIOCGETRULES: {
1122 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
1123 struct pf_ruleset *ruleset;
1124 struct pf_rule *tail;
1125 int rs_num;
1126
1127 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
1128 if (ruleset == NULL) {
1129 error = EINVAL;
1130 break;
1131 }
1132 rs_num = pf_get_ruleset_number(pr->rule.action);
1133 if (rs_num >= PF_RULESET_MAX) {
1134 error = EINVAL;
1135 break;
1136 }
1137 s = splsoftnet();
1138 tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
1139 pf_rulequeue);
1140 if (tail)
1141 pr->nr = tail->nr + 1;
1142 else
1143 pr->nr = 0;
1144 pr->ticket = ruleset->rules[rs_num].active.ticket;
1145 splx(s);
1146 break;
1147 }
1148
1149 case DIOCGETRULE: {
1150 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
1151 struct pf_ruleset *ruleset;
1152 struct pf_rule *rule;
1153 int rs_num, i;
1154
1155 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
1156 if (ruleset == NULL) {
1157 error = EINVAL;
1158 break;
1159 }
1160 rs_num = pf_get_ruleset_number(pr->rule.action);
1161 if (rs_num >= PF_RULESET_MAX) {
1162 error = EINVAL;
1163 break;
1164 }
1165 if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
1166 error = EBUSY;
1167 break;
1168 }
1169 s = splsoftnet();
1170 rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
1171 while ((rule != NULL) && (rule->nr != pr->nr))
1172 rule = TAILQ_NEXT(rule, entries);
1173 if (rule == NULL) {
1174 error = EBUSY;
1175 splx(s);
1176 break;
1177 }
1178 bcopy(rule, &pr->rule, sizeof(struct pf_rule));
1179 pf_dynaddr_copyout(&pr->rule.src.addr);
1180 pf_dynaddr_copyout(&pr->rule.dst.addr);
1181 pf_tbladdr_copyout(&pr->rule.src.addr);
1182 pf_tbladdr_copyout(&pr->rule.dst.addr);
1183 for (i = 0; i < PF_SKIP_COUNT; ++i)
1184 if (rule->skip[i].ptr == NULL)
1185 pr->rule.skip[i].nr = -1;
1186 else
1187 pr->rule.skip[i].nr =
1188 rule->skip[i].ptr->nr;
1189 splx(s);
1190 break;
1191 }
1192
1193 case DIOCCHANGERULE: {
1194 struct pfioc_rule *pcr = (struct pfioc_rule *)addr;
1195 struct pf_ruleset *ruleset;
1196 struct pf_rule *oldrule = NULL, *newrule = NULL;
1197 u_int32_t nr = 0;
1198 int rs_num;
1199
1200 if (!(pcr->action == PF_CHANGE_REMOVE ||
1201 pcr->action == PF_CHANGE_GET_TICKET) &&
1202 pcr->pool_ticket != ticket_pabuf) {
1203 error = EBUSY;
1204 break;
1205 }
1206
1207 if (pcr->action < PF_CHANGE_ADD_HEAD ||
1208 pcr->action > PF_CHANGE_GET_TICKET) {
1209 error = EINVAL;
1210 break;
1211 }
1212 ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset);
1213 if (ruleset == NULL) {
1214 error = EINVAL;
1215 break;
1216 }
1217 rs_num = pf_get_ruleset_number(pcr->rule.action);
1218 if (rs_num >= PF_RULESET_MAX) {
1219 error = EINVAL;
1220 break;
1221 }
1222
1223 if (pcr->action == PF_CHANGE_GET_TICKET) {
1224 pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
1225 break;
1226 } else {
1227 if (pcr->ticket !=
1228 ruleset->rules[rs_num].active.ticket) {
1229 error = EINVAL;
1230 break;
1231 }
1232 if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1233 error = EINVAL;
1234 break;
1235 }
1236 }
1237
1238 if (pcr->action != PF_CHANGE_REMOVE) {
1239 newrule = pool_get(&pf_rule_pl, PR_NOWAIT);
1240 if (newrule == NULL) {
1241 error = ENOMEM;
1242 break;
1243 }
1244 bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
1245 TAILQ_INIT(&newrule->rpool.list);
1246 /* initialize refcounting */
1247 newrule->states = 0;
1248 newrule->entries.tqe_prev = NULL;
1249#ifndef INET
1250 if (newrule->af == AF_INET) {
1251 pool_put(&pf_rule_pl, newrule);
1252 error = EAFNOSUPPORT;
1253 break;
1254 }
1255#endif /* INET */
1256#ifndef INET6
1257 if (newrule->af == AF_INET6) {
1258 pool_put(&pf_rule_pl, newrule);
1259 error = EAFNOSUPPORT;
1260 break;
1261 }
1262#endif /* INET6 */
1263 if (newrule->ifname[0]) {
1264 newrule->ifp = ifunit(newrule->ifname);
1265 if (newrule->ifp == NULL) {
1266 pool_put(&pf_rule_pl, newrule);
1267 error = EINVAL;
1268 break;
1269 }
1270 } else
1271 newrule->ifp = NULL;
1272
1273#ifdef ALTQ
1274 /* set queue IDs */
1275 if (newrule->qname[0] != 0) {
1276 newrule->qid = pf_qname_to_qid(newrule->qname);
1277 if (newrule->pqname[0] != 0)
1278 newrule->pqid =
1279 pf_qname_to_qid(newrule->pqname);
1280 else
1281 newrule->pqid = newrule->qid;
1282 }
1283#endif
1284 if (newrule->tagname[0])
1285 if ((newrule->tag =
1286 pf_tagname2tag(newrule->tagname)) == 0)
1287 error = EBUSY;
1288 if (newrule->match_tagname[0])
1289 if ((newrule->match_tag = pf_tagname2tag(
1290 newrule->match_tagname)) == 0)
1291 error = EBUSY;
1292
1293 if (newrule->rt && !newrule->direction)
1294 error = EINVAL;
1295 if (pf_dynaddr_setup(&newrule->src.addr, newrule->af))
1296 error = EINVAL;
1297 if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af))
1298 error = EINVAL;
1299 if (pf_tbladdr_setup(ruleset, &newrule->src.addr))
1300 error = EINVAL;
1301 if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))
1302 error = EINVAL;
1303
1304 pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
1305 if (((((newrule->action == PF_NAT) ||
1306 (newrule->action == PF_RDR) ||
1307 (newrule->action == PF_BINAT) ||
1308 (newrule->rt > PF_FASTROUTE)) &&
1309 !newrule->anchorname[0])) &&
1310 (TAILQ_FIRST(&newrule->rpool.list) == NULL))
1311 error = EINVAL;
1312
1313 if (error) {
1314 pf_rm_rule(NULL, newrule);
1315 break;
1316 }
1317 newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
1318 newrule->evaluations = newrule->packets = 0;
1319 newrule->bytes = 0;
1320 }
1321 pf_empty_pool(&pf_pabuf);
1322
1323 s = splsoftnet();
1324
1325 if (pcr->action == PF_CHANGE_ADD_HEAD)
1326 oldrule = TAILQ_FIRST(
1327 ruleset->rules[rs_num].active.ptr);
1328 else if (pcr->action == PF_CHANGE_ADD_TAIL)
1329 oldrule = TAILQ_LAST(
1330 ruleset->rules[rs_num].active.ptr, pf_rulequeue);
1331 else {
1332 oldrule = TAILQ_FIRST(
1333 ruleset->rules[rs_num].active.ptr);
1334 while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
1335 oldrule = TAILQ_NEXT(oldrule, entries);
1336 if (oldrule == NULL) {
1337 pf_rm_rule(NULL, newrule);
1338 error = EINVAL;
1339 splx(s);
1340 break;
1341 }
1342 }
1343
1344 if (pcr->action == PF_CHANGE_REMOVE)
1345 pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
1346 else {
1347 if (oldrule == NULL)
1348 TAILQ_INSERT_TAIL(
1349 ruleset->rules[rs_num].active.ptr,
1350 newrule, entries);
1351 else if (pcr->action == PF_CHANGE_ADD_HEAD ||
1352 pcr->action == PF_CHANGE_ADD_BEFORE)
1353 TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
1354 else
1355 TAILQ_INSERT_AFTER(
1356 ruleset->rules[rs_num].active.ptr,
1357 oldrule, newrule, entries);
1358 }
1359
1360 nr = 0;
1361 TAILQ_FOREACH(oldrule,
1362 ruleset->rules[rs_num].active.ptr, entries)
1363 oldrule->nr = nr++;
1364
1365 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1366 pf_remove_if_empty_ruleset(ruleset);
1367 pf_update_anchor_rules();
1368
1369 ruleset->rules[rs_num].active.ticket++;
1370 splx(s);
1371 break;
1372 }
1373
1374 case DIOCCLRSTATES: {
1375 struct pf_tree_node *n;
1376
1377 s = splsoftnet();
1378 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1379 n->state->timeout = PFTM_PURGE;
1380 pf_purge_expired_states();
1381 pf_status.states = 0;
1382 splx(s);
1383 break;
1384 }
1385
1386 case DIOCKILLSTATES: {
1387 struct pf_tree_node *n;
1388 struct pf_state *st;
1389 struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
1390 int killed = 0;
1391
1392 s = splsoftnet();
1393 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1394 st = n->state;
1395 if ((!psk->psk_af || st->af == psk->psk_af) &&
1396 (!psk->psk_proto || psk->psk_proto == st->proto) &&
1397 PF_MATCHA(psk->psk_src.not,
1398 &psk->psk_src.addr.v.a.addr,
1399 &psk->psk_src.addr.v.a.mask, &st->lan.addr,
1400 st->af) &&
1401 PF_MATCHA(psk->psk_dst.not,
1402 &psk->psk_dst.addr.v.a.addr,
1403 &psk->psk_dst.addr.v.a.mask, &st->ext.addr,
1404 st->af) &&
1405 (psk->psk_src.port_op == 0 ||
1406 pf_match_port(psk->psk_src.port_op,
1407 psk->psk_src.port[0], psk->psk_src.port[1],
1408 st->lan.port)) &&
1409 (psk->psk_dst.port_op == 0 ||
1410 pf_match_port(psk->psk_dst.port_op,
1411 psk->psk_dst.port[0], psk->psk_dst.port[1],
1412 st->ext.port))) {
1413 st->timeout = PFTM_PURGE;
1414 killed++;
1415 }
1416 }
1417 pf_purge_expired_states();
1418 splx(s);
1419 psk->psk_af = killed;
1420 break;
1421 }
1422
1423 case DIOCADDSTATE: {
1424 struct pfioc_state *ps = (struct pfioc_state *)addr;
1425 struct pf_state *state;
1426
1427 if (ps->state.timeout >= PFTM_MAX &&
1428 ps->state.timeout != PFTM_UNTIL_PACKET) {
1429 error = EINVAL;
1430 break;
1431 }
1432 state = pool_get(&pf_state_pl, PR_NOWAIT);
1433 if (state == NULL) {
1434 error = ENOMEM;
1435 break;
1436 }
1437 s = splsoftnet();
1438 bcopy(&ps->state, state, sizeof(struct pf_state));
1439 state->rule.ptr = NULL;
1440 state->nat_rule.ptr = NULL;
1441 state->anchor.ptr = NULL;
1442 state->rt_ifp = NULL;
1443#if defined(__FreeBSD__)
1444 state->creation = time_second;
1445#else
1111 state->creation = time.tv_sec;
1446 state->creation = time.tv_sec;
1447#endif
1112 state->packets[0] = state->packets[1] = 0;
1113 state->bytes[0] = state->bytes[1] = 0;
1114 if (pf_insert_state(state)) {
1115 pool_put(&pf_state_pl, state);
1116 error = ENOMEM;
1117 }
1118 splx(s);
1119 break;
1120 }
1121
1122 case DIOCGETSTATE: {
1123 struct pfioc_state *ps = (struct pfioc_state *)addr;
1124 struct pf_tree_node *n;
1125 u_int32_t nr;
1126
1127 nr = 0;
1128 s = splsoftnet();
1129 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1130 if (nr >= ps->nr)
1131 break;
1132 nr++;
1133 }
1134 if (n == NULL) {
1135 error = EBUSY;
1136 splx(s);
1137 break;
1138 }
1139 bcopy(n->state, &ps->state, sizeof(struct pf_state));
1140 ps->state.rule.nr = n->state->rule.ptr->nr;
1141 ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1142 -1 : n->state->nat_rule.ptr->nr;
1143 ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ?
1144 -1 : n->state->anchor.ptr->nr;
1145 splx(s);
1146 ps->state.expire = pf_state_expires(n->state);
1448 state->packets[0] = state->packets[1] = 0;
1449 state->bytes[0] = state->bytes[1] = 0;
1450 if (pf_insert_state(state)) {
1451 pool_put(&pf_state_pl, state);
1452 error = ENOMEM;
1453 }
1454 splx(s);
1455 break;
1456 }
1457
1458 case DIOCGETSTATE: {
1459 struct pfioc_state *ps = (struct pfioc_state *)addr;
1460 struct pf_tree_node *n;
1461 u_int32_t nr;
1462
1463 nr = 0;
1464 s = splsoftnet();
1465 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1466 if (nr >= ps->nr)
1467 break;
1468 nr++;
1469 }
1470 if (n == NULL) {
1471 error = EBUSY;
1472 splx(s);
1473 break;
1474 }
1475 bcopy(n->state, &ps->state, sizeof(struct pf_state));
1476 ps->state.rule.nr = n->state->rule.ptr->nr;
1477 ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1478 -1 : n->state->nat_rule.ptr->nr;
1479 ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ?
1480 -1 : n->state->anchor.ptr->nr;
1481 splx(s);
1482 ps->state.expire = pf_state_expires(n->state);
1483#if defined(__FreeBSD__)
1484 if (ps->state.expire > time_second)
1485 ps->state.expire -= time_second;
1486#else
1147 if (ps->state.expire > time.tv_sec)
1148 ps->state.expire -= time.tv_sec;
1487 if (ps->state.expire > time.tv_sec)
1488 ps->state.expire -= time.tv_sec;
1489#endif
1149 else
1150 ps->state.expire = 0;
1151 break;
1152 }
1153
1154 case DIOCGETSTATES: {
1155 struct pfioc_states *ps = (struct pfioc_states *)addr;
1156 struct pf_tree_node *n;
1157 struct pf_state *p, pstore;
1158 u_int32_t nr = 0;
1159 int space = ps->ps_len;
1160
1161 if (space == 0) {
1162 s = splsoftnet();
1163 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1164 nr++;
1165 splx(s);
1166 ps->ps_len = sizeof(struct pf_state) * nr;
1490 else
1491 ps->state.expire = 0;
1492 break;
1493 }
1494
1495 case DIOCGETSTATES: {
1496 struct pfioc_states *ps = (struct pfioc_states *)addr;
1497 struct pf_tree_node *n;
1498 struct pf_state *p, pstore;
1499 u_int32_t nr = 0;
1500 int space = ps->ps_len;
1501
1502 if (space == 0) {
1503 s = splsoftnet();
1504 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1505 nr++;
1506 splx(s);
1507 ps->ps_len = sizeof(struct pf_state) * nr;
1508#if defined(__FreeBSD__)
1509 PF_UNLOCK();
1510#endif
1167 return (0);
1168 }
1169
1170 s = splsoftnet();
1171 p = ps->ps_states;
1172 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1511 return (0);
1512 }
1513
1514 s = splsoftnet();
1515 p = ps->ps_states;
1516 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1517#if defined(__FreeBSD__)
1518 int secs = time_second;
1519#else
1173 int secs = time.tv_sec;
1520 int secs = time.tv_sec;
1521#endif
1174
1175 if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len)
1176 break;
1177
1178 bcopy(n->state, &pstore, sizeof(pstore));
1179 pstore.rule.nr = n->state->rule.ptr->nr;
1180 pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1181 -1 : n->state->nat_rule.ptr->nr;
1182 pstore.anchor.nr = (n->state->anchor.ptr == NULL) ?
1183 -1 : n->state->anchor.ptr->nr;
1184 pstore.creation = secs - pstore.creation;
1185 pstore.expire = pf_state_expires(n->state);
1186 if (pstore.expire > secs)
1187 pstore.expire -= secs;
1188 else
1189 pstore.expire = 0;
1522
1523 if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len)
1524 break;
1525
1526 bcopy(n->state, &pstore, sizeof(pstore));
1527 pstore.rule.nr = n->state->rule.ptr->nr;
1528 pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1529 -1 : n->state->nat_rule.ptr->nr;
1530 pstore.anchor.nr = (n->state->anchor.ptr == NULL) ?
1531 -1 : n->state->anchor.ptr->nr;
1532 pstore.creation = secs - pstore.creation;
1533 pstore.expire = pf_state_expires(n->state);
1534 if (pstore.expire > secs)
1535 pstore.expire -= secs;
1536 else
1537 pstore.expire = 0;
1538#if defined(__FreeBSD__)
1539 PF_COPYOUT(&pstore, p, sizeof(*p), error);
1540#else
1190 error = copyout(&pstore, p, sizeof(*p));
1541 error = copyout(&pstore, p, sizeof(*p));
1542#endif
1191 if (error) {
1192 splx(s);
1193 goto fail;
1194 }
1195 p++;
1196 nr++;
1197 }
1198 ps->ps_len = sizeof(struct pf_state) * nr;
1199 splx(s);
1200 break;
1201 }
1202
1203 case DIOCGETSTATUS: {
1204 struct pf_status *s = (struct pf_status *)addr;
1205 bcopy(&pf_status, s, sizeof(struct pf_status));
1206 break;
1207 }
1208
1209 case DIOCSETSTATUSIF: {
1210 struct pfioc_if *pi = (struct pfioc_if *)addr;
1211 struct ifnet *ifp;
1212
1213 if (pi->ifname[0] == 0) {
1214 status_ifp = NULL;
1215 bzero(pf_status.ifname, IFNAMSIZ);
1216 break;
1217 }
1218 if ((ifp = ifunit(pi->ifname)) == NULL) {
1219 error = EINVAL;
1220 break;
1221 } else if (ifp == status_ifp)
1222 break;
1223 status_ifp = ifp;
1224 /* fallthrough into DIOCCLRSTATUS */
1225 }
1226
1227 case DIOCCLRSTATUS: {
1228 u_int32_t running = pf_status.running;
1229 u_int32_t states = pf_status.states;
1230 u_int32_t since = pf_status.since;
1231 u_int32_t debug = pf_status.debug;
1232
1233 bzero(&pf_status, sizeof(struct pf_status));
1234 pf_status.running = running;
1235 pf_status.states = states;
1236 pf_status.since = since;
1237 pf_status.debug = debug;
1238 if (status_ifp != NULL)
1543 if (error) {
1544 splx(s);
1545 goto fail;
1546 }
1547 p++;
1548 nr++;
1549 }
1550 ps->ps_len = sizeof(struct pf_state) * nr;
1551 splx(s);
1552 break;
1553 }
1554
1555 case DIOCGETSTATUS: {
1556 struct pf_status *s = (struct pf_status *)addr;
1557 bcopy(&pf_status, s, sizeof(struct pf_status));
1558 break;
1559 }
1560
1561 case DIOCSETSTATUSIF: {
1562 struct pfioc_if *pi = (struct pfioc_if *)addr;
1563 struct ifnet *ifp;
1564
1565 if (pi->ifname[0] == 0) {
1566 status_ifp = NULL;
1567 bzero(pf_status.ifname, IFNAMSIZ);
1568 break;
1569 }
1570 if ((ifp = ifunit(pi->ifname)) == NULL) {
1571 error = EINVAL;
1572 break;
1573 } else if (ifp == status_ifp)
1574 break;
1575 status_ifp = ifp;
1576 /* fallthrough into DIOCCLRSTATUS */
1577 }
1578
1579 case DIOCCLRSTATUS: {
1580 u_int32_t running = pf_status.running;
1581 u_int32_t states = pf_status.states;
1582 u_int32_t since = pf_status.since;
1583 u_int32_t debug = pf_status.debug;
1584
1585 bzero(&pf_status, sizeof(struct pf_status));
1586 pf_status.running = running;
1587 pf_status.states = states;
1588 pf_status.since = since;
1589 pf_status.debug = debug;
1590 if (status_ifp != NULL)
1591#if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
1592 snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
1593 status_ifp->if_name, status_ifp->if_unit);
1594#else
1239 strlcpy(pf_status.ifname,
1240 status_ifp->if_xname, IFNAMSIZ);
1595 strlcpy(pf_status.ifname,
1596 status_ifp->if_xname, IFNAMSIZ);
1597#endif
1241 break;
1242 }
1243
1244 case DIOCNATLOOK: {
1245 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr;
1246 struct pf_state *st;
1247 struct pf_tree_node key;
1248 int direction = pnl->direction;
1249
1250 key.af = pnl->af;
1251 key.proto = pnl->proto;
1252
1253 /*
1254 * userland gives us source and dest of connection, reverse
1255 * the lookup so we ask for what happens with the return
1256 * traffic, enabling us to find it in the state tree.
1257 */
1258 PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af);
1259 key.port[1] = pnl->sport;
1260 PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af);
1261 key.port[0] = pnl->dport;
1262
1263 if (!pnl->proto ||
1264 PF_AZERO(&pnl->saddr, pnl->af) ||
1265 PF_AZERO(&pnl->daddr, pnl->af) ||
1266 !pnl->dport || !pnl->sport)
1267 error = EINVAL;
1268 else {
1269 s = splsoftnet();
1270 if (direction == PF_IN)
1271 st = pf_find_state(&tree_ext_gwy, &key);
1272 else
1273 st = pf_find_state(&tree_lan_ext, &key);
1274 if (st != NULL) {
1275 if (direction == PF_IN) {
1276 PF_ACPY(&pnl->rsaddr, &st->lan.addr,
1277 st->af);
1278 pnl->rsport = st->lan.port;
1279 PF_ACPY(&pnl->rdaddr, &pnl->daddr,
1280 pnl->af);
1281 pnl->rdport = pnl->dport;
1282 } else {
1283 PF_ACPY(&pnl->rdaddr, &st->gwy.addr,
1284 st->af);
1285 pnl->rdport = st->gwy.port;
1286 PF_ACPY(&pnl->rsaddr, &pnl->saddr,
1287 pnl->af);
1288 pnl->rsport = pnl->sport;
1289 }
1290 } else
1291 error = ENOENT;
1292 splx(s);
1293 }
1294 break;
1295 }
1296
1297 case DIOCSETTIMEOUT: {
1298 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
1299 int old;
1300
1301 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
1302 pt->seconds < 0) {
1303 error = EINVAL;
1304 goto fail;
1305 }
1306 old = pf_default_rule.timeout[pt->timeout];
1307 pf_default_rule.timeout[pt->timeout] = pt->seconds;
1308 pt->seconds = old;
1309 break;
1310 }
1311
1312 case DIOCGETTIMEOUT: {
1313 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
1314
1315 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
1316 error = EINVAL;
1317 goto fail;
1318 }
1319 pt->seconds = pf_default_rule.timeout[pt->timeout];
1320 break;
1321 }
1322
1323 case DIOCGETLIMIT: {
1324 struct pfioc_limit *pl = (struct pfioc_limit *)addr;
1325
1326 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1327 error = EINVAL;
1328 goto fail;
1329 }
1330 pl->limit = pf_pool_limits[pl->index].limit;
1331 break;
1332 }
1333
1334 case DIOCSETLIMIT: {
1335 struct pfioc_limit *pl = (struct pfioc_limit *)addr;
1336 int old_limit;
1337
1338 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1339 error = EINVAL;
1340 goto fail;
1341 }
1598 break;
1599 }
1600
1601 case DIOCNATLOOK: {
1602 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr;
1603 struct pf_state *st;
1604 struct pf_tree_node key;
1605 int direction = pnl->direction;
1606
1607 key.af = pnl->af;
1608 key.proto = pnl->proto;
1609
1610 /*
1611 * userland gives us source and dest of connection, reverse
1612 * the lookup so we ask for what happens with the return
1613 * traffic, enabling us to find it in the state tree.
1614 */
1615 PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af);
1616 key.port[1] = pnl->sport;
1617 PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af);
1618 key.port[0] = pnl->dport;
1619
1620 if (!pnl->proto ||
1621 PF_AZERO(&pnl->saddr, pnl->af) ||
1622 PF_AZERO(&pnl->daddr, pnl->af) ||
1623 !pnl->dport || !pnl->sport)
1624 error = EINVAL;
1625 else {
1626 s = splsoftnet();
1627 if (direction == PF_IN)
1628 st = pf_find_state(&tree_ext_gwy, &key);
1629 else
1630 st = pf_find_state(&tree_lan_ext, &key);
1631 if (st != NULL) {
1632 if (direction == PF_IN) {
1633 PF_ACPY(&pnl->rsaddr, &st->lan.addr,
1634 st->af);
1635 pnl->rsport = st->lan.port;
1636 PF_ACPY(&pnl->rdaddr, &pnl->daddr,
1637 pnl->af);
1638 pnl->rdport = pnl->dport;
1639 } else {
1640 PF_ACPY(&pnl->rdaddr, &st->gwy.addr,
1641 st->af);
1642 pnl->rdport = st->gwy.port;
1643 PF_ACPY(&pnl->rsaddr, &pnl->saddr,
1644 pnl->af);
1645 pnl->rsport = pnl->sport;
1646 }
1647 } else
1648 error = ENOENT;
1649 splx(s);
1650 }
1651 break;
1652 }
1653
1654 case DIOCSETTIMEOUT: {
1655 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
1656 int old;
1657
1658 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
1659 pt->seconds < 0) {
1660 error = EINVAL;
1661 goto fail;
1662 }
1663 old = pf_default_rule.timeout[pt->timeout];
1664 pf_default_rule.timeout[pt->timeout] = pt->seconds;
1665 pt->seconds = old;
1666 break;
1667 }
1668
1669 case DIOCGETTIMEOUT: {
1670 struct pfioc_tm *pt = (struct pfioc_tm *)addr;
1671
1672 if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
1673 error = EINVAL;
1674 goto fail;
1675 }
1676 pt->seconds = pf_default_rule.timeout[pt->timeout];
1677 break;
1678 }
1679
1680 case DIOCGETLIMIT: {
1681 struct pfioc_limit *pl = (struct pfioc_limit *)addr;
1682
1683 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1684 error = EINVAL;
1685 goto fail;
1686 }
1687 pl->limit = pf_pool_limits[pl->index].limit;
1688 break;
1689 }
1690
1691 case DIOCSETLIMIT: {
1692 struct pfioc_limit *pl = (struct pfioc_limit *)addr;
1693 int old_limit;
1694
1695 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1696 error = EINVAL;
1697 goto fail;
1698 }
1699#if defined(__FreeBSD__)
1700 uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit);
1701#else
1342 if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
1343 pl->limit, NULL, 0) != 0) {
1344 error = EBUSY;
1345 goto fail;
1346 }
1702 if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
1703 pl->limit, NULL, 0) != 0) {
1704 error = EBUSY;
1705 goto fail;
1706 }
1707#endif
1347 old_limit = pf_pool_limits[pl->index].limit;
1348 pf_pool_limits[pl->index].limit = pl->limit;
1349 pl->limit = old_limit;
1350 break;
1351 }
1352
1353 case DIOCSETDEBUG: {
1354 u_int32_t *level = (u_int32_t *)addr;
1355
1356 pf_status.debug = *level;
1357 break;
1358 }
1359
1360 case DIOCCLRRULECTRS: {
1361 struct pf_ruleset *ruleset = &pf_main_ruleset;
1362 struct pf_rule *rule;
1363
1364 s = splsoftnet();
1365 TAILQ_FOREACH(rule,
1366 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
1367 rule->evaluations = rule->packets =
1368 rule->bytes = 0;
1369 splx(s);
1370 break;
1371 }
1372
1708 old_limit = pf_pool_limits[pl->index].limit;
1709 pf_pool_limits[pl->index].limit = pl->limit;
1710 pl->limit = old_limit;
1711 break;
1712 }
1713
1714 case DIOCSETDEBUG: {
1715 u_int32_t *level = (u_int32_t *)addr;
1716
1717 pf_status.debug = *level;
1718 break;
1719 }
1720
1721 case DIOCCLRRULECTRS: {
1722 struct pf_ruleset *ruleset = &pf_main_ruleset;
1723 struct pf_rule *rule;
1724
1725 s = splsoftnet();
1726 TAILQ_FOREACH(rule,
1727 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
1728 rule->evaluations = rule->packets =
1729 rule->bytes = 0;
1730 splx(s);
1731 break;
1732 }
1733
1734#if defined(__FreeBSD__)
1735 case DIOCGIFSPEED: {
1736 struct pf_ifspeed *psp = (struct pf_ifspeed *)addr;
1737 struct pf_ifspeed ps;
1738 struct ifnet *ifp;
1739
1740 if (psp->ifname[0] != 0) {
1741 /* Can we completely trust user-land? */
1742 strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
1743 ifp = ifunit(ps.ifname);
1744 if (ifp )
1745 psp->baudrate = ifp->if_baudrate;
1746 else
1747 error = EINVAL;
1748 } else
1749 error = EINVAL;
1750 break;
1751 }
1752#endif /* __FreeBSD__ */
1753
1373#ifdef ALTQ
1374 case DIOCSTARTALTQ: {
1375 struct pf_altq *altq;
1376 struct ifnet *ifp;
1377 struct tb_profile tb;
1378
1379 /* enable all altq interfaces on active list */
1380 s = splsoftnet();
1381 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1382 if (altq->qname[0] == 0) {
1383 if ((ifp = ifunit(altq->ifname)) == NULL) {
1384 error = EINVAL;
1385 break;
1386 }
1387 if (ifp->if_snd.altq_type != ALTQT_NONE)
1388 error = altq_enable(&ifp->if_snd);
1389 if (error != 0)
1390 break;
1391 /* set tokenbucket regulator */
1392 tb.rate = altq->ifbandwidth;
1393 tb.depth = altq->tbrsize;
1394 error = tbr_set(&ifp->if_snd, &tb);
1395 if (error != 0)
1396 break;
1397 }
1398 }
1754#ifdef ALTQ
1755 case DIOCSTARTALTQ: {
1756 struct pf_altq *altq;
1757 struct ifnet *ifp;
1758 struct tb_profile tb;
1759
1760 /* enable all altq interfaces on active list */
1761 s = splsoftnet();
1762 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1763 if (altq->qname[0] == 0) {
1764 if ((ifp = ifunit(altq->ifname)) == NULL) {
1765 error = EINVAL;
1766 break;
1767 }
1768 if (ifp->if_snd.altq_type != ALTQT_NONE)
1769 error = altq_enable(&ifp->if_snd);
1770 if (error != 0)
1771 break;
1772 /* set tokenbucket regulator */
1773 tb.rate = altq->ifbandwidth;
1774 tb.depth = altq->tbrsize;
1775 error = tbr_set(&ifp->if_snd, &tb);
1776 if (error != 0)
1777 break;
1778 }
1779 }
1780#if defined(__FreeBSD__)
1781 if (error == 0) {
1782 mtx_lock(&pf_altq_mtx);
1783 pfaltq_running = 1;
1784 mtx_unlock(&pf_altq_mtx);
1785 }
1786#else
1399 if (error == 0)
1400 pfaltq_running = 1;
1787 if (error == 0)
1788 pfaltq_running = 1;
1789#endif
1401 splx(s);
1402 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
1403 break;
1404 }
1405
1406 case DIOCSTOPALTQ: {
1407 struct pf_altq *altq;
1408 struct ifnet *ifp;
1409 struct tb_profile tb;
1410 int err;
1411
1412 /* disable all altq interfaces on active list */
1413 s = splsoftnet();
1414 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1415 if (altq->qname[0] == 0) {
1416 if ((ifp = ifunit(altq->ifname)) == NULL) {
1417 error = EINVAL;
1418 break;
1419 }
1420 if (ifp->if_snd.altq_type != ALTQT_NONE) {
1421 err = altq_disable(&ifp->if_snd);
1422 if (err != 0 && error == 0)
1423 error = err;
1424 }
1425 /* clear tokenbucket regulator */
1426 tb.rate = 0;
1427 err = tbr_set(&ifp->if_snd, &tb);
1428 if (err != 0 && error == 0)
1429 error = err;
1430 }
1431 }
1790 splx(s);
1791 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
1792 break;
1793 }
1794
1795 case DIOCSTOPALTQ: {
1796 struct pf_altq *altq;
1797 struct ifnet *ifp;
1798 struct tb_profile tb;
1799 int err;
1800
1801 /* disable all altq interfaces on active list */
1802 s = splsoftnet();
1803 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1804 if (altq->qname[0] == 0) {
1805 if ((ifp = ifunit(altq->ifname)) == NULL) {
1806 error = EINVAL;
1807 break;
1808 }
1809 if (ifp->if_snd.altq_type != ALTQT_NONE) {
1810 err = altq_disable(&ifp->if_snd);
1811 if (err != 0 && error == 0)
1812 error = err;
1813 }
1814 /* clear tokenbucket regulator */
1815 tb.rate = 0;
1816 err = tbr_set(&ifp->if_snd, &tb);
1817 if (err != 0 && error == 0)
1818 error = err;
1819 }
1820 }
1821#if defined(__FreeBSD__)
1822 if (error == 0) {
1823 mtx_lock(&pf_altq_mtx);
1824 pfaltq_running = 0;
1825 mtx_unlock(&pf_altq_mtx);
1826 }
1827#else
1432 if (error == 0)
1433 pfaltq_running = 0;
1828 if (error == 0)
1829 pfaltq_running = 0;
1830#endif
1434 splx(s);
1435 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
1436 break;
1437 }
1438
1439 case DIOCBEGINALTQS: {
1440 u_int32_t *ticket = (u_int32_t *)addr;
1441 struct pf_altq *altq;
1442
1443 /* Purge the old altq list */
1444 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1445 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1446 if (altq->qname[0] == 0) {
1447 /* detach and destroy the discipline */
1831 splx(s);
1832 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
1833 break;
1834 }
1835
1836 case DIOCBEGINALTQS: {
1837 u_int32_t *ticket = (u_int32_t *)addr;
1838 struct pf_altq *altq;
1839
1840 /* Purge the old altq list */
1841 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1842 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1843 if (altq->qname[0] == 0) {
1844 /* detach and destroy the discipline */
1845#if defined(__FreeBSD__)
1846 PF_UNLOCK();
1847#endif
1448 error = altq_remove(altq);
1848 error = altq_remove(altq);
1849#if defined(__FreeBSD__)
1850 PF_LOCK();
1851#endif
1449 }
1450 pool_put(&pf_altq_pl, altq);
1451 }
1452 *ticket = ++ticket_altqs_inactive;
1453 break;
1454 }
1455
1456 case DIOCADDALTQ: {
1457 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
1458 struct pf_altq *altq, *a;
1459
1460 if (pa->ticket != ticket_altqs_inactive) {
1461 error = EBUSY;
1462 break;
1463 }
1464 altq = pool_get(&pf_altq_pl, PR_NOWAIT);
1465 if (altq == NULL) {
1466 error = ENOMEM;
1467 break;
1468 }
1469 bcopy(&pa->altq, altq, sizeof(struct pf_altq));
1470
1471 /*
1472 * if this is for a queue, find the discipline and
1473 * copy the necessary fields
1474 */
1475 if (altq->qname[0] != 0) {
1476 TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
1477 if (strncmp(a->ifname, altq->ifname,
1478 IFNAMSIZ) == 0 && a->qname[0] == 0) {
1479 altq->altq_disc = a->altq_disc;
1480 break;
1481 }
1482 }
1483 }
1484
1852 }
1853 pool_put(&pf_altq_pl, altq);
1854 }
1855 *ticket = ++ticket_altqs_inactive;
1856 break;
1857 }
1858
1859 case DIOCADDALTQ: {
1860 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
1861 struct pf_altq *altq, *a;
1862
1863 if (pa->ticket != ticket_altqs_inactive) {
1864 error = EBUSY;
1865 break;
1866 }
1867 altq = pool_get(&pf_altq_pl, PR_NOWAIT);
1868 if (altq == NULL) {
1869 error = ENOMEM;
1870 break;
1871 }
1872 bcopy(&pa->altq, altq, sizeof(struct pf_altq));
1873
1874 /*
1875 * if this is for a queue, find the discipline and
1876 * copy the necessary fields
1877 */
1878 if (altq->qname[0] != 0) {
1879 TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
1880 if (strncmp(a->ifname, altq->ifname,
1881 IFNAMSIZ) == 0 && a->qname[0] == 0) {
1882 altq->altq_disc = a->altq_disc;
1883 break;
1884 }
1885 }
1886 }
1887
1888#if defined(__FreeBSD__)
1889 PF_UNLOCK();
1890#endif
1485 error = altq_add(altq);
1891 error = altq_add(altq);
1892#if defined(__FreeBSD__)
1893 PF_LOCK();
1894#endif
1486 if (error) {
1487 pool_put(&pf_altq_pl, altq);
1488 break;
1489 }
1490
1491 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
1492 bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1493 break;
1494 }
1495
1496 case DIOCCOMMITALTQS: {
1497 u_int32_t *ticket = (u_int32_t *)addr;
1498 struct pf_altqqueue *old_altqs;
1499 struct pf_altq *altq;
1500 struct pf_anchor *anchor;
1501 struct pf_ruleset *ruleset;
1502 int err;
1503
1504 if (*ticket != ticket_altqs_inactive) {
1505 error = EBUSY;
1506 break;
1507 }
1508
1509 /* Swap altqs, keep the old. */
1510 s = splsoftnet();
1511 old_altqs = pf_altqs_active;
1512 pf_altqs_active = pf_altqs_inactive;
1513 pf_altqs_inactive = old_altqs;
1514 ticket_altqs_active = ticket_altqs_inactive;
1515
1516 /* Attach new disciplines */
1517 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1518 if (altq->qname[0] == 0) {
1519 /* attach the discipline */
1895 if (error) {
1896 pool_put(&pf_altq_pl, altq);
1897 break;
1898 }
1899
1900 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
1901 bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1902 break;
1903 }
1904
1905 case DIOCCOMMITALTQS: {
1906 u_int32_t *ticket = (u_int32_t *)addr;
1907 struct pf_altqqueue *old_altqs;
1908 struct pf_altq *altq;
1909 struct pf_anchor *anchor;
1910 struct pf_ruleset *ruleset;
1911 int err;
1912
1913 if (*ticket != ticket_altqs_inactive) {
1914 error = EBUSY;
1915 break;
1916 }
1917
1918 /* Swap altqs, keep the old. */
1919 s = splsoftnet();
1920 old_altqs = pf_altqs_active;
1921 pf_altqs_active = pf_altqs_inactive;
1922 pf_altqs_inactive = old_altqs;
1923 ticket_altqs_active = ticket_altqs_inactive;
1924
1925 /* Attach new disciplines */
1926 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1927 if (altq->qname[0] == 0) {
1928 /* attach the discipline */
1929#if defined(__FreeBSD__)
1930 PF_UNLOCK();
1931#endif
1520 error = altq_pfattach(altq);
1932 error = altq_pfattach(altq);
1933#if defined(__FreeBSD__)
1934 PF_LOCK();
1935#endif
1521 if (error) {
1522 splx(s);
1523 goto fail;
1524 }
1525 }
1526 }
1527
1528 /* Purge the old altq list */
1529 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1530 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1531 if (altq->qname[0] == 0) {
1532 /* detach and destroy the discipline */
1936 if (error) {
1937 splx(s);
1938 goto fail;
1939 }
1940 }
1941 }
1942
1943 /* Purge the old altq list */
1944 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1945 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1946 if (altq->qname[0] == 0) {
1947 /* detach and destroy the discipline */
1948#if defined(__FreeBSD__)
1949 PF_UNLOCK();
1950#endif
1533 err = altq_pfdetach(altq);
1534 if (err != 0 && error == 0)
1535 error = err;
1536 err = altq_remove(altq);
1537 if (err != 0 && error == 0)
1538 error = err;
1951 err = altq_pfdetach(altq);
1952 if (err != 0 && error == 0)
1953 error = err;
1954 err = altq_remove(altq);
1955 if (err != 0 && error == 0)
1956 error = err;
1957#if defined(__FreeBSD__)
1958 PF_LOCK();
1959#endif
1539 }
1540 pool_put(&pf_altq_pl, altq);
1541 }
1542 splx(s);
1543
1544 /* update queue IDs */
1545 pf_rule_set_qid(
1546 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
1547 TAILQ_FOREACH(anchor, &pf_anchors, entries) {
1548 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
1549 pf_rule_set_qid(
1550 ruleset->rules[PF_RULESET_FILTER].active.ptr
1551 );
1552 }
1553 }
1554 break;
1555 }
1556
1557 case DIOCGETALTQS: {
1558 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
1559 struct pf_altq *altq;
1560
1561 pa->nr = 0;
1562 s = splsoftnet();
1563 TAILQ_FOREACH(altq, pf_altqs_active, entries)
1564 pa->nr++;
1565 pa->ticket = ticket_altqs_active;
1566 splx(s);
1567 break;
1568 }
1569
1570 case DIOCGETALTQ: {
1571 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
1572 struct pf_altq *altq;
1573 u_int32_t nr;
1574
1575 if (pa->ticket != ticket_altqs_active) {
1576 error = EBUSY;
1577 break;
1578 }
1579 nr = 0;
1580 s = splsoftnet();
1581 altq = TAILQ_FIRST(pf_altqs_active);
1582 while ((altq != NULL) && (nr < pa->nr)) {
1583 altq = TAILQ_NEXT(altq, entries);
1584 nr++;
1585 }
1586 if (altq == NULL) {
1587 error = EBUSY;
1588 splx(s);
1589 break;
1590 }
1591 bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1592 splx(s);
1593 break;
1594 }
1595
1596 case DIOCCHANGEALTQ:
1597 /* CHANGEALTQ not supported yet! */
1598 error = ENODEV;
1599 break;
1600
1601 case DIOCGETQSTATS: {
1602 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr;
1603 struct pf_altq *altq;
1604 u_int32_t nr;
1605 int nbytes;
1606
1607 if (pq->ticket != ticket_altqs_active) {
1608 error = EBUSY;
1609 break;
1610 }
1611 nbytes = pq->nbytes;
1612 nr = 0;
1613 s = splsoftnet();
1614 altq = TAILQ_FIRST(pf_altqs_active);
1615 while ((altq != NULL) && (nr < pq->nr)) {
1616 altq = TAILQ_NEXT(altq, entries);
1617 nr++;
1618 }
1619 if (altq == NULL) {
1620 error = EBUSY;
1621 splx(s);
1622 break;
1623 }
1960 }
1961 pool_put(&pf_altq_pl, altq);
1962 }
1963 splx(s);
1964
1965 /* update queue IDs */
1966 pf_rule_set_qid(
1967 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
1968 TAILQ_FOREACH(anchor, &pf_anchors, entries) {
1969 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
1970 pf_rule_set_qid(
1971 ruleset->rules[PF_RULESET_FILTER].active.ptr
1972 );
1973 }
1974 }
1975 break;
1976 }
1977
1978 case DIOCGETALTQS: {
1979 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
1980 struct pf_altq *altq;
1981
1982 pa->nr = 0;
1983 s = splsoftnet();
1984 TAILQ_FOREACH(altq, pf_altqs_active, entries)
1985 pa->nr++;
1986 pa->ticket = ticket_altqs_active;
1987 splx(s);
1988 break;
1989 }
1990
1991 case DIOCGETALTQ: {
1992 struct pfioc_altq *pa = (struct pfioc_altq *)addr;
1993 struct pf_altq *altq;
1994 u_int32_t nr;
1995
1996 if (pa->ticket != ticket_altqs_active) {
1997 error = EBUSY;
1998 break;
1999 }
2000 nr = 0;
2001 s = splsoftnet();
2002 altq = TAILQ_FIRST(pf_altqs_active);
2003 while ((altq != NULL) && (nr < pa->nr)) {
2004 altq = TAILQ_NEXT(altq, entries);
2005 nr++;
2006 }
2007 if (altq == NULL) {
2008 error = EBUSY;
2009 splx(s);
2010 break;
2011 }
2012 bcopy(altq, &pa->altq, sizeof(struct pf_altq));
2013 splx(s);
2014 break;
2015 }
2016
2017 case DIOCCHANGEALTQ:
2018 /* CHANGEALTQ not supported yet! */
2019 error = ENODEV;
2020 break;
2021
2022 case DIOCGETQSTATS: {
2023 struct pfioc_qstats *pq = (struct pfioc_qstats *)addr;
2024 struct pf_altq *altq;
2025 u_int32_t nr;
2026 int nbytes;
2027
2028 if (pq->ticket != ticket_altqs_active) {
2029 error = EBUSY;
2030 break;
2031 }
2032 nbytes = pq->nbytes;
2033 nr = 0;
2034 s = splsoftnet();
2035 altq = TAILQ_FIRST(pf_altqs_active);
2036 while ((altq != NULL) && (nr < pq->nr)) {
2037 altq = TAILQ_NEXT(altq, entries);
2038 nr++;
2039 }
2040 if (altq == NULL) {
2041 error = EBUSY;
2042 splx(s);
2043 break;
2044 }
2045#if defined(__FreeBSD__)
2046 PF_UNLOCK();
2047#endif
1624 error = altq_getqstats(altq, pq->buf, &nbytes);
2048 error = altq_getqstats(altq, pq->buf, &nbytes);
2049#if defined(__FreeBSD__)
2050 PF_LOCK();
2051#endif
1625 splx(s);
1626 if (error == 0) {
1627 pq->scheduler = altq->scheduler;
1628 pq->nbytes = nbytes;
1629 }
1630 break;
1631 }
1632#endif /* ALTQ */
1633
1634 case DIOCBEGINADDRS: {
1635 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
1636
1637 pf_empty_pool(&pf_pabuf);
1638 pp->ticket = ++ticket_pabuf;
1639 break;
1640 }
1641
1642 case DIOCADDADDR: {
1643 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
1644
1645#ifndef INET
1646 if (pp->af == AF_INET) {
1647 error = EAFNOSUPPORT;
1648 break;
1649 }
1650#endif /* INET */
1651#ifndef INET6
1652 if (pp->af == AF_INET6) {
1653 error = EAFNOSUPPORT;
1654 break;
1655 }
1656#endif /* INET6 */
1657 if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
1658 pp->addr.addr.type != PF_ADDR_DYNIFTL &&
1659 pp->addr.addr.type != PF_ADDR_TABLE) {
1660 error = EINVAL;
1661 break;
1662 }
1663 pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
1664 if (pa == NULL) {
1665 error = ENOMEM;
1666 break;
1667 }
1668 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
1669 if (pa->ifname[0]) {
1670 pa->ifp = ifunit(pa->ifname);
1671 if (pa->ifp == NULL) {
1672 pool_put(&pf_pooladdr_pl, pa);
1673 error = EINVAL;
1674 break;
1675 }
1676 }
1677 if (pf_dynaddr_setup(&pa->addr, pp->af)) {
1678 pf_dynaddr_remove(&pa->addr);
1679 pool_put(&pf_pooladdr_pl, pa);
1680 error = EINVAL;
1681 break;
1682 }
1683 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
1684 break;
1685 }
1686
1687 case DIOCGETADDRS: {
1688 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
1689
1690 pp->nr = 0;
1691 s = splsoftnet();
1692 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
1693 pp->r_action, pp->r_num, 0, 1, 0);
1694 if (pool == NULL) {
1695 error = EBUSY;
1696 splx(s);
1697 break;
1698 }
1699 TAILQ_FOREACH(pa, &pool->list, entries)
1700 pp->nr++;
1701 splx(s);
1702 break;
1703 }
1704
1705 case DIOCGETADDR: {
1706 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
1707 u_int32_t nr = 0;
1708
1709 s = splsoftnet();
1710 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
1711 pp->r_action, pp->r_num, 0, 1, 1);
1712 if (pool == NULL) {
1713 error = EBUSY;
1714 splx(s);
1715 break;
1716 }
1717 pa = TAILQ_FIRST(&pool->list);
1718 while ((pa != NULL) && (nr < pp->nr)) {
1719 pa = TAILQ_NEXT(pa, entries);
1720 nr++;
1721 }
1722 if (pa == NULL) {
1723 error = EBUSY;
1724 splx(s);
1725 break;
1726 }
1727 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
1728 pf_dynaddr_copyout(&pp->addr.addr);
1729 pf_tbladdr_copyout(&pp->addr.addr);
1730 splx(s);
1731 break;
1732 }
1733
1734 case DIOCCHANGEADDR: {
1735 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr;
1736 struct pf_pooladdr *oldpa = NULL, *newpa = NULL;
1737 struct pf_ruleset *ruleset;
1738
1739 if (pca->action < PF_CHANGE_ADD_HEAD ||
1740 pca->action > PF_CHANGE_REMOVE) {
1741 error = EINVAL;
1742 break;
1743 }
1744 if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
1745 pca->addr.addr.type != PF_ADDR_DYNIFTL &&
1746 pca->addr.addr.type != PF_ADDR_TABLE) {
1747 error = EINVAL;
1748 break;
1749 }
1750
1751 ruleset = pf_find_ruleset(pca->anchor, pca->ruleset);
1752 if (ruleset == NULL) {
1753 error = EBUSY;
1754 break;
1755 }
1756 pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket,
1757 pca->r_action, pca->r_num, pca->r_last, 1, 1);
1758 if (pool == NULL) {
1759 error = EBUSY;
1760 break;
1761 }
1762 if (pca->action != PF_CHANGE_REMOVE) {
1763 newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
1764 if (newpa == NULL) {
1765 error = ENOMEM;
1766 break;
1767 }
1768 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
1769#ifndef INET
1770 if (pca->af == AF_INET) {
1771 pool_put(&pf_pooladdr_pl, newpa);
1772 error = EAFNOSUPPORT;
1773 break;
1774 }
1775#endif /* INET */
1776#ifndef INET6
1777 if (pca->af == AF_INET6) {
1778 pool_put(&pf_pooladdr_pl, newpa);
1779 error = EAFNOSUPPORT;
1780 break;
1781 }
1782#endif /* INET6 */
1783 if (newpa->ifname[0]) {
1784 newpa->ifp = ifunit(newpa->ifname);
1785 if (newpa->ifp == NULL) {
1786 pool_put(&pf_pooladdr_pl, newpa);
1787 error = EINVAL;
1788 break;
1789 }
1790 } else
1791 newpa->ifp = NULL;
1792 if (pf_dynaddr_setup(&newpa->addr, pca->af) ||
1793 pf_tbladdr_setup(ruleset, &newpa->addr)) {
1794 pf_dynaddr_remove(&newpa->addr);
1795 pool_put(&pf_pooladdr_pl, newpa);
1796 error = EINVAL;
1797 break;
1798 }
1799 }
1800
1801 s = splsoftnet();
1802
1803 if (pca->action == PF_CHANGE_ADD_HEAD)
1804 oldpa = TAILQ_FIRST(&pool->list);
1805 else if (pca->action == PF_CHANGE_ADD_TAIL)
1806 oldpa = TAILQ_LAST(&pool->list, pf_palist);
1807 else {
1808 int i = 0;
1809
1810 oldpa = TAILQ_FIRST(&pool->list);
1811 while ((oldpa != NULL) && (i < pca->nr)) {
1812 oldpa = TAILQ_NEXT(oldpa, entries);
1813 i++;
1814 }
1815 if (oldpa == NULL) {
1816 error = EINVAL;
1817 splx(s);
1818 break;
1819 }
1820 }
1821
1822 if (pca->action == PF_CHANGE_REMOVE) {
1823 TAILQ_REMOVE(&pool->list, oldpa, entries);
1824 pf_dynaddr_remove(&oldpa->addr);
1825 pf_tbladdr_remove(&oldpa->addr);
1826 pool_put(&pf_pooladdr_pl, oldpa);
1827 } else {
1828 if (oldpa == NULL)
1829 TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
1830 else if (pca->action == PF_CHANGE_ADD_HEAD ||
1831 pca->action == PF_CHANGE_ADD_BEFORE)
1832 TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
1833 else
1834 TAILQ_INSERT_AFTER(&pool->list, oldpa,
1835 newpa, entries);
1836 }
1837
1838 pool->cur = TAILQ_FIRST(&pool->list);
1839 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
1840 pca->af);
1841 splx(s);
1842 break;
1843 }
1844
1845 case DIOCGETANCHORS: {
1846 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr;
1847 struct pf_anchor *anchor;
1848
1849 pa->nr = 0;
1850 TAILQ_FOREACH(anchor, &pf_anchors, entries)
1851 pa->nr++;
1852 break;
1853 }
1854
1855 case DIOCGETANCHOR: {
1856 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr;
1857 struct pf_anchor *anchor;
1858 u_int32_t nr = 0;
1859
1860 anchor = TAILQ_FIRST(&pf_anchors);
1861 while (anchor != NULL && nr < pa->nr) {
1862 anchor = TAILQ_NEXT(anchor, entries);
1863 nr++;
1864 }
1865 if (anchor == NULL)
1866 error = EBUSY;
1867 else
1868 bcopy(anchor->name, pa->name, sizeof(pa->name));
1869 break;
1870 }
1871
1872 case DIOCGETRULESETS: {
1873 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
1874 struct pf_anchor *anchor;
1875 struct pf_ruleset *ruleset;
1876
1877 pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0;
1878 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
1879 error = EINVAL;
1880 break;
1881 }
1882 pr->nr = 0;
1883 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries)
1884 pr->nr++;
1885 break;
1886 }
1887
1888 case DIOCGETRULESET: {
1889 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
1890 struct pf_anchor *anchor;
1891 struct pf_ruleset *ruleset;
1892 u_int32_t nr = 0;
1893
1894 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
1895 error = EINVAL;
1896 break;
1897 }
1898 ruleset = TAILQ_FIRST(&anchor->rulesets);
1899 while (ruleset != NULL && nr < pr->nr) {
1900 ruleset = TAILQ_NEXT(ruleset, entries);
1901 nr++;
1902 }
1903 if (ruleset == NULL)
1904 error = EBUSY;
1905 else
1906 bcopy(ruleset->name, pr->name, sizeof(pr->name));
1907 break;
1908 }
1909
1910 case DIOCRCLRTABLES: {
1911 struct pfioc_table *io = (struct pfioc_table *)addr;
1912
1913 if (io->pfrio_esize != 0) {
1914 error = ENODEV;
1915 break;
1916 }
1917 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
1918 io->pfrio_flags);
1919 break;
1920 }
1921
1922 case DIOCRADDTABLES: {
1923 struct pfioc_table *io = (struct pfioc_table *)addr;
1924
1925 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1926 error = ENODEV;
1927 break;
1928 }
1929 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
1930 &io->pfrio_nadd, io->pfrio_flags);
1931 break;
1932 }
1933
1934 case DIOCRDELTABLES: {
1935 struct pfioc_table *io = (struct pfioc_table *)addr;
1936
1937 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1938 error = ENODEV;
1939 break;
1940 }
1941 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
1942 &io->pfrio_ndel, io->pfrio_flags);
1943 break;
1944 }
1945
1946 case DIOCRGETTABLES: {
1947 struct pfioc_table *io = (struct pfioc_table *)addr;
1948
1949 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1950 error = ENODEV;
1951 break;
1952 }
1953 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
1954 &io->pfrio_size, io->pfrio_flags);
1955 break;
1956 }
1957
1958 case DIOCRGETTSTATS: {
1959 struct pfioc_table *io = (struct pfioc_table *)addr;
1960
1961 if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
1962 error = ENODEV;
1963 break;
1964 }
1965 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
1966 &io->pfrio_size, io->pfrio_flags);
1967 break;
1968 }
1969
1970 case DIOCRCLRTSTATS: {
1971 struct pfioc_table *io = (struct pfioc_table *)addr;
1972
1973 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1974 error = ENODEV;
1975 break;
1976 }
1977 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
1978 &io->pfrio_nzero, io->pfrio_flags);
1979 break;
1980 }
1981
1982 case DIOCRSETTFLAGS: {
1983 struct pfioc_table *io = (struct pfioc_table *)addr;
1984
1985 if (io->pfrio_esize != sizeof(struct pfr_table)) {
1986 error = ENODEV;
1987 break;
1988 }
1989 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
1990 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
1991 &io->pfrio_ndel, io->pfrio_flags);
1992 break;
1993 }
1994
1995 case DIOCRCLRADDRS: {
1996 struct pfioc_table *io = (struct pfioc_table *)addr;
1997
1998 if (io->pfrio_esize != 0) {
1999 error = ENODEV;
2000 break;
2001 }
2002 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
2003 io->pfrio_flags);
2004 break;
2005 }
2006
2007 case DIOCRADDADDRS: {
2008 struct pfioc_table *io = (struct pfioc_table *)addr;
2009
2010 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2011 error = ENODEV;
2012 break;
2013 }
2014 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
2015 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags);
2016 break;
2017 }
2018
2019 case DIOCRDELADDRS: {
2020 struct pfioc_table *io = (struct pfioc_table *)addr;
2021
2022 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2023 error = ENODEV;
2024 break;
2025 }
2026 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
2027 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags);
2028 break;
2029 }
2030
2031 case DIOCRSETADDRS: {
2032 struct pfioc_table *io = (struct pfioc_table *)addr;
2033
2034 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2035 error = ENODEV;
2036 break;
2037 }
2038 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
2039 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
2040 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags);
2041 break;
2042 }
2043
2044 case DIOCRGETADDRS: {
2045 struct pfioc_table *io = (struct pfioc_table *)addr;
2046
2047 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2048 error = ENODEV;
2049 break;
2050 }
2051 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
2052 &io->pfrio_size, io->pfrio_flags);
2053 break;
2054 }
2055
2056 case DIOCRGETASTATS: {
2057 struct pfioc_table *io = (struct pfioc_table *)addr;
2058
2059 if (io->pfrio_esize != sizeof(struct pfr_astats)) {
2060 error = ENODEV;
2061 break;
2062 }
2063 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
2064 &io->pfrio_size, io->pfrio_flags);
2065 break;
2066 }
2067
2068 case DIOCRCLRASTATS: {
2069 struct pfioc_table *io = (struct pfioc_table *)addr;
2070
2071 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2072 error = ENODEV;
2073 break;
2074 }
2075 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
2076 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags);
2077 break;
2078 }
2079
2080 case DIOCRTSTADDRS: {
2081 struct pfioc_table *io = (struct pfioc_table *)addr;
2082
2083 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2084 error = ENODEV;
2085 break;
2086 }
2087 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
2088 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags);
2089 break;
2090 }
2091
2092 case DIOCRINABEGIN: {
2093 struct pfioc_table *io = (struct pfioc_table *)addr;
2094
2095 if (io->pfrio_esize != 0) {
2096 error = ENODEV;
2097 break;
2098 }
2099 error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket,
2100 &io->pfrio_ndel, io->pfrio_flags);
2101 break;
2102 }
2103
2104 case DIOCRINACOMMIT: {
2105 struct pfioc_table *io = (struct pfioc_table *)addr;
2106
2107 if (io->pfrio_esize != 0) {
2108 error = ENODEV;
2109 break;
2110 }
2111 error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket,
2112 &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags);
2113 break;
2114 }
2115
2116 case DIOCRINADEFINE: {
2117 struct pfioc_table *io = (struct pfioc_table *)addr;
2118
2119 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2120 error = ENODEV;
2121 break;
2122 }
2123 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
2124 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
2125 io->pfrio_ticket, io->pfrio_flags);
2126 break;
2127 }
2128
2129 case DIOCOSFPFLUSH:
2130 s = splsoftnet();
2131 pf_osfp_flush();
2132 splx(s);
2133 break;
2134
2135 case DIOCOSFPADD: {
2136 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2137 s = splsoftnet();
2138 error = pf_osfp_add(io);
2139 splx(s);
2140 break;
2141 }
2142
2143 case DIOCOSFPGET: {
2144 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2145 s = splsoftnet();
2146 error = pf_osfp_get(io);
2147 splx(s);
2148 break;
2149 }
2150
2151 default:
2152 error = ENODEV;
2153 break;
2154 }
2155fail:
2052 splx(s);
2053 if (error == 0) {
2054 pq->scheduler = altq->scheduler;
2055 pq->nbytes = nbytes;
2056 }
2057 break;
2058 }
2059#endif /* ALTQ */
2060
2061 case DIOCBEGINADDRS: {
2062 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
2063
2064 pf_empty_pool(&pf_pabuf);
2065 pp->ticket = ++ticket_pabuf;
2066 break;
2067 }
2068
2069 case DIOCADDADDR: {
2070 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
2071
2072#ifndef INET
2073 if (pp->af == AF_INET) {
2074 error = EAFNOSUPPORT;
2075 break;
2076 }
2077#endif /* INET */
2078#ifndef INET6
2079 if (pp->af == AF_INET6) {
2080 error = EAFNOSUPPORT;
2081 break;
2082 }
2083#endif /* INET6 */
2084 if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
2085 pp->addr.addr.type != PF_ADDR_DYNIFTL &&
2086 pp->addr.addr.type != PF_ADDR_TABLE) {
2087 error = EINVAL;
2088 break;
2089 }
2090 pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
2091 if (pa == NULL) {
2092 error = ENOMEM;
2093 break;
2094 }
2095 bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
2096 if (pa->ifname[0]) {
2097 pa->ifp = ifunit(pa->ifname);
2098 if (pa->ifp == NULL) {
2099 pool_put(&pf_pooladdr_pl, pa);
2100 error = EINVAL;
2101 break;
2102 }
2103 }
2104 if (pf_dynaddr_setup(&pa->addr, pp->af)) {
2105 pf_dynaddr_remove(&pa->addr);
2106 pool_put(&pf_pooladdr_pl, pa);
2107 error = EINVAL;
2108 break;
2109 }
2110 TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
2111 break;
2112 }
2113
2114 case DIOCGETADDRS: {
2115 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
2116
2117 pp->nr = 0;
2118 s = splsoftnet();
2119 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
2120 pp->r_action, pp->r_num, 0, 1, 0);
2121 if (pool == NULL) {
2122 error = EBUSY;
2123 splx(s);
2124 break;
2125 }
2126 TAILQ_FOREACH(pa, &pool->list, entries)
2127 pp->nr++;
2128 splx(s);
2129 break;
2130 }
2131
2132 case DIOCGETADDR: {
2133 struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
2134 u_int32_t nr = 0;
2135
2136 s = splsoftnet();
2137 pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
2138 pp->r_action, pp->r_num, 0, 1, 1);
2139 if (pool == NULL) {
2140 error = EBUSY;
2141 splx(s);
2142 break;
2143 }
2144 pa = TAILQ_FIRST(&pool->list);
2145 while ((pa != NULL) && (nr < pp->nr)) {
2146 pa = TAILQ_NEXT(pa, entries);
2147 nr++;
2148 }
2149 if (pa == NULL) {
2150 error = EBUSY;
2151 splx(s);
2152 break;
2153 }
2154 bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
2155 pf_dynaddr_copyout(&pp->addr.addr);
2156 pf_tbladdr_copyout(&pp->addr.addr);
2157 splx(s);
2158 break;
2159 }
2160
2161 case DIOCCHANGEADDR: {
2162 struct pfioc_pooladdr *pca = (struct pfioc_pooladdr *)addr;
2163 struct pf_pooladdr *oldpa = NULL, *newpa = NULL;
2164 struct pf_ruleset *ruleset;
2165
2166 if (pca->action < PF_CHANGE_ADD_HEAD ||
2167 pca->action > PF_CHANGE_REMOVE) {
2168 error = EINVAL;
2169 break;
2170 }
2171 if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
2172 pca->addr.addr.type != PF_ADDR_DYNIFTL &&
2173 pca->addr.addr.type != PF_ADDR_TABLE) {
2174 error = EINVAL;
2175 break;
2176 }
2177
2178 ruleset = pf_find_ruleset(pca->anchor, pca->ruleset);
2179 if (ruleset == NULL) {
2180 error = EBUSY;
2181 break;
2182 }
2183 pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket,
2184 pca->r_action, pca->r_num, pca->r_last, 1, 1);
2185 if (pool == NULL) {
2186 error = EBUSY;
2187 break;
2188 }
2189 if (pca->action != PF_CHANGE_REMOVE) {
2190 newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
2191 if (newpa == NULL) {
2192 error = ENOMEM;
2193 break;
2194 }
2195 bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
2196#ifndef INET
2197 if (pca->af == AF_INET) {
2198 pool_put(&pf_pooladdr_pl, newpa);
2199 error = EAFNOSUPPORT;
2200 break;
2201 }
2202#endif /* INET */
2203#ifndef INET6
2204 if (pca->af == AF_INET6) {
2205 pool_put(&pf_pooladdr_pl, newpa);
2206 error = EAFNOSUPPORT;
2207 break;
2208 }
2209#endif /* INET6 */
2210 if (newpa->ifname[0]) {
2211 newpa->ifp = ifunit(newpa->ifname);
2212 if (newpa->ifp == NULL) {
2213 pool_put(&pf_pooladdr_pl, newpa);
2214 error = EINVAL;
2215 break;
2216 }
2217 } else
2218 newpa->ifp = NULL;
2219 if (pf_dynaddr_setup(&newpa->addr, pca->af) ||
2220 pf_tbladdr_setup(ruleset, &newpa->addr)) {
2221 pf_dynaddr_remove(&newpa->addr);
2222 pool_put(&pf_pooladdr_pl, newpa);
2223 error = EINVAL;
2224 break;
2225 }
2226 }
2227
2228 s = splsoftnet();
2229
2230 if (pca->action == PF_CHANGE_ADD_HEAD)
2231 oldpa = TAILQ_FIRST(&pool->list);
2232 else if (pca->action == PF_CHANGE_ADD_TAIL)
2233 oldpa = TAILQ_LAST(&pool->list, pf_palist);
2234 else {
2235 int i = 0;
2236
2237 oldpa = TAILQ_FIRST(&pool->list);
2238 while ((oldpa != NULL) && (i < pca->nr)) {
2239 oldpa = TAILQ_NEXT(oldpa, entries);
2240 i++;
2241 }
2242 if (oldpa == NULL) {
2243 error = EINVAL;
2244 splx(s);
2245 break;
2246 }
2247 }
2248
2249 if (pca->action == PF_CHANGE_REMOVE) {
2250 TAILQ_REMOVE(&pool->list, oldpa, entries);
2251 pf_dynaddr_remove(&oldpa->addr);
2252 pf_tbladdr_remove(&oldpa->addr);
2253 pool_put(&pf_pooladdr_pl, oldpa);
2254 } else {
2255 if (oldpa == NULL)
2256 TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
2257 else if (pca->action == PF_CHANGE_ADD_HEAD ||
2258 pca->action == PF_CHANGE_ADD_BEFORE)
2259 TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
2260 else
2261 TAILQ_INSERT_AFTER(&pool->list, oldpa,
2262 newpa, entries);
2263 }
2264
2265 pool->cur = TAILQ_FIRST(&pool->list);
2266 PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
2267 pca->af);
2268 splx(s);
2269 break;
2270 }
2271
2272 case DIOCGETANCHORS: {
2273 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr;
2274 struct pf_anchor *anchor;
2275
2276 pa->nr = 0;
2277 TAILQ_FOREACH(anchor, &pf_anchors, entries)
2278 pa->nr++;
2279 break;
2280 }
2281
2282 case DIOCGETANCHOR: {
2283 struct pfioc_anchor *pa = (struct pfioc_anchor *)addr;
2284 struct pf_anchor *anchor;
2285 u_int32_t nr = 0;
2286
2287 anchor = TAILQ_FIRST(&pf_anchors);
2288 while (anchor != NULL && nr < pa->nr) {
2289 anchor = TAILQ_NEXT(anchor, entries);
2290 nr++;
2291 }
2292 if (anchor == NULL)
2293 error = EBUSY;
2294 else
2295 bcopy(anchor->name, pa->name, sizeof(pa->name));
2296 break;
2297 }
2298
2299 case DIOCGETRULESETS: {
2300 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
2301 struct pf_anchor *anchor;
2302 struct pf_ruleset *ruleset;
2303
2304 pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0;
2305 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
2306 error = EINVAL;
2307 break;
2308 }
2309 pr->nr = 0;
2310 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries)
2311 pr->nr++;
2312 break;
2313 }
2314
2315 case DIOCGETRULESET: {
2316 struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr;
2317 struct pf_anchor *anchor;
2318 struct pf_ruleset *ruleset;
2319 u_int32_t nr = 0;
2320
2321 if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
2322 error = EINVAL;
2323 break;
2324 }
2325 ruleset = TAILQ_FIRST(&anchor->rulesets);
2326 while (ruleset != NULL && nr < pr->nr) {
2327 ruleset = TAILQ_NEXT(ruleset, entries);
2328 nr++;
2329 }
2330 if (ruleset == NULL)
2331 error = EBUSY;
2332 else
2333 bcopy(ruleset->name, pr->name, sizeof(pr->name));
2334 break;
2335 }
2336
2337 case DIOCRCLRTABLES: {
2338 struct pfioc_table *io = (struct pfioc_table *)addr;
2339
2340 if (io->pfrio_esize != 0) {
2341 error = ENODEV;
2342 break;
2343 }
2344 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
2345 io->pfrio_flags);
2346 break;
2347 }
2348
2349 case DIOCRADDTABLES: {
2350 struct pfioc_table *io = (struct pfioc_table *)addr;
2351
2352 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2353 error = ENODEV;
2354 break;
2355 }
2356 error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
2357 &io->pfrio_nadd, io->pfrio_flags);
2358 break;
2359 }
2360
2361 case DIOCRDELTABLES: {
2362 struct pfioc_table *io = (struct pfioc_table *)addr;
2363
2364 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2365 error = ENODEV;
2366 break;
2367 }
2368 error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
2369 &io->pfrio_ndel, io->pfrio_flags);
2370 break;
2371 }
2372
2373 case DIOCRGETTABLES: {
2374 struct pfioc_table *io = (struct pfioc_table *)addr;
2375
2376 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2377 error = ENODEV;
2378 break;
2379 }
2380 error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
2381 &io->pfrio_size, io->pfrio_flags);
2382 break;
2383 }
2384
2385 case DIOCRGETTSTATS: {
2386 struct pfioc_table *io = (struct pfioc_table *)addr;
2387
2388 if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
2389 error = ENODEV;
2390 break;
2391 }
2392 error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
2393 &io->pfrio_size, io->pfrio_flags);
2394 break;
2395 }
2396
2397 case DIOCRCLRTSTATS: {
2398 struct pfioc_table *io = (struct pfioc_table *)addr;
2399
2400 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2401 error = ENODEV;
2402 break;
2403 }
2404 error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
2405 &io->pfrio_nzero, io->pfrio_flags);
2406 break;
2407 }
2408
2409 case DIOCRSETTFLAGS: {
2410 struct pfioc_table *io = (struct pfioc_table *)addr;
2411
2412 if (io->pfrio_esize != sizeof(struct pfr_table)) {
2413 error = ENODEV;
2414 break;
2415 }
2416 error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
2417 io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
2418 &io->pfrio_ndel, io->pfrio_flags);
2419 break;
2420 }
2421
2422 case DIOCRCLRADDRS: {
2423 struct pfioc_table *io = (struct pfioc_table *)addr;
2424
2425 if (io->pfrio_esize != 0) {
2426 error = ENODEV;
2427 break;
2428 }
2429 error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
2430 io->pfrio_flags);
2431 break;
2432 }
2433
2434 case DIOCRADDADDRS: {
2435 struct pfioc_table *io = (struct pfioc_table *)addr;
2436
2437 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2438 error = ENODEV;
2439 break;
2440 }
2441 error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
2442 io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags);
2443 break;
2444 }
2445
2446 case DIOCRDELADDRS: {
2447 struct pfioc_table *io = (struct pfioc_table *)addr;
2448
2449 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2450 error = ENODEV;
2451 break;
2452 }
2453 error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
2454 io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags);
2455 break;
2456 }
2457
2458 case DIOCRSETADDRS: {
2459 struct pfioc_table *io = (struct pfioc_table *)addr;
2460
2461 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2462 error = ENODEV;
2463 break;
2464 }
2465 error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
2466 io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
2467 &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags);
2468 break;
2469 }
2470
2471 case DIOCRGETADDRS: {
2472 struct pfioc_table *io = (struct pfioc_table *)addr;
2473
2474 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2475 error = ENODEV;
2476 break;
2477 }
2478 error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
2479 &io->pfrio_size, io->pfrio_flags);
2480 break;
2481 }
2482
2483 case DIOCRGETASTATS: {
2484 struct pfioc_table *io = (struct pfioc_table *)addr;
2485
2486 if (io->pfrio_esize != sizeof(struct pfr_astats)) {
2487 error = ENODEV;
2488 break;
2489 }
2490 error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
2491 &io->pfrio_size, io->pfrio_flags);
2492 break;
2493 }
2494
2495 case DIOCRCLRASTATS: {
2496 struct pfioc_table *io = (struct pfioc_table *)addr;
2497
2498 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2499 error = ENODEV;
2500 break;
2501 }
2502 error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
2503 io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags);
2504 break;
2505 }
2506
2507 case DIOCRTSTADDRS: {
2508 struct pfioc_table *io = (struct pfioc_table *)addr;
2509
2510 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2511 error = ENODEV;
2512 break;
2513 }
2514 error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
2515 io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags);
2516 break;
2517 }
2518
2519 case DIOCRINABEGIN: {
2520 struct pfioc_table *io = (struct pfioc_table *)addr;
2521
2522 if (io->pfrio_esize != 0) {
2523 error = ENODEV;
2524 break;
2525 }
2526 error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket,
2527 &io->pfrio_ndel, io->pfrio_flags);
2528 break;
2529 }
2530
2531 case DIOCRINACOMMIT: {
2532 struct pfioc_table *io = (struct pfioc_table *)addr;
2533
2534 if (io->pfrio_esize != 0) {
2535 error = ENODEV;
2536 break;
2537 }
2538 error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket,
2539 &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags);
2540 break;
2541 }
2542
2543 case DIOCRINADEFINE: {
2544 struct pfioc_table *io = (struct pfioc_table *)addr;
2545
2546 if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2547 error = ENODEV;
2548 break;
2549 }
2550 error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
2551 io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
2552 io->pfrio_ticket, io->pfrio_flags);
2553 break;
2554 }
2555
2556 case DIOCOSFPFLUSH:
2557 s = splsoftnet();
2558 pf_osfp_flush();
2559 splx(s);
2560 break;
2561
2562 case DIOCOSFPADD: {
2563 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2564 s = splsoftnet();
2565 error = pf_osfp_add(io);
2566 splx(s);
2567 break;
2568 }
2569
2570 case DIOCOSFPGET: {
2571 struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2572 s = splsoftnet();
2573 error = pf_osfp_get(io);
2574 splx(s);
2575 break;
2576 }
2577
2578 default:
2579 error = ENODEV;
2580 break;
2581 }
2582fail:
2583#if defined(__FreeBSD__)
2584 PF_UNLOCK();
2585#endif
2586 return (error);
2587}
2156
2588
2589#if defined(__FreeBSD__)
2590/*
2591 * XXX - Check for version missmatch!!!
2592 */
2593static int
2594pf_beginrules(void *addr)
2595{
2596 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
2597 struct pf_ruleset *ruleset;
2598 struct pf_rule *rule;
2599 int rs_num;
2600 int error = 0;
2601
2602 do {
2603 ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
2604 if (ruleset == NULL) {
2605 error = EINVAL;
2606 break;
2607 }
2608 rs_num = pf_get_ruleset_number(pr->rule.action);
2609 if (rs_num >= PF_RULESET_MAX) {
2610 error = EINVAL;
2611 break;
2612 }
2613 while ((rule =
2614 TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
2615 pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
2616 pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
2617 } while(0);
2618
2157 return (error);
2158}
2619 return (error);
2620}
2621
2622static int
2623pf_commitrules(void *addr)
2624{
2625 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
2626 struct pf_ruleset *ruleset;
2627 struct pf_rulequeue *old_rules;
2628 struct pf_rule *rule;
2629 int rs_num, s;
2630 int error = 0;
2631
2632 do {
2633 ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
2634 if (ruleset == NULL) {
2635 error = EINVAL;
2636 break;
2637 }
2638 rs_num = pf_get_ruleset_number(pr->rule.action);
2639 if (rs_num >= PF_RULESET_MAX) {
2640 error = EINVAL;
2641 break;
2642 }
2643 if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
2644 error = EBUSY;
2645 break;
2646 }
2647
2648#ifdef ALTQ
2649 /* set queue IDs */
2650 if (rs_num == PF_RULESET_FILTER)
2651 pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
2652#endif
2653
2654 /* Swap rules, keep the old. */
2655 s = splsoftnet();
2656 old_rules = ruleset->rules[rs_num].active.ptr;
2657 ruleset->rules[rs_num].active.ptr =
2658 ruleset->rules[rs_num].inactive.ptr;
2659 ruleset->rules[rs_num].inactive.ptr = old_rules;
2660 ruleset->rules[rs_num].active.ticket =
2661 ruleset->rules[rs_num].inactive.ticket;
2662 pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
2663
2664 /* Purge the old rule list. */
2665 while ((rule = TAILQ_FIRST(old_rules)) != NULL)
2666 pf_rm_rule(old_rules, rule);
2667 pf_remove_if_empty_ruleset(ruleset);
2668 pf_update_anchor_rules();
2669 splx(s);
2670 } while (0);
2671
2672 return (error);
2673}
2674
2675#if defined(ALTQ)
2676static int
2677pf_beginaltqs(void *addr)
2678{
2679 u_int32_t *ticket = (u_int32_t *)addr;
2680 struct pf_altq *altq;
2681 int error = 0;
2682
2683 /* Purge the old altq list */
2684 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
2685 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
2686 if (altq->qname[0] == 0) {
2687#if defined(__FreeBSD__)
2688 PF_UNLOCK();
2689#endif
2690 /* detach and destroy the discipline */
2691 error = altq_remove(altq);
2692#if defined(__FreeBSD__)
2693 PF_LOCK();
2694#endif
2695 }
2696 uma_zfree(pf_altq_pl, altq);
2697 }
2698 *ticket = ++ticket_altqs_inactive;
2699
2700 return (error);
2701}
2702
2703static int
2704pf_commitaltqs(void *addr)
2705{
2706 u_int32_t *ticket = (u_int32_t *)addr;
2707 struct pf_altqqueue *old_altqs;
2708 struct pf_altq *altq;
2709 struct pf_anchor *anchor;
2710 struct pf_ruleset *ruleset;
2711 int err;
2712 int s;
2713 int error = 0;
2714
2715 do {
2716 if (*ticket != ticket_altqs_inactive) {
2717 error = EBUSY;
2718 break;
2719 }
2720
2721 /* Swap altqs, keep the old. */
2722 s = splsoftnet();
2723 old_altqs = pf_altqs_active;
2724 pf_altqs_active = pf_altqs_inactive;
2725 pf_altqs_inactive = old_altqs;
2726 ticket_altqs_active = ticket_altqs_inactive;
2727
2728 /* Attach new disciplines */
2729 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2730 if (altq->qname[0] == 0) {
2731 /* attach the discipline */
2732#if defined(__FreeBSD__)
2733 PF_UNLOCK();
2734#endif
2735 error = altq_pfattach(altq);
2736#if defined(__FreeBSD__)
2737 PF_LOCK();
2738#endif
2739 if (error) {
2740 splx(s);
2741 goto altq_fail;
2742 }
2743 }
2744 }
2745
2746 /* Purge the old altq list */
2747 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
2748 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
2749 if (altq->qname[0] == 0) {
2750 /* detach and destroy the discipline */
2751#if defined(__FreeBSD__)
2752 PF_UNLOCK();
2753#endif
2754 err = altq_pfdetach(altq);
2755 if (err != 0 && error == 0)
2756 error = err;
2757 err = altq_remove(altq);
2758 if (err != 0 && error == 0)
2759 error = err;
2760#if defined(__FreeBSD__)
2761 PF_LOCK();
2762#endif
2763 }
2764 uma_zfree(pf_altq_pl, altq);
2765 }
2766 splx(s);
2767
2768 /* update queue IDs */
2769 pf_rule_set_qid(
2770 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
2771 TAILQ_FOREACH(anchor, &pf_anchors, entries) {
2772 TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
2773 pf_rule_set_qid(
2774 ruleset->rules[PF_RULESET_FILTER].active.ptr
2775 );
2776 }
2777 }
2778 } while (0);
2779
2780altq_fail:
2781
2782 return (error);
2783}
2784
2785static int
2786pf_stopaltq(void)
2787{
2788 struct pf_altq *altq;
2789 struct ifnet *ifp;
2790 struct tb_profile tb;
2791 int err;
2792 int s;
2793 int error = 0;
2794
2795 do {
2796 /* disable all altq interfaces on active list */
2797 s = splsoftnet();
2798 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2799 if (altq->qname[0] == 0) {
2800 if ((ifp = ifunit(altq->ifname)) == NULL) {
2801 error = EINVAL;
2802 break;
2803 }
2804 if (ifp->if_snd.altq_type != ALTQT_NONE) {
2805 err = altq_disable(&ifp->if_snd);
2806 if (err != 0 && error == 0)
2807 error = err;
2808 }
2809 /* clear tokenbucket regulator */
2810 tb.rate = 0;
2811 err = tbr_set(&ifp->if_snd, &tb);
2812 if (err != 0 && error == 0)
2813 error = err;
2814 }
2815 }
2816#if defined(__FreeBSD__)
2817 if (error == 0) {
2818 mtx_lock(&pf_altq_mtx);
2819 pfaltq_running = 0;
2820 mtx_unlock(&pf_altq_mtx);
2821 }
2822#else
2823 if (error == 0)
2824 pfaltq_running = 0;
2825#endif
2826 splx(s);
2827 } while (0);
2828
2829 return (error);
2830}
2831#endif
2832
2833static void
2834pf_clearstates(void)
2835{
2836 struct pf_tree_node *n;
2837 int s;
2838
2839 s = splsoftnet();
2840 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
2841 n->state->timeout = PFTM_PURGE;
2842 pf_purge_expired_states();
2843 pf_status.states = 0;
2844 splx(s);
2845}
2846
2847static int
2848pf_clear_tables(void *addr)
2849{
2850 struct pfioc_table *io = (struct pfioc_table *)addr;
2851 int error;
2852
2853 error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
2854 io->pfrio_flags);
2855
2856 return (error);
2857}
2858
2859static int
2860shutdown_pf(void)
2861{
2862 struct pfioc_rule pr;
2863#if defined(ALTQ)
2864 struct pfioc_altq pa;
2865#endif
2866 struct pfioc_table io;
2867 int error = 0;
2868
2869 callout_stop(&pf_expire_to);
2870
2871 PF_LOCK();
2872 pf_status.running = 0;
2873 do {
2874#if defined(ALTQ)
2875 if ((error = pf_stopaltq())) {
2876 DPFPRINTF(PF_DEBUG_MISC,
2877 ("ALTQ: stop(%i)\n", error));
2878 break;
2879 }
2880#endif
2881 bzero(&pr, sizeof(pr));
2882 pr.rule.action = PF_SCRUB;
2883 if ((error = pf_beginrules(&pr))) {
2884 DPFPRINTF(PF_DEBUG_MISC,
2885 ("PF_SCRUB: begin(%i)\n", error));
2886 break;
2887 }
2888 if ((error = pf_commitrules(&pr))) {
2889 DPFPRINTF(PF_DEBUG_MISC,
2890 ("PF_SCRUB: commit(%i)\n", error));
2891 break;
2892 }
2893
2894 pr.rule.action = PF_PASS;
2895 if ((error = pf_beginrules(&pr))) {
2896 DPFPRINTF(PF_DEBUG_MISC,
2897 ("PF_PASS: begin(%i)\n", error));
2898 break;
2899 }
2900 if ((error = pf_commitrules(&pr))) {
2901 DPFPRINTF(PF_DEBUG_MISC,
2902 ("PF_PASS: commit(%i)\n", error));
2903 break;
2904 }
2905
2906/*
2907 * XXX not sure, but can't hurt:
2908 */
2909 bzero(&pr, sizeof(pr));
2910 pr.rule.action = PF_NAT;
2911 if ((error = pf_beginrules(&pr))) {
2912 DPFPRINTF(PF_DEBUG_MISC,
2913 ("PF_NAT: begin(%i)\n", error));
2914 break;
2915 }
2916 if ((error = pf_commitrules(&pr))) {
2917 DPFPRINTF(PF_DEBUG_MISC,
2918 ("PF_NAT: commit(%i)\n", error));
2919 break;
2920 }
2921
2922 pr.rule.action = PF_BINAT;
2923 if ((error = pf_beginrules(&pr))) {
2924 DPFPRINTF(PF_DEBUG_MISC,
2925 ("PF_BINAT: begin(%i)\n", error));
2926 break;
2927 }
2928 if ((error = pf_commitrules(&pr))) {
2929 DPFPRINTF(PF_DEBUG_MISC,
2930 ("PF_BINAT: begin(%i)\n", error));
2931 break;
2932 }
2933
2934 pr.rule.action = PF_RDR;
2935 if ((error = pf_beginrules(&pr))) {
2936 DPFPRINTF(PF_DEBUG_MISC,
2937 ("PF_RDR: begin(%i)\n", error));
2938 break;
2939 }
2940 if ((error = pf_commitrules(&pr))) {
2941 DPFPRINTF(PF_DEBUG_MISC,
2942 ("PF_RDR: commit(%i)\n", error));
2943 break;
2944 }
2945
2946#if defined(ALTQ)
2947 bzero(&pa, sizeof(pa));
2948 if ((error = pf_beginaltqs(&pa))) {
2949 DPFPRINTF(PF_DEBUG_MISC,
2950 ("ALTQ: begin(%i)\n", error));
2951 break;
2952 }
2953 if ((error = pf_commitaltqs(&pa))) {
2954 DPFPRINTF(PF_DEBUG_MISC,
2955 ("ALTQ: commit(%i)\n", error));
2956 break;
2957 }
2958#endif
2959 pf_clearstates();
2960
2961 bzero(&io, sizeof(io));
2962 if ((error = pf_clear_tables(&io))) {
2963 DPFPRINTF(PF_DEBUG_MISC,
2964 ("TABLES: clear(%i)\n", error));
2965 break;
2966 }
2967 pf_osfp_flush();
2968 } while(0);
2969
2970 PF_UNLOCK();
2971 return (error);
2972}
2973
2974static int
2975#if (__FreeBSD_version < 501108)
2976pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
2977#else
2978pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
2979#endif
2980{
2981 /*
2982 * XXX Wed Jul 9 22:03:16 2003 UTC
2983 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
2984 * in network stack. OpenBSD's network stack have converted
2985 * ip_len/ip_off to host byte order frist as FreeBSD.
2986 * Now this is not true anymore , so we should convert back to network
2987 * byte order.
2988 */
2989 struct ip *h = NULL;
2990 int chk;
2991
2992 if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) {
2993 /* if m_pkthdr.len is less than ip header, pf will handle. */
2994 h = mtod(*m, struct ip *);
2995 HTONS(h->ip_len);
2996 HTONS(h->ip_off);
2997 }
2998 chk = pf_test(PF_IN, ifp, m);
2999 if (chk && *m) {
3000 m_freem(*m);
3001 *m = NULL;
3002 }
3003 if (*m != NULL) {
3004 /* pf_test can change ip header location */
3005 h = mtod(*m, struct ip *);
3006 NTOHS(h->ip_len);
3007 NTOHS(h->ip_off);
3008 }
3009 return chk;
3010}
3011
3012static int
3013#if (__FreeBSD_version < 501108)
3014pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
3015#else
3016pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3017#endif
3018{
3019 /*
3020 * XXX Wed Jul 9 22:03:16 2003 UTC
3021 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
3022 * in network stack. OpenBSD's network stack have converted
3023 * ip_len/ip_off to host byte order frist as FreeBSD.
3024 * Now this is not true anymore , so we should convert back to network
3025 * byte order.
3026 */
3027 struct ip *h = NULL;
3028 int chk;
3029
3030 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
3031 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
3032 in_delayed_cksum(*m);
3033 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
3034 }
3035 if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) {
3036 /* if m_pkthdr.len is less than ip header, pf will handle. */
3037 h = mtod(*m, struct ip *);
3038 HTONS(h->ip_len);
3039 HTONS(h->ip_off);
3040 }
3041 chk = pf_test(PF_OUT, ifp, m);
3042 if (chk && *m) {
3043 m_freem(*m);
3044 *m = NULL;
3045 }
3046 if (*m != NULL) {
3047 /* pf_test can change ip header location */
3048 h = mtod(*m, struct ip *);
3049 NTOHS(h->ip_len);
3050 NTOHS(h->ip_off);
3051 }
3052 return chk;
3053}
3054
3055#ifdef INET6
3056static int
3057#if (__FreeBSD_version < 501108)
3058pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
3059#else
3060pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3061#endif
3062{
3063 /*
3064 * IPv6 does not affected ip_len/ip_off byte order changes.
3065 */
3066 int chk;
3067
3068 chk = pf_test6(PF_IN, ifp, m);
3069 if (chk && *m) {
3070 m_freem(*m);
3071 *m = NULL;
3072 }
3073 return chk;
3074}
3075
3076static int
3077#if (__FreeBSD_version < 501108)
3078pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
3079#else
3080pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3081#endif
3082{
3083 /*
3084 * IPv6 does not affected ip_len/ip_off byte order changes.
3085 */
3086 int chk;
3087
3088 /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
3089 if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
3090 in_delayed_cksum(*m);
3091 (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
3092 }
3093 chk = pf_test6(PF_OUT, ifp, m);
3094 if (chk && *m) {
3095 m_freem(*m);
3096 *m = NULL;
3097 }
3098 return chk;
3099}
3100#endif /* INET6 */
3101
3102static int
3103hook_pf(void)
3104{
3105#if (__FreeBSD_version >= 501108)
3106 struct pfil_head *pfh_inet;
3107#if defined(INET6)
3108 struct pfil_head *pfh_inet6;
3109#endif
3110#endif
3111
3112 PF_ASSERT(MA_NOTOWNED);
3113
3114 if (pf_pfil_hooked)
3115 return (0);
3116
3117#if (__FreeBSD_version < 501108)
3118 /*
3119 * XXX
3120 * There is no easy way to get pfil header pointer with address
3121 * family such as AF_INET, AF_INET6.
3122 * Needs direct variable reference.
3123 */
3124
3125 pfil_add_hook(pf_check_in, PFIL_IN,
3126 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3127 pfil_add_hook(pf_check_out, PFIL_OUT,
3128 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3129#if defined(INET6)
3130 pfil_add_hook(pf_check6_in, PFIL_IN,
3131 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3132 pfil_add_hook(pf_check6_out, PFIL_OUT,
3133 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3134#endif
3135#else /* __FreeBSD_version >= 501108 */
3136 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
3137 if (pfh_inet == NULL)
3138 return (ESRCH); /* XXX */
3139 pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
3140 pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
3141#if defined(INET6)
3142 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
3143 if (pfh_inet6 == NULL) {
3144 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
3145 pfh_inet);
3146 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
3147 pfh_inet);
3148 return (ESRCH); /* XXX */
3149 }
3150 pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
3151 pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
3152#endif
3153#endif /* __FreeBSD_version >= 501108 */
3154
3155 pf_pfil_hooked = 1;
3156 return (0);
3157}
3158
3159static int
3160dehook_pf(void)
3161{
3162#if (__FreeBSD_version >= 501108)
3163 struct pfil_head *pfh_inet;
3164#if defined(INET6)
3165 struct pfil_head *pfh_inet6;
3166#endif
3167#endif
3168
3169 PF_ASSERT(MA_NOTOWNED);
3170
3171 if (pf_pfil_hooked == 0)
3172 return (0);
3173
3174#if (__FreeBSD_version < 501108)
3175 pfil_remove_hook(pf_check_in, PFIL_IN,
3176 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3177 pfil_remove_hook(pf_check_out, PFIL_OUT,
3178 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3179#if defined(INET6)
3180 pfil_remove_hook(pf_check6_in, PFIL_IN,
3181 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3182 pfil_remove_hook(pf_check6_out, PFIL_OUT,
3183 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3184#endif
3185#else /* __FreeBSD_version >= 501108 */
3186 pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
3187 if (pfh_inet == NULL)
3188 return (ESRCH); /* XXX */
3189 pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
3190 pfh_inet);
3191 pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
3192 pfh_inet);
3193#if defined(INET6)
3194 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
3195 if (pfh_inet6 == NULL)
3196 return (ESRCH); /* XXX */
3197 pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
3198 pfh_inet6);
3199 pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
3200 pfh_inet6);
3201#endif
3202#endif /* __FreeBSD_version >= 501108 */
3203
3204 pf_pfil_hooked = 0;
3205 return (0);
3206}
3207
3208static int
3209pf_load(void)
3210{
3211 init_zone_var();
3212 init_pf_mutex();
3213 pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME);
3214 if (pfattach() < 0) {
3215 destroy_dev(pf_dev);
3216 destroy_pf_mutex();
3217 return (ENOMEM);
3218 }
3219#if defined(ALTQ)
3220 mtx_lock(&pf_altq_mtx);
3221 ++pfaltq_ref;
3222 mtx_unlock(&pf_altq_mtx);
3223#endif
3224 printf("pf: $Name: $\n");
3225 return (0);
3226}
3227
3228static int
3229pf_unload(void)
3230{
3231 int error = 0;
3232
3233 PF_LOCK();
3234 pf_status.running = 0;
3235 PF_UNLOCK();
3236 error = dehook_pf();
3237 if (error) {
3238 /*
3239 * Should not happen!
3240 * XXX Due to error code ESRCH, kldunload will show
3241 * a message like 'No such process'.
3242 */
3243 printf("%s : pfil unregisteration fail\n", __FUNCTION__);
3244 return error;
3245 }
3246 shutdown_pf();
3247 cleanup_pf_zone();
3248 pf_osfp_cleanup();
3249 destroy_dev(pf_dev);
3250#if defined(ALTQ)
3251 mtx_lock(&pf_altq_mtx);
3252 --pfaltq_ref;
3253 mtx_unlock(&pf_altq_mtx);
3254#endif
3255 destroy_pf_mutex();
3256 return error;
3257}
3258
3259static int
3260pf_modevent(module_t mod, int type, void *data)
3261{
3262 int error = 0;
3263
3264 switch(type) {
3265 case MOD_LOAD:
3266 error = pf_load();
3267 break;
3268
3269 case MOD_UNLOAD:
3270 error = pf_unload();
3271 break;
3272 default:
3273 error = EINVAL;
3274 break;
3275 }
3276 return error;
3277}
3278
3279static moduledata_t pf_mod = {
3280 "pf",
3281 pf_modevent,
3282 0
3283};
3284
3285DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
3286MODULE_DEPEND(pf, pflog, PFLOG_MINVER, PFLOG_PREFVER, PFLOG_MAXVER);
3287MODULE_DEPEND(pf, pfsync, PFSYNC_MINVER, PFSYNC_PREFVER, PFSYNC_MAXVER);
3288#if defined(ALTQ)
3289MODULE_DEPEND(pf, pfaltq, PFALTQ_MINVER, PFALTQ_PREFVER, PFALTQ_MAXVER);
3290#endif
3291MODULE_VERSION(pf, PF_MODVER);
3292#endif /* __FreeBSD__ */