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