pf_ioctl.c revision 128846
1/*	$FreeBSD: head/sys/contrib/pf/net/pf_ioctl.c 128846 2004-05-02 20:47:24Z dhartmei $	*/
2/*	$OpenBSD: pf_ioctl.c,v 1.81.2.2 2004/04/30 23:28:58 brad 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_int32_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_int32_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		pf_update_anchor_rules();
647	}
648}
649
650void
651pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
652{
653	struct pf_pooladdr	*mv_pool_pa;
654
655	while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
656		TAILQ_REMOVE(poola, mv_pool_pa, entries);
657		TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
658	}
659}
660
661void
662pf_empty_pool(struct pf_palist *poola)
663{
664	struct pf_pooladdr	*empty_pool_pa;
665
666	while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
667		pf_dynaddr_remove(&empty_pool_pa->addr);
668		pf_tbladdr_remove(&empty_pool_pa->addr);
669		TAILQ_REMOVE(poola, empty_pool_pa, entries);
670		pool_put(&pf_pooladdr_pl, empty_pool_pa);
671	}
672}
673
674void
675pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
676{
677	if (rulequeue != NULL) {
678		if (rule->states <= 0) {
679			/*
680			 * XXX - we need to remove the table *before* detaching
681			 * the rule to make sure the table code does not delete
682			 * the anchor under our feet.
683			 */
684			pf_tbladdr_remove(&rule->src.addr);
685			pf_tbladdr_remove(&rule->dst.addr);
686		}
687		TAILQ_REMOVE(rulequeue, rule, entries);
688		rule->entries.tqe_prev = NULL;
689		rule->nr = -1;
690	}
691	if (rule->states > 0 || rule->entries.tqe_prev != NULL)
692		return;
693	pf_tag_unref(rule->tag);
694	pf_tag_unref(rule->match_tag);
695	pf_dynaddr_remove(&rule->src.addr);
696	pf_dynaddr_remove(&rule->dst.addr);
697	if (rulequeue == NULL) {
698		pf_tbladdr_remove(&rule->src.addr);
699		pf_tbladdr_remove(&rule->dst.addr);
700	}
701	pf_empty_pool(&rule->rpool.list);
702	pool_put(&pf_rule_pl, rule);
703}
704
705u_int16_t
706pf_tagname2tag(char *tagname)
707{
708	struct pf_tagname	*tag, *p = NULL;
709	u_int16_t		 new_tagid = 1;
710
711	TAILQ_FOREACH(tag, &pf_tags, entries)
712		if (strcmp(tagname, tag->name) == 0) {
713			tag->ref++;
714			return (tag->tag);
715		}
716
717	/*
718	 * to avoid fragmentation, we do a linear search from the beginning
719	 * and take the first free slot we find. if there is none or the list
720	 * is empty, append a new entry at the end.
721	 */
722
723	/* new entry */
724	if (!TAILQ_EMPTY(&pf_tags))
725		for (p = TAILQ_FIRST(&pf_tags); p != NULL &&
726		    p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
727			new_tagid = p->tag + 1;
728
729	if (new_tagid > TAGID_MAX)
730		return (0);
731
732	/* allocate and fill new struct pf_tagname */
733	tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname),
734	    M_TEMP, M_NOWAIT);
735	if (tag == NULL)
736		return (0);
737	bzero(tag, sizeof(struct pf_tagname));
738	strlcpy(tag->name, tagname, sizeof(tag->name));
739	tag->tag = new_tagid;
740	tag->ref++;
741
742	if (p != NULL)	/* insert new entry before p */
743		TAILQ_INSERT_BEFORE(p, tag, entries);
744	else	/* either list empty or no free slot in between */
745		TAILQ_INSERT_TAIL(&pf_tags, tag, entries);
746
747	return (tag->tag);
748}
749
750void
751pf_tag2tagname(u_int16_t tagid, char *p)
752{
753	struct pf_tagname	*tag;
754
755	TAILQ_FOREACH(tag, &pf_tags, entries)
756		if (tag->tag == tagid) {
757			strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
758			return;
759		}
760}
761
762void
763pf_tag_unref(u_int16_t tag)
764{
765	struct pf_tagname	*p, *next;
766
767	if (tag == 0)
768		return;
769
770	for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) {
771		next = TAILQ_NEXT(p, entries);
772		if (tag == p->tag) {
773			if (--p->ref == 0) {
774				TAILQ_REMOVE(&pf_tags, p, entries);
775				free(p, M_TEMP);
776			}
777			break;
778		}
779	}
780}
781
782#ifdef __FreeBSD__
783int
784pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
785#else
786int
787pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
788#endif
789{
790	struct pf_pooladdr	*pa = NULL;
791	struct pf_pool		*pool = NULL;
792	int			 s;
793	int			 error = 0;
794
795	/* XXX keep in sync with switch() below */
796	if (securelevel > 1)
797		switch (cmd) {
798		case DIOCGETRULES:
799		case DIOCGETRULE:
800		case DIOCGETADDRS:
801		case DIOCGETADDR:
802		case DIOCGETSTATE:
803		case DIOCSETSTATUSIF:
804		case DIOCGETSTATUS:
805		case DIOCCLRSTATUS:
806		case DIOCNATLOOK:
807		case DIOCSETDEBUG:
808		case DIOCGETSTATES:
809		case DIOCGETTIMEOUT:
810		case DIOCCLRRULECTRS:
811		case DIOCGETLIMIT:
812		case DIOCGETALTQS:
813		case DIOCGETALTQ:
814		case DIOCGETQSTATS:
815		case DIOCGETANCHORS:
816		case DIOCGETANCHOR:
817		case DIOCGETRULESETS:
818		case DIOCGETRULESET:
819		case DIOCRGETTABLES:
820		case DIOCRGETTSTATS:
821		case DIOCRCLRTSTATS:
822		case DIOCRCLRADDRS:
823		case DIOCRADDADDRS:
824		case DIOCRDELADDRS:
825		case DIOCRSETADDRS:
826		case DIOCRGETADDRS:
827		case DIOCRGETASTATS:
828		case DIOCRCLRASTATS:
829		case DIOCRTSTADDRS:
830		case DIOCOSFPGET:
831#ifdef __FreeBSD__
832		case DIOCGIFSPEED:
833#endif
834			break;
835		default:
836			return (EPERM);
837		}
838
839	if (!(flags & FWRITE))
840		switch (cmd) {
841		case DIOCGETRULES:
842		case DIOCGETRULE:
843		case DIOCGETADDRS:
844		case DIOCGETADDR:
845		case DIOCGETSTATE:
846		case DIOCGETSTATUS:
847		case DIOCGETSTATES:
848		case DIOCGETTIMEOUT:
849		case DIOCGETLIMIT:
850		case DIOCGETALTQS:
851		case DIOCGETALTQ:
852		case DIOCGETQSTATS:
853		case DIOCGETANCHORS:
854		case DIOCGETANCHOR:
855		case DIOCGETRULESETS:
856		case DIOCGETRULESET:
857		case DIOCRGETTABLES:
858		case DIOCRGETTSTATS:
859		case DIOCRGETADDRS:
860		case DIOCRGETASTATS:
861		case DIOCRTSTADDRS:
862		case DIOCOSFPGET:
863#ifdef __FreeBSD__
864		case DIOCGIFSPEED:
865#endif
866			break;
867		default:
868			return (EACCES);
869		}
870
871#ifdef __FreeBSD__
872	PF_LOCK();
873#endif
874
875	switch (cmd) {
876
877	case DIOCSTART:
878		if (pf_status.running)
879			error = EEXIST;
880		else {
881			u_int32_t states = pf_status.states;
882#ifdef __FreeBSD__
883			PF_UNLOCK();
884			error = hook_pf();
885			PF_LOCK();
886			if (error) {
887				DPFPRINTF(PF_DEBUG_MISC,
888				    ("pf: pfil registeration fail\n"));
889				break;
890			}
891#endif
892			bzero(&pf_status, sizeof(struct pf_status));
893			pf_status.running = 1;
894			pf_status.states = states;
895#ifdef __FreeBSD__
896			pf_status.since = time_second;
897#else
898			pf_status.since = time.tv_sec;
899#endif
900			if (status_ifp != NULL)
901#if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
902				snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
903				    status_ifp->if_name, status_ifp->if_unit);
904#else
905				strlcpy(pf_status.ifname,
906				    status_ifp->if_xname, IFNAMSIZ);
907#endif
908			DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
909		}
910		break;
911
912	case DIOCSTOP:
913		if (!pf_status.running)
914			error = ENOENT;
915		else {
916			pf_status.running = 0;
917#ifdef __FreeBSD__
918			PF_UNLOCK();
919			error = dehook_pf();
920			PF_LOCK();
921			if (error) {
922				pf_status.running = 1;
923				DPFPRINTF(PF_DEBUG_MISC,
924					("pf: pfil unregisteration failed\n"));
925			}
926#endif
927			DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
928		}
929		break;
930
931	case DIOCBEGINRULES: {
932		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
933		struct pf_ruleset	*ruleset;
934		struct pf_rule		*rule;
935		int			 rs_num;
936
937		ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
938		if (ruleset == NULL) {
939			error = EINVAL;
940			break;
941		}
942		rs_num = pf_get_ruleset_number(pr->rule.action);
943		if (rs_num >= PF_RULESET_MAX) {
944			error = EINVAL;
945			break;
946		}
947		while ((rule =
948		    TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
949			pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
950		pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
951		break;
952	}
953
954	case DIOCADDRULE: {
955		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
956		struct pf_ruleset	*ruleset;
957		struct pf_rule		*rule, *tail;
958		struct pf_pooladdr	*pa;
959		int			 rs_num;
960
961		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
962		if (ruleset == NULL) {
963			error = EINVAL;
964			break;
965		}
966		rs_num = pf_get_ruleset_number(pr->rule.action);
967		if (rs_num >= PF_RULESET_MAX) {
968			error = EINVAL;
969			break;
970		}
971		if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) {
972			error = EINVAL;
973			break;
974		}
975		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
976			error = EINVAL;
977			break;
978		}
979		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
980			error = EBUSY;
981			break;
982		}
983		if (pr->pool_ticket != ticket_pabuf) {
984			error = EBUSY;
985			break;
986		}
987		rule = pool_get(&pf_rule_pl, PR_NOWAIT);
988		if (rule == NULL) {
989			error = ENOMEM;
990			break;
991		}
992		bcopy(&pr->rule, rule, sizeof(struct pf_rule));
993		rule->anchor = NULL;
994		rule->ifp = NULL;
995		TAILQ_INIT(&rule->rpool.list);
996		/* initialize refcounting */
997		rule->states = 0;
998		rule->entries.tqe_prev = NULL;
999#ifndef INET
1000		if (rule->af == AF_INET) {
1001			pool_put(&pf_rule_pl, rule);
1002			error = EAFNOSUPPORT;
1003			break;
1004		}
1005#endif /* INET */
1006#ifndef INET6
1007		if (rule->af == AF_INET6) {
1008			pool_put(&pf_rule_pl, rule);
1009			error = EAFNOSUPPORT;
1010			break;
1011		}
1012#endif /* INET6 */
1013		tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
1014		    pf_rulequeue);
1015		if (tail)
1016			rule->nr = tail->nr + 1;
1017		else
1018			rule->nr = 0;
1019		if (rule->ifname[0]) {
1020			rule->ifp = ifunit(rule->ifname);
1021			if (rule->ifp == NULL) {
1022				pool_put(&pf_rule_pl, rule);
1023				error = EINVAL;
1024				break;
1025			}
1026		}
1027
1028		if (rule->tagname[0])
1029			if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
1030				error = EBUSY;
1031		if (rule->match_tagname[0])
1032			if ((rule->match_tag =
1033			    pf_tagname2tag(rule->match_tagname)) == 0)
1034				error = EBUSY;
1035		if (rule->rt && !rule->direction)
1036			error = EINVAL;
1037		if (pf_dynaddr_setup(&rule->src.addr, rule->af))
1038			error = EINVAL;
1039		if (pf_dynaddr_setup(&rule->dst.addr, rule->af))
1040			error = EINVAL;
1041		if (pf_tbladdr_setup(ruleset, &rule->src.addr))
1042			error = EINVAL;
1043		if (pf_tbladdr_setup(ruleset, &rule->dst.addr))
1044			error = EINVAL;
1045		TAILQ_FOREACH(pa, &pf_pabuf, entries)
1046			if (pf_tbladdr_setup(ruleset, &pa->addr))
1047				error = EINVAL;
1048
1049		pf_mv_pool(&pf_pabuf, &rule->rpool.list);
1050		if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
1051		    (rule->action == PF_BINAT)) && !rule->anchorname[0]) ||
1052		    (rule->rt > PF_FASTROUTE)) &&
1053		    (TAILQ_FIRST(&rule->rpool.list) == NULL))
1054			error = EINVAL;
1055
1056		if (error) {
1057			pf_rm_rule(NULL, rule);
1058			break;
1059		}
1060		rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
1061		rule->evaluations = rule->packets = rule->bytes = 0;
1062		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
1063		    rule, entries);
1064		break;
1065	}
1066
1067	case DIOCCOMMITRULES: {
1068		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
1069		struct pf_ruleset	*ruleset;
1070		struct pf_rulequeue	*old_rules;
1071		struct pf_rule		*rule;
1072		int			 rs_num;
1073
1074		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
1075		if (ruleset == NULL) {
1076			error = EINVAL;
1077			break;
1078		}
1079		rs_num = pf_get_ruleset_number(pr->rule.action);
1080		if (rs_num >= PF_RULESET_MAX) {
1081			error = EINVAL;
1082			break;
1083		}
1084		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
1085			error = EBUSY;
1086			break;
1087		}
1088
1089#ifdef ALTQ
1090		/* set queue IDs */
1091		if (rs_num == PF_RULESET_FILTER)
1092			pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
1093#endif
1094
1095		/* Swap rules, keep the old. */
1096		s = splsoftnet();
1097		old_rules = ruleset->rules[rs_num].active.ptr;
1098		ruleset->rules[rs_num].active.ptr =
1099		    ruleset->rules[rs_num].inactive.ptr;
1100		ruleset->rules[rs_num].inactive.ptr = old_rules;
1101		ruleset->rules[rs_num].active.ticket =
1102		    ruleset->rules[rs_num].inactive.ticket;
1103		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1104
1105		/* Purge the old rule list. */
1106		while ((rule = TAILQ_FIRST(old_rules)) != NULL)
1107			pf_rm_rule(old_rules, rule);
1108		pf_remove_if_empty_ruleset(ruleset);
1109		pf_update_anchor_rules();
1110		splx(s);
1111		break;
1112	}
1113
1114	case DIOCGETRULES: {
1115		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
1116		struct pf_ruleset	*ruleset;
1117		struct pf_rule		*tail;
1118		int			 rs_num;
1119
1120		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
1121		if (ruleset == NULL) {
1122			error = EINVAL;
1123			break;
1124		}
1125		rs_num = pf_get_ruleset_number(pr->rule.action);
1126		if (rs_num >= PF_RULESET_MAX) {
1127			error = EINVAL;
1128			break;
1129		}
1130		s = splsoftnet();
1131		tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
1132		    pf_rulequeue);
1133		if (tail)
1134			pr->nr = tail->nr + 1;
1135		else
1136			pr->nr = 0;
1137		pr->ticket = ruleset->rules[rs_num].active.ticket;
1138		splx(s);
1139		break;
1140	}
1141
1142	case DIOCGETRULE: {
1143		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
1144		struct pf_ruleset	*ruleset;
1145		struct pf_rule		*rule;
1146		int			 rs_num, i;
1147
1148		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
1149		if (ruleset == NULL) {
1150			error = EINVAL;
1151			break;
1152		}
1153		rs_num = pf_get_ruleset_number(pr->rule.action);
1154		if (rs_num >= PF_RULESET_MAX) {
1155			error = EINVAL;
1156			break;
1157		}
1158		if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
1159			error = EBUSY;
1160			break;
1161		}
1162		s = splsoftnet();
1163		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
1164		while ((rule != NULL) && (rule->nr != pr->nr))
1165			rule = TAILQ_NEXT(rule, entries);
1166		if (rule == NULL) {
1167			error = EBUSY;
1168			splx(s);
1169			break;
1170		}
1171		bcopy(rule, &pr->rule, sizeof(struct pf_rule));
1172		pf_dynaddr_copyout(&pr->rule.src.addr);
1173		pf_dynaddr_copyout(&pr->rule.dst.addr);
1174		pf_tbladdr_copyout(&pr->rule.src.addr);
1175		pf_tbladdr_copyout(&pr->rule.dst.addr);
1176		for (i = 0; i < PF_SKIP_COUNT; ++i)
1177			if (rule->skip[i].ptr == NULL)
1178				pr->rule.skip[i].nr = -1;
1179			else
1180				pr->rule.skip[i].nr =
1181				    rule->skip[i].ptr->nr;
1182		splx(s);
1183		break;
1184	}
1185
1186	case DIOCCHANGERULE: {
1187		struct pfioc_rule	*pcr = (struct pfioc_rule *)addr;
1188		struct pf_ruleset	*ruleset;
1189		struct pf_rule		*oldrule = NULL, *newrule = NULL;
1190		u_int32_t		 nr = 0;
1191		int			 rs_num;
1192
1193		if (!(pcr->action == PF_CHANGE_REMOVE ||
1194		    pcr->action == PF_CHANGE_GET_TICKET) &&
1195		    pcr->pool_ticket != ticket_pabuf) {
1196			error = EBUSY;
1197			break;
1198		}
1199
1200		if (pcr->action < PF_CHANGE_ADD_HEAD ||
1201		    pcr->action > PF_CHANGE_GET_TICKET) {
1202			error = EINVAL;
1203			break;
1204		}
1205		ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset);
1206		if (ruleset == NULL) {
1207			error = EINVAL;
1208			break;
1209		}
1210		rs_num = pf_get_ruleset_number(pcr->rule.action);
1211		if (rs_num >= PF_RULESET_MAX) {
1212			error = EINVAL;
1213			break;
1214		}
1215
1216		if (pcr->action == PF_CHANGE_GET_TICKET) {
1217			pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
1218			break;
1219		} else {
1220			if (pcr->ticket !=
1221			    ruleset->rules[rs_num].active.ticket) {
1222				error = EINVAL;
1223				break;
1224			}
1225			if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1226				error = EINVAL;
1227				break;
1228			}
1229		}
1230
1231		if (pcr->action != PF_CHANGE_REMOVE) {
1232			newrule = pool_get(&pf_rule_pl, PR_NOWAIT);
1233			if (newrule == NULL) {
1234				error = ENOMEM;
1235				break;
1236			}
1237			bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
1238			TAILQ_INIT(&newrule->rpool.list);
1239			/* initialize refcounting */
1240			newrule->states = 0;
1241			newrule->entries.tqe_prev = NULL;
1242#ifndef INET
1243			if (newrule->af == AF_INET) {
1244				pool_put(&pf_rule_pl, newrule);
1245				error = EAFNOSUPPORT;
1246				break;
1247			}
1248#endif /* INET */
1249#ifndef INET6
1250			if (newrule->af == AF_INET6) {
1251				pool_put(&pf_rule_pl, newrule);
1252				error = EAFNOSUPPORT;
1253				break;
1254			}
1255#endif /* INET6 */
1256			if (newrule->ifname[0]) {
1257				newrule->ifp = ifunit(newrule->ifname);
1258				if (newrule->ifp == NULL) {
1259					pool_put(&pf_rule_pl, newrule);
1260					error = EINVAL;
1261					break;
1262				}
1263			} else
1264				newrule->ifp = NULL;
1265
1266#ifdef ALTQ
1267			/* set queue IDs */
1268			if (newrule->qname[0] != 0) {
1269				newrule->qid = pf_qname_to_qid(newrule->qname);
1270				if (newrule->pqname[0] != 0)
1271					newrule->pqid =
1272					    pf_qname_to_qid(newrule->pqname);
1273				else
1274					newrule->pqid = newrule->qid;
1275			}
1276#endif
1277			if (newrule->tagname[0])
1278				if ((newrule->tag =
1279				    pf_tagname2tag(newrule->tagname)) == 0)
1280					error = EBUSY;
1281			if (newrule->match_tagname[0])
1282				if ((newrule->match_tag = pf_tagname2tag(
1283				    newrule->match_tagname)) == 0)
1284					error = EBUSY;
1285
1286			if (newrule->rt && !newrule->direction)
1287				error = EINVAL;
1288			if (pf_dynaddr_setup(&newrule->src.addr, newrule->af))
1289				error = EINVAL;
1290			if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af))
1291				error = EINVAL;
1292			if (pf_tbladdr_setup(ruleset, &newrule->src.addr))
1293				error = EINVAL;
1294			if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))
1295				error = EINVAL;
1296
1297			pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
1298			if (((((newrule->action == PF_NAT) ||
1299			    (newrule->action == PF_RDR) ||
1300			    (newrule->action == PF_BINAT) ||
1301			    (newrule->rt > PF_FASTROUTE)) &&
1302			    !newrule->anchorname[0])) &&
1303			    (TAILQ_FIRST(&newrule->rpool.list) == NULL))
1304				error = EINVAL;
1305
1306			if (error) {
1307				pf_rm_rule(NULL, newrule);
1308				break;
1309			}
1310			newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
1311			newrule->evaluations = newrule->packets = 0;
1312			newrule->bytes = 0;
1313		}
1314		pf_empty_pool(&pf_pabuf);
1315
1316		s = splsoftnet();
1317
1318		if (pcr->action == PF_CHANGE_ADD_HEAD)
1319			oldrule = TAILQ_FIRST(
1320			    ruleset->rules[rs_num].active.ptr);
1321		else if (pcr->action == PF_CHANGE_ADD_TAIL)
1322			oldrule = TAILQ_LAST(
1323			    ruleset->rules[rs_num].active.ptr, pf_rulequeue);
1324		else {
1325			oldrule = TAILQ_FIRST(
1326			    ruleset->rules[rs_num].active.ptr);
1327			while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
1328				oldrule = TAILQ_NEXT(oldrule, entries);
1329			if (oldrule == NULL) {
1330				pf_rm_rule(NULL, newrule);
1331				error = EINVAL;
1332				splx(s);
1333				break;
1334			}
1335		}
1336
1337		if (pcr->action == PF_CHANGE_REMOVE)
1338			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
1339		else {
1340			if (oldrule == NULL)
1341				TAILQ_INSERT_TAIL(
1342				    ruleset->rules[rs_num].active.ptr,
1343				    newrule, entries);
1344			else if (pcr->action == PF_CHANGE_ADD_HEAD ||
1345			    pcr->action == PF_CHANGE_ADD_BEFORE)
1346				TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
1347			else
1348				TAILQ_INSERT_AFTER(
1349				    ruleset->rules[rs_num].active.ptr,
1350				    oldrule, newrule, entries);
1351		}
1352
1353		nr = 0;
1354		TAILQ_FOREACH(oldrule,
1355		    ruleset->rules[rs_num].active.ptr, entries)
1356			oldrule->nr = nr++;
1357
1358		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1359		pf_remove_if_empty_ruleset(ruleset);
1360		pf_update_anchor_rules();
1361
1362		ruleset->rules[rs_num].active.ticket++;
1363		splx(s);
1364		break;
1365	}
1366
1367	case DIOCCLRSTATES: {
1368		struct pf_tree_node	*n;
1369
1370		s = splsoftnet();
1371		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1372			n->state->timeout = PFTM_PURGE;
1373		pf_purge_expired_states();
1374		pf_status.states = 0;
1375		splx(s);
1376		break;
1377	}
1378
1379	case DIOCKILLSTATES: {
1380		struct pf_tree_node	*n;
1381		struct pf_state		*st;
1382		struct pfioc_state_kill	*psk = (struct pfioc_state_kill *)addr;
1383		int			 killed = 0;
1384
1385		s = splsoftnet();
1386		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1387			st = n->state;
1388			if ((!psk->psk_af || st->af == psk->psk_af) &&
1389			    (!psk->psk_proto || psk->psk_proto == st->proto) &&
1390			    PF_MATCHA(psk->psk_src.not,
1391			    &psk->psk_src.addr.v.a.addr,
1392			    &psk->psk_src.addr.v.a.mask, &st->lan.addr,
1393			    st->af) &&
1394			    PF_MATCHA(psk->psk_dst.not,
1395			    &psk->psk_dst.addr.v.a.addr,
1396			    &psk->psk_dst.addr.v.a.mask, &st->ext.addr,
1397			    st->af) &&
1398			    (psk->psk_src.port_op == 0 ||
1399			    pf_match_port(psk->psk_src.port_op,
1400			    psk->psk_src.port[0], psk->psk_src.port[1],
1401			    st->lan.port)) &&
1402			    (psk->psk_dst.port_op == 0 ||
1403			    pf_match_port(psk->psk_dst.port_op,
1404			    psk->psk_dst.port[0], psk->psk_dst.port[1],
1405			    st->ext.port))) {
1406				st->timeout = PFTM_PURGE;
1407				killed++;
1408			}
1409		}
1410		pf_purge_expired_states();
1411		splx(s);
1412		psk->psk_af = killed;
1413		break;
1414	}
1415
1416	case DIOCADDSTATE: {
1417		struct pfioc_state	*ps = (struct pfioc_state *)addr;
1418		struct pf_state		*state;
1419
1420		if (ps->state.timeout >= PFTM_MAX &&
1421		    ps->state.timeout != PFTM_UNTIL_PACKET) {
1422			error = EINVAL;
1423			break;
1424		}
1425		state = pool_get(&pf_state_pl, PR_NOWAIT);
1426		if (state == NULL) {
1427			error = ENOMEM;
1428			break;
1429		}
1430		s = splsoftnet();
1431		bcopy(&ps->state, state, sizeof(struct pf_state));
1432		state->rule.ptr = NULL;
1433		state->nat_rule.ptr = NULL;
1434		state->anchor.ptr = NULL;
1435		state->rt_ifp = NULL;
1436#ifdef __FreeBSD__
1437		state->creation = time_second;
1438#else
1439		state->creation = time.tv_sec;
1440#endif
1441		state->packets[0] = state->packets[1] = 0;
1442		state->bytes[0] = state->bytes[1] = 0;
1443		if (pf_insert_state(state)) {
1444			pool_put(&pf_state_pl, state);
1445			error = ENOMEM;
1446		}
1447		splx(s);
1448		break;
1449	}
1450
1451	case DIOCGETSTATE: {
1452		struct pfioc_state	*ps = (struct pfioc_state *)addr;
1453		struct pf_tree_node	*n;
1454		u_int32_t		 nr;
1455
1456		nr = 0;
1457		s = splsoftnet();
1458		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1459			if (nr >= ps->nr)
1460				break;
1461			nr++;
1462		}
1463		if (n == NULL) {
1464			error = EBUSY;
1465			splx(s);
1466			break;
1467		}
1468		bcopy(n->state, &ps->state, sizeof(struct pf_state));
1469		ps->state.rule.nr = n->state->rule.ptr->nr;
1470		ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1471		    -1 : n->state->nat_rule.ptr->nr;
1472		ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ?
1473		    -1 : n->state->anchor.ptr->nr;
1474		splx(s);
1475		ps->state.expire = pf_state_expires(n->state);
1476#ifdef __FreeBSD__
1477		if (ps->state.expire > time_second)
1478			ps->state.expire -= time_second;
1479#else
1480		if (ps->state.expire > time.tv_sec)
1481			ps->state.expire -= time.tv_sec;
1482#endif
1483		else
1484			ps->state.expire = 0;
1485		break;
1486	}
1487
1488	case DIOCGETSTATES: {
1489		struct pfioc_states	*ps = (struct pfioc_states *)addr;
1490		struct pf_tree_node	*n;
1491		struct pf_state		*p, pstore;
1492		u_int32_t		 nr = 0;
1493		int			 space = ps->ps_len;
1494
1495		if (space == 0) {
1496			s = splsoftnet();
1497			RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1498				nr++;
1499			splx(s);
1500			ps->ps_len = sizeof(struct pf_state) * nr;
1501#ifdef __FreeBSD__
1502			PF_UNLOCK();
1503#endif
1504			return (0);
1505		}
1506
1507		s = splsoftnet();
1508		p = ps->ps_states;
1509		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1510#ifdef __FreeBSD__
1511			int	secs = time_second;
1512#else
1513			int	secs = time.tv_sec;
1514#endif
1515
1516			if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len)
1517				break;
1518
1519			bcopy(n->state, &pstore, sizeof(pstore));
1520			pstore.rule.nr = n->state->rule.ptr->nr;
1521			pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1522			    -1 : n->state->nat_rule.ptr->nr;
1523			pstore.anchor.nr = (n->state->anchor.ptr == NULL) ?
1524			    -1 : n->state->anchor.ptr->nr;
1525			pstore.creation = secs - pstore.creation;
1526			pstore.expire = pf_state_expires(n->state);
1527			if (pstore.expire > secs)
1528				pstore.expire -= secs;
1529			else
1530				pstore.expire = 0;
1531#ifdef __FreeBSD__
1532			PF_COPYOUT(&pstore, p, sizeof(*p), error);
1533#else
1534			error = copyout(&pstore, p, sizeof(*p));
1535#endif
1536			if (error) {
1537				splx(s);
1538				goto fail;
1539			}
1540			p++;
1541			nr++;
1542		}
1543		ps->ps_len = sizeof(struct pf_state) * nr;
1544		splx(s);
1545		break;
1546	}
1547
1548	case DIOCGETSTATUS: {
1549		struct pf_status *s = (struct pf_status *)addr;
1550		bcopy(&pf_status, s, sizeof(struct pf_status));
1551		break;
1552	}
1553
1554	case DIOCSETSTATUSIF: {
1555		struct pfioc_if	*pi = (struct pfioc_if *)addr;
1556		struct ifnet	*ifp;
1557
1558		if (pi->ifname[0] == 0) {
1559			status_ifp = NULL;
1560			bzero(pf_status.ifname, IFNAMSIZ);
1561			break;
1562		}
1563		if ((ifp = ifunit(pi->ifname)) == NULL) {
1564			error = EINVAL;
1565			break;
1566		} else if (ifp == status_ifp)
1567			break;
1568		status_ifp = ifp;
1569		/* fallthrough into DIOCCLRSTATUS */
1570	}
1571
1572	case DIOCCLRSTATUS: {
1573		u_int32_t	running = pf_status.running;
1574		u_int32_t	states = pf_status.states;
1575		u_int32_t	since = pf_status.since;
1576		u_int32_t	debug = pf_status.debug;
1577
1578		bzero(&pf_status, sizeof(struct pf_status));
1579		pf_status.running = running;
1580		pf_status.states = states;
1581		pf_status.since = since;
1582		pf_status.debug = debug;
1583		if (status_ifp != NULL)
1584#if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
1585			snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
1586			    status_ifp->if_name, status_ifp->if_unit);
1587#else
1588			strlcpy(pf_status.ifname,
1589			    status_ifp->if_xname, IFNAMSIZ);
1590#endif
1591		break;
1592	}
1593
1594	case DIOCNATLOOK: {
1595		struct pfioc_natlook	*pnl = (struct pfioc_natlook *)addr;
1596		struct pf_state		*st;
1597		struct pf_tree_node	 key;
1598		int			 direction = pnl->direction;
1599
1600		key.af = pnl->af;
1601		key.proto = pnl->proto;
1602
1603		/*
1604		 * userland gives us source and dest of connection, reverse
1605		 * the lookup so we ask for what happens with the return
1606		 * traffic, enabling us to find it in the state tree.
1607		 */
1608		PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af);
1609		key.port[1] = pnl->sport;
1610		PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af);
1611		key.port[0] = pnl->dport;
1612
1613		if (!pnl->proto ||
1614		    PF_AZERO(&pnl->saddr, pnl->af) ||
1615		    PF_AZERO(&pnl->daddr, pnl->af) ||
1616		    !pnl->dport || !pnl->sport)
1617			error = EINVAL;
1618		else {
1619			s = splsoftnet();
1620			if (direction == PF_IN)
1621				st = pf_find_state(&tree_ext_gwy, &key);
1622			else
1623				st = pf_find_state(&tree_lan_ext, &key);
1624			if (st != NULL) {
1625				if (direction == PF_IN) {
1626					PF_ACPY(&pnl->rsaddr, &st->lan.addr,
1627					    st->af);
1628					pnl->rsport = st->lan.port;
1629					PF_ACPY(&pnl->rdaddr, &pnl->daddr,
1630					    pnl->af);
1631					pnl->rdport = pnl->dport;
1632				} else {
1633					PF_ACPY(&pnl->rdaddr, &st->gwy.addr,
1634					    st->af);
1635					pnl->rdport = st->gwy.port;
1636					PF_ACPY(&pnl->rsaddr, &pnl->saddr,
1637					    pnl->af);
1638					pnl->rsport = pnl->sport;
1639				}
1640			} else
1641				error = ENOENT;
1642			splx(s);
1643		}
1644		break;
1645	}
1646
1647	case DIOCSETTIMEOUT: {
1648		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
1649		int		 old;
1650
1651		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
1652		    pt->seconds < 0) {
1653			error = EINVAL;
1654			goto fail;
1655		}
1656		old = pf_default_rule.timeout[pt->timeout];
1657		pf_default_rule.timeout[pt->timeout] = pt->seconds;
1658		pt->seconds = old;
1659		break;
1660	}
1661
1662	case DIOCGETTIMEOUT: {
1663		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
1664
1665		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
1666			error = EINVAL;
1667			goto fail;
1668		}
1669		pt->seconds = pf_default_rule.timeout[pt->timeout];
1670		break;
1671	}
1672
1673	case DIOCGETLIMIT: {
1674		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
1675
1676		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1677			error = EINVAL;
1678			goto fail;
1679		}
1680		pl->limit = pf_pool_limits[pl->index].limit;
1681		break;
1682	}
1683
1684	case DIOCSETLIMIT: {
1685		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
1686		int			 old_limit;
1687
1688		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1689			error = EINVAL;
1690			goto fail;
1691		}
1692#ifdef __FreeBSD__
1693		uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit);
1694#else
1695		if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
1696		    pl->limit, NULL, 0) != 0) {
1697			error = EBUSY;
1698			goto fail;
1699		}
1700#endif
1701		old_limit = pf_pool_limits[pl->index].limit;
1702		pf_pool_limits[pl->index].limit = pl->limit;
1703		pl->limit = old_limit;
1704		break;
1705	}
1706
1707	case DIOCSETDEBUG: {
1708		u_int32_t	*level = (u_int32_t *)addr;
1709
1710		pf_status.debug = *level;
1711		break;
1712	}
1713
1714	case DIOCCLRRULECTRS: {
1715		struct pf_ruleset	*ruleset = &pf_main_ruleset;
1716		struct pf_rule		*rule;
1717
1718		s = splsoftnet();
1719		TAILQ_FOREACH(rule,
1720		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
1721			rule->evaluations = rule->packets =
1722			    rule->bytes = 0;
1723		splx(s);
1724		break;
1725	}
1726
1727#ifdef __FreeBSD__
1728	case DIOCGIFSPEED: {
1729		struct pf_ifspeed	*psp = (struct pf_ifspeed *)addr;
1730		struct pf_ifspeed	ps;
1731		struct ifnet		*ifp;
1732
1733		if (psp->ifname[0] != 0) {
1734			/* Can we completely trust user-land? */
1735			strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
1736			ifp = ifunit(ps.ifname);
1737			if (ifp )
1738				psp->baudrate = ifp->if_baudrate;
1739			else
1740				error = EINVAL;
1741		} else
1742			error = EINVAL;
1743		break;
1744	}
1745#endif /* __FreeBSD__ */
1746
1747#ifdef ALTQ
1748	case DIOCSTARTALTQ: {
1749		struct pf_altq		*altq;
1750		struct ifnet		*ifp;
1751		struct tb_profile	 tb;
1752
1753		/* enable all altq interfaces on active list */
1754		s = splsoftnet();
1755		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1756			if (altq->qname[0] == 0) {
1757				if ((ifp = ifunit(altq->ifname)) == NULL) {
1758					error = EINVAL;
1759					break;
1760				}
1761				if (ifp->if_snd.altq_type != ALTQT_NONE)
1762					error = altq_enable(&ifp->if_snd);
1763				if (error != 0)
1764					break;
1765				/* set tokenbucket regulator */
1766				tb.rate = altq->ifbandwidth;
1767				tb.depth = altq->tbrsize;
1768				error = tbr_set(&ifp->if_snd, &tb);
1769				if (error != 0)
1770					break;
1771			}
1772		}
1773#ifdef __FreeBSD__
1774		if (error == 0) {
1775			mtx_lock(&pf_altq_mtx);
1776			pfaltq_running = 1;
1777			mtx_unlock(&pf_altq_mtx);
1778		}
1779#else
1780		if (error == 0)
1781			pfaltq_running = 1;
1782#endif
1783		splx(s);
1784		DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
1785		break;
1786	}
1787
1788	case DIOCSTOPALTQ: {
1789		struct pf_altq		*altq;
1790		struct ifnet		*ifp;
1791		struct tb_profile	 tb;
1792		int			 err;
1793
1794		/* disable all altq interfaces on active list */
1795		s = splsoftnet();
1796		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1797			if (altq->qname[0] == 0) {
1798				if ((ifp = ifunit(altq->ifname)) == NULL) {
1799					error = EINVAL;
1800					break;
1801				}
1802				if (ifp->if_snd.altq_type != ALTQT_NONE) {
1803					err = altq_disable(&ifp->if_snd);
1804					if (err != 0 && error == 0)
1805						error = err;
1806				}
1807				/* clear tokenbucket regulator */
1808				tb.rate = 0;
1809				err = tbr_set(&ifp->if_snd, &tb);
1810				if (err != 0 && error == 0)
1811					error = err;
1812			}
1813		}
1814#ifdef __FreeBSD__
1815		if (error == 0) {
1816			mtx_lock(&pf_altq_mtx);
1817			pfaltq_running = 0;
1818			mtx_unlock(&pf_altq_mtx);
1819		}
1820#else
1821		if (error == 0)
1822			pfaltq_running = 0;
1823#endif
1824		splx(s);
1825		DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
1826		break;
1827	}
1828
1829	case DIOCBEGINALTQS: {
1830		u_int32_t	*ticket = (u_int32_t *)addr;
1831		struct pf_altq	*altq;
1832
1833		/* Purge the old altq list */
1834		while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1835			TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1836			if (altq->qname[0] == 0) {
1837				/* detach and destroy the discipline */
1838#ifdef __FreeBSD__
1839				PF_UNLOCK();
1840#endif
1841				error = altq_remove(altq);
1842#ifdef __FreeBSD__
1843				PF_LOCK();
1844#endif
1845			}
1846			pool_put(&pf_altq_pl, altq);
1847		}
1848		*ticket = ++ticket_altqs_inactive;
1849		break;
1850	}
1851
1852	case DIOCADDALTQ: {
1853		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
1854		struct pf_altq		*altq, *a;
1855
1856		if (pa->ticket != ticket_altqs_inactive) {
1857			error = EBUSY;
1858			break;
1859		}
1860		altq = pool_get(&pf_altq_pl, PR_NOWAIT);
1861		if (altq == NULL) {
1862			error = ENOMEM;
1863			break;
1864		}
1865		bcopy(&pa->altq, altq, sizeof(struct pf_altq));
1866
1867		/*
1868		 * if this is for a queue, find the discipline and
1869		 * copy the necessary fields
1870		 */
1871		if (altq->qname[0] != 0) {
1872			TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
1873				if (strncmp(a->ifname, altq->ifname,
1874				    IFNAMSIZ) == 0 && a->qname[0] == 0) {
1875					altq->altq_disc = a->altq_disc;
1876					break;
1877				}
1878			}
1879		}
1880
1881#ifdef __FreeBSD__
1882		PF_UNLOCK();
1883#endif
1884		error = altq_add(altq);
1885#ifdef __FreeBSD__
1886		PF_LOCK();
1887#endif
1888		if (error) {
1889			pool_put(&pf_altq_pl, altq);
1890			break;
1891		}
1892
1893		TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
1894		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1895		break;
1896	}
1897
1898	case DIOCCOMMITALTQS: {
1899		u_int32_t		*ticket = (u_int32_t *)addr;
1900		struct pf_altqqueue	*old_altqs;
1901		struct pf_altq		*altq;
1902		struct pf_anchor	*anchor;
1903		struct pf_ruleset	*ruleset;
1904		int			 err;
1905
1906		if (*ticket != ticket_altqs_inactive) {
1907			error = EBUSY;
1908			break;
1909		}
1910
1911		/* Swap altqs, keep the old. */
1912		s = splsoftnet();
1913		old_altqs = pf_altqs_active;
1914		pf_altqs_active = pf_altqs_inactive;
1915		pf_altqs_inactive = old_altqs;
1916		ticket_altqs_active = ticket_altqs_inactive;
1917
1918		/* Attach new disciplines */
1919		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1920			if (altq->qname[0] == 0) {
1921				/* attach the discipline */
1922#ifdef __FreeBSD__
1923				PF_UNLOCK();
1924#endif
1925				error = altq_pfattach(altq);
1926#ifdef __FreeBSD__
1927				PF_LOCK();
1928#endif
1929				if (error) {
1930					splx(s);
1931					goto fail;
1932				}
1933			}
1934		}
1935
1936		/* Purge the old altq list */
1937		while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1938			TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1939			if (altq->qname[0] == 0) {
1940				/* detach and destroy the discipline */
1941#ifdef __FreeBSD__
1942				PF_UNLOCK();
1943#endif
1944				err = altq_pfdetach(altq);
1945				if (err != 0 && error == 0)
1946					error = err;
1947				err = altq_remove(altq);
1948				if (err != 0 && error == 0)
1949					error = err;
1950#ifdef __FreeBSD__
1951				PF_LOCK();
1952#endif
1953			}
1954			pool_put(&pf_altq_pl, altq);
1955		}
1956		splx(s);
1957
1958		/* update queue IDs */
1959		pf_rule_set_qid(
1960		    pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
1961		TAILQ_FOREACH(anchor, &pf_anchors, entries) {
1962			TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
1963				pf_rule_set_qid(
1964				    ruleset->rules[PF_RULESET_FILTER].active.ptr
1965				    );
1966			}
1967		}
1968		break;
1969	}
1970
1971	case DIOCGETALTQS: {
1972		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
1973		struct pf_altq		*altq;
1974
1975		pa->nr = 0;
1976		s = splsoftnet();
1977		TAILQ_FOREACH(altq, pf_altqs_active, entries)
1978			pa->nr++;
1979		pa->ticket = ticket_altqs_active;
1980		splx(s);
1981		break;
1982	}
1983
1984	case DIOCGETALTQ: {
1985		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
1986		struct pf_altq		*altq;
1987		u_int32_t		 nr;
1988
1989		if (pa->ticket != ticket_altqs_active) {
1990			error = EBUSY;
1991			break;
1992		}
1993		nr = 0;
1994		s = splsoftnet();
1995		altq = TAILQ_FIRST(pf_altqs_active);
1996		while ((altq != NULL) && (nr < pa->nr)) {
1997			altq = TAILQ_NEXT(altq, entries);
1998			nr++;
1999		}
2000		if (altq == NULL) {
2001			error = EBUSY;
2002			splx(s);
2003			break;
2004		}
2005		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
2006		splx(s);
2007		break;
2008	}
2009
2010	case DIOCCHANGEALTQ:
2011		/* CHANGEALTQ not supported yet! */
2012		error = ENODEV;
2013		break;
2014
2015	case DIOCGETQSTATS: {
2016		struct pfioc_qstats	*pq = (struct pfioc_qstats *)addr;
2017		struct pf_altq		*altq;
2018		u_int32_t		 nr;
2019		int			 nbytes;
2020
2021		if (pq->ticket != ticket_altqs_active) {
2022			error = EBUSY;
2023			break;
2024		}
2025		nbytes = pq->nbytes;
2026		nr = 0;
2027		s = splsoftnet();
2028		altq = TAILQ_FIRST(pf_altqs_active);
2029		while ((altq != NULL) && (nr < pq->nr)) {
2030			altq = TAILQ_NEXT(altq, entries);
2031			nr++;
2032		}
2033		if (altq == NULL) {
2034			error = EBUSY;
2035			splx(s);
2036			break;
2037		}
2038#ifdef __FreeBSD__
2039		PF_UNLOCK();
2040#endif
2041		error = altq_getqstats(altq, pq->buf, &nbytes);
2042#ifdef __FreeBSD__
2043		PF_LOCK();
2044#endif
2045		splx(s);
2046		if (error == 0) {
2047			pq->scheduler = altq->scheduler;
2048			pq->nbytes = nbytes;
2049		}
2050		break;
2051	}
2052#endif /* ALTQ */
2053
2054	case DIOCBEGINADDRS: {
2055		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2056
2057		pf_empty_pool(&pf_pabuf);
2058		pp->ticket = ++ticket_pabuf;
2059		break;
2060	}
2061
2062	case DIOCADDADDR: {
2063		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2064
2065#ifndef INET
2066		if (pp->af == AF_INET) {
2067			error = EAFNOSUPPORT;
2068			break;
2069		}
2070#endif /* INET */
2071#ifndef INET6
2072		if (pp->af == AF_INET6) {
2073			error = EAFNOSUPPORT;
2074			break;
2075		}
2076#endif /* INET6 */
2077		if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
2078		    pp->addr.addr.type != PF_ADDR_DYNIFTL &&
2079		    pp->addr.addr.type != PF_ADDR_TABLE) {
2080			error = EINVAL;
2081			break;
2082		}
2083		pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
2084		if (pa == NULL) {
2085			error = ENOMEM;
2086			break;
2087		}
2088		bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
2089		if (pa->ifname[0]) {
2090			pa->ifp = ifunit(pa->ifname);
2091			if (pa->ifp == NULL) {
2092				pool_put(&pf_pooladdr_pl, pa);
2093				error = EINVAL;
2094				break;
2095			}
2096		}
2097		if (pf_dynaddr_setup(&pa->addr, pp->af)) {
2098			pf_dynaddr_remove(&pa->addr);
2099			pool_put(&pf_pooladdr_pl, pa);
2100			error = EINVAL;
2101			break;
2102		}
2103		TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
2104		break;
2105	}
2106
2107	case DIOCGETADDRS: {
2108		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2109
2110		pp->nr = 0;
2111		s = splsoftnet();
2112		pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
2113		    pp->r_action, pp->r_num, 0, 1, 0);
2114		if (pool == NULL) {
2115			error = EBUSY;
2116			splx(s);
2117			break;
2118		}
2119		TAILQ_FOREACH(pa, &pool->list, entries)
2120			pp->nr++;
2121		splx(s);
2122		break;
2123	}
2124
2125	case DIOCGETADDR: {
2126		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2127		u_int32_t		 nr = 0;
2128
2129		s = splsoftnet();
2130		pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
2131		    pp->r_action, pp->r_num, 0, 1, 1);
2132		if (pool == NULL) {
2133			error = EBUSY;
2134			splx(s);
2135			break;
2136		}
2137		pa = TAILQ_FIRST(&pool->list);
2138		while ((pa != NULL) && (nr < pp->nr)) {
2139			pa = TAILQ_NEXT(pa, entries);
2140			nr++;
2141		}
2142		if (pa == NULL) {
2143			error = EBUSY;
2144			splx(s);
2145			break;
2146		}
2147		bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
2148		pf_dynaddr_copyout(&pp->addr.addr);
2149		pf_tbladdr_copyout(&pp->addr.addr);
2150		splx(s);
2151		break;
2152	}
2153
2154	case DIOCCHANGEADDR: {
2155		struct pfioc_pooladdr	*pca = (struct pfioc_pooladdr *)addr;
2156		struct pf_pooladdr	*oldpa = NULL, *newpa = NULL;
2157		struct pf_ruleset	*ruleset;
2158
2159		if (pca->action < PF_CHANGE_ADD_HEAD ||
2160		    pca->action > PF_CHANGE_REMOVE) {
2161			error = EINVAL;
2162			break;
2163		}
2164		if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
2165		    pca->addr.addr.type != PF_ADDR_DYNIFTL &&
2166		    pca->addr.addr.type != PF_ADDR_TABLE) {
2167			error = EINVAL;
2168			break;
2169		}
2170
2171		ruleset = pf_find_ruleset(pca->anchor, pca->ruleset);
2172		if (ruleset == NULL) {
2173			error = EBUSY;
2174			break;
2175		}
2176		pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket,
2177		    pca->r_action, pca->r_num, pca->r_last, 1, 1);
2178		if (pool == NULL) {
2179			error = EBUSY;
2180			break;
2181		}
2182		if (pca->action != PF_CHANGE_REMOVE) {
2183			newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
2184			if (newpa == NULL) {
2185				error = ENOMEM;
2186				break;
2187			}
2188			bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
2189#ifndef INET
2190			if (pca->af == AF_INET) {
2191				pool_put(&pf_pooladdr_pl, newpa);
2192				error = EAFNOSUPPORT;
2193				break;
2194			}
2195#endif /* INET */
2196#ifndef INET6
2197			if (pca->af == AF_INET6) {
2198				pool_put(&pf_pooladdr_pl, newpa);
2199				error = EAFNOSUPPORT;
2200				break;
2201			}
2202#endif /* INET6 */
2203			if (newpa->ifname[0]) {
2204				newpa->ifp = ifunit(newpa->ifname);
2205				if (newpa->ifp == NULL) {
2206					pool_put(&pf_pooladdr_pl, newpa);
2207					error = EINVAL;
2208					break;
2209				}
2210			} else
2211				newpa->ifp = NULL;
2212			if (pf_dynaddr_setup(&newpa->addr, pca->af) ||
2213			    pf_tbladdr_setup(ruleset, &newpa->addr)) {
2214				pf_dynaddr_remove(&newpa->addr);
2215				pool_put(&pf_pooladdr_pl, newpa);
2216				error = EINVAL;
2217				break;
2218			}
2219		}
2220
2221		s = splsoftnet();
2222
2223		if (pca->action == PF_CHANGE_ADD_HEAD)
2224			oldpa = TAILQ_FIRST(&pool->list);
2225		else if (pca->action == PF_CHANGE_ADD_TAIL)
2226			oldpa = TAILQ_LAST(&pool->list, pf_palist);
2227		else {
2228			int	i = 0;
2229
2230			oldpa = TAILQ_FIRST(&pool->list);
2231			while ((oldpa != NULL) && (i < pca->nr)) {
2232				oldpa = TAILQ_NEXT(oldpa, entries);
2233				i++;
2234			}
2235			if (oldpa == NULL) {
2236				error = EINVAL;
2237				splx(s);
2238				break;
2239			}
2240		}
2241
2242		if (pca->action == PF_CHANGE_REMOVE) {
2243			TAILQ_REMOVE(&pool->list, oldpa, entries);
2244			pf_dynaddr_remove(&oldpa->addr);
2245			pf_tbladdr_remove(&oldpa->addr);
2246			pool_put(&pf_pooladdr_pl, oldpa);
2247		} else {
2248			if (oldpa == NULL)
2249				TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
2250			else if (pca->action == PF_CHANGE_ADD_HEAD ||
2251			    pca->action == PF_CHANGE_ADD_BEFORE)
2252				TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
2253			else
2254				TAILQ_INSERT_AFTER(&pool->list, oldpa,
2255				    newpa, entries);
2256		}
2257
2258		pool->cur = TAILQ_FIRST(&pool->list);
2259		PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
2260		    pca->af);
2261		splx(s);
2262		break;
2263	}
2264
2265	case DIOCGETANCHORS: {
2266		struct pfioc_anchor	*pa = (struct pfioc_anchor *)addr;
2267		struct pf_anchor	*anchor;
2268
2269		pa->nr = 0;
2270		TAILQ_FOREACH(anchor, &pf_anchors, entries)
2271			pa->nr++;
2272		break;
2273	}
2274
2275	case DIOCGETANCHOR: {
2276		struct pfioc_anchor	*pa = (struct pfioc_anchor *)addr;
2277		struct pf_anchor	*anchor;
2278		u_int32_t		 nr = 0;
2279
2280		anchor = TAILQ_FIRST(&pf_anchors);
2281		while (anchor != NULL && nr < pa->nr) {
2282			anchor = TAILQ_NEXT(anchor, entries);
2283			nr++;
2284		}
2285		if (anchor == NULL)
2286			error = EBUSY;
2287		else
2288			bcopy(anchor->name, pa->name, sizeof(pa->name));
2289		break;
2290	}
2291
2292	case DIOCGETRULESETS: {
2293		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
2294		struct pf_anchor	*anchor;
2295		struct pf_ruleset	*ruleset;
2296
2297		pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0;
2298		if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
2299			error = EINVAL;
2300			break;
2301		}
2302		pr->nr = 0;
2303		TAILQ_FOREACH(ruleset, &anchor->rulesets, entries)
2304			pr->nr++;
2305		break;
2306	}
2307
2308	case DIOCGETRULESET: {
2309		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
2310		struct pf_anchor	*anchor;
2311		struct pf_ruleset	*ruleset;
2312		u_int32_t		 nr = 0;
2313
2314		if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
2315			error = EINVAL;
2316			break;
2317		}
2318		ruleset = TAILQ_FIRST(&anchor->rulesets);
2319		while (ruleset != NULL && nr < pr->nr) {
2320			ruleset = TAILQ_NEXT(ruleset, entries);
2321			nr++;
2322		}
2323		if (ruleset == NULL)
2324			error = EBUSY;
2325		else
2326			bcopy(ruleset->name, pr->name, sizeof(pr->name));
2327		break;
2328	}
2329
2330	case DIOCRCLRTABLES: {
2331		struct pfioc_table *io = (struct pfioc_table *)addr;
2332
2333		if (io->pfrio_esize != 0) {
2334			error = ENODEV;
2335			break;
2336		}
2337		error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
2338		    io->pfrio_flags);
2339		break;
2340	}
2341
2342	case DIOCRADDTABLES: {
2343		struct pfioc_table *io = (struct pfioc_table *)addr;
2344
2345		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2346			error = ENODEV;
2347			break;
2348		}
2349		error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
2350		    &io->pfrio_nadd, io->pfrio_flags);
2351		break;
2352	}
2353
2354	case DIOCRDELTABLES: {
2355		struct pfioc_table *io = (struct pfioc_table *)addr;
2356
2357		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2358			error = ENODEV;
2359			break;
2360		}
2361		error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
2362		    &io->pfrio_ndel, io->pfrio_flags);
2363		break;
2364	}
2365
2366	case DIOCRGETTABLES: {
2367		struct pfioc_table *io = (struct pfioc_table *)addr;
2368
2369		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2370			error = ENODEV;
2371			break;
2372		}
2373		error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
2374		    &io->pfrio_size, io->pfrio_flags);
2375		break;
2376	}
2377
2378	case DIOCRGETTSTATS: {
2379		struct pfioc_table *io = (struct pfioc_table *)addr;
2380
2381		if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
2382			error = ENODEV;
2383			break;
2384		}
2385		error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
2386		    &io->pfrio_size, io->pfrio_flags);
2387		break;
2388	}
2389
2390	case DIOCRCLRTSTATS: {
2391		struct pfioc_table *io = (struct pfioc_table *)addr;
2392
2393		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2394			error = ENODEV;
2395			break;
2396		}
2397		error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
2398		    &io->pfrio_nzero, io->pfrio_flags);
2399		break;
2400	}
2401
2402	case DIOCRSETTFLAGS: {
2403		struct pfioc_table *io = (struct pfioc_table *)addr;
2404
2405		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2406			error = ENODEV;
2407			break;
2408		}
2409		error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
2410		    io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
2411		    &io->pfrio_ndel, io->pfrio_flags);
2412		break;
2413	}
2414
2415	case DIOCRCLRADDRS: {
2416		struct pfioc_table *io = (struct pfioc_table *)addr;
2417
2418		if (io->pfrio_esize != 0) {
2419			error = ENODEV;
2420			break;
2421		}
2422		error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
2423		    io->pfrio_flags);
2424		break;
2425	}
2426
2427	case DIOCRADDADDRS: {
2428		struct pfioc_table *io = (struct pfioc_table *)addr;
2429
2430		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2431			error = ENODEV;
2432			break;
2433		}
2434		error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
2435		    io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags);
2436		break;
2437	}
2438
2439	case DIOCRDELADDRS: {
2440		struct pfioc_table *io = (struct pfioc_table *)addr;
2441
2442		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2443			error = ENODEV;
2444			break;
2445		}
2446		error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
2447		    io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags);
2448		break;
2449	}
2450
2451	case DIOCRSETADDRS: {
2452		struct pfioc_table *io = (struct pfioc_table *)addr;
2453
2454		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2455			error = ENODEV;
2456			break;
2457		}
2458		error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
2459		    io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
2460		    &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags);
2461		break;
2462	}
2463
2464	case DIOCRGETADDRS: {
2465		struct pfioc_table *io = (struct pfioc_table *)addr;
2466
2467		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2468			error = ENODEV;
2469			break;
2470		}
2471		error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
2472		    &io->pfrio_size, io->pfrio_flags);
2473		break;
2474	}
2475
2476	case DIOCRGETASTATS: {
2477		struct pfioc_table *io = (struct pfioc_table *)addr;
2478
2479		if (io->pfrio_esize != sizeof(struct pfr_astats)) {
2480			error = ENODEV;
2481			break;
2482		}
2483		error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
2484		    &io->pfrio_size, io->pfrio_flags);
2485		break;
2486	}
2487
2488	case DIOCRCLRASTATS: {
2489		struct pfioc_table *io = (struct pfioc_table *)addr;
2490
2491		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2492			error = ENODEV;
2493			break;
2494		}
2495		error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
2496		    io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags);
2497		break;
2498	}
2499
2500	case DIOCRTSTADDRS: {
2501		struct pfioc_table *io = (struct pfioc_table *)addr;
2502
2503		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2504			error = ENODEV;
2505			break;
2506		}
2507		error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
2508		    io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags);
2509		break;
2510	}
2511
2512	case DIOCRINABEGIN: {
2513		struct pfioc_table *io = (struct pfioc_table *)addr;
2514
2515		if (io->pfrio_esize != 0) {
2516			error = ENODEV;
2517			break;
2518		}
2519		error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket,
2520		    &io->pfrio_ndel, io->pfrio_flags);
2521		break;
2522	}
2523
2524	case DIOCRINACOMMIT: {
2525		struct pfioc_table *io = (struct pfioc_table *)addr;
2526
2527		if (io->pfrio_esize != 0) {
2528			error = ENODEV;
2529			break;
2530		}
2531		error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket,
2532		    &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags);
2533		break;
2534	}
2535
2536	case DIOCRINADEFINE: {
2537		struct pfioc_table *io = (struct pfioc_table *)addr;
2538
2539		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2540			error = ENODEV;
2541			break;
2542		}
2543		error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
2544		    io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
2545		    io->pfrio_ticket, io->pfrio_flags);
2546		break;
2547	}
2548
2549	case DIOCOSFPFLUSH:
2550		s = splsoftnet();
2551		pf_osfp_flush();
2552		splx(s);
2553		break;
2554
2555	case DIOCOSFPADD: {
2556		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2557		s = splsoftnet();
2558		error = pf_osfp_add(io);
2559		splx(s);
2560		break;
2561	}
2562
2563	case DIOCOSFPGET: {
2564		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2565		s = splsoftnet();
2566		error = pf_osfp_get(io);
2567		splx(s);
2568		break;
2569	}
2570
2571	default:
2572		error = ENODEV;
2573		break;
2574	}
2575fail:
2576#ifdef __FreeBSD__
2577	PF_UNLOCK();
2578#endif
2579	return (error);
2580}
2581
2582#ifdef __FreeBSD__
2583/*
2584 * XXX - Check for version missmatch!!!
2585 */
2586static int
2587pf_beginrules(void *addr)
2588{
2589	struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
2590	struct pf_ruleset	*ruleset;
2591	struct pf_rule		*rule;
2592	int			 rs_num;
2593	int			 error = 0;
2594
2595	do {
2596		ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
2597		if (ruleset == NULL) {
2598			error = EINVAL;
2599			break;
2600		}
2601		rs_num = pf_get_ruleset_number(pr->rule.action);
2602		if (rs_num >= PF_RULESET_MAX) {
2603			error = EINVAL;
2604			break;
2605		}
2606		while ((rule =
2607		    TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
2608			pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
2609		pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
2610	} while(0);
2611
2612	return (error);
2613}
2614
2615static int
2616pf_commitrules(void *addr)
2617{
2618	struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
2619	struct pf_ruleset	*ruleset;
2620	struct pf_rulequeue	*old_rules;
2621	struct pf_rule		*rule;
2622	int			 rs_num, s;
2623	int			 error = 0;
2624
2625	do {
2626		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
2627		if (ruleset == NULL) {
2628			error = EINVAL;
2629			break;
2630		}
2631		rs_num = pf_get_ruleset_number(pr->rule.action);
2632		if (rs_num >= PF_RULESET_MAX) {
2633			error = EINVAL;
2634			break;
2635		}
2636		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
2637			error = EBUSY;
2638			break;
2639		}
2640
2641#ifdef ALTQ
2642		/* set queue IDs */
2643		if (rs_num == PF_RULESET_FILTER)
2644			pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
2645#endif
2646
2647		/* Swap rules, keep the old. */
2648		s = splsoftnet();
2649		old_rules = ruleset->rules[rs_num].active.ptr;
2650		ruleset->rules[rs_num].active.ptr =
2651		    ruleset->rules[rs_num].inactive.ptr;
2652		ruleset->rules[rs_num].inactive.ptr = old_rules;
2653		ruleset->rules[rs_num].active.ticket =
2654		    ruleset->rules[rs_num].inactive.ticket;
2655		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
2656
2657		/* Purge the old rule list. */
2658		while ((rule = TAILQ_FIRST(old_rules)) != NULL)
2659			pf_rm_rule(old_rules, rule);
2660		pf_remove_if_empty_ruleset(ruleset);
2661		pf_update_anchor_rules();
2662		splx(s);
2663	} while (0);
2664
2665	return (error);
2666}
2667
2668#ifdef ALTQ
2669static int
2670pf_beginaltqs(void *addr)
2671{
2672	u_int32_t	*ticket = (u_int32_t *)addr;
2673	struct pf_altq	*altq;
2674	int		error = 0;
2675
2676	/* Purge the old altq list */
2677	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
2678		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
2679		if (altq->qname[0] == 0) {
2680#ifdef __FreeBSD__
2681			PF_UNLOCK();
2682#endif
2683			/* detach and destroy the discipline */
2684			error = altq_remove(altq);
2685#ifdef __FreeBSD__
2686			PF_LOCK();
2687#endif
2688		}
2689		uma_zfree(pf_altq_pl, altq);
2690	}
2691	*ticket = ++ticket_altqs_inactive;
2692
2693	return (error);
2694}
2695
2696static int
2697pf_commitaltqs(void *addr)
2698{
2699	u_int32_t		*ticket = (u_int32_t *)addr;
2700	struct pf_altqqueue	*old_altqs;
2701	struct pf_altq		*altq;
2702	struct pf_anchor	*anchor;
2703	struct pf_ruleset	*ruleset;
2704	int			 err;
2705	int			 s;
2706	int			 error = 0;
2707
2708	do {
2709		if (*ticket != ticket_altqs_inactive) {
2710			error = EBUSY;
2711			break;
2712		}
2713
2714		/* Swap altqs, keep the old. */
2715		s = splsoftnet();
2716		old_altqs = pf_altqs_active;
2717		pf_altqs_active = pf_altqs_inactive;
2718		pf_altqs_inactive = old_altqs;
2719		ticket_altqs_active = ticket_altqs_inactive;
2720
2721		/* Attach new disciplines */
2722		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2723			if (altq->qname[0] == 0) {
2724				/* attach the discipline */
2725#ifdef __FreeBSD__
2726				PF_UNLOCK();
2727#endif
2728				error = altq_pfattach(altq);
2729#ifdef __FreeBSD__
2730				PF_LOCK();
2731#endif
2732				if (error) {
2733					splx(s);
2734					goto altq_fail;
2735				}
2736			}
2737		}
2738
2739		/* Purge the old altq list */
2740		while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
2741			TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
2742			if (altq->qname[0] == 0) {
2743				/* detach and destroy the discipline */
2744#ifdef __FreeBSD__
2745				PF_UNLOCK();
2746#endif
2747				err = altq_pfdetach(altq);
2748				if (err != 0 && error == 0)
2749					error = err;
2750				err = altq_remove(altq);
2751				if (err != 0 && error == 0)
2752					error = err;
2753#ifdef __FreeBSD__
2754				PF_LOCK();
2755#endif
2756			}
2757			uma_zfree(pf_altq_pl, altq);
2758		}
2759		splx(s);
2760
2761		/* update queue IDs */
2762		pf_rule_set_qid(
2763		    pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
2764		TAILQ_FOREACH(anchor, &pf_anchors, entries) {
2765			TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
2766				pf_rule_set_qid(
2767				    ruleset->rules[PF_RULESET_FILTER].active.ptr
2768				    );
2769			}
2770		}
2771	} while (0);
2772
2773altq_fail:
2774
2775	return (error);
2776}
2777
2778static int
2779pf_stopaltq(void)
2780{
2781	struct pf_altq		*altq;
2782	struct ifnet		*ifp;
2783	struct tb_profile	 tb;
2784	int			 err;
2785	int			 s;
2786	int			 error = 0;
2787
2788	do {
2789		/* disable all altq interfaces on active list */
2790		s = splsoftnet();
2791		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2792			if (altq->qname[0] == 0) {
2793				if ((ifp = ifunit(altq->ifname)) == NULL) {
2794					error = EINVAL;
2795					break;
2796				}
2797				if (ifp->if_snd.altq_type != ALTQT_NONE) {
2798					err = altq_disable(&ifp->if_snd);
2799					if (err != 0 && error == 0)
2800						error = err;
2801				}
2802				/* clear tokenbucket regulator */
2803				tb.rate = 0;
2804				err = tbr_set(&ifp->if_snd, &tb);
2805				if (err != 0 && error == 0)
2806					error = err;
2807			}
2808		}
2809#ifdef __FreeBSD__
2810		if (error == 0) {
2811			mtx_lock(&pf_altq_mtx);
2812			pfaltq_running = 0;
2813			mtx_unlock(&pf_altq_mtx);
2814		}
2815#else
2816		if (error == 0)
2817			pfaltq_running = 0;
2818#endif
2819		splx(s);
2820	} while (0);
2821
2822	return (error);
2823}
2824#endif
2825
2826static void
2827pf_clearstates(void)
2828{
2829	struct pf_tree_node	*n;
2830	int s;
2831
2832	s = splsoftnet();
2833	RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
2834		n->state->timeout = PFTM_PURGE;
2835	pf_purge_expired_states();
2836	pf_status.states = 0;
2837	splx(s);
2838}
2839
2840static int
2841pf_clear_tables(void *addr)
2842{
2843	struct pfioc_table *io = (struct pfioc_table *)addr;
2844	int error;
2845
2846	error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
2847	    io->pfrio_flags);
2848
2849	return (error);
2850}
2851
2852static int
2853shutdown_pf(void)
2854{
2855	struct pfioc_rule pr;
2856#ifdef ALTQ
2857	struct pfioc_altq pa;
2858#endif
2859	struct pfioc_table io;
2860	int error = 0;
2861
2862	callout_stop(&pf_expire_to);
2863
2864	PF_LOCK();
2865	pf_status.running = 0;
2866	do {
2867#ifdef ALTQ
2868		if ((error = pf_stopaltq())) {
2869			DPFPRINTF(PF_DEBUG_MISC,
2870			    ("ALTQ: stop(%i)\n", error));
2871			break;
2872		}
2873#endif
2874		bzero(&pr, sizeof(pr));
2875		pr.rule.action = PF_SCRUB;
2876		if ((error = pf_beginrules(&pr))) {
2877			DPFPRINTF(PF_DEBUG_MISC,
2878			    ("PF_SCRUB: begin(%i)\n", error));
2879			break;
2880		}
2881		if ((error = pf_commitrules(&pr))) {
2882			DPFPRINTF(PF_DEBUG_MISC,
2883			    ("PF_SCRUB: commit(%i)\n", error));
2884			break;
2885		}
2886
2887		pr.rule.action = PF_PASS;
2888		if ((error = pf_beginrules(&pr))) {
2889			DPFPRINTF(PF_DEBUG_MISC,
2890			    ("PF_PASS: begin(%i)\n", error));
2891			break;
2892		}
2893		if ((error = pf_commitrules(&pr))) {
2894			DPFPRINTF(PF_DEBUG_MISC,
2895			    ("PF_PASS: commit(%i)\n", error));
2896			break;
2897		}
2898
2899/*
2900 * XXX not sure, but can't hurt:
2901 */
2902		bzero(&pr, sizeof(pr));
2903		pr.rule.action = PF_NAT;
2904		if ((error = pf_beginrules(&pr))) {
2905			DPFPRINTF(PF_DEBUG_MISC,
2906			    ("PF_NAT: begin(%i)\n", error));
2907			break;
2908		}
2909		if ((error = pf_commitrules(&pr))) {
2910			DPFPRINTF(PF_DEBUG_MISC,
2911			    ("PF_NAT: commit(%i)\n", error));
2912			break;
2913		}
2914
2915		pr.rule.action = PF_BINAT;
2916		if ((error = pf_beginrules(&pr))) {
2917			DPFPRINTF(PF_DEBUG_MISC,
2918			    ("PF_BINAT: begin(%i)\n", error));
2919			break;
2920		}
2921		if ((error = pf_commitrules(&pr))) {
2922			DPFPRINTF(PF_DEBUG_MISC,
2923			    ("PF_BINAT: begin(%i)\n", error));
2924			break;
2925		}
2926
2927		pr.rule.action = PF_RDR;
2928		if ((error = pf_beginrules(&pr))) {
2929			DPFPRINTF(PF_DEBUG_MISC,
2930			    ("PF_RDR: begin(%i)\n", error));
2931			break;
2932		}
2933		if ((error = pf_commitrules(&pr))) {
2934			DPFPRINTF(PF_DEBUG_MISC,
2935			    ("PF_RDR: commit(%i)\n", error));
2936			break;
2937		}
2938
2939#ifdef ALTQ
2940		bzero(&pa, sizeof(pa));
2941		if ((error = pf_beginaltqs(&pa))) {
2942			DPFPRINTF(PF_DEBUG_MISC,
2943			    ("ALTQ: begin(%i)\n", error));
2944			break;
2945		}
2946		if ((error = pf_commitaltqs(&pa))) {
2947			DPFPRINTF(PF_DEBUG_MISC,
2948			    ("ALTQ: commit(%i)\n", error));
2949			break;
2950		}
2951#endif
2952		pf_clearstates();
2953
2954		bzero(&io, sizeof(io));
2955		if ((error = pf_clear_tables(&io))) {
2956			DPFPRINTF(PF_DEBUG_MISC,
2957			    ("TABLES: clear(%i)\n", error));
2958			break;
2959		}
2960		pf_osfp_flush();
2961	} while(0);
2962
2963	PF_UNLOCK();
2964        return (error);
2965}
2966
2967static int
2968#if (__FreeBSD_version < 501108)
2969pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
2970#else
2971pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
2972#endif
2973{
2974	/*
2975	 * XXX Wed Jul 9 22:03:16 2003 UTC
2976	 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
2977	 * in network stack. OpenBSD's network stack have converted
2978	 * ip_len/ip_off to host byte order frist as FreeBSD.
2979	 * Now this is not true anymore , so we should convert back to network
2980	 * byte order.
2981	 */
2982	struct ip *h = NULL;
2983	int chk;
2984
2985	if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) {
2986		/* if m_pkthdr.len is less than ip header, pf will handle. */
2987		h = mtod(*m, struct ip *);
2988	        HTONS(h->ip_len);
2989	        HTONS(h->ip_off);
2990	}
2991	chk = pf_test(PF_IN, ifp, m);
2992	if (chk && *m) {
2993		m_freem(*m);
2994		*m = NULL;
2995	}
2996	if (*m != NULL) {
2997		/* pf_test can change ip header location */
2998		h = mtod(*m, struct ip *);
2999		NTOHS(h->ip_len);
3000		NTOHS(h->ip_off);
3001	}
3002	return chk;
3003}
3004
3005static int
3006#if (__FreeBSD_version < 501108)
3007pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
3008#else
3009pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3010#endif
3011{
3012	/*
3013	 * XXX Wed Jul 9 22:03:16 2003 UTC
3014	 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
3015	 * in network stack. OpenBSD's network stack have converted
3016	 * ip_len/ip_off to host byte order frist as FreeBSD.
3017	 * Now this is not true anymore , so we should convert back to network
3018	 * byte order.
3019	 */
3020	struct ip *h = NULL;
3021	int chk;
3022
3023	/* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
3024	if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
3025		in_delayed_cksum(*m);
3026		(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
3027	}
3028	if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) {
3029		/* if m_pkthdr.len is less than ip header, pf will handle. */
3030		h = mtod(*m, struct ip *);
3031	        HTONS(h->ip_len);
3032	        HTONS(h->ip_off);
3033	}
3034	chk = pf_test(PF_OUT, ifp, m);
3035	if (chk && *m) {
3036		m_freem(*m);
3037		*m = NULL;
3038	}
3039	if (*m != NULL) {
3040		/* pf_test can change ip header location */
3041		h = mtod(*m, struct ip *);
3042		NTOHS(h->ip_len);
3043		NTOHS(h->ip_off);
3044	}
3045	return chk;
3046}
3047
3048#ifdef INET6
3049static int
3050#if (__FreeBSD_version < 501108)
3051pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
3052#else
3053pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3054#endif
3055{
3056	/*
3057	 * IPv6 does not affected ip_len/ip_off byte order changes.
3058	 */
3059	int chk;
3060
3061	chk = pf_test6(PF_IN, ifp, m);
3062	if (chk && *m) {
3063		m_freem(*m);
3064		*m = NULL;
3065	}
3066	return chk;
3067}
3068
3069static int
3070#if (__FreeBSD_version < 501108)
3071pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
3072#else
3073pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3074#endif
3075{
3076	/*
3077	 * IPv6 does not affected ip_len/ip_off byte order changes.
3078	 */
3079	int chk;
3080
3081	/* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
3082	if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
3083		in_delayed_cksum(*m);
3084		(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
3085	}
3086	chk = pf_test6(PF_OUT, ifp, m);
3087	if (chk && *m) {
3088		m_freem(*m);
3089		*m = NULL;
3090	}
3091	return chk;
3092}
3093#endif /* INET6 */
3094
3095static int
3096hook_pf(void)
3097{
3098#if (__FreeBSD_version >= 501108)
3099	struct pfil_head *pfh_inet;
3100#ifdef INET6
3101	struct pfil_head *pfh_inet6;
3102#endif
3103#endif
3104
3105	PF_ASSERT(MA_NOTOWNED);
3106
3107	if (pf_pfil_hooked)
3108		return (0);
3109
3110#if (__FreeBSD_version < 501108)
3111	/*
3112	 * XXX
3113	 * There is no easy way to get pfil header pointer with address
3114	 * family such as AF_INET, AF_INET6.
3115	 * Needs direct variable reference.
3116	 */
3117
3118	pfil_add_hook(pf_check_in, PFIL_IN,
3119		&inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3120	pfil_add_hook(pf_check_out, PFIL_OUT,
3121		&inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3122#ifdef INET6
3123	pfil_add_hook(pf_check6_in, PFIL_IN,
3124		&inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3125	pfil_add_hook(pf_check6_out, PFIL_OUT,
3126		&inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3127#endif
3128#else /* __FreeBSD_version >= 501108 */
3129	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
3130	if (pfh_inet == NULL)
3131		return (ESRCH); /* XXX */
3132	pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
3133	pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
3134#ifdef INET6
3135	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
3136	if (pfh_inet6 == NULL) {
3137		pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
3138		    pfh_inet);
3139		pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
3140		    pfh_inet);
3141		return (ESRCH); /* XXX */
3142	}
3143	pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
3144	pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
3145#endif
3146#endif /* __FreeBSD_version >= 501108 */
3147
3148	pf_pfil_hooked = 1;
3149	return (0);
3150}
3151
3152static int
3153dehook_pf(void)
3154{
3155#if (__FreeBSD_version >= 501108)
3156	struct pfil_head *pfh_inet;
3157#ifdef INET6
3158	struct pfil_head *pfh_inet6;
3159#endif
3160#endif
3161
3162	PF_ASSERT(MA_NOTOWNED);
3163
3164	if (pf_pfil_hooked == 0)
3165		return (0);
3166
3167#if (__FreeBSD_version < 501108)
3168	pfil_remove_hook(pf_check_in, PFIL_IN,
3169		&inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3170	pfil_remove_hook(pf_check_out, PFIL_OUT,
3171		&inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3172#ifdef INET6
3173	pfil_remove_hook(pf_check6_in, PFIL_IN,
3174		&inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3175	pfil_remove_hook(pf_check6_out, PFIL_OUT,
3176		&inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3177#endif
3178#else /* __FreeBSD_version >= 501108 */
3179	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
3180	if (pfh_inet == NULL)
3181		return (ESRCH); /* XXX */
3182	pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
3183	    pfh_inet);
3184	pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
3185	    pfh_inet);
3186#ifdef INET6
3187	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
3188	if (pfh_inet6 == NULL)
3189		return (ESRCH); /* XXX */
3190	pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
3191	    pfh_inet6);
3192	pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
3193	    pfh_inet6);
3194#endif
3195#endif /* __FreeBSD_version >= 501108 */
3196
3197	pf_pfil_hooked = 0;
3198	return (0);
3199}
3200
3201static int
3202pf_load(void)
3203{
3204	init_zone_var();
3205	init_pf_mutex();
3206	pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME);
3207	if (pfattach() < 0) {
3208		destroy_dev(pf_dev);
3209		destroy_pf_mutex();
3210		return (ENOMEM);
3211	}
3212#ifdef ALTQ
3213	mtx_lock(&pf_altq_mtx);
3214	++pfaltq_ref;
3215	mtx_unlock(&pf_altq_mtx);
3216#endif
3217	return (0);
3218}
3219
3220static int
3221pf_unload(void)
3222{
3223	int error = 0;
3224
3225	PF_LOCK();
3226	pf_status.running = 0;
3227	PF_UNLOCK();
3228	error = dehook_pf();
3229	if (error) {
3230		/*
3231		 * Should not happen!
3232		 * XXX Due to error code ESRCH, kldunload will show
3233		 * a message like 'No such process'.
3234		 */
3235		printf("%s : pfil unregisteration fail\n", __FUNCTION__);
3236		return error;
3237	}
3238	shutdown_pf();
3239	cleanup_pf_zone();
3240	pf_osfp_cleanup();
3241	destroy_dev(pf_dev);
3242#ifdef ALTQ
3243	mtx_lock(&pf_altq_mtx);
3244	--pfaltq_ref;
3245	mtx_unlock(&pf_altq_mtx);
3246#endif
3247	destroy_pf_mutex();
3248	return error;
3249}
3250
3251static int
3252pf_modevent(module_t mod, int type, void *data)
3253{
3254	int error = 0;
3255
3256	switch(type) {
3257	case MOD_LOAD:
3258		error = pf_load();
3259		break;
3260
3261	case MOD_UNLOAD:
3262		error = pf_unload();
3263		break;
3264	default:
3265		error = EINVAL;
3266		break;
3267	}
3268	return error;
3269}
3270
3271static moduledata_t pf_mod = {
3272	"pf",
3273	pf_modevent,
3274	0
3275};
3276
3277DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
3278MODULE_DEPEND(pf, pflog, PFLOG_MINVER, PFLOG_PREFVER, PFLOG_MAXVER);
3279MODULE_DEPEND(pf, pfsync, PFSYNC_MINVER, PFSYNC_PREFVER, PFSYNC_MAXVER);
3280#ifdef ALTQ
3281MODULE_DEPEND(pf, pfaltq, PFALTQ_MINVER, PFALTQ_PREFVER, PFALTQ_MAXVER);
3282#endif
3283MODULE_VERSION(pf, PF_MODVER);
3284#endif	/* __FreeBSD__ */
3285