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