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