pf_ioctl.c revision 126812
1189251Ssam/*	$FreeBSD: head/sys/contrib/pf/net/pf_ioctl.c 126812 2004-03-10 15:08:21Z mlaier $	*/
2189251Ssam/*	$OpenBSD: pf_ioctl.c,v 1.81 2003/08/22 21:50:34 david Exp $ */
3189251Ssam
4189251Ssam/*
5252726Srpaulo * Copyright (c) 2001 Daniel Hartmeier
6252726Srpaulo * All rights reserved.
7189251Ssam *
8189251Ssam * Redistribution and use in source and binary forms, with or without
9189251Ssam * modification, are permitted provided that the following conditions
10189251Ssam * are met:
11189251Ssam *
12252726Srpaulo *    - Redistributions of source code must retain the above copyright
13252726Srpaulo *      notice, this list of conditions and the following disclaimer.
14189251Ssam *    - Redistributions in binary form must reproduce the above
15252726Srpaulo *      copyright notice, this list of conditions and the following
16214734Srpaulo *      disclaimer in the documentation and/or other materials provided
17252726Srpaulo *      with the distribution.
18189251Ssam *
19214734Srpaulo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20252726Srpaulo * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21252726Srpaulo * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22252726Srpaulo * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23252726Srpaulo * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24252726Srpaulo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25252726Srpaulo * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26252726Srpaulo * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27252726Srpaulo * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28252726Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29252726Srpaulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30252726Srpaulo * POSSIBILITY OF SUCH DAMAGE.
31252726Srpaulo *
32252726Srpaulo * Effort sponsored in part by the Defense Advanced Research Projects
33252726Srpaulo * Agency (DARPA) and Air Force Research Laboratory, Air Force
34252726Srpaulo * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35252726Srpaulo *
36252726Srpaulo */
37252726Srpaulo
38252726Srpaulo#if defined(__FreeBSD__)
39252726Srpaulo#include "opt_inet.h"
40252726Srpaulo#include "opt_inet6.h"
41252726Srpaulo#endif
42252726Srpaulo
43252726Srpaulo#include <sys/param.h>
44252726Srpaulo#include <sys/systm.h>
45252726Srpaulo#include <sys/mbuf.h>
46252726Srpaulo#include <sys/filio.h>
47252726Srpaulo#include <sys/fcntl.h>
48252726Srpaulo#include <sys/socket.h>
49252726Srpaulo#include <sys/socketvar.h>
50252726Srpaulo#include <sys/kernel.h>
51252726Srpaulo#include <sys/time.h>
52252726Srpaulo#include <sys/malloc.h>
53252726Srpaulo#if defined(__FreeBSD__)
54252726Srpaulo#include <sys/conf.h>
55252726Srpaulo#else
56252726Srpaulo#include <sys/timeout.h>
57252726Srpaulo#include <sys/pool.h>
58252726Srpaulo#endif
59252726Srpaulo
60252726Srpaulo#include <net/if.h>
61252726Srpaulo#include <net/if_types.h>
62252726Srpaulo#include <net/route.h>
63252726Srpaulo
64252726Srpaulo#include <netinet/in.h>
65252726Srpaulo#include <netinet/in_var.h>
66252726Srpaulo#include <netinet/in_systm.h>
67252726Srpaulo#include <netinet/ip.h>
68252726Srpaulo#include <netinet/ip_var.h>
69252726Srpaulo#include <netinet/ip_icmp.h>
70252726Srpaulo
71252726Srpaulo#include <net/pfvar.h>
72252726Srpaulo
73252726Srpaulo#ifdef INET6
74252726Srpaulo#include <netinet/ip6.h>
75252726Srpaulo#include <netinet/in_pcb.h>
76252726Srpaulo#if defined(__FreeBSD__) && (__FreeBSD_version < 501108)
77252726Srpaulo#include <netinet6/ip6protosw.h>
78252726Srpaulo#endif
79252726Srpaulo#endif /* INET6 */
80252726Srpaulo
81252726Srpaulo#ifdef ALTQ
82252726Srpaulo#include <altq/altq.h>
83252726Srpaulo#endif
84252726Srpaulo
85252726Srpaulo#if defined(__FreeBSD__)
86252726Srpaulo#if (__FreeBSD_version >= 500112)
87252726Srpaulo#include <sys/limits.h>
88252726Srpaulo#else
89252726Srpaulo#include <machine/limits.h>
90252726Srpaulo#endif
91252726Srpaulo#include <sys/lock.h>
92252726Srpaulo#include <sys/mutex.h>
93252726Srpaulo#if __FreeBSD_version < 501108
94252726Srpaulo#include <sys/protosw.h>
95252726Srpaulo#endif
96252726Srpaulo#include <net/pfil.h>
97252726Srpaulo#endif /* __FreeBSD__ */
98252726Srpaulo
99252726Srpaulo#if defined(__FreeBSD__)
100252726Srpaulovoid			 init_zone_var(void);
101252726Srpaulovoid			 cleanup_pf_zone(void);
102252726Srpauloint			 pfattach(void);
103252726Srpaulo#else
104252726Srpaulovoid			 pfattach(int);
105252726Srpauloint			 pfopen(dev_t, int, int, struct proc *);
106252726Srpauloint			 pfclose(dev_t, int, int, struct proc *);
107252726Srpaulo#endif
108252726Srpaulostruct pf_pool		*pf_get_pool(char *, char *, u_int32_t,
109252726Srpaulo			    u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t);
110252726Srpauloint			 pf_get_ruleset_number(u_int8_t);
111252726Srpaulovoid			 pf_init_ruleset(struct pf_ruleset *);
112252726Srpaulovoid			 pf_mv_pool(struct pf_palist *, struct pf_palist *);
113252726Srpaulovoid			 pf_empty_pool(struct pf_palist *);
114252726Srpaulo#if defined(__FreeBSD__)
115252726Srpauloint			 pfioctl(dev_t, u_long, caddr_t, int, struct thread *);
116252726Srpaulo#else
117252726Srpauloint			 pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
118252726Srpaulo#endif
119252726Srpaulo
120252726Srpaulo#if defined(__FreeBSD__)
121252726Srpauloextern struct callout pf_expire_to;
122252726Srpaulo#if __FreeBSD_version < 501108
123252726Srpauloextern struct protosw inetsw[];
124252726Srpaulo#endif
125252726Srpaulo#else
126252726Srpauloextern struct timeout	 pf_expire_to;
127252726Srpaulo#endif
128252726Srpaulo
129252726Srpaulostruct pf_rule		 pf_default_rule;
130252726Srpaulo
131252726Srpaulo#define	TAGID_MAX	 50000
132252726SrpauloTAILQ_HEAD(pf_tags, pf_tagname)	pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags);
133189251Ssam
134189251Ssam#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
135189251Ssam
136189251Ssam
137189251Ssam#if defined(__FreeBSD__)
138189251Ssamstatic dev_t		pf_dev;
139189251Ssam
140189251Ssam/*
141189251Ssam * XXX - These are new and need to be checked when moveing to a new version
142189251Ssam */
143189251Ssamstatic int pf_beginrules(void *addr);
144189251Ssamstatic int pf_commitrules(void *addr);
145189251Ssam#if defined(ALTQ)
146189251Ssamstatic int pf_beginaltqs(void *addr);
147189251Ssamstatic int pf_commitaltqs(void *addr);
148189251Ssamstatic int pf_stopaltq(void);
149189251Ssam#endif
150189251Ssamstatic void pf_clearstates(void);
151189251Ssamstatic int pf_clear_tables(void *addr);
152189251Ssam/*
153189251Ssam * XXX - These are new and need to be checked when moveing to a new version
154189251Ssam */
155189251Ssam
156189251Ssam#if (__FreeBSD_version < 501108)
157189251Ssamstatic int pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir,
158189251Ssam		struct mbuf **m);
159189251Ssamstatic int pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir,
160189251Ssam		struct mbuf **m);
161189251Ssam#if defined(INET6)
162189251Ssamstatic int pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir,
163189251Ssam		struct mbuf **m);
164189251Ssamstatic int pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir,
165189251Ssam		struct mbuf **m);
166189251Ssam#endif
167189251Ssam#else /* (__FreeBSD_version >= 501108) */
168189251Ssamstatic int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
169189251Ssam		int dir);
170189251Ssamstatic int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
171189251Ssam		int dir);
172189251Ssam#if defined(INET6)
173189251Ssamstatic int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
174189251Ssam		int dir);
175189251Ssamstatic int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
176189251Ssam		int dir);
177189251Ssam#endif
178189251Ssam#endif /* (__FreeBSD_version >= 501108) */
179189251Ssamstatic int hook_pf(void);
180189251Ssamstatic int dehook_pf(void);
181189251Ssamstatic int shutdown_pf(void);
182189251Ssamstatic int pf_load(void);
183189251Ssamstatic int pf_unload(void);
184189251Ssam
185189251Ssam
186189251Ssam
187189251Ssamstatic struct cdevsw pf_cdevsw = {
188189251Ssam#if (__FreeBSD_version < 500105)
189189251Ssam	/* open */	noopen,
190189251Ssam	/* close */	noclose,
191189251Ssam	/* read */	noread,
192189251Ssam	/* write */	nowrite,
193189251Ssam	/* ioctl */	pfioctl,
194189251Ssam	/* poll */	nopoll,
195189251Ssam	/* mmap */	nommap,
196189251Ssam	/* strategy */	nostrategy,
197189251Ssam	/* name */	PF_NAME,
198189251Ssam	/* maj */	PF_CDEV_MAJOR,
199189251Ssam	/* dump */	nodump,
200189251Ssam	/* psize */	nopsize,
201189251Ssam	/* flags */	0,
202189251Ssam	/* kqfilter */	nokqfilter,
203189251Ssam#elif (__FreeBSD_version < 501110)
204189251Ssam	.d_open =	noopen,
205189251Ssam	.d_close =	noclose,
206189251Ssam	.d_read =	noread,
207189251Ssam	.d_write =	nowrite,
208189251Ssam	.d_ioctl =	pfioctl,
209189251Ssam	.d_poll =	nopoll,
210189251Ssam	.d_mmap =	nommap,
211189251Ssam	.d_strategy =	nostrategy,
212189251Ssam	.d_name =	PF_NAME,
213189251Ssam	.d_maj =	MAJOR_AUTO, /* PF_CDEV_MAJOR */
214189251Ssam	.d_dump =	nodump,
215189251Ssam	.d_flags =	0,
216189251Ssam	.d_kqfilter =	nokqfilter,
217189251Ssam#else
218189251Ssam	.d_ioctl =	pfioctl,
219189251Ssam	.d_name =	PF_NAME,
220189251Ssam	.d_version =	D_VERSION,
221189251Ssam#endif
222189251Ssam};
223189251Ssam#endif /* __FreeBSD__ */
224189251Ssam
225189251Ssam#if defined(__FreeBSD__)
226214734Srpaulostatic volatile int pf_pfil_hooked = 0;
227189251Ssamstruct mtx pf_task_mtx;
228189251Ssam
229189251Ssamvoid
230189251Ssaminit_pf_mutex(void)
231189251Ssam{
232189251Ssam	mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF);
233189251Ssam/*
234189251Ssam * pf_altq_mtx is initialized at altq_subr.c.
235189251Ssam *
236189251Ssam * #if defined(ALTQ) && !defined(ALTQ3_COMPAT)
237189251Ssam *	mtx_init(&pf_altq_mtx, "pf altq mtx", NULL, MTX_DEF);
238189251Ssam * #endif
239189251Ssam */
240189251Ssam}
241189251Ssam
242189251Ssamvoid
243189251Ssamdestroy_pf_mutex(void)
244189251Ssam{
245189251Ssam	mtx_destroy(&pf_task_mtx);
246189251Ssam/*
247189251Ssam * pf_altq_mtx is initialized at altq_subr.c.
248189251Ssam *
249189251Ssam * #if defined(ALTQ) && !defined(ALTQ3_COMPAT)
250189251Ssam * 	mtx_destroy(&pf_altq_mtx);
251189251Ssam * #endif
252189251Ssam */
253189251Ssam}
254189251Ssam
255189251Ssamvoid
256189251Ssaminit_zone_var(void)
257189251Ssam{
258189251Ssam	pf_tree_pl = pf_rule_pl = pf_addr_pl = NULL;
259189251Ssam	pf_state_pl = pf_altq_pl = pf_pooladdr_pl = NULL;
260189251Ssam	pf_frent_pl = pf_frag_pl = pf_cache_pl = pf_cent_pl = NULL;
261189251Ssam	pf_state_scrub_pl = NULL;
262189251Ssam	pfr_ktable_pl = pfr_kentry_pl = NULL;
263189251Ssam}
264189251Ssam
265214734Srpaulovoid
266252726Srpaulocleanup_pf_zone(void)
267252726Srpaulo{
268252726Srpaulo	UMA_DESTROY(pf_tree_pl);
269252726Srpaulo	UMA_DESTROY(pf_rule_pl);
270214734Srpaulo	UMA_DESTROY(pf_addr_pl);
271214734Srpaulo	UMA_DESTROY(pf_state_pl);
272214734Srpaulo	UMA_DESTROY(pf_altq_pl);
273214734Srpaulo	UMA_DESTROY(pf_pooladdr_pl);
274214734Srpaulo	UMA_DESTROY(pf_frent_pl);
275252726Srpaulo	UMA_DESTROY(pf_frag_pl);
276214734Srpaulo	UMA_DESTROY(pf_cache_pl);
277189251Ssam	UMA_DESTROY(pf_cent_pl);
278189251Ssam	UMA_DESTROY(pfr_ktable_pl);
279189251Ssam	UMA_DESTROY(pfr_kentry_pl);
280189251Ssam	UMA_DESTROY(pf_state_scrub_pl);
281189251Ssam}
282189251Ssam#endif /* __FreeBSD__ */
283189251Ssam
284189251Ssam#if defined(__FreeBSD__)
285189251Ssamint
286189251Ssampfattach(void)
287189251Ssam{
288189251Ssam	u_int32_t *my_timeout = pf_default_rule.timeout;
289189251Ssam	int error = 1;
290189251Ssam
291189251Ssam	do {
292189251Ssam		UMA_CREATE(pf_tree_pl,	  struct pf_tree_node, "pftrpl");
293189251Ssam		UMA_CREATE(pf_rule_pl,	  struct pf_rule, "pfrulepl");
294189251Ssam		UMA_CREATE(pf_addr_pl,	  struct pf_addr_dyn, "pfaddrpl");
295189251Ssam		UMA_CREATE(pf_state_pl,	  struct pf_state, "pfstatepl");
296189251Ssam		UMA_CREATE(pf_altq_pl,	  struct pf_altq, "pfaltqpl");
297189251Ssam		UMA_CREATE(pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl");
298189251Ssam		UMA_CREATE(pfr_ktable_pl,  struct pfr_ktable, "pfrktable");
299189251Ssam		UMA_CREATE(pfr_kentry_pl,  struct pfr_kentry, "pfrkentry");
300189251Ssam		UMA_CREATE(pf_frent_pl,	  struct pf_frent, "pffrent");
301189251Ssam		UMA_CREATE(pf_frag_pl,	  struct pf_fragment, "pffrag");
302189251Ssam		UMA_CREATE(pf_cache_pl,	  struct pf_fragment, "pffrcache");
303189251Ssam		UMA_CREATE(pf_cent_pl,	  struct pf_frcache, "pffrcent");
304189251Ssam		UMA_CREATE(pf_state_scrub_pl, struct pf_state_scrub,
305189251Ssam		    "pfstatescrub");
306189251Ssam		error = 0;
307189251Ssam	} while(0);
308189251Ssam	if (error) {
309189251Ssam		cleanup_pf_zone();
310189251Ssam		return (error);
311189251Ssam	}
312189251Ssam	pfr_initialize();
313189251Ssam	if ( (error = pf_osfp_initialize()) ) {
314189251Ssam		cleanup_pf_zone();
315189251Ssam		pf_osfp_cleanup();
316189251Ssam		return (error);
317189251Ssam	}
318189251Ssam
319189251Ssam	pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl;
320189251Ssam	pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT;
321189251Ssam	pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl;
322189251Ssam	pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT;
323189251Ssam	uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp,
324189251Ssam		pf_pool_limits[PF_LIMIT_STATES].limit);
325189251Ssam
326189251Ssam	RB_INIT(&tree_lan_ext);
327189251Ssam	RB_INIT(&tree_ext_gwy);
328189251Ssam	TAILQ_INIT(&pf_anchors);
329189251Ssam	pf_init_ruleset(&pf_main_ruleset);
330189251Ssam	TAILQ_INIT(&pf_altqs[0]);
331189251Ssam	TAILQ_INIT(&pf_altqs[1]);
332189251Ssam	TAILQ_INIT(&pf_pabuf);
333189251Ssam	pf_altqs_active = &pf_altqs[0];
334189251Ssam	pf_altqs_inactive = &pf_altqs[1];
335189251Ssam
336189251Ssam	/* default rule should never be garbage collected */
337189251Ssam	pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
338189251Ssam	pf_default_rule.action = PF_PASS;
339189251Ssam	pf_default_rule.nr = -1;
340189251Ssam
341189251Ssam	/* initialize default timeouts */
342189251Ssam	my_timeout[PFTM_TCP_FIRST_PACKET] = 120;	/* First TCP packet */
343189251Ssam	my_timeout[PFTM_TCP_OPENING] = 30; 		/* No response yet */
344189251Ssam	my_timeout[PFTM_TCP_ESTABLISHED] = 24*60*60;	/* Established */
345189251Ssam	my_timeout[PFTM_TCP_CLOSING] = 15 * 60;		/* Half closed */
346189251Ssam	my_timeout[PFTM_TCP_FIN_WAIT] = 45;		/* Got both FINs */
347189251Ssam	my_timeout[PFTM_TCP_CLOSED] = 90;		/* Got a RST */
348189251Ssam	my_timeout[PFTM_UDP_FIRST_PACKET] = 60;		/* First UDP packet */
349189251Ssam	my_timeout[PFTM_UDP_SINGLE] = 30;		/* Unidirectional */
350189251Ssam	my_timeout[PFTM_UDP_MULTIPLE] = 60;		/* Bidirectional */
351189251Ssam	my_timeout[PFTM_ICMP_FIRST_PACKET] = 20;	/* First ICMP packet */
352189251Ssam	my_timeout[PFTM_ICMP_ERROR_REPLY] = 10;		/* Got error response */
353189251Ssam	my_timeout[PFTM_OTHER_FIRST_PACKET] = 60;	/* First packet */
354189251Ssam	my_timeout[PFTM_OTHER_SINGLE] = 30;		/* Unidirectional */
355189251Ssam	my_timeout[PFTM_OTHER_MULTIPLE] = 60;		/* Bidirectional */
356189251Ssam	my_timeout[PFTM_FRAG] = 30;			/* Fragment expire */
357189251Ssam	my_timeout[PFTM_INTERVAL] = 10;			/* Expire interval */
358189251Ssam
359189251Ssam	/*
360189251Ssam	 * XXX
361189251Ssam	 *  The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE
362189251Ssam	 * if Gaint lock is removed from the network stack.
363189251Ssam	 */
364189251Ssam	callout_init(&pf_expire_to, 0);
365189251Ssam	callout_reset(&pf_expire_to, my_timeout[PFTM_INTERVAL] * hz,
366189251Ssam	    pf_purge_timeout, &pf_expire_to);
367189251Ssam
368189251Ssam	pf_normalize_init();
369189251Ssam	pf_status.debug = PF_DEBUG_URGENT;
370189251Ssam	pf_pfil_hooked = 0;
371189251Ssam	return (error);
372189251Ssam}
373189251Ssam#else /* !__FreeBSD__ */
374189251Ssamvoid
375189251Ssampfattach(int num)
376189251Ssam{
377189251Ssam	u_int32_t *timeout = pf_default_rule.timeout;
378189251Ssam
379189251Ssam	pool_init(&pf_tree_pl, sizeof(struct pf_tree_node), 0, 0, 0, "pftrpl",
380189251Ssam	    NULL);
381189251Ssam	pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl",
382189251Ssam	    &pool_allocator_nointr);
383189251Ssam	pool_init(&pf_addr_pl, sizeof(struct pf_addr_dyn), 0, 0, 0, "pfaddrpl",
384189251Ssam	    &pool_allocator_nointr);
385189251Ssam	pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
386189251Ssam	    NULL);
387189251Ssam	pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl",
388189251Ssam	    NULL);
389189251Ssam	pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
390189251Ssam	    "pfpooladdrpl", NULL);
391189251Ssam	pfr_initialize();
392189251Ssam	pf_osfp_initialize();
393189251Ssam
394189251Ssam	pool_sethardlimit(&pf_state_pl, pf_pool_limits[PF_LIMIT_STATES].limit,
395189251Ssam	    NULL, 0);
396189251Ssam
397189251Ssam	RB_INIT(&tree_lan_ext);
398189251Ssam	RB_INIT(&tree_ext_gwy);
399189251Ssam	TAILQ_INIT(&pf_anchors);
400189251Ssam	pf_init_ruleset(&pf_main_ruleset);
401189251Ssam	TAILQ_INIT(&pf_altqs[0]);
402189251Ssam	TAILQ_INIT(&pf_altqs[1]);
403189251Ssam	TAILQ_INIT(&pf_pabuf);
404189251Ssam	pf_altqs_active = &pf_altqs[0];
405189251Ssam	pf_altqs_inactive = &pf_altqs[1];
406189251Ssam
407189251Ssam	/* default rule should never be garbage collected */
408189251Ssam	pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
409189251Ssam	pf_default_rule.action = PF_PASS;
410189251Ssam	pf_default_rule.nr = -1;
411189251Ssam
412189251Ssam	/* initialize default timeouts */
413189251Ssam	timeout[PFTM_TCP_FIRST_PACKET] = 120;		/* First TCP packet */
414189251Ssam	timeout[PFTM_TCP_OPENING] = 30; 		/* No response yet */
415189251Ssam	timeout[PFTM_TCP_ESTABLISHED] = 24*60*60;	/* Established */
416189251Ssam	timeout[PFTM_TCP_CLOSING] = 15 * 60;		/* Half closed */
417189251Ssam	timeout[PFTM_TCP_FIN_WAIT] = 45;		/* Got both FINs */
418189251Ssam	timeout[PFTM_TCP_CLOSED] = 90;			/* Got a RST */
419189251Ssam	timeout[PFTM_UDP_FIRST_PACKET] = 60;		/* First UDP packet */
420189251Ssam	timeout[PFTM_UDP_SINGLE] = 30;			/* Unidirectional */
421189251Ssam	timeout[PFTM_UDP_MULTIPLE] = 60;		/* Bidirectional */
422189251Ssam	timeout[PFTM_ICMP_FIRST_PACKET] = 20;		/* First ICMP packet */
423189251Ssam	timeout[PFTM_ICMP_ERROR_REPLY] = 10;		/* Got error response */
424189251Ssam	timeout[PFTM_OTHER_FIRST_PACKET] = 60;		/* First packet */
425189251Ssam	timeout[PFTM_OTHER_SINGLE] = 30;		/* Unidirectional */
426189251Ssam	timeout[PFTM_OTHER_MULTIPLE] = 60;		/* Bidirectional */
427189251Ssam	timeout[PFTM_FRAG] = 30;			/* Fragment expire */
428189251Ssam	timeout[PFTM_INTERVAL] = 10;			/* Expire interval */
429189251Ssam
430189251Ssam	timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
431189251Ssam	timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
432189251Ssam
433189251Ssam	pf_normalize_init();
434189251Ssam	pf_status.debug = PF_DEBUG_URGENT;
435189251Ssam}
436189251Ssam#endif /* __FreeBSD__ */
437189251Ssam
438189251Ssam#if !defined(__FreeBSD__)
439189251Ssamint
440189251Ssampfopen(dev_t dev, int flags, int fmt, struct proc *p)
441189251Ssam{
442189251Ssam	if (minor(dev) >= 1)
443189251Ssam		return (ENXIO);
444189251Ssam	return (0);
445189251Ssam}
446189251Ssam#endif
447189251Ssam
448189251Ssam#if !defined(__FreeBSD__)
449189251Ssamint
450189251Ssampfclose(dev_t dev, int flags, int fmt, struct proc *p)
451214734Srpaulo{
452189251Ssam	if (minor(dev) >= 1)
453189251Ssam		return (ENXIO);
454189251Ssam	return (0);
455189251Ssam}
456189251Ssam#endif
457189251Ssam
458189251Ssamstruct pf_pool *
459189251Ssampf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket,
460189251Ssam    u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last,
461189251Ssam    u_int8_t active, u_int8_t check_ticket)
462189251Ssam{
463189251Ssam	struct pf_ruleset	*ruleset;
464189251Ssam	struct pf_rule		*rule;
465189251Ssam	int			 rs_num;
466189251Ssam
467189251Ssam	ruleset = pf_find_ruleset(anchorname, rulesetname);
468189251Ssam	if (ruleset == NULL)
469189251Ssam		return (NULL);
470189251Ssam	rs_num = pf_get_ruleset_number(rule_action);
471189251Ssam	if (rs_num >= PF_RULESET_MAX)
472189251Ssam		return (NULL);
473189251Ssam	if (active) {
474189251Ssam		if (check_ticket && ticket !=
475189251Ssam		    ruleset->rules[rs_num].active.ticket)
476189251Ssam			return (NULL);
477189251Ssam		if (r_last)
478189251Ssam			rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
479189251Ssam			    pf_rulequeue);
480189251Ssam		else
481189251Ssam			rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
482189251Ssam	} else {
483189251Ssam		if (check_ticket && ticket !=
484189251Ssam		    ruleset->rules[rs_num].inactive.ticket)
485189251Ssam			return (NULL);
486189251Ssam		if (r_last)
487189251Ssam			rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
488189251Ssam			    pf_rulequeue);
489189251Ssam		else
490189251Ssam			rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
491189251Ssam	}
492189251Ssam	if (!r_last) {
493189251Ssam		while ((rule != NULL) && (rule->nr != rule_number))
494189251Ssam			rule = TAILQ_NEXT(rule, entries);
495189251Ssam	}
496189251Ssam	if (rule == NULL)
497189251Ssam		return (NULL);
498189251Ssam
499189251Ssam	return (&rule->rpool);
500189251Ssam}
501189251Ssam
502189251Ssamint
503189251Ssampf_get_ruleset_number(u_int8_t action)
504189251Ssam{
505189251Ssam	switch (action) {
506189251Ssam	case PF_SCRUB:
507189251Ssam		return (PF_RULESET_SCRUB);
508209158Srpaulo		break;
509209158Srpaulo	case PF_PASS:
510209158Srpaulo	case PF_DROP:
511209158Srpaulo		return (PF_RULESET_FILTER);
512209158Srpaulo		break;
513209158Srpaulo	case PF_NAT:
514209158Srpaulo	case PF_NONAT:
515209158Srpaulo		return (PF_RULESET_NAT);
516252726Srpaulo		break;
517252726Srpaulo	case PF_BINAT:
518252726Srpaulo	case PF_NOBINAT:
519252726Srpaulo		return (PF_RULESET_BINAT);
520252726Srpaulo		break;
521252726Srpaulo	case PF_RDR:
522252726Srpaulo	case PF_NORDR:
523252726Srpaulo		return (PF_RULESET_RDR);
524252726Srpaulo		break;
525252726Srpaulo	default:
526252726Srpaulo		return (PF_RULESET_MAX);
527252726Srpaulo		break;
528252726Srpaulo	}
529252726Srpaulo}
530252726Srpaulo
531252726Srpaulovoid
532252726Srpaulopf_init_ruleset(struct pf_ruleset *ruleset)
533252726Srpaulo{
534252726Srpaulo	int	i;
535252726Srpaulo
536252726Srpaulo	memset(ruleset, 0, sizeof(struct pf_ruleset));
537252726Srpaulo	for (i = 0; i < PF_RULESET_MAX; i++) {
538252726Srpaulo		TAILQ_INIT(&ruleset->rules[i].queues[0]);
539252726Srpaulo		TAILQ_INIT(&ruleset->rules[i].queues[1]);
540252726Srpaulo		ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
541252726Srpaulo		ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
542252726Srpaulo	}
543252726Srpaulo}
544252726Srpaulo
545252726Srpaulostruct pf_anchor *
546252726Srpaulopf_find_anchor(const char *anchorname)
547252726Srpaulo{
548252726Srpaulo	struct pf_anchor	*anchor;
549252726Srpaulo	int			 n = -1;
550252726Srpaulo
551252726Srpaulo	anchor = TAILQ_FIRST(&pf_anchors);
552252726Srpaulo	while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0)
553189251Ssam		anchor = TAILQ_NEXT(anchor, entries);
554189251Ssam	if (n == 0)
555189251Ssam		return (anchor);
556189251Ssam	else
557189251Ssam		return (NULL);
558189251Ssam}
559189251Ssam
560189251Ssamstruct pf_ruleset *
561189251Ssampf_find_ruleset(char *anchorname, char *rulesetname)
562189251Ssam{
563189251Ssam	struct pf_anchor	*anchor;
564189251Ssam	struct pf_ruleset	*ruleset;
565189251Ssam
566189251Ssam	if (!anchorname[0] && !rulesetname[0])
567252726Srpaulo		return (&pf_main_ruleset);
568252726Srpaulo	if (!anchorname[0] || !rulesetname[0])
569252726Srpaulo		return (NULL);
570189251Ssam	anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
571189251Ssam	rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
572189251Ssam	anchor = pf_find_anchor(anchorname);
573189251Ssam	if (anchor == NULL)
574189251Ssam		return (NULL);
575189251Ssam	ruleset = TAILQ_FIRST(&anchor->rulesets);
576189251Ssam	while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0)
577189251Ssam		ruleset = TAILQ_NEXT(ruleset, entries);
578189251Ssam	if (ruleset != NULL && !strcmp(ruleset->name, rulesetname))
579189251Ssam		return (ruleset);
580189251Ssam	else
581189251Ssam		return (NULL);
582189251Ssam}
583189251Ssam
584189251Ssamstruct pf_ruleset *
585189251Ssampf_find_or_create_ruleset(char *anchorname, char *rulesetname)
586189251Ssam{
587252726Srpaulo	struct pf_anchor	*anchor, *a;
588189251Ssam	struct pf_ruleset	*ruleset, *r;
589189251Ssam
590189251Ssam	if (!anchorname[0] && !rulesetname[0])
591252726Srpaulo		return (&pf_main_ruleset);
592252726Srpaulo	if (!anchorname[0] || !rulesetname[0])
593252726Srpaulo		return (NULL);
594252726Srpaulo	anchorname[PF_ANCHOR_NAME_SIZE-1] = 0;
595252726Srpaulo	rulesetname[PF_RULESET_NAME_SIZE-1] = 0;
596252726Srpaulo	a = TAILQ_FIRST(&pf_anchors);
597252726Srpaulo	while (a != NULL && strcmp(a->name, anchorname) < 0)
598252726Srpaulo		a = TAILQ_NEXT(a, entries);
599252726Srpaulo	if (a != NULL && !strcmp(a->name, anchorname))
600252726Srpaulo		anchor = a;
601252726Srpaulo	else {
602252726Srpaulo		anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor),
603252726Srpaulo		    M_TEMP, M_NOWAIT);
604252726Srpaulo		if (anchor == NULL)
605252726Srpaulo			return (NULL);
606252726Srpaulo		memset(anchor, 0, sizeof(struct pf_anchor));
607252726Srpaulo		bcopy(anchorname, anchor->name, sizeof(anchor->name));
608252726Srpaulo		TAILQ_INIT(&anchor->rulesets);
609189251Ssam		if (a != NULL)
610189251Ssam			TAILQ_INSERT_BEFORE(a, anchor, entries);
611189251Ssam		else
612214734Srpaulo			TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries);
613214734Srpaulo	}
614214734Srpaulo	r = TAILQ_FIRST(&anchor->rulesets);
615214734Srpaulo	while (r != NULL && strcmp(r->name, rulesetname) < 0)
616214734Srpaulo		r = TAILQ_NEXT(r, entries);
617214734Srpaulo	if (r != NULL && !strcmp(r->name, rulesetname))
618214734Srpaulo		return (r);
619214734Srpaulo	ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset),
620214734Srpaulo	    M_TEMP, M_NOWAIT);
621214734Srpaulo	if (ruleset != NULL) {
622214734Srpaulo		pf_init_ruleset(ruleset);
623214734Srpaulo		bcopy(rulesetname, ruleset->name, sizeof(ruleset->name));
624214734Srpaulo		ruleset->anchor = anchor;
625214734Srpaulo		if (r != NULL)
626214734Srpaulo			TAILQ_INSERT_BEFORE(r, ruleset, entries);
627214734Srpaulo		else
628214734Srpaulo			TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries);
629214734Srpaulo	}
630214734Srpaulo	return (ruleset);
631189251Ssam}
632189251Ssam
633189251Ssamvoid
634252726Srpaulopf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
635252726Srpaulo{
636252726Srpaulo	struct pf_anchor	*anchor;
637189251Ssam	int			 i;
638189251Ssam
639189251Ssam	if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 ||
640189251Ssam	    ruleset->topen)
641189251Ssam		return;
642	for (i = 0; i < PF_RULESET_MAX; ++i)
643		if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
644		    !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr))
645			return;
646
647	anchor = ruleset->anchor;
648	TAILQ_REMOVE(&anchor->rulesets, ruleset, entries);
649	free(ruleset, M_TEMP);
650
651	if (TAILQ_EMPTY(&anchor->rulesets)) {
652		TAILQ_REMOVE(&pf_anchors, anchor, entries);
653		free(anchor, M_TEMP);
654	}
655}
656
657void
658pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
659{
660	struct pf_pooladdr	*mv_pool_pa;
661
662	while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
663		TAILQ_REMOVE(poola, mv_pool_pa, entries);
664		TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
665	}
666}
667
668void
669pf_empty_pool(struct pf_palist *poola)
670{
671	struct pf_pooladdr	*empty_pool_pa;
672
673	while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
674		pf_dynaddr_remove(&empty_pool_pa->addr);
675		pf_tbladdr_remove(&empty_pool_pa->addr);
676		TAILQ_REMOVE(poola, empty_pool_pa, entries);
677		pool_put(&pf_pooladdr_pl, empty_pool_pa);
678	}
679}
680
681void
682pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
683{
684	if (rulequeue != NULL) {
685		if (rule->states <= 0) {
686			/*
687			 * XXX - we need to remove the table *before* detaching
688			 * the rule to make sure the table code does not delete
689			 * the anchor under our feet.
690			 */
691			pf_tbladdr_remove(&rule->src.addr);
692			pf_tbladdr_remove(&rule->dst.addr);
693		}
694		TAILQ_REMOVE(rulequeue, rule, entries);
695		rule->entries.tqe_prev = NULL;
696		rule->nr = -1;
697	}
698	if (rule->states > 0 || rule->entries.tqe_prev != NULL)
699		return;
700	pf_tag_unref(rule->tag);
701	pf_tag_unref(rule->match_tag);
702	pf_dynaddr_remove(&rule->src.addr);
703	pf_dynaddr_remove(&rule->dst.addr);
704	if (rulequeue == NULL) {
705		pf_tbladdr_remove(&rule->src.addr);
706		pf_tbladdr_remove(&rule->dst.addr);
707	}
708	pf_empty_pool(&rule->rpool.list);
709	pool_put(&pf_rule_pl, rule);
710}
711
712u_int16_t
713pf_tagname2tag(char *tagname)
714{
715	struct pf_tagname	*tag, *p = NULL;
716	u_int16_t		 new_tagid = 1;
717
718	TAILQ_FOREACH(tag, &pf_tags, entries)
719		if (strcmp(tagname, tag->name) == 0) {
720			tag->ref++;
721			return (tag->tag);
722		}
723
724	/*
725	 * to avoid fragmentation, we do a linear search from the beginning
726	 * and take the first free slot we find. if there is none or the list
727	 * is empty, append a new entry at the end.
728	 */
729
730	/* new entry */
731	if (!TAILQ_EMPTY(&pf_tags))
732		for (p = TAILQ_FIRST(&pf_tags); p != NULL &&
733		    p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
734			new_tagid = p->tag + 1;
735
736	if (new_tagid > TAGID_MAX)
737		return (0);
738
739	/* allocate and fill new struct pf_tagname */
740	tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname),
741	    M_TEMP, M_NOWAIT);
742	if (tag == NULL)
743		return (0);
744	bzero(tag, sizeof(struct pf_tagname));
745	strlcpy(tag->name, tagname, sizeof(tag->name));
746	tag->tag = new_tagid;
747	tag->ref++;
748
749	if (p != NULL)	/* insert new entry before p */
750		TAILQ_INSERT_BEFORE(p, tag, entries);
751	else	/* either list empty or no free slot in between */
752		TAILQ_INSERT_TAIL(&pf_tags, tag, entries);
753
754	return (tag->tag);
755}
756
757void
758pf_tag2tagname(u_int16_t tagid, char *p)
759{
760	struct pf_tagname	*tag;
761
762	TAILQ_FOREACH(tag, &pf_tags, entries)
763		if (tag->tag == tagid) {
764			strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
765			return;
766		}
767}
768
769void
770pf_tag_unref(u_int16_t tag)
771{
772	struct pf_tagname	*p, *next;
773
774	if (tag == 0)
775		return;
776
777	for (p = TAILQ_FIRST(&pf_tags); p != NULL; p = next) {
778		next = TAILQ_NEXT(p, entries);
779		if (tag == p->tag) {
780			if (--p->ref == 0) {
781				TAILQ_REMOVE(&pf_tags, p, entries);
782				free(p, M_TEMP);
783			}
784			break;
785		}
786	}
787}
788
789#if defined(__FreeBSD__)
790int
791pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
792#else
793int
794pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
795#endif
796{
797	struct pf_pooladdr	*pa = NULL;
798	struct pf_pool		*pool = NULL;
799	int			 s;
800	int			 error = 0;
801
802	/* XXX keep in sync with switch() below */
803	if (securelevel > 1)
804		switch (cmd) {
805		case DIOCGETRULES:
806		case DIOCGETRULE:
807		case DIOCGETADDRS:
808		case DIOCGETADDR:
809		case DIOCGETSTATE:
810		case DIOCSETSTATUSIF:
811		case DIOCGETSTATUS:
812		case DIOCCLRSTATUS:
813		case DIOCNATLOOK:
814		case DIOCSETDEBUG:
815		case DIOCGETSTATES:
816		case DIOCGETTIMEOUT:
817		case DIOCCLRRULECTRS:
818		case DIOCGETLIMIT:
819		case DIOCGETALTQS:
820		case DIOCGETALTQ:
821		case DIOCGETQSTATS:
822		case DIOCGETANCHORS:
823		case DIOCGETANCHOR:
824		case DIOCGETRULESETS:
825		case DIOCGETRULESET:
826		case DIOCRGETTABLES:
827		case DIOCRGETTSTATS:
828		case DIOCRCLRTSTATS:
829		case DIOCRCLRADDRS:
830		case DIOCRADDADDRS:
831		case DIOCRDELADDRS:
832		case DIOCRSETADDRS:
833		case DIOCRGETADDRS:
834		case DIOCRGETASTATS:
835		case DIOCRCLRASTATS:
836		case DIOCRTSTADDRS:
837		case DIOCOSFPGET:
838#if defined(__FreeBSD__)
839		case DIOCGIFSPEED:
840#endif
841			break;
842		default:
843			return (EPERM);
844		}
845
846	if (!(flags & FWRITE))
847		switch (cmd) {
848		case DIOCGETRULES:
849		case DIOCGETRULE:
850		case DIOCGETADDRS:
851		case DIOCGETADDR:
852		case DIOCGETSTATE:
853		case DIOCGETSTATUS:
854		case DIOCGETSTATES:
855		case DIOCGETTIMEOUT:
856		case DIOCGETLIMIT:
857		case DIOCGETALTQS:
858		case DIOCGETALTQ:
859		case DIOCGETQSTATS:
860		case DIOCGETANCHORS:
861		case DIOCGETANCHOR:
862		case DIOCGETRULESETS:
863		case DIOCGETRULESET:
864		case DIOCRGETTABLES:
865		case DIOCRGETTSTATS:
866		case DIOCRGETADDRS:
867		case DIOCRGETASTATS:
868		case DIOCRTSTADDRS:
869		case DIOCOSFPGET:
870#if defined(__FreeBSD__)
871		case DIOCGIFSPEED:
872#endif
873			break;
874		default:
875			return (EACCES);
876		}
877
878#if defined(__FreeBSD__)
879	PF_LOCK();
880#endif
881
882	switch (cmd) {
883
884	case DIOCSTART:
885		if (pf_status.running)
886			error = EEXIST;
887		else {
888			u_int32_t states = pf_status.states;
889#if defined(__FreeBSD__)
890			PF_UNLOCK();
891			error = hook_pf();
892			PF_LOCK();
893			if (error) {
894				DPFPRINTF(PF_DEBUG_MISC,
895				    ("pf: pfil registeration fail\n"));
896				break;
897			}
898#endif
899			bzero(&pf_status, sizeof(struct pf_status));
900			pf_status.running = 1;
901			pf_status.states = states;
902#if defined(__FreeBSD__)
903			pf_status.since = time_second;
904#else
905			pf_status.since = time.tv_sec;
906#endif
907			if (status_ifp != NULL)
908#if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
909				snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
910				    status_ifp->if_name, status_ifp->if_unit);
911#else
912				strlcpy(pf_status.ifname,
913				    status_ifp->if_xname, IFNAMSIZ);
914#endif
915			DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
916		}
917		break;
918
919	case DIOCSTOP:
920		if (!pf_status.running)
921			error = ENOENT;
922		else {
923			pf_status.running = 0;
924#if defined(__FreeBSD__)
925			PF_UNLOCK();
926			error = dehook_pf();
927			PF_LOCK();
928			if (error) {
929				pf_status.running = 1;
930				DPFPRINTF(PF_DEBUG_MISC,
931					("pf: pfil unregisteration failed\n"));
932			}
933#endif
934			DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
935		}
936		break;
937
938	case DIOCBEGINRULES: {
939		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
940		struct pf_ruleset	*ruleset;
941		struct pf_rule		*rule;
942		int			 rs_num;
943
944		ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
945		if (ruleset == NULL) {
946			error = EINVAL;
947			break;
948		}
949		rs_num = pf_get_ruleset_number(pr->rule.action);
950		if (rs_num >= PF_RULESET_MAX) {
951			error = EINVAL;
952			break;
953		}
954		while ((rule =
955		    TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
956			pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
957		pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
958		break;
959	}
960
961	case DIOCADDRULE: {
962		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
963		struct pf_ruleset	*ruleset;
964		struct pf_rule		*rule, *tail;
965		struct pf_pooladdr	*pa;
966		int			 rs_num;
967
968		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
969		if (ruleset == NULL) {
970			error = EINVAL;
971			break;
972		}
973		rs_num = pf_get_ruleset_number(pr->rule.action);
974		if (rs_num >= PF_RULESET_MAX) {
975			error = EINVAL;
976			break;
977		}
978		if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) {
979			error = EINVAL;
980			break;
981		}
982		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
983			error = EINVAL;
984			break;
985		}
986		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
987			error = EBUSY;
988			break;
989		}
990		if (pr->pool_ticket != ticket_pabuf) {
991			error = EBUSY;
992			break;
993		}
994		rule = pool_get(&pf_rule_pl, PR_NOWAIT);
995		if (rule == NULL) {
996			error = ENOMEM;
997			break;
998		}
999		bcopy(&pr->rule, rule, sizeof(struct pf_rule));
1000		rule->anchor = NULL;
1001		rule->ifp = NULL;
1002		TAILQ_INIT(&rule->rpool.list);
1003		/* initialize refcounting */
1004		rule->states = 0;
1005		rule->entries.tqe_prev = NULL;
1006#ifndef INET
1007		if (rule->af == AF_INET) {
1008			pool_put(&pf_rule_pl, rule);
1009			error = EAFNOSUPPORT;
1010			break;
1011		}
1012#endif /* INET */
1013#ifndef INET6
1014		if (rule->af == AF_INET6) {
1015			pool_put(&pf_rule_pl, rule);
1016			error = EAFNOSUPPORT;
1017			break;
1018		}
1019#endif /* INET6 */
1020		tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
1021		    pf_rulequeue);
1022		if (tail)
1023			rule->nr = tail->nr + 1;
1024		else
1025			rule->nr = 0;
1026		if (rule->ifname[0]) {
1027			rule->ifp = ifunit(rule->ifname);
1028			if (rule->ifp == NULL) {
1029				pool_put(&pf_rule_pl, rule);
1030				error = EINVAL;
1031				break;
1032			}
1033		}
1034
1035		if (rule->tagname[0])
1036			if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
1037				error = EBUSY;
1038		if (rule->match_tagname[0])
1039			if ((rule->match_tag =
1040			    pf_tagname2tag(rule->match_tagname)) == 0)
1041				error = EBUSY;
1042		if (rule->rt && !rule->direction)
1043			error = EINVAL;
1044		if (pf_dynaddr_setup(&rule->src.addr, rule->af))
1045			error = EINVAL;
1046		if (pf_dynaddr_setup(&rule->dst.addr, rule->af))
1047			error = EINVAL;
1048		if (pf_tbladdr_setup(ruleset, &rule->src.addr))
1049			error = EINVAL;
1050		if (pf_tbladdr_setup(ruleset, &rule->dst.addr))
1051			error = EINVAL;
1052		TAILQ_FOREACH(pa, &pf_pabuf, entries)
1053			if (pf_tbladdr_setup(ruleset, &pa->addr))
1054				error = EINVAL;
1055
1056		pf_mv_pool(&pf_pabuf, &rule->rpool.list);
1057		if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
1058		    (rule->action == PF_BINAT)) && !rule->anchorname[0]) ||
1059		    (rule->rt > PF_FASTROUTE)) &&
1060		    (TAILQ_FIRST(&rule->rpool.list) == NULL))
1061			error = EINVAL;
1062
1063		if (error) {
1064			pf_rm_rule(NULL, rule);
1065			break;
1066		}
1067		rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
1068		rule->evaluations = rule->packets = rule->bytes = 0;
1069		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
1070		    rule, entries);
1071		break;
1072	}
1073
1074	case DIOCCOMMITRULES: {
1075		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
1076		struct pf_ruleset	*ruleset;
1077		struct pf_rulequeue	*old_rules;
1078		struct pf_rule		*rule;
1079		int			 rs_num;
1080
1081		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
1082		if (ruleset == NULL) {
1083			error = EINVAL;
1084			break;
1085		}
1086		rs_num = pf_get_ruleset_number(pr->rule.action);
1087		if (rs_num >= PF_RULESET_MAX) {
1088			error = EINVAL;
1089			break;
1090		}
1091		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
1092			error = EBUSY;
1093			break;
1094		}
1095
1096#ifdef ALTQ
1097		/* set queue IDs */
1098		if (rs_num == PF_RULESET_FILTER)
1099			pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
1100#endif
1101
1102		/* Swap rules, keep the old. */
1103		s = splsoftnet();
1104		old_rules = ruleset->rules[rs_num].active.ptr;
1105		ruleset->rules[rs_num].active.ptr =
1106		    ruleset->rules[rs_num].inactive.ptr;
1107		ruleset->rules[rs_num].inactive.ptr = old_rules;
1108		ruleset->rules[rs_num].active.ticket =
1109		    ruleset->rules[rs_num].inactive.ticket;
1110		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1111
1112		/* Purge the old rule list. */
1113		while ((rule = TAILQ_FIRST(old_rules)) != NULL)
1114			pf_rm_rule(old_rules, rule);
1115		pf_remove_if_empty_ruleset(ruleset);
1116		pf_update_anchor_rules();
1117		splx(s);
1118		break;
1119	}
1120
1121	case DIOCGETRULES: {
1122		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
1123		struct pf_ruleset	*ruleset;
1124		struct pf_rule		*tail;
1125		int			 rs_num;
1126
1127		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
1128		if (ruleset == NULL) {
1129			error = EINVAL;
1130			break;
1131		}
1132		rs_num = pf_get_ruleset_number(pr->rule.action);
1133		if (rs_num >= PF_RULESET_MAX) {
1134			error = EINVAL;
1135			break;
1136		}
1137		s = splsoftnet();
1138		tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
1139		    pf_rulequeue);
1140		if (tail)
1141			pr->nr = tail->nr + 1;
1142		else
1143			pr->nr = 0;
1144		pr->ticket = ruleset->rules[rs_num].active.ticket;
1145		splx(s);
1146		break;
1147	}
1148
1149	case DIOCGETRULE: {
1150		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
1151		struct pf_ruleset	*ruleset;
1152		struct pf_rule		*rule;
1153		int			 rs_num, i;
1154
1155		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
1156		if (ruleset == NULL) {
1157			error = EINVAL;
1158			break;
1159		}
1160		rs_num = pf_get_ruleset_number(pr->rule.action);
1161		if (rs_num >= PF_RULESET_MAX) {
1162			error = EINVAL;
1163			break;
1164		}
1165		if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
1166			error = EBUSY;
1167			break;
1168		}
1169		s = splsoftnet();
1170		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
1171		while ((rule != NULL) && (rule->nr != pr->nr))
1172			rule = TAILQ_NEXT(rule, entries);
1173		if (rule == NULL) {
1174			error = EBUSY;
1175			splx(s);
1176			break;
1177		}
1178		bcopy(rule, &pr->rule, sizeof(struct pf_rule));
1179		pf_dynaddr_copyout(&pr->rule.src.addr);
1180		pf_dynaddr_copyout(&pr->rule.dst.addr);
1181		pf_tbladdr_copyout(&pr->rule.src.addr);
1182		pf_tbladdr_copyout(&pr->rule.dst.addr);
1183		for (i = 0; i < PF_SKIP_COUNT; ++i)
1184			if (rule->skip[i].ptr == NULL)
1185				pr->rule.skip[i].nr = -1;
1186			else
1187				pr->rule.skip[i].nr =
1188				    rule->skip[i].ptr->nr;
1189		splx(s);
1190		break;
1191	}
1192
1193	case DIOCCHANGERULE: {
1194		struct pfioc_rule	*pcr = (struct pfioc_rule *)addr;
1195		struct pf_ruleset	*ruleset;
1196		struct pf_rule		*oldrule = NULL, *newrule = NULL;
1197		u_int32_t		 nr = 0;
1198		int			 rs_num;
1199
1200		if (!(pcr->action == PF_CHANGE_REMOVE ||
1201		    pcr->action == PF_CHANGE_GET_TICKET) &&
1202		    pcr->pool_ticket != ticket_pabuf) {
1203			error = EBUSY;
1204			break;
1205		}
1206
1207		if (pcr->action < PF_CHANGE_ADD_HEAD ||
1208		    pcr->action > PF_CHANGE_GET_TICKET) {
1209			error = EINVAL;
1210			break;
1211		}
1212		ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset);
1213		if (ruleset == NULL) {
1214			error = EINVAL;
1215			break;
1216		}
1217		rs_num = pf_get_ruleset_number(pcr->rule.action);
1218		if (rs_num >= PF_RULESET_MAX) {
1219			error = EINVAL;
1220			break;
1221		}
1222
1223		if (pcr->action == PF_CHANGE_GET_TICKET) {
1224			pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
1225			break;
1226		} else {
1227			if (pcr->ticket !=
1228			    ruleset->rules[rs_num].active.ticket) {
1229				error = EINVAL;
1230				break;
1231			}
1232			if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1233				error = EINVAL;
1234				break;
1235			}
1236		}
1237
1238		if (pcr->action != PF_CHANGE_REMOVE) {
1239			newrule = pool_get(&pf_rule_pl, PR_NOWAIT);
1240			if (newrule == NULL) {
1241				error = ENOMEM;
1242				break;
1243			}
1244			bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
1245			TAILQ_INIT(&newrule->rpool.list);
1246			/* initialize refcounting */
1247			newrule->states = 0;
1248			newrule->entries.tqe_prev = NULL;
1249#ifndef INET
1250			if (newrule->af == AF_INET) {
1251				pool_put(&pf_rule_pl, newrule);
1252				error = EAFNOSUPPORT;
1253				break;
1254			}
1255#endif /* INET */
1256#ifndef INET6
1257			if (newrule->af == AF_INET6) {
1258				pool_put(&pf_rule_pl, newrule);
1259				error = EAFNOSUPPORT;
1260				break;
1261			}
1262#endif /* INET6 */
1263			if (newrule->ifname[0]) {
1264				newrule->ifp = ifunit(newrule->ifname);
1265				if (newrule->ifp == NULL) {
1266					pool_put(&pf_rule_pl, newrule);
1267					error = EINVAL;
1268					break;
1269				}
1270			} else
1271				newrule->ifp = NULL;
1272
1273#ifdef ALTQ
1274			/* set queue IDs */
1275			if (newrule->qname[0] != 0) {
1276				newrule->qid = pf_qname_to_qid(newrule->qname);
1277				if (newrule->pqname[0] != 0)
1278					newrule->pqid =
1279					    pf_qname_to_qid(newrule->pqname);
1280				else
1281					newrule->pqid = newrule->qid;
1282			}
1283#endif
1284			if (newrule->tagname[0])
1285				if ((newrule->tag =
1286				    pf_tagname2tag(newrule->tagname)) == 0)
1287					error = EBUSY;
1288			if (newrule->match_tagname[0])
1289				if ((newrule->match_tag = pf_tagname2tag(
1290				    newrule->match_tagname)) == 0)
1291					error = EBUSY;
1292
1293			if (newrule->rt && !newrule->direction)
1294				error = EINVAL;
1295			if (pf_dynaddr_setup(&newrule->src.addr, newrule->af))
1296				error = EINVAL;
1297			if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af))
1298				error = EINVAL;
1299			if (pf_tbladdr_setup(ruleset, &newrule->src.addr))
1300				error = EINVAL;
1301			if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))
1302				error = EINVAL;
1303
1304			pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
1305			if (((((newrule->action == PF_NAT) ||
1306			    (newrule->action == PF_RDR) ||
1307			    (newrule->action == PF_BINAT) ||
1308			    (newrule->rt > PF_FASTROUTE)) &&
1309			    !newrule->anchorname[0])) &&
1310			    (TAILQ_FIRST(&newrule->rpool.list) == NULL))
1311				error = EINVAL;
1312
1313			if (error) {
1314				pf_rm_rule(NULL, newrule);
1315				break;
1316			}
1317			newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
1318			newrule->evaluations = newrule->packets = 0;
1319			newrule->bytes = 0;
1320		}
1321		pf_empty_pool(&pf_pabuf);
1322
1323		s = splsoftnet();
1324
1325		if (pcr->action == PF_CHANGE_ADD_HEAD)
1326			oldrule = TAILQ_FIRST(
1327			    ruleset->rules[rs_num].active.ptr);
1328		else if (pcr->action == PF_CHANGE_ADD_TAIL)
1329			oldrule = TAILQ_LAST(
1330			    ruleset->rules[rs_num].active.ptr, pf_rulequeue);
1331		else {
1332			oldrule = TAILQ_FIRST(
1333			    ruleset->rules[rs_num].active.ptr);
1334			while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
1335				oldrule = TAILQ_NEXT(oldrule, entries);
1336			if (oldrule == NULL) {
1337				pf_rm_rule(NULL, newrule);
1338				error = EINVAL;
1339				splx(s);
1340				break;
1341			}
1342		}
1343
1344		if (pcr->action == PF_CHANGE_REMOVE)
1345			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
1346		else {
1347			if (oldrule == NULL)
1348				TAILQ_INSERT_TAIL(
1349				    ruleset->rules[rs_num].active.ptr,
1350				    newrule, entries);
1351			else if (pcr->action == PF_CHANGE_ADD_HEAD ||
1352			    pcr->action == PF_CHANGE_ADD_BEFORE)
1353				TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
1354			else
1355				TAILQ_INSERT_AFTER(
1356				    ruleset->rules[rs_num].active.ptr,
1357				    oldrule, newrule, entries);
1358		}
1359
1360		nr = 0;
1361		TAILQ_FOREACH(oldrule,
1362		    ruleset->rules[rs_num].active.ptr, entries)
1363			oldrule->nr = nr++;
1364
1365		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
1366		pf_remove_if_empty_ruleset(ruleset);
1367		pf_update_anchor_rules();
1368
1369		ruleset->rules[rs_num].active.ticket++;
1370		splx(s);
1371		break;
1372	}
1373
1374	case DIOCCLRSTATES: {
1375		struct pf_tree_node	*n;
1376
1377		s = splsoftnet();
1378		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1379			n->state->timeout = PFTM_PURGE;
1380		pf_purge_expired_states();
1381		pf_status.states = 0;
1382		splx(s);
1383		break;
1384	}
1385
1386	case DIOCKILLSTATES: {
1387		struct pf_tree_node	*n;
1388		struct pf_state		*st;
1389		struct pfioc_state_kill	*psk = (struct pfioc_state_kill *)addr;
1390		int			 killed = 0;
1391
1392		s = splsoftnet();
1393		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1394			st = n->state;
1395			if ((!psk->psk_af || st->af == psk->psk_af) &&
1396			    (!psk->psk_proto || psk->psk_proto == st->proto) &&
1397			    PF_MATCHA(psk->psk_src.not,
1398			    &psk->psk_src.addr.v.a.addr,
1399			    &psk->psk_src.addr.v.a.mask, &st->lan.addr,
1400			    st->af) &&
1401			    PF_MATCHA(psk->psk_dst.not,
1402			    &psk->psk_dst.addr.v.a.addr,
1403			    &psk->psk_dst.addr.v.a.mask, &st->ext.addr,
1404			    st->af) &&
1405			    (psk->psk_src.port_op == 0 ||
1406			    pf_match_port(psk->psk_src.port_op,
1407			    psk->psk_src.port[0], psk->psk_src.port[1],
1408			    st->lan.port)) &&
1409			    (psk->psk_dst.port_op == 0 ||
1410			    pf_match_port(psk->psk_dst.port_op,
1411			    psk->psk_dst.port[0], psk->psk_dst.port[1],
1412			    st->ext.port))) {
1413				st->timeout = PFTM_PURGE;
1414				killed++;
1415			}
1416		}
1417		pf_purge_expired_states();
1418		splx(s);
1419		psk->psk_af = killed;
1420		break;
1421	}
1422
1423	case DIOCADDSTATE: {
1424		struct pfioc_state	*ps = (struct pfioc_state *)addr;
1425		struct pf_state		*state;
1426
1427		if (ps->state.timeout >= PFTM_MAX &&
1428		    ps->state.timeout != PFTM_UNTIL_PACKET) {
1429			error = EINVAL;
1430			break;
1431		}
1432		state = pool_get(&pf_state_pl, PR_NOWAIT);
1433		if (state == NULL) {
1434			error = ENOMEM;
1435			break;
1436		}
1437		s = splsoftnet();
1438		bcopy(&ps->state, state, sizeof(struct pf_state));
1439		state->rule.ptr = NULL;
1440		state->nat_rule.ptr = NULL;
1441		state->anchor.ptr = NULL;
1442		state->rt_ifp = NULL;
1443#if defined(__FreeBSD__)
1444		state->creation = time_second;
1445#else
1446		state->creation = time.tv_sec;
1447#endif
1448		state->packets[0] = state->packets[1] = 0;
1449		state->bytes[0] = state->bytes[1] = 0;
1450		if (pf_insert_state(state)) {
1451			pool_put(&pf_state_pl, state);
1452			error = ENOMEM;
1453		}
1454		splx(s);
1455		break;
1456	}
1457
1458	case DIOCGETSTATE: {
1459		struct pfioc_state	*ps = (struct pfioc_state *)addr;
1460		struct pf_tree_node	*n;
1461		u_int32_t		 nr;
1462
1463		nr = 0;
1464		s = splsoftnet();
1465		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1466			if (nr >= ps->nr)
1467				break;
1468			nr++;
1469		}
1470		if (n == NULL) {
1471			error = EBUSY;
1472			splx(s);
1473			break;
1474		}
1475		bcopy(n->state, &ps->state, sizeof(struct pf_state));
1476		ps->state.rule.nr = n->state->rule.ptr->nr;
1477		ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1478		    -1 : n->state->nat_rule.ptr->nr;
1479		ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ?
1480		    -1 : n->state->anchor.ptr->nr;
1481		splx(s);
1482		ps->state.expire = pf_state_expires(n->state);
1483#if defined(__FreeBSD__)
1484		if (ps->state.expire > time_second)
1485			ps->state.expire -= time_second;
1486#else
1487		if (ps->state.expire > time.tv_sec)
1488			ps->state.expire -= time.tv_sec;
1489#endif
1490		else
1491			ps->state.expire = 0;
1492		break;
1493	}
1494
1495	case DIOCGETSTATES: {
1496		struct pfioc_states	*ps = (struct pfioc_states *)addr;
1497		struct pf_tree_node	*n;
1498		struct pf_state		*p, pstore;
1499		u_int32_t		 nr = 0;
1500		int			 space = ps->ps_len;
1501
1502		if (space == 0) {
1503			s = splsoftnet();
1504			RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1505				nr++;
1506			splx(s);
1507			ps->ps_len = sizeof(struct pf_state) * nr;
1508#if defined(__FreeBSD__)
1509			PF_UNLOCK();
1510#endif
1511			return (0);
1512		}
1513
1514		s = splsoftnet();
1515		p = ps->ps_states;
1516		RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1517#if defined(__FreeBSD__)
1518			int	secs = time_second;
1519#else
1520			int	secs = time.tv_sec;
1521#endif
1522
1523			if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len)
1524				break;
1525
1526			bcopy(n->state, &pstore, sizeof(pstore));
1527			pstore.rule.nr = n->state->rule.ptr->nr;
1528			pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1529			    -1 : n->state->nat_rule.ptr->nr;
1530			pstore.anchor.nr = (n->state->anchor.ptr == NULL) ?
1531			    -1 : n->state->anchor.ptr->nr;
1532			pstore.creation = secs - pstore.creation;
1533			pstore.expire = pf_state_expires(n->state);
1534			if (pstore.expire > secs)
1535				pstore.expire -= secs;
1536			else
1537				pstore.expire = 0;
1538#if defined(__FreeBSD__)
1539			PF_COPYOUT(&pstore, p, sizeof(*p), error);
1540#else
1541			error = copyout(&pstore, p, sizeof(*p));
1542#endif
1543			if (error) {
1544				splx(s);
1545				goto fail;
1546			}
1547			p++;
1548			nr++;
1549		}
1550		ps->ps_len = sizeof(struct pf_state) * nr;
1551		splx(s);
1552		break;
1553	}
1554
1555	case DIOCGETSTATUS: {
1556		struct pf_status *s = (struct pf_status *)addr;
1557		bcopy(&pf_status, s, sizeof(struct pf_status));
1558		break;
1559	}
1560
1561	case DIOCSETSTATUSIF: {
1562		struct pfioc_if	*pi = (struct pfioc_if *)addr;
1563		struct ifnet	*ifp;
1564
1565		if (pi->ifname[0] == 0) {
1566			status_ifp = NULL;
1567			bzero(pf_status.ifname, IFNAMSIZ);
1568			break;
1569		}
1570		if ((ifp = ifunit(pi->ifname)) == NULL) {
1571			error = EINVAL;
1572			break;
1573		} else if (ifp == status_ifp)
1574			break;
1575		status_ifp = ifp;
1576		/* fallthrough into DIOCCLRSTATUS */
1577	}
1578
1579	case DIOCCLRSTATUS: {
1580		u_int32_t	running = pf_status.running;
1581		u_int32_t	states = pf_status.states;
1582		u_int32_t	since = pf_status.since;
1583		u_int32_t	debug = pf_status.debug;
1584
1585		bzero(&pf_status, sizeof(struct pf_status));
1586		pf_status.running = running;
1587		pf_status.states = states;
1588		pf_status.since = since;
1589		pf_status.debug = debug;
1590		if (status_ifp != NULL)
1591#if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
1592			snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
1593			    status_ifp->if_name, status_ifp->if_unit);
1594#else
1595			strlcpy(pf_status.ifname,
1596			    status_ifp->if_xname, IFNAMSIZ);
1597#endif
1598		break;
1599	}
1600
1601	case DIOCNATLOOK: {
1602		struct pfioc_natlook	*pnl = (struct pfioc_natlook *)addr;
1603		struct pf_state		*st;
1604		struct pf_tree_node	 key;
1605		int			 direction = pnl->direction;
1606
1607		key.af = pnl->af;
1608		key.proto = pnl->proto;
1609
1610		/*
1611		 * userland gives us source and dest of connection, reverse
1612		 * the lookup so we ask for what happens with the return
1613		 * traffic, enabling us to find it in the state tree.
1614		 */
1615		PF_ACPY(&key.addr[1], &pnl->saddr, pnl->af);
1616		key.port[1] = pnl->sport;
1617		PF_ACPY(&key.addr[0], &pnl->daddr, pnl->af);
1618		key.port[0] = pnl->dport;
1619
1620		if (!pnl->proto ||
1621		    PF_AZERO(&pnl->saddr, pnl->af) ||
1622		    PF_AZERO(&pnl->daddr, pnl->af) ||
1623		    !pnl->dport || !pnl->sport)
1624			error = EINVAL;
1625		else {
1626			s = splsoftnet();
1627			if (direction == PF_IN)
1628				st = pf_find_state(&tree_ext_gwy, &key);
1629			else
1630				st = pf_find_state(&tree_lan_ext, &key);
1631			if (st != NULL) {
1632				if (direction == PF_IN) {
1633					PF_ACPY(&pnl->rsaddr, &st->lan.addr,
1634					    st->af);
1635					pnl->rsport = st->lan.port;
1636					PF_ACPY(&pnl->rdaddr, &pnl->daddr,
1637					    pnl->af);
1638					pnl->rdport = pnl->dport;
1639				} else {
1640					PF_ACPY(&pnl->rdaddr, &st->gwy.addr,
1641					    st->af);
1642					pnl->rdport = st->gwy.port;
1643					PF_ACPY(&pnl->rsaddr, &pnl->saddr,
1644					    pnl->af);
1645					pnl->rsport = pnl->sport;
1646				}
1647			} else
1648				error = ENOENT;
1649			splx(s);
1650		}
1651		break;
1652	}
1653
1654	case DIOCSETTIMEOUT: {
1655		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
1656		int		 old;
1657
1658		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
1659		    pt->seconds < 0) {
1660			error = EINVAL;
1661			goto fail;
1662		}
1663		old = pf_default_rule.timeout[pt->timeout];
1664		pf_default_rule.timeout[pt->timeout] = pt->seconds;
1665		pt->seconds = old;
1666		break;
1667	}
1668
1669	case DIOCGETTIMEOUT: {
1670		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
1671
1672		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
1673			error = EINVAL;
1674			goto fail;
1675		}
1676		pt->seconds = pf_default_rule.timeout[pt->timeout];
1677		break;
1678	}
1679
1680	case DIOCGETLIMIT: {
1681		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
1682
1683		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1684			error = EINVAL;
1685			goto fail;
1686		}
1687		pl->limit = pf_pool_limits[pl->index].limit;
1688		break;
1689	}
1690
1691	case DIOCSETLIMIT: {
1692		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
1693		int			 old_limit;
1694
1695		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1696			error = EINVAL;
1697			goto fail;
1698		}
1699#if defined(__FreeBSD__)
1700		uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit);
1701#else
1702		if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
1703		    pl->limit, NULL, 0) != 0) {
1704			error = EBUSY;
1705			goto fail;
1706		}
1707#endif
1708		old_limit = pf_pool_limits[pl->index].limit;
1709		pf_pool_limits[pl->index].limit = pl->limit;
1710		pl->limit = old_limit;
1711		break;
1712	}
1713
1714	case DIOCSETDEBUG: {
1715		u_int32_t	*level = (u_int32_t *)addr;
1716
1717		pf_status.debug = *level;
1718		break;
1719	}
1720
1721	case DIOCCLRRULECTRS: {
1722		struct pf_ruleset	*ruleset = &pf_main_ruleset;
1723		struct pf_rule		*rule;
1724
1725		s = splsoftnet();
1726		TAILQ_FOREACH(rule,
1727		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
1728			rule->evaluations = rule->packets =
1729			    rule->bytes = 0;
1730		splx(s);
1731		break;
1732	}
1733
1734#if defined(__FreeBSD__)
1735	case DIOCGIFSPEED: {
1736		struct pf_ifspeed	*psp = (struct pf_ifspeed *)addr;
1737		struct pf_ifspeed	ps;
1738		struct ifnet		*ifp;
1739
1740		if (psp->ifname[0] != 0) {
1741			/* Can we completely trust user-land? */
1742			strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
1743			ifp = ifunit(ps.ifname);
1744			if (ifp )
1745				psp->baudrate = ifp->if_baudrate;
1746			else
1747				error = EINVAL;
1748		} else
1749			error = EINVAL;
1750		break;
1751	}
1752#endif /* __FreeBSD__ */
1753
1754#ifdef ALTQ
1755	case DIOCSTARTALTQ: {
1756		struct pf_altq		*altq;
1757		struct ifnet		*ifp;
1758		struct tb_profile	 tb;
1759
1760		/* enable all altq interfaces on active list */
1761		s = splsoftnet();
1762		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1763			if (altq->qname[0] == 0) {
1764				if ((ifp = ifunit(altq->ifname)) == NULL) {
1765					error = EINVAL;
1766					break;
1767				}
1768				if (ifp->if_snd.altq_type != ALTQT_NONE)
1769					error = altq_enable(&ifp->if_snd);
1770				if (error != 0)
1771					break;
1772				/* set tokenbucket regulator */
1773				tb.rate = altq->ifbandwidth;
1774				tb.depth = altq->tbrsize;
1775				error = tbr_set(&ifp->if_snd, &tb);
1776				if (error != 0)
1777					break;
1778			}
1779		}
1780#if defined(__FreeBSD__)
1781		if (error == 0) {
1782			mtx_lock(&pf_altq_mtx);
1783			pfaltq_running = 1;
1784			mtx_unlock(&pf_altq_mtx);
1785		}
1786#else
1787		if (error == 0)
1788			pfaltq_running = 1;
1789#endif
1790		splx(s);
1791		DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
1792		break;
1793	}
1794
1795	case DIOCSTOPALTQ: {
1796		struct pf_altq		*altq;
1797		struct ifnet		*ifp;
1798		struct tb_profile	 tb;
1799		int			 err;
1800
1801		/* disable all altq interfaces on active list */
1802		s = splsoftnet();
1803		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1804			if (altq->qname[0] == 0) {
1805				if ((ifp = ifunit(altq->ifname)) == NULL) {
1806					error = EINVAL;
1807					break;
1808				}
1809				if (ifp->if_snd.altq_type != ALTQT_NONE) {
1810					err = altq_disable(&ifp->if_snd);
1811					if (err != 0 && error == 0)
1812						error = err;
1813				}
1814				/* clear tokenbucket regulator */
1815				tb.rate = 0;
1816				err = tbr_set(&ifp->if_snd, &tb);
1817				if (err != 0 && error == 0)
1818					error = err;
1819			}
1820		}
1821#if defined(__FreeBSD__)
1822		if (error == 0) {
1823			mtx_lock(&pf_altq_mtx);
1824			pfaltq_running = 0;
1825			mtx_unlock(&pf_altq_mtx);
1826		}
1827#else
1828		if (error == 0)
1829			pfaltq_running = 0;
1830#endif
1831		splx(s);
1832		DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
1833		break;
1834	}
1835
1836	case DIOCBEGINALTQS: {
1837		u_int32_t	*ticket = (u_int32_t *)addr;
1838		struct pf_altq	*altq;
1839
1840		/* Purge the old altq list */
1841		while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1842			TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1843			if (altq->qname[0] == 0) {
1844				/* detach and destroy the discipline */
1845#if defined(__FreeBSD__)
1846				PF_UNLOCK();
1847#endif
1848				error = altq_remove(altq);
1849#if defined(__FreeBSD__)
1850				PF_LOCK();
1851#endif
1852			}
1853			pool_put(&pf_altq_pl, altq);
1854		}
1855		*ticket = ++ticket_altqs_inactive;
1856		break;
1857	}
1858
1859	case DIOCADDALTQ: {
1860		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
1861		struct pf_altq		*altq, *a;
1862
1863		if (pa->ticket != ticket_altqs_inactive) {
1864			error = EBUSY;
1865			break;
1866		}
1867		altq = pool_get(&pf_altq_pl, PR_NOWAIT);
1868		if (altq == NULL) {
1869			error = ENOMEM;
1870			break;
1871		}
1872		bcopy(&pa->altq, altq, sizeof(struct pf_altq));
1873
1874		/*
1875		 * if this is for a queue, find the discipline and
1876		 * copy the necessary fields
1877		 */
1878		if (altq->qname[0] != 0) {
1879			TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
1880				if (strncmp(a->ifname, altq->ifname,
1881				    IFNAMSIZ) == 0 && a->qname[0] == 0) {
1882					altq->altq_disc = a->altq_disc;
1883					break;
1884				}
1885			}
1886		}
1887
1888#if defined(__FreeBSD__)
1889		PF_UNLOCK();
1890#endif
1891		error = altq_add(altq);
1892#if defined(__FreeBSD__)
1893		PF_LOCK();
1894#endif
1895		if (error) {
1896			pool_put(&pf_altq_pl, altq);
1897			break;
1898		}
1899
1900		TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
1901		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1902		break;
1903	}
1904
1905	case DIOCCOMMITALTQS: {
1906		u_int32_t		*ticket = (u_int32_t *)addr;
1907		struct pf_altqqueue	*old_altqs;
1908		struct pf_altq		*altq;
1909		struct pf_anchor	*anchor;
1910		struct pf_ruleset	*ruleset;
1911		int			 err;
1912
1913		if (*ticket != ticket_altqs_inactive) {
1914			error = EBUSY;
1915			break;
1916		}
1917
1918		/* Swap altqs, keep the old. */
1919		s = splsoftnet();
1920		old_altqs = pf_altqs_active;
1921		pf_altqs_active = pf_altqs_inactive;
1922		pf_altqs_inactive = old_altqs;
1923		ticket_altqs_active = ticket_altqs_inactive;
1924
1925		/* Attach new disciplines */
1926		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1927			if (altq->qname[0] == 0) {
1928				/* attach the discipline */
1929#if defined(__FreeBSD__)
1930				PF_UNLOCK();
1931#endif
1932				error = altq_pfattach(altq);
1933#if defined(__FreeBSD__)
1934				PF_LOCK();
1935#endif
1936				if (error) {
1937					splx(s);
1938					goto fail;
1939				}
1940			}
1941		}
1942
1943		/* Purge the old altq list */
1944		while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1945			TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1946			if (altq->qname[0] == 0) {
1947				/* detach and destroy the discipline */
1948#if defined(__FreeBSD__)
1949				PF_UNLOCK();
1950#endif
1951				err = altq_pfdetach(altq);
1952				if (err != 0 && error == 0)
1953					error = err;
1954				err = altq_remove(altq);
1955				if (err != 0 && error == 0)
1956					error = err;
1957#if defined(__FreeBSD__)
1958				PF_LOCK();
1959#endif
1960			}
1961			pool_put(&pf_altq_pl, altq);
1962		}
1963		splx(s);
1964
1965		/* update queue IDs */
1966		pf_rule_set_qid(
1967		    pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
1968		TAILQ_FOREACH(anchor, &pf_anchors, entries) {
1969			TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
1970				pf_rule_set_qid(
1971				    ruleset->rules[PF_RULESET_FILTER].active.ptr
1972				    );
1973			}
1974		}
1975		break;
1976	}
1977
1978	case DIOCGETALTQS: {
1979		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
1980		struct pf_altq		*altq;
1981
1982		pa->nr = 0;
1983		s = splsoftnet();
1984		TAILQ_FOREACH(altq, pf_altqs_active, entries)
1985			pa->nr++;
1986		pa->ticket = ticket_altqs_active;
1987		splx(s);
1988		break;
1989	}
1990
1991	case DIOCGETALTQ: {
1992		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
1993		struct pf_altq		*altq;
1994		u_int32_t		 nr;
1995
1996		if (pa->ticket != ticket_altqs_active) {
1997			error = EBUSY;
1998			break;
1999		}
2000		nr = 0;
2001		s = splsoftnet();
2002		altq = TAILQ_FIRST(pf_altqs_active);
2003		while ((altq != NULL) && (nr < pa->nr)) {
2004			altq = TAILQ_NEXT(altq, entries);
2005			nr++;
2006		}
2007		if (altq == NULL) {
2008			error = EBUSY;
2009			splx(s);
2010			break;
2011		}
2012		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
2013		splx(s);
2014		break;
2015	}
2016
2017	case DIOCCHANGEALTQ:
2018		/* CHANGEALTQ not supported yet! */
2019		error = ENODEV;
2020		break;
2021
2022	case DIOCGETQSTATS: {
2023		struct pfioc_qstats	*pq = (struct pfioc_qstats *)addr;
2024		struct pf_altq		*altq;
2025		u_int32_t		 nr;
2026		int			 nbytes;
2027
2028		if (pq->ticket != ticket_altqs_active) {
2029			error = EBUSY;
2030			break;
2031		}
2032		nbytes = pq->nbytes;
2033		nr = 0;
2034		s = splsoftnet();
2035		altq = TAILQ_FIRST(pf_altqs_active);
2036		while ((altq != NULL) && (nr < pq->nr)) {
2037			altq = TAILQ_NEXT(altq, entries);
2038			nr++;
2039		}
2040		if (altq == NULL) {
2041			error = EBUSY;
2042			splx(s);
2043			break;
2044		}
2045#if defined(__FreeBSD__)
2046		PF_UNLOCK();
2047#endif
2048		error = altq_getqstats(altq, pq->buf, &nbytes);
2049#if defined(__FreeBSD__)
2050		PF_LOCK();
2051#endif
2052		splx(s);
2053		if (error == 0) {
2054			pq->scheduler = altq->scheduler;
2055			pq->nbytes = nbytes;
2056		}
2057		break;
2058	}
2059#endif /* ALTQ */
2060
2061	case DIOCBEGINADDRS: {
2062		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2063
2064		pf_empty_pool(&pf_pabuf);
2065		pp->ticket = ++ticket_pabuf;
2066		break;
2067	}
2068
2069	case DIOCADDADDR: {
2070		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2071
2072#ifndef INET
2073		if (pp->af == AF_INET) {
2074			error = EAFNOSUPPORT;
2075			break;
2076		}
2077#endif /* INET */
2078#ifndef INET6
2079		if (pp->af == AF_INET6) {
2080			error = EAFNOSUPPORT;
2081			break;
2082		}
2083#endif /* INET6 */
2084		if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
2085		    pp->addr.addr.type != PF_ADDR_DYNIFTL &&
2086		    pp->addr.addr.type != PF_ADDR_TABLE) {
2087			error = EINVAL;
2088			break;
2089		}
2090		pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
2091		if (pa == NULL) {
2092			error = ENOMEM;
2093			break;
2094		}
2095		bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
2096		if (pa->ifname[0]) {
2097			pa->ifp = ifunit(pa->ifname);
2098			if (pa->ifp == NULL) {
2099				pool_put(&pf_pooladdr_pl, pa);
2100				error = EINVAL;
2101				break;
2102			}
2103		}
2104		if (pf_dynaddr_setup(&pa->addr, pp->af)) {
2105			pf_dynaddr_remove(&pa->addr);
2106			pool_put(&pf_pooladdr_pl, pa);
2107			error = EINVAL;
2108			break;
2109		}
2110		TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
2111		break;
2112	}
2113
2114	case DIOCGETADDRS: {
2115		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2116
2117		pp->nr = 0;
2118		s = splsoftnet();
2119		pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
2120		    pp->r_action, pp->r_num, 0, 1, 0);
2121		if (pool == NULL) {
2122			error = EBUSY;
2123			splx(s);
2124			break;
2125		}
2126		TAILQ_FOREACH(pa, &pool->list, entries)
2127			pp->nr++;
2128		splx(s);
2129		break;
2130	}
2131
2132	case DIOCGETADDR: {
2133		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2134		u_int32_t		 nr = 0;
2135
2136		s = splsoftnet();
2137		pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,
2138		    pp->r_action, pp->r_num, 0, 1, 1);
2139		if (pool == NULL) {
2140			error = EBUSY;
2141			splx(s);
2142			break;
2143		}
2144		pa = TAILQ_FIRST(&pool->list);
2145		while ((pa != NULL) && (nr < pp->nr)) {
2146			pa = TAILQ_NEXT(pa, entries);
2147			nr++;
2148		}
2149		if (pa == NULL) {
2150			error = EBUSY;
2151			splx(s);
2152			break;
2153		}
2154		bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
2155		pf_dynaddr_copyout(&pp->addr.addr);
2156		pf_tbladdr_copyout(&pp->addr.addr);
2157		splx(s);
2158		break;
2159	}
2160
2161	case DIOCCHANGEADDR: {
2162		struct pfioc_pooladdr	*pca = (struct pfioc_pooladdr *)addr;
2163		struct pf_pooladdr	*oldpa = NULL, *newpa = NULL;
2164		struct pf_ruleset	*ruleset;
2165
2166		if (pca->action < PF_CHANGE_ADD_HEAD ||
2167		    pca->action > PF_CHANGE_REMOVE) {
2168			error = EINVAL;
2169			break;
2170		}
2171		if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
2172		    pca->addr.addr.type != PF_ADDR_DYNIFTL &&
2173		    pca->addr.addr.type != PF_ADDR_TABLE) {
2174			error = EINVAL;
2175			break;
2176		}
2177
2178		ruleset = pf_find_ruleset(pca->anchor, pca->ruleset);
2179		if (ruleset == NULL) {
2180			error = EBUSY;
2181			break;
2182		}
2183		pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket,
2184		    pca->r_action, pca->r_num, pca->r_last, 1, 1);
2185		if (pool == NULL) {
2186			error = EBUSY;
2187			break;
2188		}
2189		if (pca->action != PF_CHANGE_REMOVE) {
2190			newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
2191			if (newpa == NULL) {
2192				error = ENOMEM;
2193				break;
2194			}
2195			bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
2196#ifndef INET
2197			if (pca->af == AF_INET) {
2198				pool_put(&pf_pooladdr_pl, newpa);
2199				error = EAFNOSUPPORT;
2200				break;
2201			}
2202#endif /* INET */
2203#ifndef INET6
2204			if (pca->af == AF_INET6) {
2205				pool_put(&pf_pooladdr_pl, newpa);
2206				error = EAFNOSUPPORT;
2207				break;
2208			}
2209#endif /* INET6 */
2210			if (newpa->ifname[0]) {
2211				newpa->ifp = ifunit(newpa->ifname);
2212				if (newpa->ifp == NULL) {
2213					pool_put(&pf_pooladdr_pl, newpa);
2214					error = EINVAL;
2215					break;
2216				}
2217			} else
2218				newpa->ifp = NULL;
2219			if (pf_dynaddr_setup(&newpa->addr, pca->af) ||
2220			    pf_tbladdr_setup(ruleset, &newpa->addr)) {
2221				pf_dynaddr_remove(&newpa->addr);
2222				pool_put(&pf_pooladdr_pl, newpa);
2223				error = EINVAL;
2224				break;
2225			}
2226		}
2227
2228		s = splsoftnet();
2229
2230		if (pca->action == PF_CHANGE_ADD_HEAD)
2231			oldpa = TAILQ_FIRST(&pool->list);
2232		else if (pca->action == PF_CHANGE_ADD_TAIL)
2233			oldpa = TAILQ_LAST(&pool->list, pf_palist);
2234		else {
2235			int	i = 0;
2236
2237			oldpa = TAILQ_FIRST(&pool->list);
2238			while ((oldpa != NULL) && (i < pca->nr)) {
2239				oldpa = TAILQ_NEXT(oldpa, entries);
2240				i++;
2241			}
2242			if (oldpa == NULL) {
2243				error = EINVAL;
2244				splx(s);
2245				break;
2246			}
2247		}
2248
2249		if (pca->action == PF_CHANGE_REMOVE) {
2250			TAILQ_REMOVE(&pool->list, oldpa, entries);
2251			pf_dynaddr_remove(&oldpa->addr);
2252			pf_tbladdr_remove(&oldpa->addr);
2253			pool_put(&pf_pooladdr_pl, oldpa);
2254		} else {
2255			if (oldpa == NULL)
2256				TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
2257			else if (pca->action == PF_CHANGE_ADD_HEAD ||
2258			    pca->action == PF_CHANGE_ADD_BEFORE)
2259				TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
2260			else
2261				TAILQ_INSERT_AFTER(&pool->list, oldpa,
2262				    newpa, entries);
2263		}
2264
2265		pool->cur = TAILQ_FIRST(&pool->list);
2266		PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
2267		    pca->af);
2268		splx(s);
2269		break;
2270	}
2271
2272	case DIOCGETANCHORS: {
2273		struct pfioc_anchor	*pa = (struct pfioc_anchor *)addr;
2274		struct pf_anchor	*anchor;
2275
2276		pa->nr = 0;
2277		TAILQ_FOREACH(anchor, &pf_anchors, entries)
2278			pa->nr++;
2279		break;
2280	}
2281
2282	case DIOCGETANCHOR: {
2283		struct pfioc_anchor	*pa = (struct pfioc_anchor *)addr;
2284		struct pf_anchor	*anchor;
2285		u_int32_t		 nr = 0;
2286
2287		anchor = TAILQ_FIRST(&pf_anchors);
2288		while (anchor != NULL && nr < pa->nr) {
2289			anchor = TAILQ_NEXT(anchor, entries);
2290			nr++;
2291		}
2292		if (anchor == NULL)
2293			error = EBUSY;
2294		else
2295			bcopy(anchor->name, pa->name, sizeof(pa->name));
2296		break;
2297	}
2298
2299	case DIOCGETRULESETS: {
2300		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
2301		struct pf_anchor	*anchor;
2302		struct pf_ruleset	*ruleset;
2303
2304		pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0;
2305		if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
2306			error = EINVAL;
2307			break;
2308		}
2309		pr->nr = 0;
2310		TAILQ_FOREACH(ruleset, &anchor->rulesets, entries)
2311			pr->nr++;
2312		break;
2313	}
2314
2315	case DIOCGETRULESET: {
2316		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
2317		struct pf_anchor	*anchor;
2318		struct pf_ruleset	*ruleset;
2319		u_int32_t		 nr = 0;
2320
2321		if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {
2322			error = EINVAL;
2323			break;
2324		}
2325		ruleset = TAILQ_FIRST(&anchor->rulesets);
2326		while (ruleset != NULL && nr < pr->nr) {
2327			ruleset = TAILQ_NEXT(ruleset, entries);
2328			nr++;
2329		}
2330		if (ruleset == NULL)
2331			error = EBUSY;
2332		else
2333			bcopy(ruleset->name, pr->name, sizeof(pr->name));
2334		break;
2335	}
2336
2337	case DIOCRCLRTABLES: {
2338		struct pfioc_table *io = (struct pfioc_table *)addr;
2339
2340		if (io->pfrio_esize != 0) {
2341			error = ENODEV;
2342			break;
2343		}
2344		error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
2345		    io->pfrio_flags);
2346		break;
2347	}
2348
2349	case DIOCRADDTABLES: {
2350		struct pfioc_table *io = (struct pfioc_table *)addr;
2351
2352		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2353			error = ENODEV;
2354			break;
2355		}
2356		error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
2357		    &io->pfrio_nadd, io->pfrio_flags);
2358		break;
2359	}
2360
2361	case DIOCRDELTABLES: {
2362		struct pfioc_table *io = (struct pfioc_table *)addr;
2363
2364		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2365			error = ENODEV;
2366			break;
2367		}
2368		error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
2369		    &io->pfrio_ndel, io->pfrio_flags);
2370		break;
2371	}
2372
2373	case DIOCRGETTABLES: {
2374		struct pfioc_table *io = (struct pfioc_table *)addr;
2375
2376		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2377			error = ENODEV;
2378			break;
2379		}
2380		error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
2381		    &io->pfrio_size, io->pfrio_flags);
2382		break;
2383	}
2384
2385	case DIOCRGETTSTATS: {
2386		struct pfioc_table *io = (struct pfioc_table *)addr;
2387
2388		if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
2389			error = ENODEV;
2390			break;
2391		}
2392		error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
2393		    &io->pfrio_size, io->pfrio_flags);
2394		break;
2395	}
2396
2397	case DIOCRCLRTSTATS: {
2398		struct pfioc_table *io = (struct pfioc_table *)addr;
2399
2400		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2401			error = ENODEV;
2402			break;
2403		}
2404		error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
2405		    &io->pfrio_nzero, io->pfrio_flags);
2406		break;
2407	}
2408
2409	case DIOCRSETTFLAGS: {
2410		struct pfioc_table *io = (struct pfioc_table *)addr;
2411
2412		if (io->pfrio_esize != sizeof(struct pfr_table)) {
2413			error = ENODEV;
2414			break;
2415		}
2416		error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
2417		    io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
2418		    &io->pfrio_ndel, io->pfrio_flags);
2419		break;
2420	}
2421
2422	case DIOCRCLRADDRS: {
2423		struct pfioc_table *io = (struct pfioc_table *)addr;
2424
2425		if (io->pfrio_esize != 0) {
2426			error = ENODEV;
2427			break;
2428		}
2429		error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
2430		    io->pfrio_flags);
2431		break;
2432	}
2433
2434	case DIOCRADDADDRS: {
2435		struct pfioc_table *io = (struct pfioc_table *)addr;
2436
2437		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2438			error = ENODEV;
2439			break;
2440		}
2441		error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
2442		    io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags);
2443		break;
2444	}
2445
2446	case DIOCRDELADDRS: {
2447		struct pfioc_table *io = (struct pfioc_table *)addr;
2448
2449		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2450			error = ENODEV;
2451			break;
2452		}
2453		error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
2454		    io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags);
2455		break;
2456	}
2457
2458	case DIOCRSETADDRS: {
2459		struct pfioc_table *io = (struct pfioc_table *)addr;
2460
2461		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2462			error = ENODEV;
2463			break;
2464		}
2465		error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
2466		    io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
2467		    &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags);
2468		break;
2469	}
2470
2471	case DIOCRGETADDRS: {
2472		struct pfioc_table *io = (struct pfioc_table *)addr;
2473
2474		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2475			error = ENODEV;
2476			break;
2477		}
2478		error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
2479		    &io->pfrio_size, io->pfrio_flags);
2480		break;
2481	}
2482
2483	case DIOCRGETASTATS: {
2484		struct pfioc_table *io = (struct pfioc_table *)addr;
2485
2486		if (io->pfrio_esize != sizeof(struct pfr_astats)) {
2487			error = ENODEV;
2488			break;
2489		}
2490		error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
2491		    &io->pfrio_size, io->pfrio_flags);
2492		break;
2493	}
2494
2495	case DIOCRCLRASTATS: {
2496		struct pfioc_table *io = (struct pfioc_table *)addr;
2497
2498		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2499			error = ENODEV;
2500			break;
2501		}
2502		error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
2503		    io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags);
2504		break;
2505	}
2506
2507	case DIOCRTSTADDRS: {
2508		struct pfioc_table *io = (struct pfioc_table *)addr;
2509
2510		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2511			error = ENODEV;
2512			break;
2513		}
2514		error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
2515		    io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags);
2516		break;
2517	}
2518
2519	case DIOCRINABEGIN: {
2520		struct pfioc_table *io = (struct pfioc_table *)addr;
2521
2522		if (io->pfrio_esize != 0) {
2523			error = ENODEV;
2524			break;
2525		}
2526		error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket,
2527		    &io->pfrio_ndel, io->pfrio_flags);
2528		break;
2529	}
2530
2531	case DIOCRINACOMMIT: {
2532		struct pfioc_table *io = (struct pfioc_table *)addr;
2533
2534		if (io->pfrio_esize != 0) {
2535			error = ENODEV;
2536			break;
2537		}
2538		error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket,
2539		    &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags);
2540		break;
2541	}
2542
2543	case DIOCRINADEFINE: {
2544		struct pfioc_table *io = (struct pfioc_table *)addr;
2545
2546		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
2547			error = ENODEV;
2548			break;
2549		}
2550		error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
2551		    io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
2552		    io->pfrio_ticket, io->pfrio_flags);
2553		break;
2554	}
2555
2556	case DIOCOSFPFLUSH:
2557		s = splsoftnet();
2558		pf_osfp_flush();
2559		splx(s);
2560		break;
2561
2562	case DIOCOSFPADD: {
2563		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2564		s = splsoftnet();
2565		error = pf_osfp_add(io);
2566		splx(s);
2567		break;
2568	}
2569
2570	case DIOCOSFPGET: {
2571		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
2572		s = splsoftnet();
2573		error = pf_osfp_get(io);
2574		splx(s);
2575		break;
2576	}
2577
2578	default:
2579		error = ENODEV;
2580		break;
2581	}
2582fail:
2583#if defined(__FreeBSD__)
2584	PF_UNLOCK();
2585#endif
2586	return (error);
2587}
2588
2589#if defined(__FreeBSD__)
2590/*
2591 * XXX - Check for version missmatch!!!
2592 */
2593static int
2594pf_beginrules(void *addr)
2595{
2596	struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
2597	struct pf_ruleset	*ruleset;
2598	struct pf_rule		*rule;
2599	int			 rs_num;
2600	int			 error = 0;
2601
2602	do {
2603		ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
2604		if (ruleset == NULL) {
2605			error = EINVAL;
2606			break;
2607		}
2608		rs_num = pf_get_ruleset_number(pr->rule.action);
2609		if (rs_num >= PF_RULESET_MAX) {
2610			error = EINVAL;
2611			break;
2612		}
2613		while ((rule =
2614		    TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
2615			pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
2616		pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
2617	} while(0);
2618
2619	return (error);
2620}
2621
2622static int
2623pf_commitrules(void *addr)
2624{
2625	struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
2626	struct pf_ruleset	*ruleset;
2627	struct pf_rulequeue	*old_rules;
2628	struct pf_rule		*rule;
2629	int			 rs_num, s;
2630	int			 error = 0;
2631
2632	do {
2633		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
2634		if (ruleset == NULL) {
2635			error = EINVAL;
2636			break;
2637		}
2638		rs_num = pf_get_ruleset_number(pr->rule.action);
2639		if (rs_num >= PF_RULESET_MAX) {
2640			error = EINVAL;
2641			break;
2642		}
2643		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
2644			error = EBUSY;
2645			break;
2646		}
2647
2648#ifdef ALTQ
2649		/* set queue IDs */
2650		if (rs_num == PF_RULESET_FILTER)
2651			pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
2652#endif
2653
2654		/* Swap rules, keep the old. */
2655		s = splsoftnet();
2656		old_rules = ruleset->rules[rs_num].active.ptr;
2657		ruleset->rules[rs_num].active.ptr =
2658		    ruleset->rules[rs_num].inactive.ptr;
2659		ruleset->rules[rs_num].inactive.ptr = old_rules;
2660		ruleset->rules[rs_num].active.ticket =
2661		    ruleset->rules[rs_num].inactive.ticket;
2662		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
2663
2664		/* Purge the old rule list. */
2665		while ((rule = TAILQ_FIRST(old_rules)) != NULL)
2666			pf_rm_rule(old_rules, rule);
2667		pf_remove_if_empty_ruleset(ruleset);
2668		pf_update_anchor_rules();
2669		splx(s);
2670	} while (0);
2671
2672	return (error);
2673}
2674
2675#if defined(ALTQ)
2676static int
2677pf_beginaltqs(void *addr)
2678{
2679	u_int32_t	*ticket = (u_int32_t *)addr;
2680	struct pf_altq	*altq;
2681	int		error = 0;
2682
2683	/* Purge the old altq list */
2684	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
2685		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
2686		if (altq->qname[0] == 0) {
2687#if defined(__FreeBSD__)
2688			PF_UNLOCK();
2689#endif
2690			/* detach and destroy the discipline */
2691			error = altq_remove(altq);
2692#if defined(__FreeBSD__)
2693			PF_LOCK();
2694#endif
2695		}
2696		uma_zfree(pf_altq_pl, altq);
2697	}
2698	*ticket = ++ticket_altqs_inactive;
2699
2700	return (error);
2701}
2702
2703static int
2704pf_commitaltqs(void *addr)
2705{
2706	u_int32_t		*ticket = (u_int32_t *)addr;
2707	struct pf_altqqueue	*old_altqs;
2708	struct pf_altq		*altq;
2709	struct pf_anchor	*anchor;
2710	struct pf_ruleset	*ruleset;
2711	int			 err;
2712	int			 s;
2713	int			 error = 0;
2714
2715	do {
2716		if (*ticket != ticket_altqs_inactive) {
2717			error = EBUSY;
2718			break;
2719		}
2720
2721		/* Swap altqs, keep the old. */
2722		s = splsoftnet();
2723		old_altqs = pf_altqs_active;
2724		pf_altqs_active = pf_altqs_inactive;
2725		pf_altqs_inactive = old_altqs;
2726		ticket_altqs_active = ticket_altqs_inactive;
2727
2728		/* Attach new disciplines */
2729		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2730			if (altq->qname[0] == 0) {
2731				/* attach the discipline */
2732#if defined(__FreeBSD__)
2733				PF_UNLOCK();
2734#endif
2735				error = altq_pfattach(altq);
2736#if defined(__FreeBSD__)
2737				PF_LOCK();
2738#endif
2739				if (error) {
2740					splx(s);
2741					goto altq_fail;
2742				}
2743			}
2744		}
2745
2746		/* Purge the old altq list */
2747		while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
2748			TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
2749			if (altq->qname[0] == 0) {
2750				/* detach and destroy the discipline */
2751#if defined(__FreeBSD__)
2752				PF_UNLOCK();
2753#endif
2754				err = altq_pfdetach(altq);
2755				if (err != 0 && error == 0)
2756					error = err;
2757				err = altq_remove(altq);
2758				if (err != 0 && error == 0)
2759					error = err;
2760#if defined(__FreeBSD__)
2761				PF_LOCK();
2762#endif
2763			}
2764			uma_zfree(pf_altq_pl, altq);
2765		}
2766		splx(s);
2767
2768		/* update queue IDs */
2769		pf_rule_set_qid(
2770		    pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
2771		TAILQ_FOREACH(anchor, &pf_anchors, entries) {
2772			TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
2773				pf_rule_set_qid(
2774				    ruleset->rules[PF_RULESET_FILTER].active.ptr
2775				    );
2776			}
2777		}
2778	} while (0);
2779
2780altq_fail:
2781
2782	return (error);
2783}
2784
2785static int
2786pf_stopaltq(void)
2787{
2788	struct pf_altq		*altq;
2789	struct ifnet		*ifp;
2790	struct tb_profile	 tb;
2791	int			 err;
2792	int			 s;
2793	int			 error = 0;
2794
2795	do {
2796		/* disable all altq interfaces on active list */
2797		s = splsoftnet();
2798		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2799			if (altq->qname[0] == 0) {
2800				if ((ifp = ifunit(altq->ifname)) == NULL) {
2801					error = EINVAL;
2802					break;
2803				}
2804				if (ifp->if_snd.altq_type != ALTQT_NONE) {
2805					err = altq_disable(&ifp->if_snd);
2806					if (err != 0 && error == 0)
2807						error = err;
2808				}
2809				/* clear tokenbucket regulator */
2810				tb.rate = 0;
2811				err = tbr_set(&ifp->if_snd, &tb);
2812				if (err != 0 && error == 0)
2813					error = err;
2814			}
2815		}
2816#if defined(__FreeBSD__)
2817		if (error == 0) {
2818			mtx_lock(&pf_altq_mtx);
2819			pfaltq_running = 0;
2820			mtx_unlock(&pf_altq_mtx);
2821		}
2822#else
2823		if (error == 0)
2824			pfaltq_running = 0;
2825#endif
2826		splx(s);
2827	} while (0);
2828
2829	return (error);
2830}
2831#endif
2832
2833static void
2834pf_clearstates(void)
2835{
2836	struct pf_tree_node	*n;
2837	int s;
2838
2839	s = splsoftnet();
2840	RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
2841		n->state->timeout = PFTM_PURGE;
2842	pf_purge_expired_states();
2843	pf_status.states = 0;
2844	splx(s);
2845}
2846
2847static int
2848pf_clear_tables(void *addr)
2849{
2850	struct pfioc_table *io = (struct pfioc_table *)addr;
2851	int error;
2852
2853	error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
2854	    io->pfrio_flags);
2855
2856	return (error);
2857}
2858
2859static int
2860shutdown_pf(void)
2861{
2862	struct pfioc_rule pr;
2863#if defined(ALTQ)
2864	struct pfioc_altq pa;
2865#endif
2866	struct pfioc_table io;
2867	int error = 0;
2868
2869	callout_stop(&pf_expire_to);
2870
2871	PF_LOCK();
2872	pf_status.running = 0;
2873	do {
2874#if defined(ALTQ)
2875		if ((error = pf_stopaltq())) {
2876			DPFPRINTF(PF_DEBUG_MISC,
2877			    ("ALTQ: stop(%i)\n", error));
2878			break;
2879		}
2880#endif
2881		bzero(&pr, sizeof(pr));
2882		pr.rule.action = PF_SCRUB;
2883		if ((error = pf_beginrules(&pr))) {
2884			DPFPRINTF(PF_DEBUG_MISC,
2885			    ("PF_SCRUB: begin(%i)\n", error));
2886			break;
2887		}
2888		if ((error = pf_commitrules(&pr))) {
2889			DPFPRINTF(PF_DEBUG_MISC,
2890			    ("PF_SCRUB: commit(%i)\n", error));
2891			break;
2892		}
2893
2894		pr.rule.action = PF_PASS;
2895		if ((error = pf_beginrules(&pr))) {
2896			DPFPRINTF(PF_DEBUG_MISC,
2897			    ("PF_PASS: begin(%i)\n", error));
2898			break;
2899		}
2900		if ((error = pf_commitrules(&pr))) {
2901			DPFPRINTF(PF_DEBUG_MISC,
2902			    ("PF_PASS: commit(%i)\n", error));
2903			break;
2904		}
2905
2906/*
2907 * XXX not sure, but can't hurt:
2908 */
2909		bzero(&pr, sizeof(pr));
2910		pr.rule.action = PF_NAT;
2911		if ((error = pf_beginrules(&pr))) {
2912			DPFPRINTF(PF_DEBUG_MISC,
2913			    ("PF_NAT: begin(%i)\n", error));
2914			break;
2915		}
2916		if ((error = pf_commitrules(&pr))) {
2917			DPFPRINTF(PF_DEBUG_MISC,
2918			    ("PF_NAT: commit(%i)\n", error));
2919			break;
2920		}
2921
2922		pr.rule.action = PF_BINAT;
2923		if ((error = pf_beginrules(&pr))) {
2924			DPFPRINTF(PF_DEBUG_MISC,
2925			    ("PF_BINAT: begin(%i)\n", error));
2926			break;
2927		}
2928		if ((error = pf_commitrules(&pr))) {
2929			DPFPRINTF(PF_DEBUG_MISC,
2930			    ("PF_BINAT: begin(%i)\n", error));
2931			break;
2932		}
2933
2934		pr.rule.action = PF_RDR;
2935		if ((error = pf_beginrules(&pr))) {
2936			DPFPRINTF(PF_DEBUG_MISC,
2937			    ("PF_RDR: begin(%i)\n", error));
2938			break;
2939		}
2940		if ((error = pf_commitrules(&pr))) {
2941			DPFPRINTF(PF_DEBUG_MISC,
2942			    ("PF_RDR: commit(%i)\n", error));
2943			break;
2944		}
2945
2946#if defined(ALTQ)
2947		bzero(&pa, sizeof(pa));
2948		if ((error = pf_beginaltqs(&pa))) {
2949			DPFPRINTF(PF_DEBUG_MISC,
2950			    ("ALTQ: begin(%i)\n", error));
2951			break;
2952		}
2953		if ((error = pf_commitaltqs(&pa))) {
2954			DPFPRINTF(PF_DEBUG_MISC,
2955			    ("ALTQ: commit(%i)\n", error));
2956			break;
2957		}
2958#endif
2959		pf_clearstates();
2960
2961		bzero(&io, sizeof(io));
2962		if ((error = pf_clear_tables(&io))) {
2963			DPFPRINTF(PF_DEBUG_MISC,
2964			    ("TABLES: clear(%i)\n", error));
2965			break;
2966		}
2967		pf_osfp_flush();
2968	} while(0);
2969
2970	PF_UNLOCK();
2971        return (error);
2972}
2973
2974static int
2975#if (__FreeBSD_version < 501108)
2976pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
2977#else
2978pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
2979#endif
2980{
2981	/*
2982	 * XXX Wed Jul 9 22:03:16 2003 UTC
2983	 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
2984	 * in network stack. OpenBSD's network stack have converted
2985	 * ip_len/ip_off to host byte order frist as FreeBSD.
2986	 * Now this is not true anymore , so we should convert back to network
2987	 * byte order.
2988	 */
2989	struct ip *h = NULL;
2990	int chk;
2991
2992	if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) {
2993		/* if m_pkthdr.len is less than ip header, pf will handle. */
2994		h = mtod(*m, struct ip *);
2995	        HTONS(h->ip_len);
2996	        HTONS(h->ip_off);
2997	}
2998	chk = pf_test(PF_IN, ifp, m);
2999	if (chk && *m) {
3000		m_freem(*m);
3001		*m = NULL;
3002	}
3003	if (*m != NULL) {
3004		/* pf_test can change ip header location */
3005		h = mtod(*m, struct ip *);
3006		NTOHS(h->ip_len);
3007		NTOHS(h->ip_off);
3008	}
3009	return chk;
3010}
3011
3012static int
3013#if (__FreeBSD_version < 501108)
3014pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
3015#else
3016pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3017#endif
3018{
3019	/*
3020	 * XXX Wed Jul 9 22:03:16 2003 UTC
3021	 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
3022	 * in network stack. OpenBSD's network stack have converted
3023	 * ip_len/ip_off to host byte order frist as FreeBSD.
3024	 * Now this is not true anymore , so we should convert back to network
3025	 * byte order.
3026	 */
3027	struct ip *h = NULL;
3028	int chk;
3029
3030	/* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
3031	if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
3032		in_delayed_cksum(*m);
3033		(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
3034	}
3035	if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) {
3036		/* if m_pkthdr.len is less than ip header, pf will handle. */
3037		h = mtod(*m, struct ip *);
3038	        HTONS(h->ip_len);
3039	        HTONS(h->ip_off);
3040	}
3041	chk = pf_test(PF_OUT, ifp, m);
3042	if (chk && *m) {
3043		m_freem(*m);
3044		*m = NULL;
3045	}
3046	if (*m != NULL) {
3047		/* pf_test can change ip header location */
3048		h = mtod(*m, struct ip *);
3049		NTOHS(h->ip_len);
3050		NTOHS(h->ip_off);
3051	}
3052	return chk;
3053}
3054
3055#ifdef INET6
3056static int
3057#if (__FreeBSD_version < 501108)
3058pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
3059#else
3060pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3061#endif
3062{
3063	/*
3064	 * IPv6 does not affected ip_len/ip_off byte order changes.
3065	 */
3066	int chk;
3067
3068	chk = pf_test6(PF_IN, ifp, m);
3069	if (chk && *m) {
3070		m_freem(*m);
3071		*m = NULL;
3072	}
3073	return chk;
3074}
3075
3076static int
3077#if (__FreeBSD_version < 501108)
3078pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
3079#else
3080pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
3081#endif
3082{
3083	/*
3084	 * IPv6 does not affected ip_len/ip_off byte order changes.
3085	 */
3086	int chk;
3087
3088	/* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
3089	if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
3090		in_delayed_cksum(*m);
3091		(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
3092	}
3093	chk = pf_test6(PF_OUT, ifp, m);
3094	if (chk && *m) {
3095		m_freem(*m);
3096		*m = NULL;
3097	}
3098	return chk;
3099}
3100#endif /* INET6 */
3101
3102static int
3103hook_pf(void)
3104{
3105#if (__FreeBSD_version >= 501108)
3106	struct pfil_head *pfh_inet;
3107#if defined(INET6)
3108	struct pfil_head *pfh_inet6;
3109#endif
3110#endif
3111
3112	PF_ASSERT(MA_NOTOWNED);
3113
3114	if (pf_pfil_hooked)
3115		return (0);
3116
3117#if (__FreeBSD_version < 501108)
3118	/*
3119	 * XXX
3120	 * There is no easy way to get pfil header pointer with address
3121	 * family such as AF_INET, AF_INET6.
3122	 * Needs direct variable reference.
3123	 */
3124
3125	pfil_add_hook(pf_check_in, PFIL_IN,
3126		&inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3127	pfil_add_hook(pf_check_out, PFIL_OUT,
3128		&inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3129#if defined(INET6)
3130	pfil_add_hook(pf_check6_in, PFIL_IN,
3131		&inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3132	pfil_add_hook(pf_check6_out, PFIL_OUT,
3133		&inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3134#endif
3135#else /* __FreeBSD_version >= 501108 */
3136	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
3137	if (pfh_inet == NULL)
3138		return (ESRCH); /* XXX */
3139	pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
3140	pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
3141#if defined(INET6)
3142	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
3143	if (pfh_inet6 == NULL) {
3144		pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
3145		    pfh_inet);
3146		pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
3147		    pfh_inet);
3148		return (ESRCH); /* XXX */
3149	}
3150	pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
3151	pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
3152#endif
3153#endif /* __FreeBSD_version >= 501108 */
3154
3155	pf_pfil_hooked = 1;
3156	return (0);
3157}
3158
3159static int
3160dehook_pf(void)
3161{
3162#if (__FreeBSD_version >= 501108)
3163	struct pfil_head *pfh_inet;
3164#if defined(INET6)
3165	struct pfil_head *pfh_inet6;
3166#endif
3167#endif
3168
3169	PF_ASSERT(MA_NOTOWNED);
3170
3171	if (pf_pfil_hooked == 0)
3172		return (0);
3173
3174#if (__FreeBSD_version < 501108)
3175	pfil_remove_hook(pf_check_in, PFIL_IN,
3176		&inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3177	pfil_remove_hook(pf_check_out, PFIL_OUT,
3178		&inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
3179#if defined(INET6)
3180	pfil_remove_hook(pf_check6_in, PFIL_IN,
3181		&inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3182	pfil_remove_hook(pf_check6_out, PFIL_OUT,
3183		&inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
3184#endif
3185#else /* __FreeBSD_version >= 501108 */
3186	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
3187	if (pfh_inet == NULL)
3188		return (ESRCH); /* XXX */
3189	pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
3190	    pfh_inet);
3191	pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
3192	    pfh_inet);
3193#if defined(INET6)
3194	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
3195	if (pfh_inet6 == NULL)
3196		return (ESRCH); /* XXX */
3197	pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
3198	    pfh_inet6);
3199	pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
3200	    pfh_inet6);
3201#endif
3202#endif /* __FreeBSD_version >= 501108 */
3203
3204	pf_pfil_hooked = 0;
3205	return (0);
3206}
3207
3208static int
3209pf_load(void)
3210{
3211	init_zone_var();
3212	init_pf_mutex();
3213	pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME);
3214	if (pfattach() < 0) {
3215		destroy_dev(pf_dev);
3216		destroy_pf_mutex();
3217		return (ENOMEM);
3218	}
3219#if defined(ALTQ)
3220	mtx_lock(&pf_altq_mtx);
3221	++pfaltq_ref;
3222	mtx_unlock(&pf_altq_mtx);
3223#endif
3224	return (0);
3225}
3226
3227static int
3228pf_unload(void)
3229{
3230	int error = 0;
3231
3232	PF_LOCK();
3233	pf_status.running = 0;
3234	PF_UNLOCK();
3235	error = dehook_pf();
3236	if (error) {
3237		/*
3238		 * Should not happen!
3239		 * XXX Due to error code ESRCH, kldunload will show
3240		 * a message like 'No such process'.
3241		 */
3242		printf("%s : pfil unregisteration fail\n", __FUNCTION__);
3243		return error;
3244	}
3245	shutdown_pf();
3246	cleanup_pf_zone();
3247	pf_osfp_cleanup();
3248	destroy_dev(pf_dev);
3249#if defined(ALTQ)
3250	mtx_lock(&pf_altq_mtx);
3251	--pfaltq_ref;
3252	mtx_unlock(&pf_altq_mtx);
3253#endif
3254	destroy_pf_mutex();
3255	return error;
3256}
3257
3258static int
3259pf_modevent(module_t mod, int type, void *data)
3260{
3261	int error = 0;
3262
3263	switch(type) {
3264	case MOD_LOAD:
3265		error = pf_load();
3266		break;
3267
3268	case MOD_UNLOAD:
3269		error = pf_unload();
3270		break;
3271	default:
3272		error = EINVAL;
3273		break;
3274	}
3275	return error;
3276}
3277
3278static moduledata_t pf_mod = {
3279	"pf",
3280	pf_modevent,
3281	0
3282};
3283
3284DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
3285MODULE_DEPEND(pf, pflog, PFLOG_MINVER, PFLOG_PREFVER, PFLOG_MAXVER);
3286MODULE_DEPEND(pf, pfsync, PFSYNC_MINVER, PFSYNC_PREFVER, PFSYNC_MAXVER);
3287#if defined(ALTQ)
3288MODULE_DEPEND(pf, pfaltq, PFALTQ_MINVER, PFALTQ_PREFVER, PFALTQ_MAXVER);
3289#endif
3290MODULE_VERSION(pf, PF_MODVER);
3291#endif	/* __FreeBSD__ */
3292