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