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