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