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