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