xref: /openbsd-src/sys/net/pf_ioctl.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: pf_ioctl.c,v 1.76 2003/07/19 13:08:58 cedric 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 
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>
46 #include <sys/timeout.h>
47 #include <sys/pool.h>
48 #include <sys/malloc.h>
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>
66 #endif /* INET6 */
67 
68 #ifdef ALTQ
69 #include <altq/altq.h>
70 #endif
71 
72 void			 pfattach(int);
73 int			 pfopen(dev_t, int, int, struct proc *);
74 int			 pfclose(dev_t, int, int, struct proc *);
75 struct 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);
77 int			 pf_get_ruleset_number(u_int8_t);
78 void			 pf_init_ruleset(struct pf_ruleset *);
79 void			 pf_mv_pool(struct pf_palist *, struct pf_palist *);
80 void			 pf_empty_pool(struct pf_palist *);
81 int			 pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
82 
83 extern struct timeout	 pf_expire_to;
84 
85 struct pf_rule		 pf_default_rule;
86 
87 #define	TAGID_MAX	 50000
88 TAILQ_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 
92 void
93 pfattach(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 
111 	pool_sethardlimit(&pf_state_pl, pf_pool_limits[PF_LIMIT_STATES].limit,
112 	    NULL, 0);
113 
114 	RB_INIT(&tree_lan_ext);
115 	RB_INIT(&tree_ext_gwy);
116 	TAILQ_INIT(&pf_anchors);
117 	pf_init_ruleset(&pf_main_ruleset);
118 	TAILQ_INIT(&pf_altqs[0]);
119 	TAILQ_INIT(&pf_altqs[1]);
120 	TAILQ_INIT(&pf_pabuf);
121 	pf_altqs_active = &pf_altqs[0];
122 	pf_altqs_inactive = &pf_altqs[1];
123 
124 	/* default rule should never be garbage collected */
125 	pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
126 	pf_default_rule.action = PF_PASS;
127 	pf_default_rule.nr = -1;
128 
129 	/* initialize default timeouts */
130 	timeout[PFTM_TCP_FIRST_PACKET] = 120;		/* First TCP packet */
131 	timeout[PFTM_TCP_OPENING] = 30;			/* No response yet */
132 	timeout[PFTM_TCP_ESTABLISHED] = 24*60*60;	/* Established */
133 	timeout[PFTM_TCP_CLOSING] = 15 * 60;		/* Half closed */
134 	timeout[PFTM_TCP_FIN_WAIT] = 45;		/* Got both FINs */
135 	timeout[PFTM_TCP_CLOSED] = 90;			/* Got a RST */
136 	timeout[PFTM_UDP_FIRST_PACKET] = 60;		/* First UDP packet */
137 	timeout[PFTM_UDP_SINGLE] = 30;			/* Unidirectional */
138 	timeout[PFTM_UDP_MULTIPLE] = 60;		/* Bidirectional */
139 	timeout[PFTM_ICMP_FIRST_PACKET] = 20;		/* First ICMP packet */
140 	timeout[PFTM_ICMP_ERROR_REPLY] = 10;		/* Got error response */
141 	timeout[PFTM_OTHER_FIRST_PACKET] = 60;		/* First packet */
142 	timeout[PFTM_OTHER_SINGLE] = 30;		/* Unidirectional */
143 	timeout[PFTM_OTHER_MULTIPLE] = 60;		/* Bidirectional */
144 	timeout[PFTM_FRAG] = 30;			/* Fragment expire */
145 	timeout[PFTM_INTERVAL] = 10;			/* Expire interval */
146 
147 	timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
148 	timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
149 
150 	pf_normalize_init();
151 	pf_status.debug = PF_DEBUG_URGENT;
152 }
153 
154 int
155 pfopen(dev_t dev, int flags, int fmt, struct proc *p)
156 {
157 	if (minor(dev) >= 1)
158 		return (ENXIO);
159 	return (0);
160 }
161 
162 int
163 pfclose(dev_t dev, int flags, int fmt, struct proc *p)
164 {
165 	if (minor(dev) >= 1)
166 		return (ENXIO);
167 	return (0);
168 }
169 
170 struct pf_pool *
171 pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket,
172     u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last,
173     u_int8_t active, u_int8_t check_ticket)
174 {
175 	struct pf_ruleset	*ruleset;
176 	struct pf_rule		*rule;
177 	int			 rs_num;
178 
179 	ruleset = pf_find_ruleset(anchorname, rulesetname);
180 	if (ruleset == NULL)
181 		return (NULL);
182 	rs_num = pf_get_ruleset_number(rule_action);
183 	if (rs_num >= PF_RULESET_MAX)
184 		return (NULL);
185 	if (active) {
186 		if (check_ticket && ticket !=
187 		    ruleset->rules[rs_num].active.ticket)
188 			return (NULL);
189 		if (r_last)
190 			rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
191 			    pf_rulequeue);
192 		else
193 			rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
194 	} else {
195 		if (check_ticket && ticket !=
196 		    ruleset->rules[rs_num].inactive.ticket)
197 			return (NULL);
198 		if (r_last)
199 			rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
200 			    pf_rulequeue);
201 		else
202 			rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
203 	}
204 	if (!r_last) {
205 		while ((rule != NULL) && (rule->nr != rule_number))
206 			rule = TAILQ_NEXT(rule, entries);
207 	}
208 	if (rule == NULL)
209 		return (NULL);
210 
211 	return (&rule->rpool);
212 }
213 
214 int
215 pf_get_ruleset_number(u_int8_t action)
216 {
217 	switch (action) {
218 	case PF_SCRUB:
219 		return (PF_RULESET_SCRUB);
220 		break;
221 	case PF_PASS:
222 	case PF_DROP:
223 		return (PF_RULESET_FILTER);
224 		break;
225 	case PF_NAT:
226 	case PF_NONAT:
227 		return (PF_RULESET_NAT);
228 		break;
229 	case PF_BINAT:
230 	case PF_NOBINAT:
231 		return (PF_RULESET_BINAT);
232 		break;
233 	case PF_RDR:
234 	case PF_NORDR:
235 		return (PF_RULESET_RDR);
236 		break;
237 	default:
238 		return (PF_RULESET_MAX);
239 		break;
240 	}
241 }
242 
243 void
244 pf_init_ruleset(struct pf_ruleset *ruleset)
245 {
246 	int	i;
247 
248 	memset(ruleset, 0, sizeof(struct pf_ruleset));
249 	for (i = 0; i < PF_RULESET_MAX; i++) {
250 		TAILQ_INIT(&ruleset->rules[i].queues[0]);
251 		TAILQ_INIT(&ruleset->rules[i].queues[1]);
252 		ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
253 		ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
254 	}
255 }
256 
257 struct pf_anchor *
258 pf_find_anchor(const char *anchorname)
259 {
260 	struct pf_anchor	*anchor;
261 	int			 n = -1;
262 
263 	anchor = TAILQ_FIRST(&pf_anchors);
264 	while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0)
265 		anchor = TAILQ_NEXT(anchor, entries);
266 	if (n == 0)
267 		return (anchor);
268 	else
269 		return (NULL);
270 }
271 
272 struct pf_ruleset *
273 pf_find_ruleset(char *anchorname, char *rulesetname)
274 {
275 	struct pf_anchor	*anchor;
276 	struct pf_ruleset	*ruleset;
277 
278 	if (!anchorname[0] && !rulesetname[0])
279 		return (&pf_main_ruleset);
280 	if (!anchorname[0] || !rulesetname[0])
281 		return (NULL);
282 	anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
283 	rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
284 	anchor = pf_find_anchor(anchorname);
285 	if (anchor == NULL)
286 		return (NULL);
287 	ruleset = TAILQ_FIRST(&anchor->rulesets);
288 	while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0)
289 		ruleset = TAILQ_NEXT(ruleset, entries);
290 	if (ruleset != NULL && !strcmp(ruleset->name, rulesetname))
291 		return (ruleset);
292 	else
293 		return (NULL);
294 }
295 
296 struct pf_ruleset *
297 pf_find_or_create_ruleset(char *anchorname, char *rulesetname)
298 {
299 	struct pf_anchor	*anchor, *a;
300 	struct pf_ruleset	*ruleset, *r;
301 
302 	if (!anchorname[0] && !rulesetname[0])
303 		return (&pf_main_ruleset);
304 	if (!anchorname[0] || !rulesetname[0])
305 		return (NULL);
306 	anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
307 	rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
308 	a = TAILQ_FIRST(&pf_anchors);
309 	while (a != NULL && strcmp(a->name, anchorname) < 0)
310 		a = TAILQ_NEXT(a, entries);
311 	if (a != NULL && !strcmp(a->name, anchorname))
312 		anchor = a;
313 	else {
314 		anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor),
315 		    M_TEMP, M_NOWAIT);
316 		if (anchor == NULL)
317 			return (NULL);
318 		memset(anchor, 0, sizeof(struct pf_anchor));
319 		bcopy(anchorname, anchor->name, sizeof(anchor->name));
320 		TAILQ_INIT(&anchor->rulesets);
321 		if (a != NULL)
322 			TAILQ_INSERT_BEFORE(a, anchor, entries);
323 		else
324 			TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries);
325 	}
326 	r = TAILQ_FIRST(&anchor->rulesets);
327 	while (r != NULL && strcmp(r->name, rulesetname) < 0)
328 		r = TAILQ_NEXT(r, entries);
329 	if (r != NULL && !strcmp(r->name, rulesetname))
330 		return (r);
331 	ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset),
332 	    M_TEMP, M_NOWAIT);
333 	if (ruleset != NULL) {
334 		pf_init_ruleset(ruleset);
335 		bcopy(rulesetname, ruleset->name, sizeof(ruleset->name));
336 		ruleset->anchor = anchor;
337 		if (r != NULL)
338 			TAILQ_INSERT_BEFORE(r, ruleset, entries);
339 		else
340 			TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries);
341 	}
342 	return (ruleset);
343 }
344 
345 void
346 pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
347 {
348 	struct pf_anchor	*anchor;
349 	int			 i;
350 
351 	if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0)
352 		return;
353 	for (i = 0; i < PF_RULESET_MAX; ++i)
354 		if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
355 		    !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr))
356 			return;
357 
358 	anchor = ruleset->anchor;
359 	TAILQ_REMOVE(&anchor->rulesets, ruleset, entries);
360 	free(ruleset, M_TEMP);
361 
362 	if (TAILQ_EMPTY(&anchor->rulesets)) {
363 		TAILQ_REMOVE(&pf_anchors, anchor, entries);
364 		free(anchor, M_TEMP);
365 	}
366 }
367 
368 void
369 pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
370 {
371 	struct pf_pooladdr	*mv_pool_pa;
372 
373 	while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
374 		TAILQ_REMOVE(poola, mv_pool_pa, entries);
375 		TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
376 	}
377 }
378 
379 void
380 pf_empty_pool(struct pf_palist *poola)
381 {
382 	struct pf_pooladdr	*empty_pool_pa;
383 
384 	while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
385 		pf_dynaddr_remove(&empty_pool_pa->addr);
386 		TAILQ_REMOVE(poola, empty_pool_pa, entries);
387 		pool_put(&pf_pooladdr_pl, empty_pool_pa);
388 	}
389 }
390 
391 void
392 pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
393 {
394 	if (rulequeue != NULL) {
395 		if (rule->states <= 0) {
396 			/*
397 			 * XXX - we need to remove the table *before* detaching
398 			 * the rule to make sure the table code does not delete
399 			 * the anchor under our feet.
400 			 */
401 			pf_tbladdr_remove(&rule->src.addr);
402 			pf_tbladdr_remove(&rule->dst.addr);
403 		}
404 		TAILQ_REMOVE(rulequeue, rule, entries);
405 		rule->entries.tqe_prev = NULL;
406 		rule->nr = -1;
407 	}
408 	if (rule->states > 0 || rule->entries.tqe_prev != NULL)
409 		return;
410 	pf_tag_unref(rule->tag);
411 	pf_tag_unref(rule->match_tag);
412 	pf_dynaddr_remove(&rule->src.addr);
413 	pf_dynaddr_remove(&rule->dst.addr);
414 	if (rulequeue == NULL) {
415 		pf_tbladdr_remove(&rule->src.addr);
416 		pf_tbladdr_remove(&rule->dst.addr);
417 	}
418 	pf_empty_pool(&rule->rpool.list);
419 	pool_put(&pf_rule_pl, rule);
420 }
421 
422 u_int16_t
423 pf_tagname2tag(char *tagname)
424 {
425 	struct pf_tagname	*tag, *p = NULL;
426 	u_int16_t		 new_tagid = 1;
427 
428 	TAILQ_FOREACH(tag, &pf_tags, entries)
429 		if (strcmp(tagname, tag->name) == 0) {
430 			tag->ref++;
431 			return (tag->tag);
432 		}
433 
434 	/*
435 	 * to avoid fragmentation, we do a linear search from the beginning
436 	 * and take the first free slot we find. if there is none or the list
437 	 * is empty, append a new entry at the end.
438 	 */
439 
440 	/* new entry */
441 	if (!TAILQ_EMPTY(&pf_tags))
442 		for (p = TAILQ_FIRST(&pf_tags); p != NULL &&
443 		    p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
444 			new_tagid = p->tag + 1;
445 
446 	if (new_tagid > TAGID_MAX)
447 		return (0);
448 
449 	/* allocate and fill new struct pf_tagname */
450 	tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname),
451 	    M_TEMP, M_NOWAIT);
452 	if (tag == NULL)
453 		return (0);
454 	bzero(tag, sizeof(struct pf_tagname));
455 	strlcpy(tag->name, tagname, sizeof(tag->name));
456 	tag->tag = new_tagid;
457 	tag->ref++;
458 
459 	if (p != NULL)	/* insert new entry before p */
460 		TAILQ_INSERT_BEFORE(p, tag, entries);
461 	else	/* either list empty or no free slot in between */
462 		TAILQ_INSERT_TAIL(&pf_tags, tag, entries);
463 
464 	return (tag->tag);
465 }
466 
467 void
468 pf_tag2tagname(u_int16_t tagid, char *p)
469 {
470 	struct pf_tagname	*tag;
471 
472 	TAILQ_FOREACH(tag, &pf_tags, entries)
473 		if (tag->tag == tagid) {
474 			strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
475 			return;
476 		}
477 }
478 
479 void
480 pf_tag_unref(u_int16_t tag)
481 {
482 	struct pf_tagname	*p, *next;
483 
484 	if (tag == 0)
485 		return;
486 
487 	for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) {
488 		next = TAILQ_NEXT(p, entries);
489 		if (tag == p->tag) {
490 			if (--p->ref == 0) {
491 				TAILQ_REMOVE(&pf_tags, p, entries);
492 				free(p, M_TEMP);
493 			}
494 			break;
495 		}
496 	}
497 }
498 
499 int
500 pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
501 {
502 	struct pf_pooladdr	*pa = NULL;
503 	struct pf_pool		*pool = NULL;
504 	int			 s;
505 	int			 error = 0;
506 
507 	/* XXX keep in sync with switch() below */
508 	if (securelevel > 1)
509 		switch (cmd) {
510 		case DIOCGETRULES:
511 		case DIOCGETRULE:
512 		case DIOCGETADDRS:
513 		case DIOCGETADDR:
514 		case DIOCGETSTATE:
515 		case DIOCSETSTATUSIF:
516 		case DIOCGETSTATUS:
517 		case DIOCCLRSTATUS:
518 		case DIOCNATLOOK:
519 		case DIOCSETDEBUG:
520 		case DIOCGETSTATES:
521 		case DIOCGETTIMEOUT:
522 		case DIOCCLRRULECTRS:
523 		case DIOCGETLIMIT:
524 		case DIOCGETALTQS:
525 		case DIOCGETALTQ:
526 		case DIOCGETQSTATS:
527 		case DIOCGETANCHORS:
528 		case DIOCGETANCHOR:
529 		case DIOCGETRULESETS:
530 		case DIOCGETRULESET:
531 		case DIOCRGETTABLES:
532 		case DIOCRGETTSTATS:
533 		case DIOCRCLRTSTATS:
534 		case DIOCRCLRADDRS:
535 		case DIOCRADDADDRS:
536 		case DIOCRDELADDRS:
537 		case DIOCRSETADDRS:
538 		case DIOCRGETADDRS:
539 		case DIOCRGETASTATS:
540 		case DIOCRCLRASTATS:
541 		case DIOCRTSTADDRS:
542 			break;
543 		default:
544 			return (EPERM);
545 		}
546 
547 	if (!(flags & FWRITE))
548 		switch (cmd) {
549 		case DIOCGETRULES:
550 		case DIOCGETRULE:
551 		case DIOCGETADDRS:
552 		case DIOCGETADDR:
553 		case DIOCGETSTATE:
554 		case DIOCGETSTATUS:
555 		case DIOCGETSTATES:
556 		case DIOCGETTIMEOUT:
557 		case DIOCGETLIMIT:
558 		case DIOCGETALTQS:
559 		case DIOCGETALTQ:
560 		case DIOCGETQSTATS:
561 		case DIOCGETANCHORS:
562 		case DIOCGETANCHOR:
563 		case DIOCGETRULESETS:
564 		case DIOCGETRULESET:
565 		case DIOCRGETTABLES:
566 		case DIOCRGETTSTATS:
567 		case DIOCRGETADDRS:
568 		case DIOCRGETASTATS:
569 		case DIOCRTSTADDRS:
570 			break;
571 		default:
572 			return (EACCES);
573 		}
574 
575 	switch (cmd) {
576 
577 	case DIOCSTART:
578 		if (pf_status.running)
579 			error = EEXIST;
580 		else {
581 			u_int32_t states = pf_status.states;
582 			bzero(&pf_status, sizeof(struct pf_status));
583 			pf_status.running = 1;
584 			pf_status.states = states;
585 			pf_status.since = time.tv_sec;
586 			if (status_ifp != NULL)
587 				strlcpy(pf_status.ifname,
588 				    status_ifp->if_xname, IFNAMSIZ);
589 			DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
590 		}
591 		break;
592 
593 	case DIOCSTOP:
594 		if (!pf_status.running)
595 			error = ENOENT;
596 		else {
597 			pf_status.running = 0;
598 			DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
599 		}
600 		break;
601 
602 	case DIOCBEGINRULES: {
603 		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
604 		struct pf_ruleset	*ruleset;
605 		struct pf_rule		*rule;
606 		int			 rs_num;
607 
608 		ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
609 		if (ruleset == NULL) {
610 			error = EINVAL;
611 			break;
612 		}
613 		rs_num = pf_get_ruleset_number(pr->rule.action);
614 		if (rs_num >= PF_RULESET_MAX) {
615 			error = EINVAL;
616 			break;
617 		}
618 		while ((rule =
619 		    TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
620 			pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
621 		pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
622 		break;
623 	}
624 
625 	case DIOCADDRULE: {
626 		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
627 		struct pf_ruleset	*ruleset;
628 		struct pf_rule		*rule, *tail;
629 		int			 rs_num;
630 
631 		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
632 		if (ruleset == NULL) {
633 			error = EINVAL;
634 			break;
635 		}
636 		rs_num = pf_get_ruleset_number(pr->rule.action);
637 		if (rs_num >= PF_RULESET_MAX) {
638 			error = EINVAL;
639 			break;
640 		}
641 		if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) {
642 			error = EINVAL;
643 			break;
644 		}
645 		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
646 			error = EINVAL;
647 			break;
648 		}
649 		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
650 			error = EBUSY;
651 			break;
652 		}
653 		if (pr->pool_ticket != ticket_pabuf) {
654 			error = EBUSY;
655 			break;
656 		}
657 		rule = pool_get(&pf_rule_pl, PR_NOWAIT);
658 		if (rule == NULL) {
659 			error = ENOMEM;
660 			break;
661 		}
662 		bcopy(&pr->rule, rule, sizeof(struct pf_rule));
663 		rule->anchor = NULL;
664 		rule->ifp = NULL;
665 		TAILQ_INIT(&rule->rpool.list);
666 		/* initialize refcounting */
667 		rule->states = 0;
668 		rule->entries.tqe_prev = NULL;
669 #ifndef INET
670 		if (rule->af == AF_INET) {
671 			pool_put(&pf_rule_pl, rule);
672 			error = EAFNOSUPPORT;
673 			break;
674 		}
675 #endif /* INET */
676 #ifndef INET6
677 		if (rule->af == AF_INET6) {
678 			pool_put(&pf_rule_pl, rule);
679 			error = EAFNOSUPPORT;
680 			break;
681 		}
682 #endif /* INET6 */
683 		tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
684 		    pf_rulequeue);
685 		if (tail)
686 			rule->nr = tail->nr + 1;
687 		else
688 			rule->nr = 0;
689 		if (rule->ifname[0]) {
690 			rule->ifp = ifunit(rule->ifname);
691 			if (rule->ifp == NULL) {
692 				pool_put(&pf_rule_pl, rule);
693 				error = EINVAL;
694 				break;
695 			}
696 		}
697 
698 		if (rule->tagname[0])
699 			if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
700 				error = EBUSY;
701 		if (rule->match_tagname[0])
702 			if ((rule->match_tag =
703 			    pf_tagname2tag(rule->match_tagname)) == 0)
704 				error = EBUSY;
705 		if (rule->rt && !rule->direction)
706 			error = EINVAL;
707 		if (pf_dynaddr_setup(&rule->src.addr, rule->af))
708 			error = EINVAL;
709 		if (pf_dynaddr_setup(&rule->dst.addr, rule->af))
710 			error = EINVAL;
711 		if (pf_tbladdr_setup(ruleset, &rule->src.addr))
712 			error = EINVAL;
713 		if (pf_tbladdr_setup(ruleset, &rule->dst.addr))
714 			error = EINVAL;
715 
716 		pf_mv_pool(&pf_pabuf, &rule->rpool.list);
717 		if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
718 		    (rule->action == PF_BINAT)) && !rule->anchorname[0]) ||
719 		    (rule->rt > PF_FASTROUTE)) &&
720 		    (TAILQ_FIRST(&rule->rpool.list) == NULL))
721 			error = EINVAL;
722 
723 		if (error) {
724 			pf_rm_rule(NULL, rule);
725 			break;
726 		}
727 		rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
728 		rule->evaluations = rule->packets = rule->bytes = 0;
729 		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
730 		    rule, entries);
731 		break;
732 	}
733 
734 	case DIOCCOMMITRULES: {
735 		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
736 		struct pf_ruleset	*ruleset;
737 		struct pf_rulequeue	*old_rules;
738 		struct pf_rule		*rule;
739 		int			 rs_num;
740 
741 		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
742 		if (ruleset == NULL) {
743 			error = EINVAL;
744 			break;
745 		}
746 		rs_num = pf_get_ruleset_number(pr->rule.action);
747 		if (rs_num >= PF_RULESET_MAX) {
748 			error = EINVAL;
749 			break;
750 		}
751 		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
752 			error = EBUSY;
753 			break;
754 		}
755 
756 #ifdef ALTQ
757 		/* set queue IDs */
758 		if (rs_num == PF_RULESET_FILTER)
759 			pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
760 #endif
761 
762 		/* Swap rules, keep the old. */
763 		s = splsoftnet();
764 		old_rules = ruleset->rules[rs_num].active.ptr;
765 		ruleset->rules[rs_num].active.ptr =
766 		    ruleset->rules[rs_num].inactive.ptr;
767 		ruleset->rules[rs_num].inactive.ptr = old_rules;
768 		ruleset->rules[rs_num].active.ticket =
769 		    ruleset->rules[rs_num].inactive.ticket;
770 		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
771 
772 		/* Purge the old rule list. */
773 		while ((rule = TAILQ_FIRST(old_rules)) != NULL)
774 			pf_rm_rule(old_rules, rule);
775 		pf_remove_if_empty_ruleset(ruleset);
776 		pf_update_anchor_rules();
777 		splx(s);
778 		break;
779 	}
780 
781 	case DIOCGETRULES: {
782 		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
783 		struct pf_ruleset	*ruleset;
784 		struct pf_rule		*tail;
785 		int			 rs_num;
786 
787 		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
788 		if (ruleset == NULL) {
789 			error = EINVAL;
790 			break;
791 		}
792 		rs_num = pf_get_ruleset_number(pr->rule.action);
793 		if (rs_num >= PF_RULESET_MAX) {
794 			error = EINVAL;
795 			break;
796 		}
797 		s = splsoftnet();
798 		tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
799 		    pf_rulequeue);
800 		if (tail)
801 			pr->nr = tail->nr + 1;
802 		else
803 			pr->nr = 0;
804 		pr->ticket = ruleset->rules[rs_num].active.ticket;
805 		splx(s);
806 		break;
807 	}
808 
809 	case DIOCGETRULE: {
810 		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
811 		struct pf_ruleset	*ruleset;
812 		struct pf_rule		*rule;
813 		int			 rs_num, i;
814 
815 		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
816 		if (ruleset == NULL) {
817 			error = EINVAL;
818 			break;
819 		}
820 		rs_num = pf_get_ruleset_number(pr->rule.action);
821 		if (rs_num >= PF_RULESET_MAX) {
822 			error = EINVAL;
823 			break;
824 		}
825 		if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
826 			error = EBUSY;
827 			break;
828 		}
829 		s = splsoftnet();
830 		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
831 		while ((rule != NULL) && (rule->nr != pr->nr))
832 			rule = TAILQ_NEXT(rule, entries);
833 		if (rule == NULL) {
834 			error = EBUSY;
835 			splx(s);
836 			break;
837 		}
838 		bcopy(rule, &pr->rule, sizeof(struct pf_rule));
839 		pf_dynaddr_copyout(&pr->rule.src.addr);
840 		pf_dynaddr_copyout(&pr->rule.dst.addr);
841 		pf_tbladdr_copyout(&pr->rule.src.addr);
842 		pf_tbladdr_copyout(&pr->rule.dst.addr);
843 		for (i = 0; i < PF_SKIP_COUNT; ++i)
844 			if (rule->skip[i].ptr == NULL)
845 				pr->rule.skip[i].nr = -1;
846 			else
847 				pr->rule.skip[i].nr =
848 				    rule->skip[i].ptr->nr;
849 		splx(s);
850 		break;
851 	}
852 
853 	case DIOCCHANGERULE: {
854 		struct pfioc_rule	*pcr = (struct pfioc_rule *)addr;
855 		struct pf_ruleset	*ruleset;
856 		struct pf_rule		*oldrule = NULL, *newrule = NULL;
857 		u_int32_t		 nr = 0;
858 		int			 rs_num;
859 
860 		if (!(pcr->action == PF_CHANGE_REMOVE ||
861 		    pcr->action == PF_CHANGE_GET_TICKET) &&
862 		    pcr->pool_ticket != ticket_pabuf) {
863 			error = EBUSY;
864 			break;
865 		}
866 
867 		if (pcr->action < PF_CHANGE_ADD_HEAD ||
868 		    pcr->action > PF_CHANGE_GET_TICKET) {
869 			error = EINVAL;
870 			break;
871 		}
872 		ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset);
873 		if (ruleset == NULL) {
874 			error = EINVAL;
875 			break;
876 		}
877 		rs_num = pf_get_ruleset_number(pcr->rule.action);
878 		if (rs_num >= PF_RULESET_MAX) {
879 			error = EINVAL;
880 			break;
881 		}
882 
883 		if (pcr->action == PF_CHANGE_GET_TICKET) {
884 			pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
885 			break;
886 		} else {
887 			if (pcr->ticket !=
888 			    ruleset->rules[rs_num].active.ticket) {
889 				error = EINVAL;
890 				break;
891 			}
892 			if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
893 				error = EINVAL;
894 				break;
895 			}
896 		}
897 
898 		if (pcr->action != PF_CHANGE_REMOVE) {
899 			newrule = pool_get(&pf_rule_pl, PR_NOWAIT);
900 			if (newrule == NULL) {
901 				error = ENOMEM;
902 				break;
903 			}
904 			bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
905 			TAILQ_INIT(&newrule->rpool.list);
906 			/* initialize refcounting */
907 			newrule->states = 0;
908 			newrule->entries.tqe_prev = NULL;
909 #ifndef INET
910 			if (newrule->af == AF_INET) {
911 				pool_put(&pf_rule_pl, newrule);
912 				error = EAFNOSUPPORT;
913 				break;
914 			}
915 #endif /* INET */
916 #ifndef INET6
917 			if (newrule->af == AF_INET6) {
918 				pool_put(&pf_rule_pl, newrule);
919 				error = EAFNOSUPPORT;
920 				break;
921 			}
922 #endif /* INET6 */
923 			if (newrule->ifname[0]) {
924 				newrule->ifp = ifunit(newrule->ifname);
925 				if (newrule->ifp == NULL) {
926 					pool_put(&pf_rule_pl, newrule);
927 					error = EINVAL;
928 					break;
929 				}
930 			} else
931 				newrule->ifp = NULL;
932 
933 #ifdef ALTQ
934 			/* set queue IDs */
935 			if (newrule->qname[0] != 0) {
936 				newrule->qid = pf_qname_to_qid(newrule->qname);
937 				if (newrule->pqname[0] != 0)
938 					newrule->pqid =
939 					    pf_qname_to_qid(newrule->pqname);
940 				else
941 					newrule->pqid = newrule->qid;
942 			}
943 #endif
944 			if (newrule->tagname[0])
945 				if ((newrule->tag =
946 				    pf_tagname2tag(newrule->tagname)) == 0)
947 					error = EBUSY;
948 			if (newrule->match_tagname[0])
949 				if ((newrule->match_tag = pf_tagname2tag(
950 				    newrule->match_tagname)) == 0)
951 					error = EBUSY;
952 
953 			if (newrule->rt && !newrule->direction)
954 				error = EINVAL;
955 			if (pf_dynaddr_setup(&newrule->src.addr, newrule->af))
956 				error = EINVAL;
957 			if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af))
958 				error = EINVAL;
959 			if (pf_tbladdr_setup(ruleset, &newrule->src.addr))
960 				error = EINVAL;
961 			if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))
962 				error = EINVAL;
963 
964 			pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
965 			if (((((newrule->action == PF_NAT) ||
966 			    (newrule->action == PF_RDR) ||
967 			    (newrule->action == PF_BINAT) ||
968 			    (newrule->rt > PF_FASTROUTE)) &&
969 			    !newrule->anchorname[0])) &&
970 			    (TAILQ_FIRST(&newrule->rpool.list) == NULL))
971 				error = EINVAL;
972 
973 			if (error) {
974 				pf_rm_rule(NULL, newrule);
975 				break;
976 			}
977 			newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
978 			newrule->evaluations = newrule->packets = 0;
979 			newrule->bytes = 0;
980 		}
981 		pf_empty_pool(&pf_pabuf);
982 
983 		s = splsoftnet();
984 
985 		if (pcr->action == PF_CHANGE_ADD_HEAD)
986 			oldrule = TAILQ_FIRST(
987 			    ruleset->rules[rs_num].active.ptr);
988 		else if (pcr->action == PF_CHANGE_ADD_TAIL)
989 			oldrule = TAILQ_LAST(
990 			    ruleset->rules[rs_num].active.ptr, pf_rulequeue);
991 		else {
992 			oldrule = TAILQ_FIRST(
993 			    ruleset->rules[rs_num].active.ptr);
994 			while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
995 				oldrule = TAILQ_NEXT(oldrule, entries);
996 			if (oldrule == NULL) {
997 				pf_rm_rule(NULL, newrule);
998 				error = EINVAL;
999 				splx(s);
1000 				break;
1001 			}
1002 		}
1003 
1004 		if (pcr->action == PF_CHANGE_REMOVE)
1005 			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
1006 		else {
1007 			if (oldrule == NULL)
1008 				TAILQ_INSERT_TAIL(
1009 				    ruleset->rules[rs_num].active.ptr,
1010 				    newrule, entries);
1011 			else if (pcr->action == PF_CHANGE_ADD_HEAD ||
1012 			    pcr->action == PF_CHANGE_ADD_BEFORE)
1013 				TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
1014 			else
1015 				TAILQ_INSERT_AFTER(
1016 				    ruleset->rules[rs_num].active.ptr,
1017 				    oldrule, newrule, entries);
1018 		}
1019 
1020 		nr = 0;
1021 		TAILQ_FOREACH(oldrule,
1022 		    ruleset->rules[rs_num].active.ptr, entries)
1023 			oldrule->nr = nr++;
1024 
1025 		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1026 		pf_remove_if_empty_ruleset(ruleset);
1027 		pf_update_anchor_rules();
1028 
1029 		ruleset->rules[rs_num].active.ticket++;
1030 		splx(s);
1031 		break;
1032 	}
1033 
1034 	case DIOCCLRSTATES: {
1035 		struct pf_tree_node	*n;
1036 
1037 		s = splsoftnet();
1038 		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1039 			n->state->timeout = PFTM_PURGE;
1040 		pf_purge_expired_states();
1041 		pf_status.states = 0;
1042 		splx(s);
1043 		break;
1044 	}
1045 
1046 	case DIOCKILLSTATES: {
1047 		struct pf_tree_node	*n;
1048 		struct pf_state		*st;
1049 		struct pfioc_state_kill	*psk = (struct pfioc_state_kill *)addr;
1050 		int			 killed = 0;
1051 
1052 		s = splsoftnet();
1053 		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1054 			st = n->state;
1055 			if ((!psk->psk_af || st->af == psk->psk_af) &&
1056 			    (!psk->psk_proto || psk->psk_proto == st->proto) &&
1057 			    PF_MATCHA(psk->psk_src.not,
1058 			    &psk->psk_src.addr.v.a.addr,
1059 			    &psk->psk_src.addr.v.a.mask, &st->lan.addr,
1060 			    st->af) &&
1061 			    PF_MATCHA(psk->psk_dst.not,
1062 			    &psk->psk_dst.addr.v.a.addr,
1063 			    &psk->psk_dst.addr.v.a.mask, &st->ext.addr,
1064 			    st->af) &&
1065 			    (psk->psk_src.port_op == 0 ||
1066 			    pf_match_port(psk->psk_src.port_op,
1067 			    psk->psk_src.port[0], psk->psk_src.port[1],
1068 			    st->lan.port)) &&
1069 			    (psk->psk_dst.port_op == 0 ||
1070 			    pf_match_port(psk->psk_dst.port_op,
1071 			    psk->psk_dst.port[0], psk->psk_dst.port[1],
1072 			    st->ext.port))) {
1073 				st->timeout = PFTM_PURGE;
1074 				killed++;
1075 			}
1076 		}
1077 		pf_purge_expired_states();
1078 		splx(s);
1079 		psk->psk_af = killed;
1080 		break;
1081 	}
1082 
1083 	case DIOCADDSTATE: {
1084 		struct pfioc_state	*ps = (struct pfioc_state *)addr;
1085 		struct pf_state		*state;
1086 
1087 		if (ps->state.timeout >= PFTM_MAX &&
1088 		    ps->state.timeout != PFTM_UNTIL_PACKET) {
1089 			error = EINVAL;
1090 			break;
1091 		}
1092 		state = pool_get(&pf_state_pl, PR_NOWAIT);
1093 		if (state == NULL) {
1094 			error = ENOMEM;
1095 			break;
1096 		}
1097 		s = splsoftnet();
1098 		bcopy(&ps->state, state, sizeof(struct pf_state));
1099 		state->rule.ptr = NULL;
1100 		state->nat_rule.ptr = NULL;
1101 		state->anchor.ptr = NULL;
1102 		state->rt_ifp = NULL;
1103 		state->creation = time.tv_sec;
1104 		state->packets[0] = state->packets[1] = 0;
1105 		state->bytes[0] = state->bytes[1] = 0;
1106 		if (pf_insert_state(state)) {
1107 			pool_put(&pf_state_pl, state);
1108 			error = ENOMEM;
1109 		}
1110 		splx(s);
1111 		break;
1112 	}
1113 
1114 	case DIOCGETSTATE: {
1115 		struct pfioc_state	*ps = (struct pfioc_state *)addr;
1116 		struct pf_tree_node	*n;
1117 		u_int32_t		 nr;
1118 
1119 		nr = 0;
1120 		s = splsoftnet();
1121 		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1122 			if (nr >= ps->nr)
1123 				break;
1124 			nr++;
1125 		}
1126 		if (n == NULL) {
1127 			error = EBUSY;
1128 			splx(s);
1129 			break;
1130 		}
1131 		bcopy(n->state, &ps->state, sizeof(struct pf_state));
1132 		ps->state.rule.nr = n->state->rule.ptr->nr;
1133 		ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1134 		    -1 : n->state->nat_rule.ptr->nr;
1135 		ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ?
1136 		    -1 : n->state->anchor.ptr->nr;
1137 		splx(s);
1138 		ps->state.expire = pf_state_expires(n->state);
1139 		if (ps->state.expire > time.tv_sec)
1140 			ps->state.expire -= time.tv_sec;
1141 		else
1142 			ps->state.expire = 0;
1143 		break;
1144 	}
1145 
1146 	case DIOCGETSTATES: {
1147 		struct pfioc_states	*ps = (struct pfioc_states *)addr;
1148 		struct pf_tree_node	*n;
1149 		struct pf_state		*p, pstore;
1150 		u_int32_t		 nr = 0;
1151 		int			 space = ps->ps_len;
1152 
1153 		if (space == 0) {
1154 			s = splsoftnet();
1155 			RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1156 				nr++;
1157 			splx(s);
1158 			ps->ps_len = sizeof(struct pf_state) * nr;
1159 			return (0);
1160 		}
1161 
1162 		s = splsoftnet();
1163 		p = ps->ps_states;
1164 		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1165 			int	secs = time.tv_sec;
1166 
1167 			if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len)
1168 				break;
1169 
1170 			bcopy(n->state, &pstore, sizeof(pstore));
1171 			pstore.rule.nr = n->state->rule.ptr->nr;
1172 			pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1173 			    -1 : n->state->nat_rule.ptr->nr;
1174 			pstore.anchor.nr = (n->state->anchor.ptr == NULL) ?
1175 			    -1 : n->state->anchor.ptr->nr;
1176 			pstore.creation = secs - pstore.creation;
1177 			pstore.expire = pf_state_expires(n->state);
1178 			if (pstore.expire > secs)
1179 				pstore.expire -= secs;
1180 			else
1181 				pstore.expire = 0;
1182 			error = copyout(&pstore, p, sizeof(*p));
1183 			if (error) {
1184 				splx(s);
1185 				goto fail;
1186 			}
1187 			p++;
1188 			nr++;
1189 		}
1190 		ps->ps_len = sizeof(struct pf_state) * nr;
1191 		splx(s);
1192 		break;
1193 	}
1194 
1195 	case DIOCGETSTATUS: {
1196 		struct pf_status *s = (struct pf_status *)addr;
1197 		bcopy(&pf_status, s, sizeof(struct pf_status));
1198 		break;
1199 	}
1200 
1201 	case DIOCSETSTATUSIF: {
1202 		struct pfioc_if	*pi = (struct pfioc_if *)addr;
1203 		struct ifnet	*ifp;
1204 
1205 		if (pi->ifname[0] == 0) {
1206 			status_ifp = NULL;
1207 			bzero(pf_status.ifname, IFNAMSIZ);
1208 			break;
1209 		}
1210 		if ((ifp = ifunit(pi->ifname)) == NULL) {
1211 			error = EINVAL;
1212 			break;
1213 		} else if (ifp == status_ifp)
1214 			break;
1215 		status_ifp = ifp;
1216 		/* fallthrough into DIOCCLRSTATUS */
1217 	}
1218 
1219 	case DIOCCLRSTATUS: {
1220 		u_int32_t	running = pf_status.running;
1221 		u_int32_t	states = pf_status.states;
1222 		u_int32_t	since = pf_status.since;
1223 		u_int32_t	debug = pf_status.debug;
1224 
1225 		bzero(&pf_status, sizeof(struct pf_status));
1226 		pf_status.running = running;
1227 		pf_status.states = states;
1228 		pf_status.since = since;
1229 		pf_status.debug = debug;
1230 		if (status_ifp != NULL)
1231 			strlcpy(pf_status.ifname,
1232 			    status_ifp->if_xname, IFNAMSIZ);
1233 		break;
1234 	}
1235 
1236 	case DIOCNATLOOK: {
1237 		struct pfioc_natlook	*pnl = (struct pfioc_natlook *)addr;
1238 		struct pf_state		*st;
1239 		struct pf_tree_node	 key;
1240 		int			 direction = pnl->direction;
1241 
1242 		key.af = pnl->af;
1243 		key.proto = pnl->proto;
1244 
1245 		/*
1246 		 * userland gives us source and dest of connetion, reverse
1247 		 * the lookup so we ask for what happens with the return
1248 		 * traffic, enabling us to find it in the state tree.
1249 		 */
1250 		PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af);
1251 		key.port[1] = pnl->sport;
1252 		PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af);
1253 		key.port[0] = pnl->dport;
1254 
1255 		if (!pnl->proto ||
1256 		    PF_AZERO(&pnl->saddr, pnl->af) ||
1257 		    PF_AZERO(&pnl->daddr, pnl->af) ||
1258 		    !pnl->dport || !pnl->sport)
1259 			error = EINVAL;
1260 		else {
1261 			s = splsoftnet();
1262 			if (direction == PF_IN)
1263 				st = pf_find_state(&tree_ext_gwy, &key);
1264 			else
1265 				st = pf_find_state(&tree_lan_ext, &key);
1266 			if (st != NULL) {
1267 				if (direction == PF_IN) {
1268 					PF_ACPY(&pnl->rsaddr, &st->lan.addr,
1269 					    st->af);
1270 					pnl->rsport = st->lan.port;
1271 					PF_ACPY(&pnl->rdaddr, &pnl->daddr,
1272 					    pnl->af);
1273 					pnl->rdport = pnl->dport;
1274 				} else {
1275 					PF_ACPY(&pnl->rdaddr, &st->gwy.addr,
1276 					    st->af);
1277 					pnl->rdport = st->gwy.port;
1278 					PF_ACPY(&pnl->rsaddr, &pnl->saddr,
1279 					    pnl->af);
1280 					pnl->rsport = pnl->sport;
1281 				}
1282 			} else
1283 				error = ENOENT;
1284 			splx(s);
1285 		}
1286 		break;
1287 	}
1288 
1289 	case DIOCSETTIMEOUT: {
1290 		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
1291 		int		 old;
1292 
1293 		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
1294 		    pt->seconds < 0) {
1295 			error = EINVAL;
1296 			goto fail;
1297 		}
1298 		old = pf_default_rule.timeout[pt->timeout];
1299 		pf_default_rule.timeout[pt->timeout] = pt->seconds;
1300 		pt->seconds = old;
1301 		break;
1302 	}
1303 
1304 	case DIOCGETTIMEOUT: {
1305 		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
1306 
1307 		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
1308 			error = EINVAL;
1309 			goto fail;
1310 		}
1311 		pt->seconds = pf_default_rule.timeout[pt->timeout];
1312 		break;
1313 	}
1314 
1315 	case DIOCGETLIMIT: {
1316 		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
1317 
1318 		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1319 			error = EINVAL;
1320 			goto fail;
1321 		}
1322 		pl->limit = pf_pool_limits[pl->index].limit;
1323 		break;
1324 	}
1325 
1326 	case DIOCSETLIMIT: {
1327 		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
1328 		int			 old_limit;
1329 
1330 		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1331 			error = EINVAL;
1332 			goto fail;
1333 		}
1334 		if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
1335 		    pl->limit, NULL, 0) != 0) {
1336 			error = EBUSY;
1337 			goto fail;
1338 		}
1339 		old_limit = pf_pool_limits[pl->index].limit;
1340 		pf_pool_limits[pl->index].limit = pl->limit;
1341 		pl->limit = old_limit;
1342 		break;
1343 	}
1344 
1345 	case DIOCSETDEBUG: {
1346 		u_int32_t	*level = (u_int32_t *)addr;
1347 
1348 		pf_status.debug = *level;
1349 		break;
1350 	}
1351 
1352 	case DIOCCLRRULECTRS: {
1353 		struct pf_ruleset	*ruleset = &pf_main_ruleset;
1354 		struct pf_rule		*rule;
1355 
1356 		s = splsoftnet();
1357 		TAILQ_FOREACH(rule,
1358 		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
1359 			rule->evaluations = rule->packets =
1360 			    rule->bytes = 0;
1361 		splx(s);
1362 		break;
1363 	}
1364 
1365 #ifdef ALTQ
1366 	case DIOCSTARTALTQ: {
1367 		struct pf_altq		*altq;
1368 		struct ifnet		*ifp;
1369 		struct tb_profile	 tb;
1370 
1371 		/* enable all altq interfaces on active list */
1372 		s = splsoftnet();
1373 		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1374 			if (altq->qname[0] == 0) {
1375 				if ((ifp = ifunit(altq->ifname)) == NULL) {
1376 					error = EINVAL;
1377 					break;
1378 				}
1379 				if (ifp->if_snd.altq_type != ALTQT_NONE)
1380 					error = altq_enable(&ifp->if_snd);
1381 				if (error != 0)
1382 					break;
1383 				/* set tokenbucket regulator */
1384 				tb.rate = altq->ifbandwidth;
1385 				tb.depth = altq->tbrsize;
1386 				error = tbr_set(&ifp->if_snd, &tb);
1387 				if (error != 0)
1388 					break;
1389 			}
1390 		}
1391 		if (error == 0)
1392 			pfaltq_running = 1;
1393 		splx(s);
1394 		DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
1395 		break;
1396 	}
1397 
1398 	case DIOCSTOPALTQ: {
1399 		struct pf_altq		*altq;
1400 		struct ifnet		*ifp;
1401 		struct tb_profile	 tb;
1402 		int			 err;
1403 
1404 		/* disable all altq interfaces on active list */
1405 		s = splsoftnet();
1406 		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1407 			if (altq->qname[0] == 0) {
1408 				if ((ifp = ifunit(altq->ifname)) == NULL) {
1409 					error = EINVAL;
1410 					break;
1411 				}
1412 				if (ifp->if_snd.altq_type != ALTQT_NONE) {
1413 					err = altq_disable(&ifp->if_snd);
1414 					if (err != 0 && error == 0)
1415 						error = err;
1416 				}
1417 				/* clear tokenbucket regulator */
1418 				tb.rate = 0;
1419 				err = tbr_set(&ifp->if_snd, &tb);
1420 				if (err != 0 && error == 0)
1421 					error = err;
1422 			}
1423 		}
1424 		if (error == 0)
1425 			pfaltq_running = 0;
1426 		splx(s);
1427 		DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
1428 		break;
1429 	}
1430 
1431 	case DIOCBEGINALTQS: {
1432 		u_int32_t	*ticket = (u_int32_t *)addr;
1433 		struct pf_altq	*altq;
1434 
1435 		/* Purge the old altq list */
1436 		while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1437 			TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1438 			if (altq->qname[0] == 0) {
1439 				/* detach and destroy the discipline */
1440 				error = altq_remove(altq);
1441 			}
1442 			pool_put(&pf_altq_pl, altq);
1443 		}
1444 		*ticket = ++ticket_altqs_inactive;
1445 		break;
1446 	}
1447 
1448 	case DIOCADDALTQ: {
1449 		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
1450 		struct pf_altq		*altq, *a;
1451 
1452 		if (pa->ticket != ticket_altqs_inactive) {
1453 			error = EBUSY;
1454 			break;
1455 		}
1456 		altq = pool_get(&pf_altq_pl, PR_NOWAIT);
1457 		if (altq == NULL) {
1458 			error = ENOMEM;
1459 			break;
1460 		}
1461 		bcopy(&pa->altq, altq, sizeof(struct pf_altq));
1462 
1463 		/*
1464 		 * if this is for a queue, find the discipline and
1465 		 * copy the necessary fields
1466 		 */
1467 		if (altq->qname[0] != 0) {
1468 			TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
1469 				if (strncmp(a->ifname, altq->ifname,
1470 				    IFNAMSIZ) == 0 && a->qname[0] == 0) {
1471 					altq->altq_disc = a->altq_disc;
1472 					break;
1473 				}
1474 			}
1475 		}
1476 
1477 		error = altq_add(altq);
1478 		if (error) {
1479 			pool_put(&pf_altq_pl, altq);
1480 			break;
1481 		}
1482 
1483 		TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
1484 		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1485 		break;
1486 	}
1487 
1488 	case DIOCCOMMITALTQS: {
1489 		u_int32_t		*ticket = (u_int32_t *)addr;
1490 		struct pf_altqqueue	*old_altqs;
1491 		struct pf_altq		*altq;
1492 		struct pf_anchor	*anchor;
1493 		struct pf_ruleset	*ruleset;
1494 		int			 err;
1495 
1496 		if (*ticket != ticket_altqs_inactive) {
1497 			error = EBUSY;
1498 			break;
1499 		}
1500 
1501 		/* Swap altqs, keep the old. */
1502 		s = splsoftnet();
1503 		old_altqs = pf_altqs_active;
1504 		pf_altqs_active = pf_altqs_inactive;
1505 		pf_altqs_inactive = old_altqs;
1506 		ticket_altqs_active = ticket_altqs_inactive;
1507 
1508 		/* Attach new disciplines */
1509 		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1510 			if (altq->qname[0] == 0) {
1511 				/* attach the discipline */
1512 				error = altq_pfattach(altq);
1513 				if (error) {
1514 					splx(s);
1515 					goto fail;
1516 				}
1517 			}
1518 		}
1519 
1520 		/* Purge the old altq list */
1521 		while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1522 			TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1523 			if (altq->qname[0] == 0) {
1524 				/* detach and destroy the discipline */
1525 				err = altq_pfdetach(altq);
1526 				if (err != 0 && error == 0)
1527 					error = err;
1528 				err = altq_remove(altq);
1529 				if (err != 0 && error == 0)
1530 					error = err;
1531 			}
1532 			pool_put(&pf_altq_pl, altq);
1533 		}
1534 		splx(s);
1535 
1536 		/* update queue IDs */
1537 		pf_rule_set_qid(
1538 		    pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
1539 		TAILQ_FOREACH(anchor, &pf_anchors, entries) {
1540 			TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
1541 				pf_rule_set_qid(
1542 				    ruleset->rules[PF_RULESET_FILTER].active.ptr
1543 				    );
1544 			}
1545 		}
1546 		break;
1547 	}
1548 
1549 	case DIOCGETALTQS: {
1550 		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
1551 		struct pf_altq		*altq;
1552 
1553 		pa->nr = 0;
1554 		s = splsoftnet();
1555 		TAILQ_FOREACH(altq, pf_altqs_active, entries)
1556 			pa->nr++;
1557 		pa->ticket = ticket_altqs_active;
1558 		splx(s);
1559 		break;
1560 	}
1561 
1562 	case DIOCGETALTQ: {
1563 		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
1564 		struct pf_altq		*altq;
1565 		u_int32_t		 nr;
1566 
1567 		if (pa->ticket != ticket_altqs_active) {
1568 			error = EBUSY;
1569 			break;
1570 		}
1571 		nr = 0;
1572 		s = splsoftnet();
1573 		altq = TAILQ_FIRST(pf_altqs_active);
1574 		while ((altq != NULL) && (nr < pa->nr)) {
1575 			altq = TAILQ_NEXT(altq, entries);
1576 			nr++;
1577 		}
1578 		if (altq == NULL) {
1579 			error = EBUSY;
1580 			splx(s);
1581 			break;
1582 		}
1583 		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1584 		splx(s);
1585 		break;
1586 	}
1587 
1588 	case DIOCCHANGEALTQ:
1589 		/* CHANGEALTQ not supported yet! */
1590 		error = ENODEV;
1591 		break;
1592 
1593 	case DIOCGETQSTATS: {
1594 		struct pfioc_qstats	*pq = (struct pfioc_qstats *)addr;
1595 		struct pf_altq		*altq;
1596 		u_int32_t		 nr;
1597 		int			 nbytes;
1598 
1599 		if (pq->ticket != ticket_altqs_active) {
1600 			error = EBUSY;
1601 			break;
1602 		}
1603 		nbytes = pq->nbytes;
1604 		nr = 0;
1605 		s = splsoftnet();
1606 		altq = TAILQ_FIRST(pf_altqs_active);
1607 		while ((altq != NULL) && (nr < pq->nr)) {
1608 			altq = TAILQ_NEXT(altq, entries);
1609 			nr++;
1610 		}
1611 		if (altq == NULL) {
1612 			error = EBUSY;
1613 			splx(s);
1614 			break;
1615 		}
1616 		error = altq_getqstats(altq, pq->buf, &nbytes);
1617 		splx(s);
1618 		if (error == 0) {
1619 			pq->scheduler = altq->scheduler;
1620 			pq->nbytes = nbytes;
1621 		}
1622 		break;
1623 	}
1624 #endif /* ALTQ */
1625 
1626 	case DIOCBEGINADDRS: {
1627 		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
1628 
1629 		pf_empty_pool(&pf_pabuf);
1630 		pp->ticket = ++ticket_pabuf;
1631 		break;
1632 	}
1633 
1634 	case DIOCADDADDR: {
1635 		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
1636 
1637 #ifndef INET
1638 		if (pp->af == AF_INET) {
1639 			error = EAFNOSUPPORT;
1640 			break;
1641 		}
1642 #endif /* INET */
1643 #ifndef INET6
1644 		if (pp->af == AF_INET6) {
1645 			error = EAFNOSUPPORT;
1646 			break;
1647 		}
1648 #endif /* INET6 */
1649 		if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
1650 		    pp->addr.addr.type != PF_ADDR_DYNIFTL) {
1651 			error = EINVAL;
1652 			break;
1653 		}
1654 		pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
1655 		if (pa == NULL) {
1656 			error = ENOMEM;
1657 			break;
1658 		}
1659 		bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
1660 		if (pa->ifname[0]) {
1661 			pa->ifp = ifunit(pa->ifname);
1662 			if (pa->ifp == NULL) {
1663 				pool_put(&pf_pooladdr_pl, pa);
1664 				error = EINVAL;
1665 				break;
1666 			}
1667 		}
1668 		if (pf_dynaddr_setup(&pa->addr, pp->af)) {
1669 			pf_dynaddr_remove(&pa->addr);
1670 			pool_put(&pf_pooladdr_pl, pa);
1671 			error = EINVAL;
1672 			break;
1673 		}
1674 		TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
1675 		break;
1676 	}
1677 
1678 	case DIOCGETADDRS: {
1679 		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
1680 
1681 		pp->nr = 0;
1682 		s = splsoftnet();
1683 		pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
1684 		    pp->r_action, pp->r_num, 0, 1, 0);
1685 		if (pool == NULL) {
1686 			error = EBUSY;
1687 			splx(s);
1688 			break;
1689 		}
1690 		TAILQ_FOREACH(pa, &pool->list, entries)
1691 			pp->nr++;
1692 		splx(s);
1693 		break;
1694 	}
1695 
1696 	case DIOCGETADDR: {
1697 		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
1698 		u_int32_t		 nr = 0;
1699 
1700 		s = splsoftnet();
1701 		pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
1702 		    pp->r_action, pp->r_num, 0, 1, 1);
1703 		if (pool == NULL) {
1704 			error = EBUSY;
1705 			splx(s);
1706 			break;
1707 		}
1708 		pa = TAILQ_FIRST(&pool->list);
1709 		while ((pa != NULL) && (nr < pp->nr)) {
1710 			pa = TAILQ_NEXT(pa, entries);
1711 			nr++;
1712 		}
1713 		if (pa == NULL) {
1714 			error = EBUSY;
1715 			splx(s);
1716 			break;
1717 		}
1718 		bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
1719 		pf_dynaddr_copyout(&pp->addr.addr);
1720 		splx(s);
1721 		break;
1722 	}
1723 
1724 	case DIOCCHANGEADDR: {
1725 		struct pfioc_pooladdr	*pca = (struct pfioc_pooladdr *)addr;
1726 		struct pf_pooladdr	*oldpa = NULL, *newpa = NULL;
1727 
1728 		if (pca->action < PF_CHANGE_ADD_HEAD ||
1729 		    pca->action > PF_CHANGE_REMOVE) {
1730 			error = EINVAL;
1731 			break;
1732 		}
1733 		if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
1734 		    pca->addr.addr.type != PF_ADDR_DYNIFTL) {
1735 			error = EINVAL;
1736 			break;
1737 		}
1738 
1739 		pool = pf_get_pool(pca->anchor, pca->ruleset, 0,
1740 		    pca->r_action, pca->r_num, pca->r_last, 1, 1);
1741 		if (pool == NULL) {
1742 			error = EBUSY;
1743 			break;
1744 		}
1745 		if (pca->action != PF_CHANGE_REMOVE) {
1746 			newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
1747 			if (newpa == NULL) {
1748 				error = ENOMEM;
1749 				break;
1750 			}
1751 			bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
1752 #ifndef INET
1753 			if (pca->af == AF_INET) {
1754 				pool_put(&pf_pooladdr_pl, newpa);
1755 				error = EAFNOSUPPORT;
1756 				break;
1757 			}
1758 #endif /* INET */
1759 #ifndef INET6
1760 			if (pca->af == AF_INET6) {
1761 				pool_put(&pf_pooladdr_pl, newpa);
1762 				error = EAFNOSUPPORT;
1763 				break;
1764 			}
1765 #endif /* INET6 */
1766 			if (newpa->ifname[0]) {
1767 				newpa->ifp = ifunit(newpa->ifname);
1768 				if (newpa->ifp == NULL) {
1769 					pool_put(&pf_pooladdr_pl, newpa);
1770 					error = EINVAL;
1771 					break;
1772 				}
1773 			} else
1774 				newpa->ifp = NULL;
1775 			if (pf_dynaddr_setup(&newpa->addr, pca->af)) {
1776 				pf_dynaddr_remove(&newpa->addr);
1777 				pool_put(&pf_pooladdr_pl, newpa);
1778 				error = EINVAL;
1779 				break;
1780 			}
1781 		}
1782 
1783 		s = splsoftnet();
1784 
1785 		if (pca->action == PF_CHANGE_ADD_HEAD)
1786 			oldpa = TAILQ_FIRST(&pool->list);
1787 		else if (pca->action == PF_CHANGE_ADD_TAIL)
1788 			oldpa = TAILQ_LAST(&pool->list, pf_palist);
1789 		else {
1790 			int	i = 0;
1791 
1792 			oldpa = TAILQ_FIRST(&pool->list);
1793 			while ((oldpa != NULL) && (i < pca->nr)) {
1794 				oldpa = TAILQ_NEXT(oldpa, entries);
1795 				i++;
1796 			}
1797 			if (oldpa == NULL) {
1798 				error = EINVAL;
1799 				splx(s);
1800 				break;
1801 			}
1802 		}
1803 
1804 		if (pca->action == PF_CHANGE_REMOVE) {
1805 			TAILQ_REMOVE(&pool->list, oldpa, entries);
1806 			pf_dynaddr_remove(&oldpa->addr);
1807 			pool_put(&pf_pooladdr_pl, oldpa);
1808 		} else {
1809 			if (oldpa == NULL)
1810 				TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
1811 			else if (pca->action == PF_CHANGE_ADD_HEAD ||
1812 			    pca->action == PF_CHANGE_ADD_BEFORE)
1813 				TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
1814 			else
1815 				TAILQ_INSERT_AFTER(&pool->list, oldpa,
1816 				    newpa, entries);
1817 		}
1818 
1819 		pool->cur = TAILQ_FIRST(&pool->list);
1820 		PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
1821 		    pca->af);
1822 		splx(s);
1823 		break;
1824 	}
1825 
1826 	case DIOCGETANCHORS: {
1827 		struct pfioc_anchor	*pa = (struct pfioc_anchor *)addr;
1828 		struct pf_anchor	*anchor;
1829 
1830 		pa->nr = 0;
1831 		TAILQ_FOREACH(anchor, &pf_anchors, entries)
1832 			pa->nr++;
1833 		break;
1834 	}
1835 
1836 	case DIOCGETANCHOR: {
1837 		struct pfioc_anchor	*pa = (struct pfioc_anchor *)addr;
1838 		struct pf_anchor	*anchor;
1839 		u_int32_t		 nr = 0;
1840 
1841 		anchor = TAILQ_FIRST(&pf_anchors);
1842 		while (anchor != NULL && nr < pa->nr) {
1843 			anchor = TAILQ_NEXT(anchor, entries);
1844 			nr++;
1845 		}
1846 		if (anchor == NULL)
1847 			error = EBUSY;
1848 		else
1849 			bcopy(anchor->name, pa->name, sizeof(pa->name));
1850 		break;
1851 	}
1852 
1853 	case DIOCGETRULESETS: {
1854 		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
1855 		struct pf_anchor	*anchor;
1856 		struct pf_ruleset	*ruleset;
1857 
1858 		pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0;
1859 		if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
1860 			error = EINVAL;
1861 			break;
1862 		}
1863 		pr->nr = 0;
1864 		TAILQ_FOREACH(ruleset, &anchor->rulesets, entries)
1865 			pr->nr++;
1866 		break;
1867 	}
1868 
1869 	case DIOCGETRULESET: {
1870 		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
1871 		struct pf_anchor	*anchor;
1872 		struct pf_ruleset	*ruleset;
1873 		u_int32_t		 nr = 0;
1874 
1875 		if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
1876 			error = EINVAL;
1877 			break;
1878 		}
1879 		ruleset = TAILQ_FIRST(&anchor->rulesets);
1880 		while (ruleset != NULL && nr < pr->nr) {
1881 			ruleset = TAILQ_NEXT(ruleset, entries);
1882 			nr++;
1883 		}
1884 		if (ruleset == NULL)
1885 			error = EBUSY;
1886 		else
1887 			bcopy(ruleset->name, pr->name, sizeof(pr->name));
1888 		break;
1889 	}
1890 
1891 	case DIOCRCLRTABLES: {
1892 		struct pfioc_table *io = (struct pfioc_table *)addr;
1893 
1894 		if (io->pfrio_esize != 0) {
1895 			error = ENODEV;
1896 			break;
1897 		}
1898 		error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
1899 		    io->pfrio_flags);
1900 		break;
1901 	}
1902 
1903 	case DIOCRADDTABLES: {
1904 		struct pfioc_table *io = (struct pfioc_table *)addr;
1905 
1906 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
1907 			error = ENODEV;
1908 			break;
1909 		}
1910 		error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
1911 		    &io->pfrio_nadd, io->pfrio_flags);
1912 		break;
1913 	}
1914 
1915 	case DIOCRDELTABLES: {
1916 		struct pfioc_table *io = (struct pfioc_table *)addr;
1917 
1918 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
1919 			error = ENODEV;
1920 			break;
1921 		}
1922 		error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
1923 		    &io->pfrio_ndel, io->pfrio_flags);
1924 		break;
1925 	}
1926 
1927 	case DIOCRGETTABLES: {
1928 		struct pfioc_table *io = (struct pfioc_table *)addr;
1929 
1930 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
1931 			error = ENODEV;
1932 			break;
1933 		}
1934 		error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
1935 		    &io->pfrio_size, io->pfrio_flags);
1936 		break;
1937 	}
1938 
1939 	case DIOCRGETTSTATS: {
1940 		struct pfioc_table *io = (struct pfioc_table *)addr;
1941 
1942 		if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
1943 			error = ENODEV;
1944 			break;
1945 		}
1946 		error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
1947 		    &io->pfrio_size, io->pfrio_flags);
1948 		break;
1949 	}
1950 
1951 	case DIOCRCLRTSTATS: {
1952 		struct pfioc_table *io = (struct pfioc_table *)addr;
1953 
1954 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
1955 			error = ENODEV;
1956 			break;
1957 		}
1958 		error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
1959 		    &io->pfrio_nzero, io->pfrio_flags);
1960 		break;
1961 	}
1962 
1963 	case DIOCRSETTFLAGS: {
1964 		struct pfioc_table *io = (struct pfioc_table *)addr;
1965 
1966 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
1967 			error = ENODEV;
1968 			break;
1969 		}
1970 		error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
1971 		    io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
1972 		    &io->pfrio_ndel, io->pfrio_flags);
1973 		break;
1974 	}
1975 
1976 	case DIOCRCLRADDRS: {
1977 		struct pfioc_table *io = (struct pfioc_table *)addr;
1978 
1979 		if (io->pfrio_esize != 0) {
1980 			error = ENODEV;
1981 			break;
1982 		}
1983 		error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
1984 		    io->pfrio_flags);
1985 		break;
1986 	}
1987 
1988 	case DIOCRADDADDRS: {
1989 		struct pfioc_table *io = (struct pfioc_table *)addr;
1990 
1991 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
1992 			error = ENODEV;
1993 			break;
1994 		}
1995 		error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
1996 		    io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags);
1997 		break;
1998 	}
1999 
2000 	case DIOCRDELADDRS: {
2001 		struct pfioc_table *io = (struct pfioc_table *)addr;
2002 
2003 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2004 			error = ENODEV;
2005 			break;
2006 		}
2007 		error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
2008 		    io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags);
2009 		break;
2010 	}
2011 
2012 	case DIOCRSETADDRS: {
2013 		struct pfioc_table *io = (struct pfioc_table *)addr;
2014 
2015 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2016 			error = ENODEV;
2017 			break;
2018 		}
2019 		error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
2020 		    io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
2021 		    &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags);
2022 		break;
2023 	}
2024 
2025 	case DIOCRGETADDRS: {
2026 		struct pfioc_table *io = (struct pfioc_table *)addr;
2027 
2028 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2029 			error = ENODEV;
2030 			break;
2031 		}
2032 		error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
2033 		    &io->pfrio_size, io->pfrio_flags);
2034 		break;
2035 	}
2036 
2037 	case DIOCRGETASTATS: {
2038 		struct pfioc_table *io = (struct pfioc_table *)addr;
2039 
2040 		if (io->pfrio_esize != sizeof(struct pfr_astats)) {
2041 			error = ENODEV;
2042 			break;
2043 		}
2044 		error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
2045 		    &io->pfrio_size, io->pfrio_flags);
2046 		break;
2047 	}
2048 
2049 	case DIOCRCLRASTATS: {
2050 		struct pfioc_table *io = (struct pfioc_table *)addr;
2051 
2052 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2053 			error = ENODEV;
2054 			break;
2055 		}
2056 		error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
2057 		    io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags);
2058 		break;
2059 	}
2060 
2061 	case DIOCRTSTADDRS: {
2062 		struct pfioc_table *io = (struct pfioc_table *)addr;
2063 
2064 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2065 			error = ENODEV;
2066 			break;
2067 		}
2068 		error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
2069 		    io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags);
2070 		break;
2071 	}
2072 
2073 	case DIOCRINABEGIN: {
2074 		struct pfioc_table *io = (struct pfioc_table *)addr;
2075 
2076 		if (io->pfrio_esize != 0) {
2077 			error = ENODEV;
2078 			break;
2079 		}
2080 		error = pfr_ina_begin(&io->pfrio_ticket, &io->pfrio_ndel,
2081 		    io->pfrio_flags);
2082 		break;
2083 	}
2084 
2085 	case DIOCRINACOMMIT: {
2086 		struct pfioc_table *io = (struct pfioc_table *)addr;
2087 
2088 		if (io->pfrio_esize != 0) {
2089 			error = ENODEV;
2090 			break;
2091 		}
2092 		error = pfr_ina_commit(io->pfrio_ticket, &io->pfrio_nadd,
2093 		    &io->pfrio_nchange, io->pfrio_flags);
2094 		break;
2095 	}
2096 
2097 	case DIOCRINADEFINE: {
2098 		struct pfioc_table *io = (struct pfioc_table *)addr;
2099 
2100 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2101 			error = ENODEV;
2102 			break;
2103 		}
2104 		error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
2105 		    io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
2106 		    io->pfrio_ticket, io->pfrio_flags);
2107 		break;
2108 	}
2109 
2110 	default:
2111 		error = ENODEV;
2112 		break;
2113 	}
2114 fail:
2115 
2116 	return (error);
2117 }
2118