1223637Sbz/*	$OpenBSD: pf_ioctl.c,v 1.213 2009/02/15 21:46:12 mbalmer Exp $ */
2126258Smlaier
3126258Smlaier/*
4126258Smlaier * Copyright (c) 2001 Daniel Hartmeier
5130613Smlaier * Copyright (c) 2002,2003 Henning Brauer
6126258Smlaier * All rights reserved.
7126258Smlaier *
8126258Smlaier * Redistribution and use in source and binary forms, with or without
9126258Smlaier * modification, are permitted provided that the following conditions
10126258Smlaier * are met:
11126258Smlaier *
12126258Smlaier *    - Redistributions of source code must retain the above copyright
13126258Smlaier *      notice, this list of conditions and the following disclaimer.
14126258Smlaier *    - Redistributions in binary form must reproduce the above
15126258Smlaier *      copyright notice, this list of conditions and the following
16126258Smlaier *      disclaimer in the documentation and/or other materials provided
17126258Smlaier *      with the distribution.
18126258Smlaier *
19126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30126258Smlaier * POSSIBILITY OF SUCH DAMAGE.
31126258Smlaier *
32126258Smlaier * Effort sponsored in part by the Defense Advanced Research Projects
33126258Smlaier * Agency (DARPA) and Air Force Research Laboratory, Air Force
34126258Smlaier * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35126258Smlaier *
36126258Smlaier */
37126258Smlaier
38127145Smlaier#ifdef __FreeBSD__
39171168Smlaier#include <sys/cdefs.h>
40171168Smlaier__FBSDID("$FreeBSD$");
41126261Smlaier
42189106Sbz#include "opt_inet.h"
43189106Sbz#include "opt_inet6.h"
44130613Smlaier#include "opt_bpf.h"
45130613Smlaier#include "opt_pf.h"
46153110Sru
47230868Sglebius#define		NPFSYNC		1
48153110Sru
49153110Sru#ifdef DEV_PFLOG
50223637Sbz#define		NPFLOG		DEV_PFLOG
51153110Sru#else
52223637Sbz#define		NPFLOG		0
53153110Sru#endif
54153110Sru
55230868Sglebius#else /* !__FreeBSD__ */
56223637Sbz#include "pfsync.h"
57130613Smlaier#include "pflog.h"
58230868Sglebius#endif /* __FreeBSD__ */
59130613Smlaier
60126258Smlaier#include <sys/param.h>
61126258Smlaier#include <sys/systm.h>
62126258Smlaier#include <sys/mbuf.h>
63126258Smlaier#include <sys/filio.h>
64126258Smlaier#include <sys/fcntl.h>
65126258Smlaier#include <sys/socket.h>
66126258Smlaier#include <sys/socketvar.h>
67126258Smlaier#include <sys/kernel.h>
68126258Smlaier#include <sys/time.h>
69127145Smlaier#ifdef __FreeBSD__
70223637Sbz#include <sys/ucred.h>
71223637Sbz#include <sys/jail.h>
72129907Smlaier#include <sys/module.h>
73126261Smlaier#include <sys/conf.h>
74134166Smlaier#include <sys/proc.h>
75171168Smlaier#include <sys/sysctl.h>
76126261Smlaier#else
77126258Smlaier#include <sys/timeout.h>
78126258Smlaier#include <sys/pool.h>
79126261Smlaier#endif
80171168Smlaier#include <sys/proc.h>
81171168Smlaier#include <sys/malloc.h>
82171168Smlaier#include <sys/kthread.h>
83171168Smlaier#ifndef __FreeBSD__
84171168Smlaier#include <sys/rwlock.h>
85171168Smlaier#include <uvm/uvm_extern.h>
86171168Smlaier#endif
87126258Smlaier
88126258Smlaier#include <net/if.h>
89126258Smlaier#include <net/if_types.h>
90185571Sbz#ifdef __FreeBSD__
91185571Sbz#include <net/vnet.h>
92185571Sbz#endif
93223637Sbz#include <net/route.h>
94126258Smlaier
95126258Smlaier#include <netinet/in.h>
96126258Smlaier#include <netinet/in_var.h>
97126258Smlaier#include <netinet/in_systm.h>
98126258Smlaier#include <netinet/ip.h>
99126258Smlaier#include <netinet/ip_var.h>
100126258Smlaier#include <netinet/ip_icmp.h>
101126258Smlaier
102171168Smlaier#ifdef __FreeBSD__
103171168Smlaier#include <sys/md5.h>
104171168Smlaier#else
105130613Smlaier#include <dev/rndvar.h>
106171168Smlaier#include <crypto/md5.h>
107130613Smlaier#endif
108126258Smlaier#include <net/pfvar.h>
109126258Smlaier
110130613Smlaier#include <net/if_pfsync.h>
111130613Smlaier
112223637Sbz#if NPFLOG > 0
113155337Smlaier#include <net/if_pflog.h>
114223637Sbz#endif /* NPFLOG > 0 */
115155337Smlaier
116126258Smlaier#ifdef INET6
117126258Smlaier#include <netinet/ip6.h>
118126258Smlaier#include <netinet/in_pcb.h>
119126258Smlaier#endif /* INET6 */
120126258Smlaier
121126258Smlaier#ifdef ALTQ
122126258Smlaier#include <altq/altq.h>
123126258Smlaier#endif
124126258Smlaier
125127145Smlaier#ifdef __FreeBSD__
126126261Smlaier#include <sys/limits.h>
127126261Smlaier#include <sys/lock.h>
128126261Smlaier#include <sys/mutex.h>
129126261Smlaier#include <net/pfil.h>
130126261Smlaier#endif /* __FreeBSD__ */
131126261Smlaier
132127145Smlaier#ifdef __FreeBSD__
133126261Smlaiervoid			 init_zone_var(void);
134126261Smlaiervoid			 cleanup_pf_zone(void);
135126261Smlaierint			 pfattach(void);
136126261Smlaier#else
137126258Smlaiervoid			 pfattach(int);
138171168Smlaiervoid			 pf_thread_create(void *);
139145836Smlaierint			 pfopen(dev_t, int, int, struct proc *);
140145836Smlaierint			 pfclose(dev_t, int, int, struct proc *);
141126261Smlaier#endif
142145836Smlaierstruct pf_pool		*pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
143145836Smlaier			    u_int8_t, u_int8_t, u_int8_t);
144145836Smlaier
145126258Smlaiervoid			 pf_mv_pool(struct pf_palist *, struct pf_palist *);
146126258Smlaiervoid			 pf_empty_pool(struct pf_palist *);
147127145Smlaier#ifdef __FreeBSD__
148130585Sphkint			 pfioctl(struct cdev *, u_long, caddr_t, int, struct thread *);
149126261Smlaier#else
150223637Sbzint			 pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
151126261Smlaier#endif
152130613Smlaier#ifdef ALTQ
153130613Smlaierint			 pf_begin_altq(u_int32_t *);
154130613Smlaierint			 pf_rollback_altq(u_int32_t);
155130613Smlaierint			 pf_commit_altq(u_int32_t);
156135352Smlaierint			 pf_enable_altq(struct pf_altq *);
157135352Smlaierint			 pf_disable_altq(struct pf_altq *);
158130613Smlaier#endif /* ALTQ */
159145836Smlaierint			 pf_begin_rules(u_int32_t *, int, const char *);
160145836Smlaierint			 pf_rollback_rules(u_int32_t, int, char *);
161171168Smlaierint			 pf_setup_pfsync_matching(struct pf_ruleset *);
162171168Smlaiervoid			 pf_hash_rule(MD5_CTX *, struct pf_rule *);
163171168Smlaiervoid			 pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *);
164145836Smlaierint			 pf_commit_rules(u_int32_t, int, char *);
165223637Sbzint			 pf_addr_setup(struct pf_ruleset *,
166223637Sbz			    struct pf_addr_wrap *, sa_family_t);
167223637Sbzvoid			 pf_addr_copyout(struct pf_addr_wrap *);
168126258Smlaier
169223637Sbz#define	TAGID_MAX	 50000
170223637Sbz
171127145Smlaier#ifdef __FreeBSD__
172223637SbzVNET_DEFINE(struct pf_rule,	 pf_default_rule);
173223637SbzVNET_DEFINE(struct sx,		 pf_consistency_lock);
174223637Sbz
175223637Sbz#ifdef ALTQ
176223637Sbzstatic VNET_DEFINE(int,		pf_altq_running);
177223637Sbz#define	V_pf_altq_running	VNET(pf_altq_running)
178126261Smlaier#endif
179223637Sbz
180223637SbzTAILQ_HEAD(pf_tags, pf_tagname);
181223637Sbz
182223637Sbz#define	V_pf_tags		VNET(pf_tags)
183223637SbzVNET_DEFINE(struct pf_tags, pf_tags);
184223637Sbz#define	V_pf_qids		VNET(pf_qids)
185223637SbzVNET_DEFINE(struct pf_tags, pf_qids);
186223637Sbz
187223637Sbz#else /* !__FreeBSD__ */
188223637Sbzstruct pf_rule		 pf_default_rule;
189223637Sbzstruct rwlock		 pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk");
190135352Smlaier#ifdef ALTQ
191135352Smlaierstatic int		 pf_altq_running;
192135352Smlaier#endif
193126258Smlaier
194130613SmlaierTAILQ_HEAD(pf_tags, pf_tagname)	pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
195130613Smlaier				pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids);
196223637Sbz#endif /* __FreeBSD__ */
197126258Smlaier
198130613Smlaier#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
199130613Smlaier#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
200130613Smlaier#endif
201223637Sbz
202171168Smlaieru_int16_t		 tagname2tag(struct pf_tags *, char *);
203171168Smlaiervoid			 tag2tagname(struct pf_tags *, u_int16_t, char *);
204171168Smlaiervoid			 tag_unref(struct pf_tags *, u_int16_t);
205145836Smlaierint			 pf_rtlabel_add(struct pf_addr_wrap *);
206145836Smlaiervoid			 pf_rtlabel_remove(struct pf_addr_wrap *);
207145836Smlaiervoid			 pf_rtlabel_copyout(struct pf_addr_wrap *);
208130613Smlaier
209223637Sbz#ifdef __FreeBSD__
210223637Sbz#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
211223637Sbz#else
212126258Smlaier#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
213223637Sbz#endif
214126258Smlaier
215127145Smlaier#ifdef __FreeBSD__
216223637Sbzstruct cdev *pf_dev;
217223637Sbz
218126261Smlaier/*
219126261Smlaier * XXX - These are new and need to be checked when moveing to a new version
220126261Smlaier */
221130613Smlaierstatic void		 pf_clear_states(void);
222130613Smlaierstatic int		 pf_clear_tables(void);
223130613Smlaierstatic void		 pf_clear_srcnodes(void);
224126261Smlaier/*
225126261Smlaier * XXX - These are new and need to be checked when moveing to a new version
226126261Smlaier */
227126261Smlaier
228130613Smlaier/*
229130613Smlaier * Wrapper functions for pfil(9) hooks
230130613Smlaier */
231221132Sbz#ifdef INET
232126261Smlaierstatic int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
233223637Sbz    int dir, struct inpcb *inp);
234126261Smlaierstatic int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
235223637Sbz    int dir, struct inpcb *inp);
236221132Sbz#endif
237127145Smlaier#ifdef INET6
238126261Smlaierstatic int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
239223637Sbz    int dir, struct inpcb *inp);
240126261Smlaierstatic int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
241223637Sbz    int dir, struct inpcb *inp);
242126261Smlaier#endif
243223637Sbz
244223637Sbzstatic int		hook_pf(void);
245223637Sbzstatic int		dehook_pf(void);
246223637Sbzstatic int		shutdown_pf(void);
247223637Sbzstatic int		pf_load(void);
248223637Sbzstatic int		pf_unload(void);
249126261Smlaier
250126261Smlaierstatic struct cdevsw pf_cdevsw = {
251126261Smlaier	.d_ioctl =	pfioctl,
252126261Smlaier	.d_name =	PF_NAME,
253126261Smlaier	.d_version =	D_VERSION,
254126261Smlaier};
255126261Smlaier
256223637Sbzstatic volatile VNET_DEFINE(int, pf_pfil_hooked);
257223637Sbz#define V_pf_pfil_hooked	VNET(pf_pfil_hooked)
258223637SbzVNET_DEFINE(int,		pf_end_threads);
259226801Sglebiusstruct mtx			pf_task_mtx;
260126261Smlaier
261223637Sbz/* pfsync */
262223637Sbzpfsync_state_import_t 		*pfsync_state_import_ptr = NULL;
263223637Sbzpfsync_insert_state_t		*pfsync_insert_state_ptr = NULL;
264223637Sbzpfsync_update_state_t		*pfsync_update_state_ptr = NULL;
265223637Sbzpfsync_delete_state_t		*pfsync_delete_state_ptr = NULL;
266223637Sbzpfsync_clear_states_t		*pfsync_clear_states_ptr = NULL;
267223637Sbzpfsync_state_in_use_t		*pfsync_state_in_use_ptr = NULL;
268223637Sbzpfsync_defer_t			*pfsync_defer_ptr = NULL;
269223637Sbzpfsync_up_t			*pfsync_up_ptr = NULL;
270223637Sbz/* pflow */
271223637Sbzexport_pflow_t			*export_pflow_ptr = NULL;
272223637Sbz/* pflog */
273223637Sbzpflog_packet_t			*pflog_packet_ptr = NULL;
274171168Smlaier
275223637SbzVNET_DEFINE(int, debug_pfugidhack);
276223637SbzSYSCTL_VNET_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW,
277223637Sbz	&VNET_NAME(debug_pfugidhack), 0,
278223637Sbz	"Enable/disable pf user/group rules mpsafe hack");
279223637Sbz
280226801Sglebiusstatic void
281126261Smlaierinit_pf_mutex(void)
282126261Smlaier{
283223637Sbz
284226801Sglebius	mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF);
285126261Smlaier}
286126261Smlaier
287226801Sglebiusstatic void
288126261Smlaierdestroy_pf_mutex(void)
289126261Smlaier{
290223637Sbz
291226801Sglebius	mtx_destroy(&pf_task_mtx);
292126261Smlaier}
293126261Smlaiervoid
294126261Smlaierinit_zone_var(void)
295126261Smlaier{
296223637Sbz	V_pf_src_tree_pl = V_pf_rule_pl = NULL;
297223637Sbz	V_pf_state_pl = V_pf_state_key_pl = V_pf_state_item_pl = NULL;
298223637Sbz	V_pf_altq_pl = V_pf_pooladdr_pl = NULL;
299223637Sbz	V_pf_frent_pl = V_pf_frag_pl = V_pf_cache_pl = V_pf_cent_pl = NULL;
300223637Sbz	V_pf_state_scrub_pl = NULL;
301237776Sglebius	V_pfr_ktable_pl = V_pfr_kentry_pl = V_pfr_kcounters_pl = NULL;
302126261Smlaier}
303126261Smlaier
304126261Smlaiervoid
305126261Smlaiercleanup_pf_zone(void)
306126261Smlaier{
307223637Sbz	UMA_DESTROY(V_pf_src_tree_pl);
308223637Sbz	UMA_DESTROY(V_pf_rule_pl);
309223637Sbz	UMA_DESTROY(V_pf_state_pl);
310223637Sbz	UMA_DESTROY(V_pf_state_key_pl);
311223637Sbz	UMA_DESTROY(V_pf_state_item_pl);
312223637Sbz	UMA_DESTROY(V_pf_altq_pl);
313223637Sbz	UMA_DESTROY(V_pf_pooladdr_pl);
314223637Sbz	UMA_DESTROY(V_pf_frent_pl);
315223637Sbz	UMA_DESTROY(V_pf_frag_pl);
316223637Sbz	UMA_DESTROY(V_pf_cache_pl);
317223637Sbz	UMA_DESTROY(V_pf_cent_pl);
318223637Sbz	UMA_DESTROY(V_pfr_ktable_pl);
319223637Sbz	UMA_DESTROY(V_pfr_kentry_pl);
320237776Sglebius	UMA_DESTROY(V_pfr_kcounters_pl);
321223637Sbz	UMA_DESTROY(V_pf_state_scrub_pl);
322223637Sbz	UMA_DESTROY(V_pfi_addr_pl);
323126261Smlaier}
324126261Smlaier
325126261Smlaierint
326126261Smlaierpfattach(void)
327126261Smlaier{
328223637Sbz	u_int32_t *my_timeout = V_pf_default_rule.timeout;
329126261Smlaier	int error = 1;
330126261Smlaier
331126261Smlaier	do {
332223637Sbz		UMA_CREATE(V_pf_src_tree_pl,	struct pf_src_node, "pfsrctrpl");
333223637Sbz		UMA_CREATE(V_pf_rule_pl,	struct pf_rule, "pfrulepl");
334223637Sbz		UMA_CREATE(V_pf_state_pl,	struct pf_state, "pfstatepl");
335223637Sbz		UMA_CREATE(V_pf_state_key_pl,	struct pf_state, "pfstatekeypl");
336223637Sbz		UMA_CREATE(V_pf_state_item_pl,	struct pf_state, "pfstateitempl");
337223637Sbz		UMA_CREATE(V_pf_altq_pl,	struct pf_altq, "pfaltqpl");
338223637Sbz		UMA_CREATE(V_pf_pooladdr_pl,	struct pf_pooladdr, "pfpooladdrpl");
339223637Sbz		UMA_CREATE(V_pfr_ktable_pl,	struct pfr_ktable, "pfrktable");
340223637Sbz		UMA_CREATE(V_pfr_kentry_pl,	struct pfr_kentry, "pfrkentry");
341237776Sglebius		UMA_CREATE(V_pfr_kcounters_pl,	struct pfr_kcounters, "pfrkcounters");
342223637Sbz		UMA_CREATE(V_pf_frent_pl,	struct pf_frent, "pffrent");
343223637Sbz		UMA_CREATE(V_pf_frag_pl,	struct pf_fragment, "pffrag");
344223637Sbz		UMA_CREATE(V_pf_cache_pl,	struct pf_fragment, "pffrcache");
345223637Sbz		UMA_CREATE(V_pf_cent_pl,	struct pf_frcache, "pffrcent");
346223637Sbz		UMA_CREATE(V_pf_state_scrub_pl,	struct pf_state_scrub,
347126261Smlaier		    "pfstatescrub");
348223637Sbz		UMA_CREATE(V_pfi_addr_pl,	struct pfi_dynaddr, "pfiaddrpl");
349126261Smlaier		error = 0;
350126261Smlaier	} while(0);
351126261Smlaier	if (error) {
352126261Smlaier		cleanup_pf_zone();
353126261Smlaier		return (error);
354126261Smlaier	}
355126261Smlaier	pfr_initialize();
356130613Smlaier	pfi_initialize();
357126261Smlaier	if ( (error = pf_osfp_initialize()) ) {
358126261Smlaier		cleanup_pf_zone();
359126261Smlaier		pf_osfp_cleanup();
360126261Smlaier		return (error);
361126261Smlaier	}
362126261Smlaier
363223637Sbz	V_pf_pool_limits[PF_LIMIT_STATES].pp = V_pf_state_pl;
364223637Sbz	V_pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT;
365223637Sbz	V_pf_pool_limits[PF_LIMIT_SRC_NODES].pp = V_pf_src_tree_pl;
366223637Sbz	V_pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT;
367223637Sbz	V_pf_pool_limits[PF_LIMIT_FRAGS].pp = V_pf_frent_pl;
368223637Sbz	V_pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT;
369223637Sbz	V_pf_pool_limits[PF_LIMIT_TABLES].pp = V_pfr_ktable_pl;
370223637Sbz	V_pf_pool_limits[PF_LIMIT_TABLES].limit = PFR_KTABLE_HIWAT;
371223637Sbz	V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].pp = V_pfr_kentry_pl;
372223637Sbz	V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT;
373223637Sbz	uma_zone_set_max(V_pf_pool_limits[PF_LIMIT_STATES].pp,
374223637Sbz	    V_pf_pool_limits[PF_LIMIT_STATES].limit);
375126261Smlaier
376223637Sbz	RB_INIT(&V_tree_src_tracking);
377223637Sbz	RB_INIT(&V_pf_anchors);
378130613Smlaier	pf_init_ruleset(&pf_main_ruleset);
379126261Smlaier
380223637Sbz	TAILQ_INIT(&V_pf_altqs[0]);
381223637Sbz	TAILQ_INIT(&V_pf_altqs[1]);
382223637Sbz	TAILQ_INIT(&V_pf_pabuf);
383223637Sbz	V_pf_altqs_active = &V_pf_altqs[0];
384223637Sbz	V_pf_altqs_inactive = &V_pf_altqs[1];
385223637Sbz	TAILQ_INIT(&V_state_list);
386223637Sbz
387126261Smlaier	/* default rule should never be garbage collected */
388223637Sbz	V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next;
389223637Sbz	V_pf_default_rule.action = PF_PASS;
390223637Sbz	V_pf_default_rule.nr = -1;
391223637Sbz	V_pf_default_rule.rtableid = -1;
392126261Smlaier
393126261Smlaier	/* initialize default timeouts */
394145836Smlaier	my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
395145836Smlaier	my_timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
396145836Smlaier	my_timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
397145836Smlaier	my_timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
398145836Smlaier	my_timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
399145836Smlaier	my_timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
400145836Smlaier	my_timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
401145836Smlaier	my_timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
402145836Smlaier	my_timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
403145836Smlaier	my_timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
404145836Smlaier	my_timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
405145836Smlaier	my_timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
406145836Smlaier	my_timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
407145836Smlaier	my_timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
408145836Smlaier	my_timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
409145836Smlaier	my_timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
410145836Smlaier	my_timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
411145836Smlaier	my_timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
412171168Smlaier	my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
413171168Smlaier	my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
414126261Smlaier
415126261Smlaier	pf_normalize_init();
416171168Smlaier
417223637Sbz	bzero(&V_pf_status, sizeof(V_pf_status));
418223637Sbz	V_pf_status.debug = PF_DEBUG_URGENT;
419130613Smlaier
420223637Sbz	V_pf_pfil_hooked = 0;
421223637Sbz
422130613Smlaier	/* XXX do our best to avoid a conflict */
423223637Sbz	V_pf_status.hostid = arc4random();
424130613Smlaier
425223637Sbz	if (kproc_create(pf_purge_thread, curvnet, NULL, 0, 0, "pfpurge"))
426171168Smlaier		return (ENXIO);
427171168Smlaier
428223637Sbz	m_addr_chg_pf_p = pf_pkt_addr_changed;
429223637Sbz
430126261Smlaier	return (error);
431126261Smlaier}
432126261Smlaier#else /* !__FreeBSD__ */
433223637Sbz
434126261Smlaiervoid
435126258Smlaierpfattach(int num)
436126258Smlaier{
437126258Smlaier	u_int32_t *timeout = pf_default_rule.timeout;
438126258Smlaier
439126258Smlaier	pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl",
440126258Smlaier	    &pool_allocator_nointr);
441130613Smlaier	pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0,
442130613Smlaier	    "pfsrctrpl", NULL);
443126258Smlaier	pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
444126258Smlaier	    NULL);
445223637Sbz	pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0,
446223637Sbz	    "pfstatekeypl", NULL);
447223637Sbz	pool_init(&pf_state_item_pl, sizeof(struct pf_state_item), 0, 0, 0,
448223637Sbz	    "pfstateitempl", NULL);
449126258Smlaier	pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl",
450145836Smlaier	    &pool_allocator_nointr);
451126258Smlaier	pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
452145836Smlaier	    "pfpooladdrpl", &pool_allocator_nointr);
453126258Smlaier	pfr_initialize();
454130613Smlaier	pfi_initialize();
455126258Smlaier	pf_osfp_initialize();
456126258Smlaier
457130613Smlaier	pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp,
458130613Smlaier	    pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0);
459126258Smlaier
460223637Sbz	if (physmem <= atop(100*1024*1024))
461171168Smlaier		pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
462171168Smlaier		    PFR_KENTRY_HIWAT_SMALL;
463171168Smlaier
464130613Smlaier	RB_INIT(&tree_src_tracking);
465145836Smlaier	RB_INIT(&pf_anchors);
466126258Smlaier	pf_init_ruleset(&pf_main_ruleset);
467126258Smlaier	TAILQ_INIT(&pf_altqs[0]);
468126258Smlaier	TAILQ_INIT(&pf_altqs[1]);
469126258Smlaier	TAILQ_INIT(&pf_pabuf);
470126258Smlaier	pf_altqs_active = &pf_altqs[0];
471126258Smlaier	pf_altqs_inactive = &pf_altqs[1];
472171168Smlaier	TAILQ_INIT(&state_list);
473126258Smlaier
474126258Smlaier	/* default rule should never be garbage collected */
475126258Smlaier	pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
476126258Smlaier	pf_default_rule.action = PF_PASS;
477126258Smlaier	pf_default_rule.nr = -1;
478171168Smlaier	pf_default_rule.rtableid = -1;
479126258Smlaier
480126258Smlaier	/* initialize default timeouts */
481145836Smlaier	timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
482145836Smlaier	timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
483145836Smlaier	timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
484145836Smlaier	timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
485145836Smlaier	timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
486145836Smlaier	timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
487145836Smlaier	timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
488145836Smlaier	timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
489145836Smlaier	timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
490145836Smlaier	timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
491145836Smlaier	timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
492145836Smlaier	timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
493145836Smlaier	timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
494145836Smlaier	timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
495145836Smlaier	timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
496145836Smlaier	timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
497145836Smlaier	timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
498145836Smlaier	timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
499171168Smlaier	timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
500171168Smlaier	timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
501126258Smlaier
502126258Smlaier	pf_normalize_init();
503130613Smlaier	bzero(&pf_status, sizeof(pf_status));
504126258Smlaier	pf_status.debug = PF_DEBUG_URGENT;
505130613Smlaier
506130613Smlaier	/* XXX do our best to avoid a conflict */
507130613Smlaier	pf_status.hostid = arc4random();
508171168Smlaier
509171168Smlaier	/* require process context to purge states, so perform in a thread */
510223637Sbz	kthread_create_deferred(pf_thread_create, NULL);
511126258Smlaier}
512126258Smlaier
513171168Smlaiervoid
514171168Smlaierpf_thread_create(void *v)
515171168Smlaier{
516223637Sbz	if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge"))
517171168Smlaier		panic("pfpurge thread");
518171168Smlaier}
519187689Sed
520187689Sedint
521223637Sbzpfopen(dev_t dev, int flags, int fmt, struct proc *p)
522187689Sed{
523223637Sbz	if (minor(dev) >= 1)
524187689Sed		return (ENXIO);
525187689Sed	return (0);
526187689Sed}
527187689Sed
528187689Sedint
529223637Sbzpfclose(dev_t dev, int flags, int fmt, struct proc *p)
530187689Sed{
531223637Sbz	if (minor(dev) >= 1)
532187689Sed		return (ENXIO);
533187689Sed	return (0);
534187689Sed}
535223637Sbz#endif
536126258Smlaier
537126258Smlaierstruct pf_pool *
538145836Smlaierpf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
539145836Smlaier    u_int32_t rule_number, u_int8_t r_last, u_int8_t active,
540145836Smlaier    u_int8_t check_ticket)
541126258Smlaier{
542126258Smlaier	struct pf_ruleset	*ruleset;
543126258Smlaier	struct pf_rule		*rule;
544126258Smlaier	int			 rs_num;
545126258Smlaier
546145836Smlaier	ruleset = pf_find_ruleset(anchor);
547126258Smlaier	if (ruleset == NULL)
548126258Smlaier		return (NULL);
549126258Smlaier	rs_num = pf_get_ruleset_number(rule_action);
550126258Smlaier	if (rs_num >= PF_RULESET_MAX)
551126258Smlaier		return (NULL);
552126258Smlaier	if (active) {
553126258Smlaier		if (check_ticket && ticket !=
554126258Smlaier		    ruleset->rules[rs_num].active.ticket)
555126258Smlaier			return (NULL);
556126258Smlaier		if (r_last)
557126258Smlaier			rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
558126258Smlaier			    pf_rulequeue);
559126258Smlaier		else
560126258Smlaier			rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
561126258Smlaier	} else {
562126258Smlaier		if (check_ticket && ticket !=
563126258Smlaier		    ruleset->rules[rs_num].inactive.ticket)
564126258Smlaier			return (NULL);
565126258Smlaier		if (r_last)
566126258Smlaier			rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
567126258Smlaier			    pf_rulequeue);
568126258Smlaier		else
569126258Smlaier			rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
570126258Smlaier	}
571126258Smlaier	if (!r_last) {
572126258Smlaier		while ((rule != NULL) && (rule->nr != rule_number))
573126258Smlaier			rule = TAILQ_NEXT(rule, entries);
574126258Smlaier	}
575126258Smlaier	if (rule == NULL)
576126258Smlaier		return (NULL);
577126258Smlaier
578126258Smlaier	return (&rule->rpool);
579126258Smlaier}
580126258Smlaier
581126258Smlaiervoid
582126258Smlaierpf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
583126258Smlaier{
584126258Smlaier	struct pf_pooladdr	*mv_pool_pa;
585126258Smlaier
586126258Smlaier	while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
587126258Smlaier		TAILQ_REMOVE(poola, mv_pool_pa, entries);
588126258Smlaier		TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
589126258Smlaier	}
590126258Smlaier}
591126258Smlaier
592126258Smlaiervoid
593126258Smlaierpf_empty_pool(struct pf_palist *poola)
594126258Smlaier{
595126258Smlaier	struct pf_pooladdr	*empty_pool_pa;
596126258Smlaier
597126258Smlaier	while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
598130613Smlaier		pfi_dynaddr_remove(&empty_pool_pa->addr);
599126258Smlaier		pf_tbladdr_remove(&empty_pool_pa->addr);
600171168Smlaier		pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
601126258Smlaier		TAILQ_REMOVE(poola, empty_pool_pa, entries);
602223637Sbz#ifdef __FreeBSD__
603223637Sbz		pool_put(&V_pf_pooladdr_pl, empty_pool_pa);
604223637Sbz#else
605126258Smlaier		pool_put(&pf_pooladdr_pl, empty_pool_pa);
606223637Sbz#endif
607126258Smlaier	}
608126258Smlaier}
609126258Smlaier
610126258Smlaiervoid
611126258Smlaierpf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
612126258Smlaier{
613126258Smlaier	if (rulequeue != NULL) {
614223637Sbz		if (rule->states_cur <= 0) {
615126258Smlaier			/*
616126258Smlaier			 * XXX - we need to remove the table *before* detaching
617126258Smlaier			 * the rule to make sure the table code does not delete
618126258Smlaier			 * the anchor under our feet.
619126258Smlaier			 */
620126258Smlaier			pf_tbladdr_remove(&rule->src.addr);
621126258Smlaier			pf_tbladdr_remove(&rule->dst.addr);
622145836Smlaier			if (rule->overload_tbl)
623145836Smlaier				pfr_detach_table(rule->overload_tbl);
624126258Smlaier		}
625126258Smlaier		TAILQ_REMOVE(rulequeue, rule, entries);
626126258Smlaier		rule->entries.tqe_prev = NULL;
627126258Smlaier		rule->nr = -1;
628126258Smlaier	}
629130613Smlaier
630223637Sbz	if (rule->states_cur > 0 || rule->src_nodes > 0 ||
631130613Smlaier	    rule->entries.tqe_prev != NULL)
632126258Smlaier		return;
633126258Smlaier	pf_tag_unref(rule->tag);
634126258Smlaier	pf_tag_unref(rule->match_tag);
635130613Smlaier#ifdef ALTQ
636130613Smlaier	if (rule->pqid != rule->qid)
637130613Smlaier		pf_qid_unref(rule->pqid);
638130613Smlaier	pf_qid_unref(rule->qid);
639130613Smlaier#endif
640145836Smlaier	pf_rtlabel_remove(&rule->src.addr);
641145836Smlaier	pf_rtlabel_remove(&rule->dst.addr);
642130613Smlaier	pfi_dynaddr_remove(&rule->src.addr);
643130613Smlaier	pfi_dynaddr_remove(&rule->dst.addr);
644126258Smlaier	if (rulequeue == NULL) {
645126258Smlaier		pf_tbladdr_remove(&rule->src.addr);
646126258Smlaier		pf_tbladdr_remove(&rule->dst.addr);
647145836Smlaier		if (rule->overload_tbl)
648145836Smlaier			pfr_detach_table(rule->overload_tbl);
649126258Smlaier	}
650171168Smlaier	pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
651145836Smlaier	pf_anchor_remove(rule);
652126258Smlaier	pf_empty_pool(&rule->rpool.list);
653223637Sbz#ifdef __FreeBSD__
654223637Sbz	pool_put(&V_pf_rule_pl, rule);
655223637Sbz#else
656126258Smlaier	pool_put(&pf_rule_pl, rule);
657223637Sbz#endif
658126258Smlaier}
659126258Smlaier
660171168Smlaieru_int16_t
661130613Smlaiertagname2tag(struct pf_tags *head, char *tagname)
662126258Smlaier{
663126258Smlaier	struct pf_tagname	*tag, *p = NULL;
664126258Smlaier	u_int16_t		 new_tagid = 1;
665126258Smlaier
666130613Smlaier	TAILQ_FOREACH(tag, head, entries)
667126258Smlaier		if (strcmp(tagname, tag->name) == 0) {
668126258Smlaier			tag->ref++;
669126258Smlaier			return (tag->tag);
670126258Smlaier		}
671126258Smlaier
672126258Smlaier	/*
673126258Smlaier	 * to avoid fragmentation, we do a linear search from the beginning
674126258Smlaier	 * and take the first free slot we find. if there is none or the list
675126258Smlaier	 * is empty, append a new entry at the end.
676126258Smlaier	 */
677126258Smlaier
678126258Smlaier	/* new entry */
679130613Smlaier	if (!TAILQ_EMPTY(head))
680130613Smlaier		for (p = TAILQ_FIRST(head); p != NULL &&
681126258Smlaier		    p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
682126258Smlaier			new_tagid = p->tag + 1;
683126258Smlaier
684126258Smlaier	if (new_tagid > TAGID_MAX)
685126258Smlaier		return (0);
686126258Smlaier
687126258Smlaier	/* allocate and fill new struct pf_tagname */
688223637Sbz	tag = malloc(sizeof(*tag), M_TEMP, M_NOWAIT|M_ZERO);
689126258Smlaier	if (tag == NULL)
690126258Smlaier		return (0);
691126258Smlaier	strlcpy(tag->name, tagname, sizeof(tag->name));
692126258Smlaier	tag->tag = new_tagid;
693126258Smlaier	tag->ref++;
694126258Smlaier
695126258Smlaier	if (p != NULL)	/* insert new entry before p */
696126258Smlaier		TAILQ_INSERT_BEFORE(p, tag, entries);
697126258Smlaier	else	/* either list empty or no free slot in between */
698130613Smlaier		TAILQ_INSERT_TAIL(head, tag, entries);
699126258Smlaier
700126258Smlaier	return (tag->tag);
701126258Smlaier}
702126258Smlaier
703171168Smlaiervoid
704130613Smlaiertag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
705126258Smlaier{
706126258Smlaier	struct pf_tagname	*tag;
707126258Smlaier
708130613Smlaier	TAILQ_FOREACH(tag, head, entries)
709126258Smlaier		if (tag->tag == tagid) {
710126258Smlaier			strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
711126258Smlaier			return;
712126258Smlaier		}
713126258Smlaier}
714126258Smlaier
715171168Smlaiervoid
716130613Smlaiertag_unref(struct pf_tags *head, u_int16_t tag)
717126258Smlaier{
718126258Smlaier	struct pf_tagname	*p, *next;
719126258Smlaier
720126258Smlaier	if (tag == 0)
721126258Smlaier		return;
722126258Smlaier
723130613Smlaier	for (p = TAILQ_FIRST(head); p != NULL; p = next) {
724126258Smlaier		next = TAILQ_NEXT(p, entries);
725126258Smlaier		if (tag == p->tag) {
726126258Smlaier			if (--p->ref == 0) {
727130613Smlaier				TAILQ_REMOVE(head, p, entries);
728126258Smlaier				free(p, M_TEMP);
729126258Smlaier			}
730126258Smlaier			break;
731126258Smlaier		}
732126258Smlaier	}
733126258Smlaier}
734126258Smlaier
735130613Smlaieru_int16_t
736130613Smlaierpf_tagname2tag(char *tagname)
737130613Smlaier{
738223637Sbz#ifdef __FreeBSD__
739223637Sbz	return (tagname2tag(&V_pf_tags, tagname));
740223637Sbz#else
741130613Smlaier	return (tagname2tag(&pf_tags, tagname));
742223637Sbz#endif
743130613Smlaier}
744130613Smlaier
745130613Smlaiervoid
746130613Smlaierpf_tag2tagname(u_int16_t tagid, char *p)
747130613Smlaier{
748223637Sbz#ifdef __FreeBSD__
749223637Sbz	tag2tagname(&V_pf_tags, tagid, p);
750223637Sbz#else
751171168Smlaier	tag2tagname(&pf_tags, tagid, p);
752223637Sbz#endif
753130613Smlaier}
754130613Smlaier
755130613Smlaiervoid
756145836Smlaierpf_tag_ref(u_int16_t tag)
757145836Smlaier{
758145836Smlaier	struct pf_tagname *t;
759145836Smlaier
760223637Sbz#ifdef __FreeBSD__
761223637Sbz	TAILQ_FOREACH(t, &V_pf_tags, entries)
762223637Sbz#else
763145836Smlaier	TAILQ_FOREACH(t, &pf_tags, entries)
764223637Sbz#endif
765145836Smlaier		if (t->tag == tag)
766145836Smlaier			break;
767145836Smlaier	if (t != NULL)
768145836Smlaier		t->ref++;
769145836Smlaier}
770145836Smlaier
771145836Smlaiervoid
772130613Smlaierpf_tag_unref(u_int16_t tag)
773130613Smlaier{
774223637Sbz#ifdef __FreeBSD__
775223637Sbz	tag_unref(&V_pf_tags, tag);
776223637Sbz#else
777171168Smlaier	tag_unref(&pf_tags, tag);
778223637Sbz#endif
779130613Smlaier}
780130613Smlaier
781145836Smlaierint
782145836Smlaierpf_rtlabel_add(struct pf_addr_wrap *a)
783145836Smlaier{
784145836Smlaier#ifdef __FreeBSD__
785145836Smlaier	/* XXX_IMPORT: later */
786145836Smlaier	return (0);
787145836Smlaier#else
788145836Smlaier	if (a->type == PF_ADDR_RTLABEL &&
789145836Smlaier	    (a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0)
790145836Smlaier		return (-1);
791145836Smlaier	return (0);
792145836Smlaier#endif
793145836Smlaier}
794145836Smlaier
795145836Smlaiervoid
796145836Smlaierpf_rtlabel_remove(struct pf_addr_wrap *a)
797145836Smlaier{
798145836Smlaier#ifdef __FreeBSD__
799145836Smlaier	/* XXX_IMPORT: later */
800145836Smlaier#else
801145836Smlaier	if (a->type == PF_ADDR_RTLABEL)
802145836Smlaier		rtlabel_unref(a->v.rtlabel);
803145836Smlaier#endif
804145836Smlaier}
805145836Smlaier
806145836Smlaiervoid
807145836Smlaierpf_rtlabel_copyout(struct pf_addr_wrap *a)
808145836Smlaier{
809145836Smlaier#ifdef __FreeBSD__
810145836Smlaier	/* XXX_IMPORT: later */
811145836Smlaier	if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel)
812145836Smlaier		strlcpy(a->v.rtlabelname, "?", sizeof(a->v.rtlabelname));
813145836Smlaier#else
814145836Smlaier	const char	*name;
815145836Smlaier
816145836Smlaier	if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) {
817145836Smlaier		if ((name = rtlabel_id2name(a->v.rtlabel)) == NULL)
818145836Smlaier			strlcpy(a->v.rtlabelname, "?",
819145836Smlaier			    sizeof(a->v.rtlabelname));
820145836Smlaier		else
821145836Smlaier			strlcpy(a->v.rtlabelname, name,
822145836Smlaier			    sizeof(a->v.rtlabelname));
823145836Smlaier	}
824145836Smlaier#endif
825145836Smlaier}
826145836Smlaier
827130613Smlaier#ifdef ALTQ
828130613Smlaieru_int32_t
829130613Smlaierpf_qname2qid(char *qname)
830130613Smlaier{
831223637Sbz#ifdef __FreeBSD__
832223637Sbz	return ((u_int32_t)tagname2tag(&V_pf_qids, qname));
833223637Sbz#else
834130613Smlaier	return ((u_int32_t)tagname2tag(&pf_qids, qname));
835223637Sbz#endif
836130613Smlaier}
837130613Smlaier
838130613Smlaiervoid
839130613Smlaierpf_qid2qname(u_int32_t qid, char *p)
840130613Smlaier{
841223637Sbz#ifdef __FreeBSD__
842223637Sbz	tag2tagname(&V_pf_qids, (u_int16_t)qid, p);
843223637Sbz#else
844171168Smlaier	tag2tagname(&pf_qids, (u_int16_t)qid, p);
845223637Sbz#endif
846130613Smlaier}
847130613Smlaier
848130613Smlaiervoid
849130613Smlaierpf_qid_unref(u_int32_t qid)
850130613Smlaier{
851223637Sbz#ifdef __FreeBSD__
852223637Sbz	tag_unref(&V_pf_qids, (u_int16_t)qid);
853223637Sbz#else
854171168Smlaier	tag_unref(&pf_qids, (u_int16_t)qid);
855223637Sbz#endif
856130613Smlaier}
857130613Smlaier
858130613Smlaierint
859130613Smlaierpf_begin_altq(u_int32_t *ticket)
860130613Smlaier{
861130613Smlaier	struct pf_altq	*altq;
862130613Smlaier	int		 error = 0;
863130613Smlaier
864130613Smlaier	/* Purge the old altq list */
865177700Smlaier#ifdef __FreeBSD__
866223637Sbz	while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) {
867223637Sbz		TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries);
868177700Smlaier		if (altq->qname[0] == 0 &&
869177700Smlaier		    (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
870177700Smlaier#else
871223637Sbz	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
872223637Sbz		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
873130613Smlaier		if (altq->qname[0] == 0) {
874177700Smlaier#endif
875130613Smlaier			/* detach and destroy the discipline */
876130613Smlaier			error = altq_remove(altq);
877130613Smlaier		} else
878130613Smlaier			pf_qid_unref(altq->qid);
879223637Sbz#ifdef __FreeBSD__
880223637Sbz		pool_put(&V_pf_altq_pl, altq);
881223637Sbz#else
882130613Smlaier		pool_put(&pf_altq_pl, altq);
883223637Sbz#endif
884130613Smlaier	}
885130613Smlaier	if (error)
886130613Smlaier		return (error);
887223637Sbz#ifdef __FreeBSD__
888223637Sbz	*ticket = ++V_ticket_altqs_inactive;
889223637Sbz	V_altqs_inactive_open = 1;
890223637Sbz#else
891130613Smlaier	*ticket = ++ticket_altqs_inactive;
892130613Smlaier	altqs_inactive_open = 1;
893223637Sbz#endif
894130613Smlaier	return (0);
895130613Smlaier}
896130613Smlaier
897130613Smlaierint
898130613Smlaierpf_rollback_altq(u_int32_t ticket)
899130613Smlaier{
900130613Smlaier	struct pf_altq	*altq;
901130613Smlaier	int		 error = 0;
902130613Smlaier
903223637Sbz#ifdef __FreeBSD__
904223637Sbz	if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive)
905223637Sbz		return (0);
906223637Sbz	/* Purge the old altq list */
907223637Sbz	while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) {
908223637Sbz		TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries);
909223637Sbz		if (altq->qname[0] == 0 &&
910223637Sbz		   (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
911223637Sbz#else
912130613Smlaier	if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
913130613Smlaier		return (0);
914130613Smlaier	/* Purge the old altq list */
915130613Smlaier	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
916130613Smlaier		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
917130613Smlaier		if (altq->qname[0] == 0) {
918177700Smlaier#endif
919130613Smlaier			/* detach and destroy the discipline */
920130613Smlaier			error = altq_remove(altq);
921130613Smlaier		} else
922130613Smlaier			pf_qid_unref(altq->qid);
923223637Sbz#ifdef __FreeBSD__
924223637Sbz		pool_put(&V_pf_altq_pl, altq);
925223637Sbz#else
926130613Smlaier		pool_put(&pf_altq_pl, altq);
927223637Sbz#endif
928130613Smlaier	}
929223637Sbz#ifdef __FreeBSD__
930223637Sbz	V_altqs_inactive_open = 0;
931223637Sbz#else
932130613Smlaier	altqs_inactive_open = 0;
933223637Sbz#endif
934130613Smlaier	return (error);
935130613Smlaier}
936130613Smlaier
937130613Smlaierint
938130613Smlaierpf_commit_altq(u_int32_t ticket)
939130613Smlaier{
940130613Smlaier	struct pf_altqqueue	*old_altqs;
941130613Smlaier	struct pf_altq		*altq;
942130613Smlaier	int			 s, err, error = 0;
943130613Smlaier
944223637Sbz#ifdef __FreeBSD__
945223637Sbz	if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive)
946223637Sbz#else
947130613Smlaier	if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
948223637Sbz#endif
949130613Smlaier		return (EBUSY);
950130613Smlaier
951130613Smlaier	/* swap altqs, keep the old. */
952130613Smlaier	s = splsoftnet();
953223637Sbz#ifdef __FreeBSD__
954223637Sbz	old_altqs = V_pf_altqs_active;
955223637Sbz	V_pf_altqs_active = V_pf_altqs_inactive;
956223637Sbz	V_pf_altqs_inactive = old_altqs;
957223637Sbz	V_ticket_altqs_active = V_ticket_altqs_inactive;
958223637Sbz#else
959130613Smlaier	old_altqs = pf_altqs_active;
960130613Smlaier	pf_altqs_active = pf_altqs_inactive;
961130613Smlaier	pf_altqs_inactive = old_altqs;
962130613Smlaier	ticket_altqs_active = ticket_altqs_inactive;
963223637Sbz#endif
964130613Smlaier
965130613Smlaier	/* Attach new disciplines */
966177700Smlaier#ifdef __FreeBSD__
967223637Sbz	TAILQ_FOREACH(altq, V_pf_altqs_active, entries) {
968223637Sbz	if (altq->qname[0] == 0 &&
969223637Sbz	   (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
970177700Smlaier#else
971223637Sbz	TAILQ_FOREACH(altq, pf_altqs_active, entries) {
972130613Smlaier		if (altq->qname[0] == 0) {
973177700Smlaier#endif
974130613Smlaier			/* attach the discipline */
975130613Smlaier			error = altq_pfattach(altq);
976223637Sbz#ifdef __FreeBSD__
977223637Sbz			if (error == 0 && V_pf_altq_running)
978223637Sbz#else
979135352Smlaier			if (error == 0 && pf_altq_running)
980223637Sbz#endif
981135352Smlaier				error = pf_enable_altq(altq);
982135352Smlaier			if (error != 0) {
983130613Smlaier				splx(s);
984130613Smlaier				return (error);
985130613Smlaier			}
986130613Smlaier		}
987130613Smlaier	}
988130613Smlaier
989130613Smlaier	/* Purge the old altq list */
990177700Smlaier#ifdef __FreeBSD__
991223637Sbz	while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) {
992223637Sbz		TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries);
993177700Smlaier		if (altq->qname[0] == 0 &&
994177700Smlaier		    (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) {
995177700Smlaier#else
996223637Sbz	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
997223637Sbz		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
998130613Smlaier		if (altq->qname[0] == 0) {
999177700Smlaier#endif
1000130613Smlaier			/* detach and destroy the discipline */
1001223637Sbz#ifdef __FreeBSD__
1002223637Sbz			if (V_pf_altq_running)
1003223637Sbz#else
1004135352Smlaier			if (pf_altq_running)
1005223637Sbz#endif
1006135352Smlaier				error = pf_disable_altq(altq);
1007130613Smlaier			err = altq_pfdetach(altq);
1008130613Smlaier			if (err != 0 && error == 0)
1009130613Smlaier				error = err;
1010130613Smlaier			err = altq_remove(altq);
1011130613Smlaier			if (err != 0 && error == 0)
1012130613Smlaier				error = err;
1013130613Smlaier		} else
1014130613Smlaier			pf_qid_unref(altq->qid);
1015223637Sbz#ifdef __FreeBSD__
1016223637Sbz		pool_put(&V_pf_altq_pl, altq);
1017223637Sbz#else
1018130613Smlaier		pool_put(&pf_altq_pl, altq);
1019223637Sbz#endif
1020130613Smlaier	}
1021130613Smlaier	splx(s);
1022130613Smlaier
1023223637Sbz#ifdef __FreeBSD__
1024223637Sbz	V_altqs_inactive_open = 0;
1025223637Sbz#else
1026130613Smlaier	altqs_inactive_open = 0;
1027223637Sbz#endif
1028130613Smlaier	return (error);
1029130613Smlaier}
1030135352Smlaier
1031135352Smlaierint
1032135352Smlaierpf_enable_altq(struct pf_altq *altq)
1033135352Smlaier{
1034135352Smlaier	struct ifnet		*ifp;
1035135352Smlaier	struct tb_profile	 tb;
1036135352Smlaier	int			 s, error = 0;
1037135352Smlaier
1038135352Smlaier	if ((ifp = ifunit(altq->ifname)) == NULL)
1039135352Smlaier		return (EINVAL);
1040135352Smlaier
1041135352Smlaier	if (ifp->if_snd.altq_type != ALTQT_NONE)
1042135352Smlaier		error = altq_enable(&ifp->if_snd);
1043135352Smlaier
1044135352Smlaier	/* set tokenbucket regulator */
1045135352Smlaier	if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
1046135352Smlaier		tb.rate = altq->ifbandwidth;
1047135352Smlaier		tb.depth = altq->tbrsize;
1048171168Smlaier		s = splnet();
1049135352Smlaier#ifdef __FreeBSD__
1050135352Smlaier		PF_UNLOCK();
1051135352Smlaier#endif
1052135352Smlaier		error = tbr_set(&ifp->if_snd, &tb);
1053135352Smlaier#ifdef __FreeBSD__
1054135352Smlaier		PF_LOCK();
1055145836Smlaier#endif
1056135352Smlaier		splx(s);
1057135352Smlaier	}
1058135352Smlaier
1059135352Smlaier	return (error);
1060135352Smlaier}
1061135352Smlaier
1062135352Smlaierint
1063135352Smlaierpf_disable_altq(struct pf_altq *altq)
1064135352Smlaier{
1065135352Smlaier	struct ifnet		*ifp;
1066135352Smlaier	struct tb_profile	 tb;
1067135352Smlaier	int			 s, error;
1068135352Smlaier
1069135352Smlaier	if ((ifp = ifunit(altq->ifname)) == NULL)
1070135352Smlaier		return (EINVAL);
1071135352Smlaier
1072135352Smlaier	/*
1073135352Smlaier	 * when the discipline is no longer referenced, it was overridden
1074135352Smlaier	 * by a new one.  if so, just return.
1075135352Smlaier	 */
1076135352Smlaier	if (altq->altq_disc != ifp->if_snd.altq_disc)
1077135352Smlaier		return (0);
1078135352Smlaier
1079135352Smlaier	error = altq_disable(&ifp->if_snd);
1080135352Smlaier
1081135352Smlaier	if (error == 0) {
1082135352Smlaier		/* clear tokenbucket regulator */
1083135352Smlaier		tb.rate = 0;
1084171168Smlaier		s = splnet();
1085135352Smlaier#ifdef __FreeBSD__
1086135352Smlaier		PF_UNLOCK();
1087135352Smlaier#endif
1088135352Smlaier		error = tbr_set(&ifp->if_snd, &tb);
1089135352Smlaier#ifdef __FreeBSD__
1090135352Smlaier		PF_LOCK();
1091135352Smlaier#endif
1092135352Smlaier		splx(s);
1093135352Smlaier	}
1094135352Smlaier
1095135352Smlaier	return (error);
1096135352Smlaier}
1097177700Smlaier
1098177700Smlaier#ifdef __FreeBSD__
1099177700Smlaiervoid
1100177700Smlaierpf_altq_ifnet_event(struct ifnet *ifp, int remove)
1101177700Smlaier{
1102223637Sbz	struct ifnet	*ifp1;
1103223637Sbz	struct pf_altq	*a1, *a2, *a3;
1104223637Sbz	u_int32_t	 ticket;
1105223637Sbz	int		 error = 0;
1106177700Smlaier
1107177700Smlaier	/* Interrupt userland queue modifications */
1108223637Sbz#ifdef __FreeBSD__
1109223637Sbz	if (V_altqs_inactive_open)
1110223637Sbz		pf_rollback_altq(V_ticket_altqs_inactive);
1111223637Sbz#else
1112177700Smlaier	if (altqs_inactive_open)
1113177700Smlaier		pf_rollback_altq(ticket_altqs_inactive);
1114223637Sbz#endif
1115177700Smlaier
1116177700Smlaier	/* Start new altq ruleset */
1117177700Smlaier	if (pf_begin_altq(&ticket))
1118177700Smlaier		return;
1119177700Smlaier
1120177700Smlaier	/* Copy the current active set */
1121223637Sbz#ifdef __FreeBSD__
1122223637Sbz	TAILQ_FOREACH(a1, V_pf_altqs_active, entries) {
1123223637Sbz		a2 = pool_get(&V_pf_altq_pl, PR_NOWAIT);
1124223637Sbz#else
1125177700Smlaier	TAILQ_FOREACH(a1, pf_altqs_active, entries) {
1126177700Smlaier		a2 = pool_get(&pf_altq_pl, PR_NOWAIT);
1127223637Sbz#endif
1128177700Smlaier		if (a2 == NULL) {
1129177700Smlaier			error = ENOMEM;
1130177700Smlaier			break;
1131177700Smlaier		}
1132177700Smlaier		bcopy(a1, a2, sizeof(struct pf_altq));
1133177700Smlaier
1134177700Smlaier		if (a2->qname[0] != 0) {
1135177700Smlaier			if ((a2->qid = pf_qname2qid(a2->qname)) == 0) {
1136177700Smlaier				error = EBUSY;
1137223637Sbz#ifdef __FreeBSD__
1138223637Sbz				pool_put(&V_pf_altq_pl, a2);
1139223637Sbz#else
1140177700Smlaier				pool_put(&pf_altq_pl, a2);
1141223637Sbz#endif
1142177700Smlaier				break;
1143177700Smlaier			}
1144177700Smlaier			a2->altq_disc = NULL;
1145223637Sbz#ifdef __FreeBSD__
1146223637Sbz			TAILQ_FOREACH(a3, V_pf_altqs_inactive, entries) {
1147223637Sbz#else
1148177700Smlaier			TAILQ_FOREACH(a3, pf_altqs_inactive, entries) {
1149223637Sbz#endif
1150177700Smlaier				if (strncmp(a3->ifname, a2->ifname,
1151177700Smlaier				    IFNAMSIZ) == 0 && a3->qname[0] == 0) {
1152177700Smlaier					a2->altq_disc = a3->altq_disc;
1153177700Smlaier					break;
1154177700Smlaier				}
1155177700Smlaier			}
1156177700Smlaier		}
1157177700Smlaier		/* Deactivate the interface in question */
1158177700Smlaier		a2->local_flags &= ~PFALTQ_FLAG_IF_REMOVED;
1159177700Smlaier		if ((ifp1 = ifunit(a2->ifname)) == NULL ||
1160177700Smlaier		    (remove && ifp1 == ifp)) {
1161177700Smlaier			a2->local_flags |= PFALTQ_FLAG_IF_REMOVED;
1162177700Smlaier		} else {
1163177700Smlaier			PF_UNLOCK();
1164177700Smlaier			error = altq_add(a2);
1165177700Smlaier			PF_LOCK();
1166177700Smlaier
1167223637Sbz#ifdef __FreeBSD__
1168223637Sbz			if (ticket != V_ticket_altqs_inactive)
1169223637Sbz#else
1170177700Smlaier			if (ticket != ticket_altqs_inactive)
1171223637Sbz#endif
1172177700Smlaier				error = EBUSY;
1173177700Smlaier
1174177700Smlaier			if (error) {
1175223637Sbz#ifdef __FreeBSD__
1176223637Sbz				pool_put(&V_pf_altq_pl, a2);
1177223637Sbz#else
1178177700Smlaier				pool_put(&pf_altq_pl, a2);
1179223637Sbz#endif
1180177700Smlaier				break;
1181177700Smlaier			}
1182177700Smlaier		}
1183177700Smlaier
1184223637Sbz#ifdef __FreeBSD__
1185223637Sbz		TAILQ_INSERT_TAIL(V_pf_altqs_inactive, a2, entries);
1186223637Sbz#else
1187177700Smlaier		TAILQ_INSERT_TAIL(pf_altqs_inactive, a2, entries);
1188223637Sbz#endif
1189177700Smlaier	}
1190177700Smlaier
1191177700Smlaier	if (error != 0)
1192177700Smlaier		pf_rollback_altq(ticket);
1193177700Smlaier	else
1194177700Smlaier		pf_commit_altq(ticket);
1195223637Sbz	}
1196177700Smlaier#endif
1197130613Smlaier#endif /* ALTQ */
1198130613Smlaier
1199130613Smlaierint
1200145836Smlaierpf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
1201130613Smlaier{
1202130613Smlaier	struct pf_ruleset	*rs;
1203130613Smlaier	struct pf_rule		*rule;
1204130613Smlaier
1205130613Smlaier	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
1206130613Smlaier		return (EINVAL);
1207145836Smlaier	rs = pf_find_or_create_ruleset(anchor);
1208130613Smlaier	if (rs == NULL)
1209130613Smlaier		return (EINVAL);
1210171168Smlaier	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
1211130613Smlaier		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
1212171168Smlaier		rs->rules[rs_num].inactive.rcount--;
1213171168Smlaier	}
1214130613Smlaier	*ticket = ++rs->rules[rs_num].inactive.ticket;
1215130613Smlaier	rs->rules[rs_num].inactive.open = 1;
1216130613Smlaier	return (0);
1217130613Smlaier}
1218130613Smlaier
1219130613Smlaierint
1220145836Smlaierpf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
1221130613Smlaier{
1222130613Smlaier	struct pf_ruleset	*rs;
1223130613Smlaier	struct pf_rule		*rule;
1224130613Smlaier
1225130613Smlaier	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
1226130613Smlaier		return (EINVAL);
1227145836Smlaier	rs = pf_find_ruleset(anchor);
1228130613Smlaier	if (rs == NULL || !rs->rules[rs_num].inactive.open ||
1229130613Smlaier	    rs->rules[rs_num].inactive.ticket != ticket)
1230130613Smlaier		return (0);
1231171168Smlaier	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
1232130613Smlaier		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
1233171168Smlaier		rs->rules[rs_num].inactive.rcount--;
1234171168Smlaier	}
1235130613Smlaier	rs->rules[rs_num].inactive.open = 0;
1236130613Smlaier	return (0);
1237130613Smlaier}
1238130613Smlaier
1239171168Smlaier#define PF_MD5_UPD(st, elm)						\
1240171168Smlaier		MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm))
1241171168Smlaier
1242171168Smlaier#define PF_MD5_UPD_STR(st, elm)						\
1243171168Smlaier		MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm))
1244171168Smlaier
1245171168Smlaier#define PF_MD5_UPD_HTONL(st, elm, stor) do {				\
1246171168Smlaier		(stor) = htonl((st)->elm);				\
1247171168Smlaier		MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\
1248171168Smlaier} while (0)
1249171168Smlaier
1250171168Smlaier#define PF_MD5_UPD_HTONS(st, elm, stor) do {				\
1251171168Smlaier		(stor) = htons((st)->elm);				\
1252171168Smlaier		MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\
1253171168Smlaier} while (0)
1254171168Smlaier
1255171168Smlaiervoid
1256171168Smlaierpf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
1257171168Smlaier{
1258171168Smlaier	PF_MD5_UPD(pfr, addr.type);
1259171168Smlaier	switch (pfr->addr.type) {
1260171168Smlaier		case PF_ADDR_DYNIFTL:
1261171168Smlaier			PF_MD5_UPD(pfr, addr.v.ifname);
1262171168Smlaier			PF_MD5_UPD(pfr, addr.iflags);
1263171168Smlaier			break;
1264171168Smlaier		case PF_ADDR_TABLE:
1265171168Smlaier			PF_MD5_UPD(pfr, addr.v.tblname);
1266171168Smlaier			break;
1267171168Smlaier		case PF_ADDR_ADDRMASK:
1268171168Smlaier			/* XXX ignore af? */
1269171168Smlaier			PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
1270171168Smlaier			PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
1271171168Smlaier			break;
1272171168Smlaier		case PF_ADDR_RTLABEL:
1273171168Smlaier			PF_MD5_UPD(pfr, addr.v.rtlabelname);
1274171168Smlaier			break;
1275171168Smlaier	}
1276171168Smlaier
1277171168Smlaier	PF_MD5_UPD(pfr, port[0]);
1278171168Smlaier	PF_MD5_UPD(pfr, port[1]);
1279171168Smlaier	PF_MD5_UPD(pfr, neg);
1280171168Smlaier	PF_MD5_UPD(pfr, port_op);
1281171168Smlaier}
1282171168Smlaier
1283171168Smlaiervoid
1284171168Smlaierpf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
1285171168Smlaier{
1286171168Smlaier	u_int16_t x;
1287171168Smlaier	u_int32_t y;
1288171168Smlaier
1289171168Smlaier	pf_hash_rule_addr(ctx, &rule->src);
1290171168Smlaier	pf_hash_rule_addr(ctx, &rule->dst);
1291171168Smlaier	PF_MD5_UPD_STR(rule, label);
1292171168Smlaier	PF_MD5_UPD_STR(rule, ifname);
1293171168Smlaier	PF_MD5_UPD_STR(rule, match_tagname);
1294171168Smlaier	PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
1295171168Smlaier	PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
1296171168Smlaier	PF_MD5_UPD_HTONL(rule, prob, y);
1297171168Smlaier	PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
1298171168Smlaier	PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
1299171168Smlaier	PF_MD5_UPD(rule, uid.op);
1300171168Smlaier	PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
1301171168Smlaier	PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
1302171168Smlaier	PF_MD5_UPD(rule, gid.op);
1303171168Smlaier	PF_MD5_UPD_HTONL(rule, rule_flag, y);
1304171168Smlaier	PF_MD5_UPD(rule, action);
1305171168Smlaier	PF_MD5_UPD(rule, direction);
1306171168Smlaier	PF_MD5_UPD(rule, af);
1307171168Smlaier	PF_MD5_UPD(rule, quick);
1308171168Smlaier	PF_MD5_UPD(rule, ifnot);
1309171168Smlaier	PF_MD5_UPD(rule, match_tag_not);
1310171168Smlaier	PF_MD5_UPD(rule, natpass);
1311171168Smlaier	PF_MD5_UPD(rule, keep_state);
1312171168Smlaier	PF_MD5_UPD(rule, proto);
1313171168Smlaier	PF_MD5_UPD(rule, type);
1314171168Smlaier	PF_MD5_UPD(rule, code);
1315171168Smlaier	PF_MD5_UPD(rule, flags);
1316171168Smlaier	PF_MD5_UPD(rule, flagset);
1317171168Smlaier	PF_MD5_UPD(rule, allow_opts);
1318171168Smlaier	PF_MD5_UPD(rule, rt);
1319171168Smlaier	PF_MD5_UPD(rule, tos);
1320171168Smlaier}
1321171168Smlaier
1322130613Smlaierint
1323145836Smlaierpf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
1324130613Smlaier{
1325130613Smlaier	struct pf_ruleset	*rs;
1326171168Smlaier	struct pf_rule		*rule, **old_array;
1327130613Smlaier	struct pf_rulequeue	*old_rules;
1328171168Smlaier	int			 s, error;
1329171168Smlaier	u_int32_t		 old_rcount;
1330130613Smlaier
1331130613Smlaier	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
1332130613Smlaier		return (EINVAL);
1333145836Smlaier	rs = pf_find_ruleset(anchor);
1334130613Smlaier	if (rs == NULL || !rs->rules[rs_num].inactive.open ||
1335130613Smlaier	    ticket != rs->rules[rs_num].inactive.ticket)
1336130613Smlaier		return (EBUSY);
1337130613Smlaier
1338171168Smlaier	/* Calculate checksum for the main ruleset */
1339171168Smlaier	if (rs == &pf_main_ruleset) {
1340171168Smlaier		error = pf_setup_pfsync_matching(rs);
1341171168Smlaier		if (error != 0)
1342171168Smlaier			return (error);
1343171168Smlaier	}
1344171168Smlaier
1345130613Smlaier	/* Swap rules, keep the old. */
1346130613Smlaier	s = splsoftnet();
1347130613Smlaier	old_rules = rs->rules[rs_num].active.ptr;
1348171168Smlaier	old_rcount = rs->rules[rs_num].active.rcount;
1349171168Smlaier	old_array = rs->rules[rs_num].active.ptr_array;
1350171168Smlaier
1351130613Smlaier	rs->rules[rs_num].active.ptr =
1352130613Smlaier	    rs->rules[rs_num].inactive.ptr;
1353171168Smlaier	rs->rules[rs_num].active.ptr_array =
1354171168Smlaier	    rs->rules[rs_num].inactive.ptr_array;
1355171168Smlaier	rs->rules[rs_num].active.rcount =
1356171168Smlaier	    rs->rules[rs_num].inactive.rcount;
1357130613Smlaier	rs->rules[rs_num].inactive.ptr = old_rules;
1358171168Smlaier	rs->rules[rs_num].inactive.ptr_array = old_array;
1359171168Smlaier	rs->rules[rs_num].inactive.rcount = old_rcount;
1360171168Smlaier
1361130613Smlaier	rs->rules[rs_num].active.ticket =
1362130613Smlaier	    rs->rules[rs_num].inactive.ticket;
1363130613Smlaier	pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
1364130613Smlaier
1365171168Smlaier
1366130613Smlaier	/* Purge the old rule list. */
1367130613Smlaier	while ((rule = TAILQ_FIRST(old_rules)) != NULL)
1368130613Smlaier		pf_rm_rule(old_rules, rule);
1369171168Smlaier	if (rs->rules[rs_num].inactive.ptr_array)
1370171168Smlaier		free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
1371171168Smlaier	rs->rules[rs_num].inactive.ptr_array = NULL;
1372171168Smlaier	rs->rules[rs_num].inactive.rcount = 0;
1373130613Smlaier	rs->rules[rs_num].inactive.open = 0;
1374130613Smlaier	pf_remove_if_empty_ruleset(rs);
1375130613Smlaier	splx(s);
1376130613Smlaier	return (0);
1377130613Smlaier}
1378130613Smlaier
1379171168Smlaierint
1380171168Smlaierpf_setup_pfsync_matching(struct pf_ruleset *rs)
1381171168Smlaier{
1382171168Smlaier	MD5_CTX			 ctx;
1383171168Smlaier	struct pf_rule		*rule;
1384171168Smlaier	int			 rs_cnt;
1385171168Smlaier	u_int8_t		 digest[PF_MD5_DIGEST_LENGTH];
1386171168Smlaier
1387171168Smlaier	MD5Init(&ctx);
1388171168Smlaier	for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
1389171168Smlaier		/* XXX PF_RULESET_SCRUB as well? */
1390171168Smlaier		if (rs_cnt == PF_RULESET_SCRUB)
1391171168Smlaier			continue;
1392171168Smlaier
1393171168Smlaier		if (rs->rules[rs_cnt].inactive.ptr_array)
1394171168Smlaier			free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
1395171168Smlaier		rs->rules[rs_cnt].inactive.ptr_array = NULL;
1396171168Smlaier
1397171168Smlaier		if (rs->rules[rs_cnt].inactive.rcount) {
1398171168Smlaier			rs->rules[rs_cnt].inactive.ptr_array =
1399171168Smlaier			    malloc(sizeof(caddr_t) *
1400171168Smlaier			    rs->rules[rs_cnt].inactive.rcount,
1401171168Smlaier			    M_TEMP, M_NOWAIT);
1402171168Smlaier
1403171168Smlaier			if (!rs->rules[rs_cnt].inactive.ptr_array)
1404171168Smlaier				return (ENOMEM);
1405171168Smlaier		}
1406171168Smlaier
1407171168Smlaier		TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
1408171168Smlaier		    entries) {
1409171168Smlaier			pf_hash_rule(&ctx, rule);
1410171168Smlaier			(rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
1411171168Smlaier		}
1412171168Smlaier	}
1413171168Smlaier
1414171168Smlaier	MD5Final(digest, &ctx);
1415223637Sbz#ifdef __FreeBSD__
1416223637Sbz	memcpy(V_pf_status.pf_chksum, digest, sizeof(V_pf_status.pf_chksum));
1417223637Sbz#else
1418171168Smlaier	memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
1419223637Sbz#endif
1420171168Smlaier	return (0);
1421171168Smlaier}
1422171168Smlaier
1423171168Smlaierint
1424223637Sbzpf_addr_setup(struct pf_ruleset *ruleset, struct pf_addr_wrap *addr,
1425223637Sbz    sa_family_t af)
1426223637Sbz{
1427223637Sbz	if (pfi_dynaddr_setup(addr, af) ||
1428223637Sbz	    pf_tbladdr_setup(ruleset, addr))
1429223637Sbz		return (EINVAL);
1430223637Sbz
1431223637Sbz	return (0);
1432223637Sbz}
1433223637Sbz
1434223637Sbzvoid
1435223637Sbzpf_addr_copyout(struct pf_addr_wrap *addr)
1436223637Sbz{
1437223637Sbz	pfi_dynaddr_copyout(addr);
1438223637Sbz	pf_tbladdr_copyout(addr);
1439223637Sbz	pf_rtlabel_copyout(addr);
1440223637Sbz}
1441223637Sbz
1442223637Sbzint
1443127145Smlaier#ifdef __FreeBSD__
1444130585Sphkpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
1445126261Smlaier#else
1446171168Smlaierpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
1447126261Smlaier#endif
1448126258Smlaier{
1449126258Smlaier	struct pf_pooladdr	*pa = NULL;
1450126258Smlaier	struct pf_pool		*pool = NULL;
1451145836Smlaier#ifndef __FreeBSD__
1452126258Smlaier	int			 s;
1453145836Smlaier#endif
1454126258Smlaier	int			 error = 0;
1455126258Smlaier
1456223637Sbz	CURVNET_SET(TD_TO_VNET(td));
1457223637Sbz
1458126258Smlaier	/* XXX keep in sync with switch() below */
1459134166Smlaier#ifdef __FreeBSD__
1460140494Sdhartmei	if (securelevel_gt(td->td_ucred, 2))
1461134166Smlaier#else
1462126258Smlaier	if (securelevel > 1)
1463134166Smlaier#endif
1464126258Smlaier		switch (cmd) {
1465126258Smlaier		case DIOCGETRULES:
1466126258Smlaier		case DIOCGETRULE:
1467126258Smlaier		case DIOCGETADDRS:
1468126258Smlaier		case DIOCGETADDR:
1469126258Smlaier		case DIOCGETSTATE:
1470126258Smlaier		case DIOCSETSTATUSIF:
1471126258Smlaier		case DIOCGETSTATUS:
1472126258Smlaier		case DIOCCLRSTATUS:
1473126258Smlaier		case DIOCNATLOOK:
1474126258Smlaier		case DIOCSETDEBUG:
1475126258Smlaier		case DIOCGETSTATES:
1476126258Smlaier		case DIOCGETTIMEOUT:
1477126258Smlaier		case DIOCCLRRULECTRS:
1478126258Smlaier		case DIOCGETLIMIT:
1479126258Smlaier		case DIOCGETALTQS:
1480126258Smlaier		case DIOCGETALTQ:
1481126258Smlaier		case DIOCGETQSTATS:
1482126258Smlaier		case DIOCGETRULESETS:
1483126258Smlaier		case DIOCGETRULESET:
1484126258Smlaier		case DIOCRGETTABLES:
1485126258Smlaier		case DIOCRGETTSTATS:
1486126258Smlaier		case DIOCRCLRTSTATS:
1487126258Smlaier		case DIOCRCLRADDRS:
1488126258Smlaier		case DIOCRADDADDRS:
1489126258Smlaier		case DIOCRDELADDRS:
1490126258Smlaier		case DIOCRSETADDRS:
1491126258Smlaier		case DIOCRGETADDRS:
1492126258Smlaier		case DIOCRGETASTATS:
1493126258Smlaier		case DIOCRCLRASTATS:
1494126258Smlaier		case DIOCRTSTADDRS:
1495126258Smlaier		case DIOCOSFPGET:
1496130613Smlaier		case DIOCGETSRCNODES:
1497130613Smlaier		case DIOCCLRSRCNODES:
1498130613Smlaier		case DIOCIGETIFACES:
1499127145Smlaier#ifdef __FreeBSD__
1500126261Smlaier		case DIOCGIFSPEED:
1501126261Smlaier#endif
1502145836Smlaier		case DIOCSETIFFLAG:
1503145836Smlaier		case DIOCCLRIFFLAG:
1504126258Smlaier			break;
1505130613Smlaier		case DIOCRCLRTABLES:
1506130613Smlaier		case DIOCRADDTABLES:
1507130613Smlaier		case DIOCRDELTABLES:
1508130613Smlaier		case DIOCRSETTFLAGS:
1509130613Smlaier			if (((struct pfioc_table *)addr)->pfrio_flags &
1510130613Smlaier			    PFR_FLAG_DUMMY)
1511130613Smlaier				break; /* dummy operation ok */
1512130613Smlaier			return (EPERM);
1513126258Smlaier		default:
1514126258Smlaier			return (EPERM);
1515126258Smlaier		}
1516126258Smlaier
1517126258Smlaier	if (!(flags & FWRITE))
1518126258Smlaier		switch (cmd) {
1519126258Smlaier		case DIOCGETRULES:
1520126258Smlaier		case DIOCGETADDRS:
1521126258Smlaier		case DIOCGETADDR:
1522126258Smlaier		case DIOCGETSTATE:
1523126258Smlaier		case DIOCGETSTATUS:
1524126258Smlaier		case DIOCGETSTATES:
1525126258Smlaier		case DIOCGETTIMEOUT:
1526126258Smlaier		case DIOCGETLIMIT:
1527126258Smlaier		case DIOCGETALTQS:
1528126258Smlaier		case DIOCGETALTQ:
1529126258Smlaier		case DIOCGETQSTATS:
1530126258Smlaier		case DIOCGETRULESETS:
1531126258Smlaier		case DIOCGETRULESET:
1532171168Smlaier		case DIOCNATLOOK:
1533126258Smlaier		case DIOCRGETTABLES:
1534126258Smlaier		case DIOCRGETTSTATS:
1535126258Smlaier		case DIOCRGETADDRS:
1536126258Smlaier		case DIOCRGETASTATS:
1537126258Smlaier		case DIOCRTSTADDRS:
1538126258Smlaier		case DIOCOSFPGET:
1539130613Smlaier		case DIOCGETSRCNODES:
1540130613Smlaier		case DIOCIGETIFACES:
1541127145Smlaier#ifdef __FreeBSD__
1542126261Smlaier		case DIOCGIFSPEED:
1543126261Smlaier#endif
1544126258Smlaier			break;
1545130613Smlaier		case DIOCRCLRTABLES:
1546130613Smlaier		case DIOCRADDTABLES:
1547130613Smlaier		case DIOCRDELTABLES:
1548130613Smlaier		case DIOCRCLRTSTATS:
1549130613Smlaier		case DIOCRCLRADDRS:
1550130613Smlaier		case DIOCRADDADDRS:
1551130613Smlaier		case DIOCRDELADDRS:
1552130613Smlaier		case DIOCRSETADDRS:
1553130613Smlaier		case DIOCRSETTFLAGS:
1554130613Smlaier			if (((struct pfioc_table *)addr)->pfrio_flags &
1555171168Smlaier			    PFR_FLAG_DUMMY) {
1556171168Smlaier				flags |= FWRITE; /* need write lock for dummy */
1557130613Smlaier				break; /* dummy operation ok */
1558171168Smlaier			}
1559130613Smlaier			return (EACCES);
1560171168Smlaier		case DIOCGETRULE:
1561223637Sbz			if (((struct pfioc_rule *)addr)->action ==
1562223637Sbz			    PF_GET_CLR_CNTR)
1563171168Smlaier				return (EACCES);
1564171168Smlaier			break;
1565126258Smlaier		default:
1566126258Smlaier			return (EACCES);
1567126258Smlaier		}
1568126258Smlaier
1569171168Smlaier	if (flags & FWRITE)
1570127145Smlaier#ifdef __FreeBSD__
1571223637Sbz		sx_xlock(&V_pf_consistency_lock);
1572171168Smlaier	else
1573223637Sbz		sx_slock(&V_pf_consistency_lock);
1574171168Smlaier#else
1575171168Smlaier		rw_enter_write(&pf_consistency_lock);
1576171168Smlaier	else
1577171168Smlaier		rw_enter_read(&pf_consistency_lock);
1578171168Smlaier#endif
1579171168Smlaier
1580171168Smlaier#ifdef __FreeBSD__
1581126261Smlaier	PF_LOCK();
1582145836Smlaier#else
1583145836Smlaier	s = splsoftnet();
1584126261Smlaier#endif
1585126258Smlaier	switch (cmd) {
1586126258Smlaier
1587126258Smlaier	case DIOCSTART:
1588223637Sbz#ifdef __FreeBSD__
1589223637Sbz		if (V_pf_status.running)
1590223637Sbz#else
1591126258Smlaier		if (pf_status.running)
1592223637Sbz#endif
1593126258Smlaier			error = EEXIST;
1594126258Smlaier		else {
1595127145Smlaier#ifdef __FreeBSD__
1596126261Smlaier			PF_UNLOCK();
1597126261Smlaier			error = hook_pf();
1598126261Smlaier			PF_LOCK();
1599126261Smlaier			if (error) {
1600126261Smlaier				DPFPRINTF(PF_DEBUG_MISC,
1601126261Smlaier				    ("pf: pfil registeration fail\n"));
1602126261Smlaier				break;
1603126261Smlaier			}
1604223637Sbz			V_pf_status.running = 1;
1605223637Sbz			V_pf_status.since = time_second;
1606223637Sbz
1607223637Sbz			if (V_pf_status.stateid == 0) {
1608223637Sbz				V_pf_status.stateid = time_second;
1609223637Sbz				V_pf_status.stateid = V_pf_status.stateid << 32;
1610223637Sbz			}
1611223637Sbz#else
1612126258Smlaier			pf_status.running = 1;
1613126261Smlaier			pf_status.since = time_second;
1614223637Sbz
1615130613Smlaier			if (pf_status.stateid == 0) {
1616130613Smlaier				pf_status.stateid = time_second;
1617130613Smlaier				pf_status.stateid = pf_status.stateid << 32;
1618130613Smlaier			}
1619223637Sbz#endif
1620126258Smlaier			DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
1621126258Smlaier		}
1622126258Smlaier		break;
1623126258Smlaier
1624126258Smlaier	case DIOCSTOP:
1625223637Sbz#ifdef __FreeBSD__
1626223637Sbz		if (!V_pf_status.running)
1627126258Smlaier			error = ENOENT;
1628126258Smlaier		else {
1629223637Sbz			V_pf_status.running = 0;
1630126261Smlaier			PF_UNLOCK();
1631126261Smlaier			error = dehook_pf();
1632126261Smlaier			PF_LOCK();
1633126261Smlaier			if (error) {
1634223637Sbz				V_pf_status.running = 1;
1635126261Smlaier				DPFPRINTF(PF_DEBUG_MISC,
1636223637Sbz				    ("pf: pfil unregisteration failed\n"));
1637126261Smlaier			}
1638223637Sbz			V_pf_status.since = time_second;
1639223637Sbz#else
1640223637Sbz		if (!pf_status.running)
1641223637Sbz			error = ENOENT;
1642223637Sbz		else {
1643223637Sbz			pf_status.running = 0;
1644223637Sbz			pf_status.since = time_second;
1645145836Smlaier#endif
1646126258Smlaier			DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
1647126258Smlaier		}
1648126258Smlaier		break;
1649126258Smlaier
1650126258Smlaier	case DIOCADDRULE: {
1651126258Smlaier		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
1652126258Smlaier		struct pf_ruleset	*ruleset;
1653126258Smlaier		struct pf_rule		*rule, *tail;
1654126258Smlaier		struct pf_pooladdr	*pa;
1655126258Smlaier		int			 rs_num;
1656126258Smlaier
1657145836Smlaier		pr->anchor[sizeof(pr->anchor) - 1] = 0;
1658145836Smlaier		ruleset = pf_find_ruleset(pr->anchor);
1659126258Smlaier		if (ruleset == NULL) {
1660126258Smlaier			error = EINVAL;
1661126258Smlaier			break;
1662126258Smlaier		}
1663126258Smlaier		rs_num = pf_get_ruleset_number(pr->rule.action);
1664126258Smlaier		if (rs_num >= PF_RULESET_MAX) {
1665126258Smlaier			error = EINVAL;
1666126258Smlaier			break;
1667126258Smlaier		}
1668126258Smlaier		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1669126258Smlaier			error = EINVAL;
1670126258Smlaier			break;
1671126258Smlaier		}
1672126258Smlaier		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
1673158486Smlaier#ifdef __FreeBSD__
1674158486Smlaier			DPFPRINTF(PF_DEBUG_MISC,
1675158486Smlaier			    ("ticket: %d != [%d]%d\n", pr->ticket, rs_num,
1676158486Smlaier			    ruleset->rules[rs_num].inactive.ticket));
1677158486Smlaier#endif
1678126258Smlaier			error = EBUSY;
1679126258Smlaier			break;
1680126258Smlaier		}
1681158486Smlaier#ifdef __FreeBSD__
1682223637Sbz		if (pr->pool_ticket != V_ticket_pabuf) {
1683158486Smlaier			DPFPRINTF(PF_DEBUG_MISC,
1684158486Smlaier			    ("pool_ticket: %d != %d\n", pr->pool_ticket,
1685223637Sbz			    V_ticket_pabuf));
1686223637Sbz#else
1687223637Sbz		if (pr->pool_ticket != ticket_pabuf) {
1688158486Smlaier#endif
1689126258Smlaier			error = EBUSY;
1690126258Smlaier			break;
1691126258Smlaier		}
1692223637Sbz#ifdef __FreeBSD__
1693223637Sbz		rule = pool_get(&V_pf_rule_pl, PR_NOWAIT);
1694223637Sbz#else
1695223637Sbz		rule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL);
1696223637Sbz#endif
1697126258Smlaier		if (rule == NULL) {
1698126258Smlaier			error = ENOMEM;
1699126258Smlaier			break;
1700126258Smlaier		}
1701126258Smlaier		bcopy(&pr->rule, rule, sizeof(struct pf_rule));
1702171168Smlaier#ifdef __FreeBSD__
1703171168Smlaier		rule->cuid = td->td_ucred->cr_ruid;
1704171168Smlaier		rule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
1705171168Smlaier#else
1706171168Smlaier		rule->cuid = p->p_cred->p_ruid;
1707171168Smlaier		rule->cpid = p->p_pid;
1708171168Smlaier#endif
1709126258Smlaier		rule->anchor = NULL;
1710130613Smlaier		rule->kif = NULL;
1711126258Smlaier		TAILQ_INIT(&rule->rpool.list);
1712126258Smlaier		/* initialize refcounting */
1713223637Sbz		rule->states_cur = 0;
1714130613Smlaier		rule->src_nodes = 0;
1715126258Smlaier		rule->entries.tqe_prev = NULL;
1716126258Smlaier#ifndef INET
1717126258Smlaier		if (rule->af == AF_INET) {
1718223637Sbz#ifdef __FreeBSD__
1719223637Sbz			pool_put(&V_pf_rule_pl, rule);
1720223637Sbz#else
1721126258Smlaier			pool_put(&pf_rule_pl, rule);
1722223637Sbz#endif
1723126258Smlaier			error = EAFNOSUPPORT;
1724126258Smlaier			break;
1725126258Smlaier		}
1726126258Smlaier#endif /* INET */
1727126258Smlaier#ifndef INET6
1728126258Smlaier		if (rule->af == AF_INET6) {
1729223637Sbz#ifdef __FreeBSD__
1730223637Sbz			pool_put(&V_pf_rule_pl, rule);
1731223637Sbz#else
1732126258Smlaier			pool_put(&pf_rule_pl, rule);
1733223637Sbz#endif
1734126258Smlaier			error = EAFNOSUPPORT;
1735126258Smlaier			break;
1736126258Smlaier		}
1737126258Smlaier#endif /* INET6 */
1738126258Smlaier		tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
1739126258Smlaier		    pf_rulequeue);
1740126258Smlaier		if (tail)
1741126258Smlaier			rule->nr = tail->nr + 1;
1742126258Smlaier		else
1743126258Smlaier			rule->nr = 0;
1744126258Smlaier		if (rule->ifname[0]) {
1745171168Smlaier			rule->kif = pfi_kif_get(rule->ifname);
1746130613Smlaier			if (rule->kif == NULL) {
1747223637Sbz#ifdef __FreeBSD__
1748223637Sbz				pool_put(&V_pf_rule_pl, rule);
1749223637Sbz#else
1750126258Smlaier				pool_put(&pf_rule_pl, rule);
1751223637Sbz#endif
1752126258Smlaier				error = EINVAL;
1753126258Smlaier				break;
1754126258Smlaier			}
1755171168Smlaier			pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
1756126258Smlaier		}
1757126258Smlaier
1758180788Sjulian#ifdef __FreeBSD__ /* ROUTING */
1759232292Sbz		if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
1760171168Smlaier#else
1761171168Smlaier		if (rule->rtableid > 0 && !rtable_exists(rule->rtableid))
1762171168Smlaier#endif
1763171168Smlaier			error = EBUSY;
1764171168Smlaier
1765130613Smlaier#ifdef ALTQ
1766130613Smlaier		/* set queue IDs */
1767130613Smlaier		if (rule->qname[0] != 0) {
1768130613Smlaier			if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
1769130613Smlaier				error = EBUSY;
1770130613Smlaier			else if (rule->pqname[0] != 0) {
1771130613Smlaier				if ((rule->pqid =
1772130613Smlaier				    pf_qname2qid(rule->pqname)) == 0)
1773130613Smlaier					error = EBUSY;
1774130613Smlaier			} else
1775130613Smlaier				rule->pqid = rule->qid;
1776130613Smlaier		}
1777130613Smlaier#endif
1778126258Smlaier		if (rule->tagname[0])
1779126258Smlaier			if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
1780126258Smlaier				error = EBUSY;
1781126258Smlaier		if (rule->match_tagname[0])
1782126258Smlaier			if ((rule->match_tag =
1783126258Smlaier			    pf_tagname2tag(rule->match_tagname)) == 0)
1784126258Smlaier				error = EBUSY;
1785126258Smlaier		if (rule->rt && !rule->direction)
1786126258Smlaier			error = EINVAL;
1787171168Smlaier#if NPFLOG > 0
1788171168Smlaier		if (!rule->log)
1789171168Smlaier			rule->logif = 0;
1790171168Smlaier		if (rule->logif >= PFLOGIFS_MAX)
1791171168Smlaier			error = EINVAL;
1792171168Smlaier#endif
1793145836Smlaier		if (pf_rtlabel_add(&rule->src.addr) ||
1794145836Smlaier		    pf_rtlabel_add(&rule->dst.addr))
1795145836Smlaier			error = EBUSY;
1796223637Sbz		if (pf_addr_setup(ruleset, &rule->src.addr, rule->af))
1797126258Smlaier			error = EINVAL;
1798223637Sbz		if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af))
1799126258Smlaier			error = EINVAL;
1800145836Smlaier		if (pf_anchor_setup(rule, ruleset, pr->anchor_call))
1801145836Smlaier			error = EINVAL;
1802223637Sbz#ifdef __FreeBSD__
1803223637Sbz		TAILQ_FOREACH(pa, &V_pf_pabuf, entries)
1804223637Sbz#else
1805126258Smlaier		TAILQ_FOREACH(pa, &pf_pabuf, entries)
1806223637Sbz#endif
1807126258Smlaier			if (pf_tbladdr_setup(ruleset, &pa->addr))
1808126258Smlaier				error = EINVAL;
1809126258Smlaier
1810145836Smlaier		if (rule->overload_tblname[0]) {
1811145836Smlaier			if ((rule->overload_tbl = pfr_attach_table(ruleset,
1812223637Sbz			    rule->overload_tblname, 0)) == NULL)
1813145836Smlaier				error = EINVAL;
1814145836Smlaier			else
1815145836Smlaier				rule->overload_tbl->pfrkt_flags |=
1816145836Smlaier				    PFR_TFLAG_ACTIVE;
1817145836Smlaier		}
1818145836Smlaier
1819223637Sbz#ifdef __FreeBSD__
1820223637Sbz		pf_mv_pool(&V_pf_pabuf, &rule->rpool.list);
1821223637Sbz#else
1822126258Smlaier		pf_mv_pool(&pf_pabuf, &rule->rpool.list);
1823223637Sbz#endif
1824126258Smlaier		if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
1825145836Smlaier		    (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
1826126258Smlaier		    (rule->rt > PF_FASTROUTE)) &&
1827126258Smlaier		    (TAILQ_FIRST(&rule->rpool.list) == NULL))
1828126258Smlaier			error = EINVAL;
1829126258Smlaier
1830126258Smlaier		if (error) {
1831126258Smlaier			pf_rm_rule(NULL, rule);
1832126258Smlaier			break;
1833126258Smlaier		}
1834171168Smlaier
1835171168Smlaier#ifdef __FreeBSD__
1836223637Sbz		if (!V_debug_pfugidhack && (rule->uid.op || rule->gid.op ||
1837171168Smlaier		    rule->log & PF_LOG_SOCKET_LOOKUP)) {
1838171168Smlaier			DPFPRINTF(PF_DEBUG_MISC,
1839171168Smlaier			    ("pf: debug.pfugidhack enabled\n"));
1840223637Sbz			V_debug_pfugidhack = 1;
1841171168Smlaier		}
1842171168Smlaier#endif
1843126258Smlaier		rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
1844171168Smlaier		rule->evaluations = rule->packets[0] = rule->packets[1] =
1845171168Smlaier		    rule->bytes[0] = rule->bytes[1] = 0;
1846126258Smlaier		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
1847126258Smlaier		    rule, entries);
1848171168Smlaier		ruleset->rules[rs_num].inactive.rcount++;
1849126258Smlaier		break;
1850126258Smlaier	}
1851126258Smlaier
1852126258Smlaier	case DIOCGETRULES: {
1853126258Smlaier		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
1854126258Smlaier		struct pf_ruleset	*ruleset;
1855126258Smlaier		struct pf_rule		*tail;
1856126258Smlaier		int			 rs_num;
1857126258Smlaier
1858145836Smlaier		pr->anchor[sizeof(pr->anchor) - 1] = 0;
1859145836Smlaier		ruleset = pf_find_ruleset(pr->anchor);
1860126258Smlaier		if (ruleset == NULL) {
1861126258Smlaier			error = EINVAL;
1862126258Smlaier			break;
1863126258Smlaier		}
1864126258Smlaier		rs_num = pf_get_ruleset_number(pr->rule.action);
1865126258Smlaier		if (rs_num >= PF_RULESET_MAX) {
1866126258Smlaier			error = EINVAL;
1867126258Smlaier			break;
1868126258Smlaier		}
1869126258Smlaier		tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
1870126258Smlaier		    pf_rulequeue);
1871126258Smlaier		if (tail)
1872126258Smlaier			pr->nr = tail->nr + 1;
1873126258Smlaier		else
1874126258Smlaier			pr->nr = 0;
1875126258Smlaier		pr->ticket = ruleset->rules[rs_num].active.ticket;
1876126258Smlaier		break;
1877126258Smlaier	}
1878126258Smlaier
1879126258Smlaier	case DIOCGETRULE: {
1880126258Smlaier		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
1881126258Smlaier		struct pf_ruleset	*ruleset;
1882126258Smlaier		struct pf_rule		*rule;
1883126258Smlaier		int			 rs_num, i;
1884126258Smlaier
1885145836Smlaier		pr->anchor[sizeof(pr->anchor) - 1] = 0;
1886145836Smlaier		ruleset = pf_find_ruleset(pr->anchor);
1887126258Smlaier		if (ruleset == NULL) {
1888126258Smlaier			error = EINVAL;
1889126258Smlaier			break;
1890126258Smlaier		}
1891126258Smlaier		rs_num = pf_get_ruleset_number(pr->rule.action);
1892126258Smlaier		if (rs_num >= PF_RULESET_MAX) {
1893126258Smlaier			error = EINVAL;
1894126258Smlaier			break;
1895126258Smlaier		}
1896126258Smlaier		if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
1897126258Smlaier			error = EBUSY;
1898126258Smlaier			break;
1899126258Smlaier		}
1900126258Smlaier		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
1901126258Smlaier		while ((rule != NULL) && (rule->nr != pr->nr))
1902126258Smlaier			rule = TAILQ_NEXT(rule, entries);
1903126258Smlaier		if (rule == NULL) {
1904126258Smlaier			error = EBUSY;
1905126258Smlaier			break;
1906126258Smlaier		}
1907126258Smlaier		bcopy(rule, &pr->rule, sizeof(struct pf_rule));
1908145836Smlaier		if (pf_anchor_copyout(ruleset, rule, pr)) {
1909145836Smlaier			error = EBUSY;
1910145836Smlaier			break;
1911145836Smlaier		}
1912223637Sbz		pf_addr_copyout(&pr->rule.src.addr);
1913223637Sbz		pf_addr_copyout(&pr->rule.dst.addr);
1914126258Smlaier		for (i = 0; i < PF_SKIP_COUNT; ++i)
1915126258Smlaier			if (rule->skip[i].ptr == NULL)
1916126258Smlaier				pr->rule.skip[i].nr = -1;
1917126258Smlaier			else
1918126258Smlaier				pr->rule.skip[i].nr =
1919126258Smlaier				    rule->skip[i].ptr->nr;
1920171168Smlaier
1921171168Smlaier		if (pr->action == PF_GET_CLR_CNTR) {
1922171168Smlaier			rule->evaluations = 0;
1923171168Smlaier			rule->packets[0] = rule->packets[1] = 0;
1924171168Smlaier			rule->bytes[0] = rule->bytes[1] = 0;
1925223637Sbz			rule->states_tot = 0;
1926171168Smlaier		}
1927126258Smlaier		break;
1928126258Smlaier	}
1929126258Smlaier
1930126258Smlaier	case DIOCCHANGERULE: {
1931126258Smlaier		struct pfioc_rule	*pcr = (struct pfioc_rule *)addr;
1932126258Smlaier		struct pf_ruleset	*ruleset;
1933126258Smlaier		struct pf_rule		*oldrule = NULL, *newrule = NULL;
1934126258Smlaier		u_int32_t		 nr = 0;
1935126258Smlaier		int			 rs_num;
1936126258Smlaier
1937126258Smlaier		if (!(pcr->action == PF_CHANGE_REMOVE ||
1938126258Smlaier		    pcr->action == PF_CHANGE_GET_TICKET) &&
1939223637Sbz#ifdef __FreeBSD__
1940223637Sbz		    pcr->pool_ticket != V_ticket_pabuf) {
1941223637Sbz#else
1942126258Smlaier		    pcr->pool_ticket != ticket_pabuf) {
1943223637Sbz#endif
1944126258Smlaier			error = EBUSY;
1945126258Smlaier			break;
1946126258Smlaier		}
1947126258Smlaier
1948126258Smlaier		if (pcr->action < PF_CHANGE_ADD_HEAD ||
1949126258Smlaier		    pcr->action > PF_CHANGE_GET_TICKET) {
1950126258Smlaier			error = EINVAL;
1951126258Smlaier			break;
1952126258Smlaier		}
1953145836Smlaier		ruleset = pf_find_ruleset(pcr->anchor);
1954126258Smlaier		if (ruleset == NULL) {
1955126258Smlaier			error = EINVAL;
1956126258Smlaier			break;
1957126258Smlaier		}
1958126258Smlaier		rs_num = pf_get_ruleset_number(pcr->rule.action);
1959126258Smlaier		if (rs_num >= PF_RULESET_MAX) {
1960126258Smlaier			error = EINVAL;
1961126258Smlaier			break;
1962126258Smlaier		}
1963126258Smlaier
1964126258Smlaier		if (pcr->action == PF_CHANGE_GET_TICKET) {
1965126258Smlaier			pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
1966126258Smlaier			break;
1967126258Smlaier		} else {
1968126258Smlaier			if (pcr->ticket !=
1969126258Smlaier			    ruleset->rules[rs_num].active.ticket) {
1970126258Smlaier				error = EINVAL;
1971126258Smlaier				break;
1972126258Smlaier			}
1973126258Smlaier			if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
1974126258Smlaier				error = EINVAL;
1975126258Smlaier				break;
1976126258Smlaier			}
1977126258Smlaier		}
1978126258Smlaier
1979126258Smlaier		if (pcr->action != PF_CHANGE_REMOVE) {
1980223637Sbz#ifdef __FreeBSD__
1981223637Sbz			newrule = pool_get(&V_pf_rule_pl, PR_NOWAIT);
1982223637Sbz#else
1983223637Sbz			newrule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL);
1984223637Sbz#endif
1985126258Smlaier			if (newrule == NULL) {
1986126258Smlaier				error = ENOMEM;
1987126258Smlaier				break;
1988126258Smlaier			}
1989126258Smlaier			bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
1990171168Smlaier#ifdef __FreeBSD__
1991171168Smlaier			newrule->cuid = td->td_ucred->cr_ruid;
1992171168Smlaier			newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
1993171168Smlaier#else
1994171168Smlaier			newrule->cuid = p->p_cred->p_ruid;
1995171168Smlaier			newrule->cpid = p->p_pid;
1996171168Smlaier#endif
1997126258Smlaier			TAILQ_INIT(&newrule->rpool.list);
1998126258Smlaier			/* initialize refcounting */
1999223637Sbz			newrule->states_cur = 0;
2000126258Smlaier			newrule->entries.tqe_prev = NULL;
2001126258Smlaier#ifndef INET
2002126258Smlaier			if (newrule->af == AF_INET) {
2003223637Sbz#ifdef __FreeBSD__
2004223637Sbz				pool_put(&V_pf_rule_pl, newrule);
2005223637Sbz#else
2006126258Smlaier				pool_put(&pf_rule_pl, newrule);
2007223637Sbz#endif
2008126258Smlaier				error = EAFNOSUPPORT;
2009126258Smlaier				break;
2010126258Smlaier			}
2011126258Smlaier#endif /* INET */
2012126258Smlaier#ifndef INET6
2013126258Smlaier			if (newrule->af == AF_INET6) {
2014223637Sbz#ifdef __FreeBSD__
2015223637Sbz				pool_put(&V_pf_rule_pl, newrule);
2016223637Sbz#else
2017126258Smlaier				pool_put(&pf_rule_pl, newrule);
2018223637Sbz#endif
2019126258Smlaier				error = EAFNOSUPPORT;
2020126258Smlaier				break;
2021126258Smlaier			}
2022126258Smlaier#endif /* INET6 */
2023126258Smlaier			if (newrule->ifname[0]) {
2024171168Smlaier				newrule->kif = pfi_kif_get(newrule->ifname);
2025130613Smlaier				if (newrule->kif == NULL) {
2026223637Sbz#ifdef __FreeBSD__
2027223637Sbz					pool_put(&V_pf_rule_pl, newrule);
2028223637Sbz#else
2029126258Smlaier					pool_put(&pf_rule_pl, newrule);
2030223637Sbz#endif
2031126258Smlaier					error = EINVAL;
2032126258Smlaier					break;
2033126258Smlaier				}
2034171168Smlaier				pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
2035126258Smlaier			} else
2036130613Smlaier				newrule->kif = NULL;
2037126258Smlaier
2038171168Smlaier			if (newrule->rtableid > 0 &&
2039171168Smlaier#ifdef __FreeBSD__ /* ROUTING */
2040232292Sbz			    newrule->rtableid >= rt_numfibs)
2041171168Smlaier#else
2042171168Smlaier			    !rtable_exists(newrule->rtableid))
2043171168Smlaier#endif
2044171168Smlaier				error = EBUSY;
2045171168Smlaier
2046126258Smlaier#ifdef ALTQ
2047126258Smlaier			/* set queue IDs */
2048126258Smlaier			if (newrule->qname[0] != 0) {
2049130613Smlaier				if ((newrule->qid =
2050130613Smlaier				    pf_qname2qid(newrule->qname)) == 0)
2051130613Smlaier					error = EBUSY;
2052130613Smlaier				else if (newrule->pqname[0] != 0) {
2053130613Smlaier					if ((newrule->pqid =
2054130613Smlaier					    pf_qname2qid(newrule->pqname)) == 0)
2055130613Smlaier						error = EBUSY;
2056130613Smlaier				} else
2057126258Smlaier					newrule->pqid = newrule->qid;
2058126258Smlaier			}
2059145836Smlaier#endif /* ALTQ */
2060126258Smlaier			if (newrule->tagname[0])
2061126258Smlaier				if ((newrule->tag =
2062126258Smlaier				    pf_tagname2tag(newrule->tagname)) == 0)
2063126258Smlaier					error = EBUSY;
2064126258Smlaier			if (newrule->match_tagname[0])
2065126258Smlaier				if ((newrule->match_tag = pf_tagname2tag(
2066126258Smlaier				    newrule->match_tagname)) == 0)
2067126258Smlaier					error = EBUSY;
2068126258Smlaier			if (newrule->rt && !newrule->direction)
2069126258Smlaier				error = EINVAL;
2070171168Smlaier#if NPFLOG > 0
2071171168Smlaier			if (!newrule->log)
2072171168Smlaier				newrule->logif = 0;
2073171168Smlaier			if (newrule->logif >= PFLOGIFS_MAX)
2074171168Smlaier				error = EINVAL;
2075171168Smlaier#endif
2076145836Smlaier			if (pf_rtlabel_add(&newrule->src.addr) ||
2077145836Smlaier			    pf_rtlabel_add(&newrule->dst.addr))
2078145836Smlaier				error = EBUSY;
2079223637Sbz			if (pf_addr_setup(ruleset, &newrule->src.addr, newrule->af))
2080126258Smlaier				error = EINVAL;
2081223637Sbz			if (pf_addr_setup(ruleset, &newrule->dst.addr, newrule->af))
2082126258Smlaier				error = EINVAL;
2083145836Smlaier			if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call))
2084145836Smlaier				error = EINVAL;
2085223637Sbz#ifdef __FreeBSD__
2086223637Sbz			TAILQ_FOREACH(pa, &V_pf_pabuf, entries)
2087223637Sbz#else
2088149884Smlaier			TAILQ_FOREACH(pa, &pf_pabuf, entries)
2089223637Sbz#endif
2090149884Smlaier				if (pf_tbladdr_setup(ruleset, &pa->addr))
2091149884Smlaier					error = EINVAL;
2092126258Smlaier
2093145836Smlaier			if (newrule->overload_tblname[0]) {
2094145836Smlaier				if ((newrule->overload_tbl = pfr_attach_table(
2095223637Sbz				    ruleset, newrule->overload_tblname, 0)) ==
2096145836Smlaier				    NULL)
2097145836Smlaier					error = EINVAL;
2098145836Smlaier				else
2099145836Smlaier					newrule->overload_tbl->pfrkt_flags |=
2100145836Smlaier					    PFR_TFLAG_ACTIVE;
2101145836Smlaier			}
2102145836Smlaier
2103223637Sbz#ifdef __FreeBSD__
2104223637Sbz			pf_mv_pool(&V_pf_pabuf, &newrule->rpool.list);
2105223637Sbz#else
2106126258Smlaier			pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
2107223637Sbz#endif
2108126258Smlaier			if (((((newrule->action == PF_NAT) ||
2109126258Smlaier			    (newrule->action == PF_RDR) ||
2110126258Smlaier			    (newrule->action == PF_BINAT) ||
2111126258Smlaier			    (newrule->rt > PF_FASTROUTE)) &&
2112160543Smlaier			    !newrule->anchor)) &&
2113126258Smlaier			    (TAILQ_FIRST(&newrule->rpool.list) == NULL))
2114126258Smlaier				error = EINVAL;
2115126258Smlaier
2116126258Smlaier			if (error) {
2117126258Smlaier				pf_rm_rule(NULL, newrule);
2118126258Smlaier				break;
2119126258Smlaier			}
2120171168Smlaier
2121171168Smlaier#ifdef __FreeBSD__
2122223637Sbz			if (!V_debug_pfugidhack && (newrule->uid.op ||
2123171168Smlaier			    newrule->gid.op ||
2124171168Smlaier			    newrule->log & PF_LOG_SOCKET_LOOKUP)) {
2125171168Smlaier				DPFPRINTF(PF_DEBUG_MISC,
2126171168Smlaier				    ("pf: debug.pfugidhack enabled\n"));
2127223637Sbz				V_debug_pfugidhack = 1;
2128171168Smlaier			}
2129171168Smlaier#endif
2130171168Smlaier
2131126258Smlaier			newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
2132171168Smlaier			newrule->evaluations = 0;
2133171168Smlaier			newrule->packets[0] = newrule->packets[1] = 0;
2134171168Smlaier			newrule->bytes[0] = newrule->bytes[1] = 0;
2135126258Smlaier		}
2136223637Sbz#ifdef __FreeBSD__
2137223637Sbz		pf_empty_pool(&V_pf_pabuf);
2138223637Sbz#else
2139126258Smlaier		pf_empty_pool(&pf_pabuf);
2140223637Sbz#endif
2141126258Smlaier
2142126258Smlaier		if (pcr->action == PF_CHANGE_ADD_HEAD)
2143126258Smlaier			oldrule = TAILQ_FIRST(
2144126258Smlaier			    ruleset->rules[rs_num].active.ptr);
2145126258Smlaier		else if (pcr->action == PF_CHANGE_ADD_TAIL)
2146126258Smlaier			oldrule = TAILQ_LAST(
2147126258Smlaier			    ruleset->rules[rs_num].active.ptr, pf_rulequeue);
2148126258Smlaier		else {
2149126258Smlaier			oldrule = TAILQ_FIRST(
2150126258Smlaier			    ruleset->rules[rs_num].active.ptr);
2151126258Smlaier			while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
2152126258Smlaier				oldrule = TAILQ_NEXT(oldrule, entries);
2153126258Smlaier			if (oldrule == NULL) {
2154133577Smlaier				if (newrule != NULL)
2155133577Smlaier					pf_rm_rule(NULL, newrule);
2156126258Smlaier				error = EINVAL;
2157126258Smlaier				break;
2158126258Smlaier			}
2159126258Smlaier		}
2160126258Smlaier
2161171168Smlaier		if (pcr->action == PF_CHANGE_REMOVE) {
2162126258Smlaier			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
2163171168Smlaier			ruleset->rules[rs_num].active.rcount--;
2164171168Smlaier		} else {
2165126258Smlaier			if (oldrule == NULL)
2166126258Smlaier				TAILQ_INSERT_TAIL(
2167126258Smlaier				    ruleset->rules[rs_num].active.ptr,
2168126258Smlaier				    newrule, entries);
2169126258Smlaier			else if (pcr->action == PF_CHANGE_ADD_HEAD ||
2170126258Smlaier			    pcr->action == PF_CHANGE_ADD_BEFORE)
2171126258Smlaier				TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
2172126258Smlaier			else
2173126258Smlaier				TAILQ_INSERT_AFTER(
2174126258Smlaier				    ruleset->rules[rs_num].active.ptr,
2175126258Smlaier				    oldrule, newrule, entries);
2176171168Smlaier			ruleset->rules[rs_num].active.rcount++;
2177126258Smlaier		}
2178126258Smlaier
2179126258Smlaier		nr = 0;
2180126258Smlaier		TAILQ_FOREACH(oldrule,
2181126258Smlaier		    ruleset->rules[rs_num].active.ptr, entries)
2182126258Smlaier			oldrule->nr = nr++;
2183126258Smlaier
2184145836Smlaier		ruleset->rules[rs_num].active.ticket++;
2185145836Smlaier
2186126258Smlaier		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
2187126258Smlaier		pf_remove_if_empty_ruleset(ruleset);
2188126258Smlaier
2189126258Smlaier		break;
2190126258Smlaier	}
2191126258Smlaier
2192126258Smlaier	case DIOCCLRSTATES: {
2193223637Sbz		struct pf_state		*s, *nexts;
2194130613Smlaier		struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
2195223637Sbz		u_int			 killed = 0;
2196126258Smlaier
2197223637Sbz#ifdef __FreeBSD__
2198223637Sbz		for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s; s = nexts) {
2199223637Sbz			nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s);
2200223637Sbz#else
2201223637Sbz		for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) {
2202223637Sbz			nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
2203223637Sbz#endif
2204171168Smlaier
2205130613Smlaier			if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
2206223637Sbz			    s->kif->pfik_name)) {
2207223637Sbz#if NPFSYNC > 0
2208130613Smlaier				/* don't send out individual delete messages */
2209223637Sbz				SET(s->state_flags, PFSTATE_NOSYNC);
2210130613Smlaier#endif
2211223637Sbz				pf_unlink_state(s);
2212130613Smlaier				killed++;
2213130613Smlaier			}
2214130613Smlaier		}
2215223637Sbz		psk->psk_killed = killed;
2216223637Sbz#if NPFSYNC > 0
2217223637Sbz#ifdef __FreeBSD__
2218223637Sbz		if (pfsync_clear_states_ptr != NULL)
2219223637Sbz			pfsync_clear_states_ptr(V_pf_status.hostid, psk->psk_ifname);
2220223637Sbz#else
2221130613Smlaier		pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
2222130613Smlaier#endif
2223223637Sbz#endif
2224126258Smlaier		break;
2225126258Smlaier	}
2226126258Smlaier
2227126258Smlaier	case DIOCKILLSTATES: {
2228223637Sbz		struct pf_state		*s, *nexts;
2229223637Sbz		struct pf_state_key	*sk;
2230223637Sbz		struct pf_addr		*srcaddr, *dstaddr;
2231223637Sbz		u_int16_t		 srcport, dstport;
2232126258Smlaier		struct pfioc_state_kill	*psk = (struct pfioc_state_kill *)addr;
2233223637Sbz		u_int			 killed = 0;
2234126258Smlaier
2235223637Sbz		if (psk->psk_pfcmp.id) {
2236223637Sbz			if (psk->psk_pfcmp.creatorid == 0)
2237223637Sbz#ifdef __FreeBSD__
2238223637Sbz				psk->psk_pfcmp.creatorid = V_pf_status.hostid;
2239223637Sbz#else
2240223637Sbz				psk->psk_pfcmp.creatorid = pf_status.hostid;
2241223637Sbz#endif
2242223637Sbz			if ((s = pf_find_state_byid(&psk->psk_pfcmp))) {
2243223637Sbz				pf_unlink_state(s);
2244223637Sbz				psk->psk_killed = 1;
2245223637Sbz			}
2246223637Sbz			break;
2247223637Sbz		}
2248171168Smlaier
2249223637Sbz#ifdef __FreeBSD__
2250223637Sbz		for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s;
2251223637Sbz		    s = nexts) {
2252223637Sbz			nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s);
2253223637Sbz#else
2254223637Sbz		for (s = RB_MIN(pf_state_tree_id, &tree_id); s;
2255223637Sbz		    s = nexts) {
2256223637Sbz			nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
2257223637Sbz#endif
2258223637Sbz			sk = s->key[PF_SK_WIRE];
2259223637Sbz
2260223637Sbz			if (s->direction == PF_OUT) {
2261223637Sbz				srcaddr = &sk->addr[1];
2262223637Sbz				dstaddr = &sk->addr[0];
2263223637Sbz				srcport = sk->port[0];
2264223637Sbz				dstport = sk->port[0];
2265171168Smlaier			} else {
2266223637Sbz				srcaddr = &sk->addr[0];
2267223637Sbz				dstaddr = &sk->addr[1];
2268223637Sbz				srcport = sk->port[0];
2269223637Sbz				dstport = sk->port[0];
2270171168Smlaier			}
2271223637Sbz			if ((!psk->psk_af || sk->af == psk->psk_af)
2272130613Smlaier			    && (!psk->psk_proto || psk->psk_proto ==
2273223637Sbz			    sk->proto) &&
2274145836Smlaier			    PF_MATCHA(psk->psk_src.neg,
2275126258Smlaier			    &psk->psk_src.addr.v.a.addr,
2276130613Smlaier			    &psk->psk_src.addr.v.a.mask,
2277223637Sbz			    srcaddr, sk->af) &&
2278145836Smlaier			    PF_MATCHA(psk->psk_dst.neg,
2279126258Smlaier			    &psk->psk_dst.addr.v.a.addr,
2280130613Smlaier			    &psk->psk_dst.addr.v.a.mask,
2281223637Sbz			    dstaddr, sk->af) &&
2282126258Smlaier			    (psk->psk_src.port_op == 0 ||
2283126258Smlaier			    pf_match_port(psk->psk_src.port_op,
2284126258Smlaier			    psk->psk_src.port[0], psk->psk_src.port[1],
2285223637Sbz			    srcport)) &&
2286126258Smlaier			    (psk->psk_dst.port_op == 0 ||
2287126258Smlaier			    pf_match_port(psk->psk_dst.port_op,
2288126258Smlaier			    psk->psk_dst.port[0], psk->psk_dst.port[1],
2289223637Sbz			    dstport)) &&
2290223637Sbz			    (!psk->psk_label[0] || (s->rule.ptr->label[0] &&
2291223637Sbz			    !strcmp(psk->psk_label, s->rule.ptr->label))) &&
2292130613Smlaier			    (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
2293223637Sbz			    s->kif->pfik_name))) {
2294223637Sbz				pf_unlink_state(s);
2295126258Smlaier				killed++;
2296126258Smlaier			}
2297126258Smlaier		}
2298223637Sbz		psk->psk_killed = killed;
2299126258Smlaier		break;
2300126258Smlaier	}
2301126258Smlaier
2302126258Smlaier	case DIOCADDSTATE: {
2303126258Smlaier		struct pfioc_state	*ps = (struct pfioc_state *)addr;
2304223637Sbz		struct pfsync_state	*sp = &ps->state;
2305126258Smlaier
2306223637Sbz		if (sp->timeout >= PFTM_MAX &&
2307223637Sbz		    sp->timeout != PFTM_UNTIL_PACKET) {
2308126258Smlaier			error = EINVAL;
2309126258Smlaier			break;
2310126258Smlaier		}
2311223637Sbz#ifdef __FreeBSD__
2312223637Sbz		if (pfsync_state_import_ptr != NULL)
2313223637Sbz			error = pfsync_state_import_ptr(sp, PFSYNC_SI_IOCTL);
2314223637Sbz#else
2315223637Sbz		error = pfsync_state_import(sp, PFSYNC_SI_IOCTL);
2316223637Sbz#endif
2317126258Smlaier		break;
2318126258Smlaier	}
2319126258Smlaier
2320126258Smlaier	case DIOCGETSTATE: {
2321126258Smlaier		struct pfioc_state	*ps = (struct pfioc_state *)addr;
2322223637Sbz		struct pf_state		*s;
2323223637Sbz		struct pf_state_cmp	 id_key;
2324126258Smlaier
2325223637Sbz		bcopy(ps->state.id, &id_key.id, sizeof(id_key.id));
2326223637Sbz		id_key.creatorid = ps->state.creatorid;
2327223637Sbz
2328223637Sbz		s = pf_find_state_byid(&id_key);
2329223637Sbz		if (s == NULL) {
2330223637Sbz			error = ENOENT;
2331126258Smlaier			break;
2332126258Smlaier		}
2333223637Sbz
2334223637Sbz		pfsync_state_export(&ps->state, s);
2335126258Smlaier		break;
2336126258Smlaier	}
2337126258Smlaier
2338126258Smlaier	case DIOCGETSTATES: {
2339126258Smlaier		struct pfioc_states	*ps = (struct pfioc_states *)addr;
2340130613Smlaier		struct pf_state		*state;
2341223637Sbz		struct pfsync_state	*p, *pstore;
2342126258Smlaier		u_int32_t		 nr = 0;
2343126258Smlaier
2344223637Sbz		if (ps->ps_len == 0) {
2345223637Sbz#ifdef __FreeBSD__
2346223637Sbz			nr = V_pf_status.states;
2347223637Sbz#else
2348171168Smlaier			nr = pf_status.states;
2349223637Sbz#endif
2350223637Sbz			ps->ps_len = sizeof(struct pfsync_state) * nr;
2351145836Smlaier			break;
2352126258Smlaier		}
2353126258Smlaier
2354171168Smlaier#ifdef __FreeBSD__
2355171168Smlaier		PF_UNLOCK();
2356171168Smlaier#endif
2357171168Smlaier		pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
2358171168Smlaier#ifdef __FreeBSD__
2359171168Smlaier		PF_LOCK();
2360171168Smlaier#endif
2361171168Smlaier
2362126258Smlaier		p = ps->ps_states;
2363171168Smlaier
2364223637Sbz#ifdef __FreeBSD__
2365223637Sbz		state = TAILQ_FIRST(&V_state_list);
2366223637Sbz#else
2367171168Smlaier		state = TAILQ_FIRST(&state_list);
2368223637Sbz#endif
2369171168Smlaier		while (state) {
2370171168Smlaier			if (state->timeout != PFTM_UNLINKED) {
2371130613Smlaier				if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len)
2372130613Smlaier					break;
2373223637Sbz				pfsync_state_export(pstore, state);
2374127145Smlaier#ifdef __FreeBSD__
2375171168Smlaier				PF_COPYOUT(pstore, p, sizeof(*p), error);
2376126261Smlaier#else
2377171168Smlaier				error = copyout(pstore, p, sizeof(*p));
2378126261Smlaier#endif
2379171168Smlaier				if (error) {
2380171168Smlaier					free(pstore, M_TEMP);
2381130613Smlaier					goto fail;
2382171168Smlaier				}
2383130613Smlaier				p++;
2384130613Smlaier				nr++;
2385126258Smlaier			}
2386223637Sbz			state = TAILQ_NEXT(state, entry_list);
2387171168Smlaier		}
2388171168Smlaier
2389223637Sbz		ps->ps_len = sizeof(struct pfsync_state) * nr;
2390171168Smlaier
2391171168Smlaier		free(pstore, M_TEMP);
2392126258Smlaier		break;
2393126258Smlaier	}
2394126258Smlaier
2395126258Smlaier	case DIOCGETSTATUS: {
2396126258Smlaier		struct pf_status *s = (struct pf_status *)addr;
2397223637Sbz#ifdef __FreeBSD__
2398223637Sbz		bcopy(&V_pf_status, s, sizeof(struct pf_status));
2399223637Sbz#else
2400126258Smlaier		bcopy(&pf_status, s, sizeof(struct pf_status));
2401223637Sbz#endif
2402223637Sbz		pfi_update_status(s->ifname, s);
2403126258Smlaier		break;
2404126258Smlaier	}
2405126258Smlaier
2406126258Smlaier	case DIOCSETSTATUSIF: {
2407126258Smlaier		struct pfioc_if	*pi = (struct pfioc_if *)addr;
2408126258Smlaier
2409126258Smlaier		if (pi->ifname[0] == 0) {
2410223637Sbz#ifdef __FreeBSD__
2411223637Sbz			bzero(V_pf_status.ifname, IFNAMSIZ);
2412223637Sbz#else
2413126258Smlaier			bzero(pf_status.ifname, IFNAMSIZ);
2414223637Sbz#endif
2415126258Smlaier			break;
2416126258Smlaier		}
2417223637Sbz#ifdef __FreeBSD__
2418223637Sbz		strlcpy(V_pf_status.ifname, pi->ifname, IFNAMSIZ);
2419223637Sbz#else
2420130613Smlaier		strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ);
2421223637Sbz#endif
2422130613Smlaier		break;
2423126258Smlaier	}
2424126258Smlaier
2425126258Smlaier	case DIOCCLRSTATUS: {
2426223637Sbz#ifdef __FreeBSD__
2427223637Sbz		bzero(V_pf_status.counters, sizeof(V_pf_status.counters));
2428223637Sbz		bzero(V_pf_status.fcounters, sizeof(V_pf_status.fcounters));
2429223637Sbz		bzero(V_pf_status.scounters, sizeof(V_pf_status.scounters));
2430223637Sbz		V_pf_status.since = time_second;
2431223637Sbz		if (*V_pf_status.ifname)
2432223637Sbz			pfi_update_status(V_pf_status.ifname, NULL);
2433223637Sbz#else
2434130613Smlaier		bzero(pf_status.counters, sizeof(pf_status.counters));
2435130613Smlaier		bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
2436130613Smlaier		bzero(pf_status.scounters, sizeof(pf_status.scounters));
2437171168Smlaier		pf_status.since = time_second;
2438130613Smlaier		if (*pf_status.ifname)
2439223637Sbz			pfi_update_status(pf_status.ifname, NULL);
2440223637Sbz#endif
2441126258Smlaier		break;
2442126258Smlaier	}
2443126258Smlaier
2444126258Smlaier	case DIOCNATLOOK: {
2445126258Smlaier		struct pfioc_natlook	*pnl = (struct pfioc_natlook *)addr;
2446223637Sbz		struct pf_state_key	*sk;
2447130613Smlaier		struct pf_state		*state;
2448223637Sbz		struct pf_state_key_cmp	 key;
2449130613Smlaier		int			 m = 0, direction = pnl->direction;
2450223637Sbz		int			 sidx, didx;
2451126258Smlaier
2452223637Sbz		/* NATLOOK src and dst are reversed, so reverse sidx/didx */
2453223637Sbz		sidx = (direction == PF_IN) ? 1 : 0;
2454223637Sbz		didx = (direction == PF_IN) ? 0 : 1;
2455126258Smlaier
2456126258Smlaier		if (!pnl->proto ||
2457126258Smlaier		    PF_AZERO(&pnl->saddr, pnl->af) ||
2458126258Smlaier		    PF_AZERO(&pnl->daddr, pnl->af) ||
2459171168Smlaier		    ((pnl->proto == IPPROTO_TCP ||
2460171168Smlaier		    pnl->proto == IPPROTO_UDP) &&
2461171168Smlaier		    (!pnl->dport || !pnl->sport)))
2462126258Smlaier			error = EINVAL;
2463126258Smlaier		else {
2464223637Sbz			key.af = pnl->af;
2465223637Sbz			key.proto = pnl->proto;
2466223637Sbz			PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af);
2467223637Sbz			key.port[sidx] = pnl->sport;
2468223637Sbz			PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af);
2469223637Sbz			key.port[didx] = pnl->dport;
2470223637Sbz
2471223637Sbz			state = pf_find_state_all(&key, direction, &m);
2472223637Sbz
2473130613Smlaier			if (m > 1)
2474130613Smlaier				error = E2BIG;	/* more than one state */
2475130613Smlaier			else if (state != NULL) {
2476223637Sbz				sk = state->key[sidx];
2477223637Sbz				PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af);
2478223637Sbz				pnl->rsport = sk->port[sidx];
2479223637Sbz				PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af);
2480223637Sbz				pnl->rdport = sk->port[didx];
2481126258Smlaier			} else
2482126258Smlaier				error = ENOENT;
2483126258Smlaier		}
2484126258Smlaier		break;
2485126258Smlaier	}
2486126258Smlaier
2487126258Smlaier	case DIOCSETTIMEOUT: {
2488126258Smlaier		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
2489126258Smlaier		int		 old;
2490126258Smlaier
2491126258Smlaier		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
2492126258Smlaier		    pt->seconds < 0) {
2493126258Smlaier			error = EINVAL;
2494126258Smlaier			goto fail;
2495126258Smlaier		}
2496223637Sbz#ifdef __FreeBSD__
2497223637Sbz		old = V_pf_default_rule.timeout[pt->timeout];
2498223637Sbz#else
2499126258Smlaier		old = pf_default_rule.timeout[pt->timeout];
2500223637Sbz#endif
2501171168Smlaier		if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
2502171168Smlaier			pt->seconds = 1;
2503223637Sbz#ifdef __FreeBSD__
2504223637Sbz		V_pf_default_rule.timeout[pt->timeout] = pt->seconds;
2505223637Sbz#else
2506126258Smlaier		pf_default_rule.timeout[pt->timeout] = pt->seconds;
2507223637Sbz#endif
2508171168Smlaier		if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
2509171168Smlaier			wakeup(pf_purge_thread);
2510126258Smlaier		pt->seconds = old;
2511126258Smlaier		break;
2512126258Smlaier	}
2513126258Smlaier
2514126258Smlaier	case DIOCGETTIMEOUT: {
2515126258Smlaier		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
2516126258Smlaier
2517126258Smlaier		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
2518126258Smlaier			error = EINVAL;
2519126258Smlaier			goto fail;
2520126258Smlaier		}
2521223637Sbz#ifdef __FreeBSD__
2522223637Sbz		pt->seconds = V_pf_default_rule.timeout[pt->timeout];
2523223637Sbz#else
2524126258Smlaier		pt->seconds = pf_default_rule.timeout[pt->timeout];
2525223637Sbz#endif
2526126258Smlaier		break;
2527126258Smlaier	}
2528126258Smlaier
2529126258Smlaier	case DIOCGETLIMIT: {
2530126258Smlaier		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
2531126258Smlaier
2532126258Smlaier		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
2533126258Smlaier			error = EINVAL;
2534126258Smlaier			goto fail;
2535126258Smlaier		}
2536223637Sbz#ifdef __FreeBSD__
2537223637Sbz		pl->limit = V_pf_pool_limits[pl->index].limit;
2538223637Sbz#else
2539126258Smlaier		pl->limit = pf_pool_limits[pl->index].limit;
2540223637Sbz#endif
2541126258Smlaier		break;
2542126258Smlaier	}
2543126258Smlaier
2544126258Smlaier	case DIOCSETLIMIT: {
2545126258Smlaier		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
2546126258Smlaier		int			 old_limit;
2547126258Smlaier
2548130613Smlaier		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
2549223637Sbz#ifdef __FreeBSD__
2550223637Sbz		    V_pf_pool_limits[pl->index].pp == NULL) {
2551223637Sbz#else
2552130613Smlaier		    pf_pool_limits[pl->index].pp == NULL) {
2553223637Sbz#endif
2554126258Smlaier			error = EINVAL;
2555126258Smlaier			goto fail;
2556126258Smlaier		}
2557127145Smlaier#ifdef __FreeBSD__
2558223637Sbz		uma_zone_set_max(V_pf_pool_limits[pl->index].pp, pl->limit);
2559223637Sbz		old_limit = V_pf_pool_limits[pl->index].limit;
2560223637Sbz		V_pf_pool_limits[pl->index].limit = pl->limit;
2561223637Sbz		pl->limit = old_limit;
2562126261Smlaier#else
2563126258Smlaier		if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
2564126258Smlaier		    pl->limit, NULL, 0) != 0) {
2565126258Smlaier			error = EBUSY;
2566126258Smlaier			goto fail;
2567126258Smlaier		}
2568126258Smlaier		old_limit = pf_pool_limits[pl->index].limit;
2569126258Smlaier		pf_pool_limits[pl->index].limit = pl->limit;
2570126258Smlaier		pl->limit = old_limit;
2571223637Sbz#endif
2572126258Smlaier		break;
2573126258Smlaier	}
2574126258Smlaier
2575126258Smlaier	case DIOCSETDEBUG: {
2576126258Smlaier		u_int32_t	*level = (u_int32_t *)addr;
2577126258Smlaier
2578223637Sbz#ifdef __FreeBSD__
2579223637Sbz		V_pf_status.debug = *level;
2580223637Sbz#else
2581126258Smlaier		pf_status.debug = *level;
2582223637Sbz#endif
2583126258Smlaier		break;
2584126258Smlaier	}
2585126258Smlaier
2586126258Smlaier	case DIOCCLRRULECTRS: {
2587171168Smlaier		/* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
2588126258Smlaier		struct pf_ruleset	*ruleset = &pf_main_ruleset;
2589126258Smlaier		struct pf_rule		*rule;
2590126258Smlaier
2591126258Smlaier		TAILQ_FOREACH(rule,
2592171168Smlaier		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
2593171168Smlaier			rule->evaluations = 0;
2594171168Smlaier			rule->packets[0] = rule->packets[1] = 0;
2595171168Smlaier			rule->bytes[0] = rule->bytes[1] = 0;
2596171168Smlaier		}
2597126258Smlaier		break;
2598126258Smlaier	}
2599126258Smlaier
2600127145Smlaier#ifdef __FreeBSD__
2601126261Smlaier	case DIOCGIFSPEED: {
2602126261Smlaier		struct pf_ifspeed	*psp = (struct pf_ifspeed *)addr;
2603126261Smlaier		struct pf_ifspeed	ps;
2604126261Smlaier		struct ifnet		*ifp;
2605126261Smlaier
2606126261Smlaier		if (psp->ifname[0] != 0) {
2607126261Smlaier			/* Can we completely trust user-land? */
2608126261Smlaier			strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
2609126261Smlaier			ifp = ifunit(ps.ifname);
2610141584Smlaier			if (ifp != NULL)
2611126261Smlaier				psp->baudrate = ifp->if_baudrate;
2612126261Smlaier			else
2613126261Smlaier				error = EINVAL;
2614126261Smlaier		} else
2615126261Smlaier			error = EINVAL;
2616126261Smlaier		break;
2617126261Smlaier	}
2618126261Smlaier#endif /* __FreeBSD__ */
2619126261Smlaier
2620126258Smlaier#ifdef ALTQ
2621126258Smlaier	case DIOCSTARTALTQ: {
2622126258Smlaier		struct pf_altq		*altq;
2623126258Smlaier
2624126258Smlaier		/* enable all altq interfaces on active list */
2625177700Smlaier#ifdef __FreeBSD__
2626223637Sbz		TAILQ_FOREACH(altq, V_pf_altqs_active, entries) {
2627177700Smlaier			if (altq->qname[0] == 0 && (altq->local_flags &
2628177700Smlaier			    PFALTQ_FLAG_IF_REMOVED) == 0) {
2629177700Smlaier#else
2630223637Sbz		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2631126258Smlaier			if (altq->qname[0] == 0) {
2632177700Smlaier#endif
2633135352Smlaier				error = pf_enable_altq(altq);
2634126258Smlaier				if (error != 0)
2635126258Smlaier					break;
2636126258Smlaier			}
2637126258Smlaier		}
2638126258Smlaier		if (error == 0)
2639223637Sbz#ifdef __FreeBSD__
2640223637Sbz			V_pf_altq_running = 1;
2641223637Sbz#else
2642135352Smlaier			pf_altq_running = 1;
2643223637Sbz#endif
2644126258Smlaier		DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
2645126258Smlaier		break;
2646126258Smlaier	}
2647126258Smlaier
2648126258Smlaier	case DIOCSTOPALTQ: {
2649126258Smlaier		struct pf_altq		*altq;
2650126258Smlaier
2651126258Smlaier		/* disable all altq interfaces on active list */
2652177700Smlaier#ifdef __FreeBSD__
2653223637Sbz		TAILQ_FOREACH(altq, V_pf_altqs_active, entries) {
2654177700Smlaier			if (altq->qname[0] == 0 && (altq->local_flags &
2655177700Smlaier			    PFALTQ_FLAG_IF_REMOVED) == 0) {
2656177700Smlaier#else
2657223637Sbz		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2658126258Smlaier			if (altq->qname[0] == 0) {
2659177700Smlaier#endif
2660135352Smlaier				error = pf_disable_altq(altq);
2661135352Smlaier				if (error != 0)
2662126258Smlaier					break;
2663126258Smlaier			}
2664126258Smlaier		}
2665126258Smlaier		if (error == 0)
2666223637Sbz#ifdef __FreeBSD__
2667223637Sbz			V_pf_altq_running = 0;
2668223637Sbz#else
2669135352Smlaier			pf_altq_running = 0;
2670223637Sbz#endif
2671126258Smlaier		DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
2672126258Smlaier		break;
2673126258Smlaier	}
2674126258Smlaier
2675126258Smlaier	case DIOCADDALTQ: {
2676126258Smlaier		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
2677126258Smlaier		struct pf_altq		*altq, *a;
2678126258Smlaier
2679223637Sbz#ifdef __FreeBSD__
2680223637Sbz		if (pa->ticket != V_ticket_altqs_inactive) {
2681223637Sbz#else
2682126258Smlaier		if (pa->ticket != ticket_altqs_inactive) {
2683223637Sbz#endif
2684126258Smlaier			error = EBUSY;
2685126258Smlaier			break;
2686126258Smlaier		}
2687223637Sbz#ifdef __FreeBSD__
2688223637Sbz		altq = pool_get(&V_pf_altq_pl, PR_NOWAIT);
2689223637Sbz#else
2690223637Sbz		altq = pool_get(&pf_altq_pl, PR_WAITOK|PR_LIMITFAIL);
2691223637Sbz#endif
2692126258Smlaier		if (altq == NULL) {
2693126258Smlaier			error = ENOMEM;
2694126258Smlaier			break;
2695126258Smlaier		}
2696126258Smlaier		bcopy(&pa->altq, altq, sizeof(struct pf_altq));
2697177700Smlaier#ifdef __FreeBSD__
2698177700Smlaier		altq->local_flags = 0;
2699177700Smlaier#endif
2700126258Smlaier
2701126258Smlaier		/*
2702126258Smlaier		 * if this is for a queue, find the discipline and
2703126258Smlaier		 * copy the necessary fields
2704126258Smlaier		 */
2705126258Smlaier		if (altq->qname[0] != 0) {
2706130613Smlaier			if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {
2707130613Smlaier				error = EBUSY;
2708223637Sbz#ifdef __FreeBSD__
2709223637Sbz				pool_put(&V_pf_altq_pl, altq);
2710223637Sbz#else
2711130613Smlaier				pool_put(&pf_altq_pl, altq);
2712223637Sbz#endif
2713130613Smlaier				break;
2714130613Smlaier			}
2715177700Smlaier			altq->altq_disc = NULL;
2716223637Sbz#ifdef __FreeBSD__
2717223637Sbz			TAILQ_FOREACH(a, V_pf_altqs_inactive, entries) {
2718223637Sbz#else
2719126258Smlaier			TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
2720223637Sbz#endif
2721126258Smlaier				if (strncmp(a->ifname, altq->ifname,
2722126258Smlaier				    IFNAMSIZ) == 0 && a->qname[0] == 0) {
2723126258Smlaier					altq->altq_disc = a->altq_disc;
2724126258Smlaier					break;
2725126258Smlaier				}
2726126258Smlaier			}
2727126258Smlaier		}
2728126258Smlaier
2729127145Smlaier#ifdef __FreeBSD__
2730177700Smlaier		struct ifnet *ifp;
2731177700Smlaier
2732177700Smlaier		if ((ifp = ifunit(altq->ifname)) == NULL) {
2733177700Smlaier			altq->local_flags |= PFALTQ_FLAG_IF_REMOVED;
2734177700Smlaier		} else {
2735177700Smlaier			PF_UNLOCK();
2736223637Sbz#endif
2737126258Smlaier		error = altq_add(altq);
2738127145Smlaier#ifdef __FreeBSD__
2739177700Smlaier			PF_LOCK();
2740177700Smlaier		}
2741126261Smlaier#endif
2742126258Smlaier		if (error) {
2743223637Sbz#ifdef __FreeBSD__
2744223637Sbz			pool_put(&V_pf_altq_pl, altq);
2745223637Sbz#else
2746126258Smlaier			pool_put(&pf_altq_pl, altq);
2747223637Sbz#endif
2748126258Smlaier			break;
2749126258Smlaier		}
2750126258Smlaier
2751223637Sbz#ifdef __FreeBSD__
2752223637Sbz		TAILQ_INSERT_TAIL(V_pf_altqs_inactive, altq, entries);
2753223637Sbz#else
2754126258Smlaier		TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
2755223637Sbz#endif
2756126258Smlaier		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
2757126258Smlaier		break;
2758126258Smlaier	}
2759126258Smlaier
2760126258Smlaier	case DIOCGETALTQS: {
2761126258Smlaier		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
2762126258Smlaier		struct pf_altq		*altq;
2763126258Smlaier
2764126258Smlaier		pa->nr = 0;
2765223637Sbz#ifdef __FreeBSD__
2766223637Sbz		TAILQ_FOREACH(altq, V_pf_altqs_active, entries)
2767223637Sbz			pa->nr++;
2768223637Sbz		pa->ticket = V_ticket_altqs_active;
2769223637Sbz#else
2770126258Smlaier		TAILQ_FOREACH(altq, pf_altqs_active, entries)
2771126258Smlaier			pa->nr++;
2772126258Smlaier		pa->ticket = ticket_altqs_active;
2773223637Sbz#endif
2774126258Smlaier		break;
2775126258Smlaier	}
2776126258Smlaier
2777126258Smlaier	case DIOCGETALTQ: {
2778126258Smlaier		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
2779126258Smlaier		struct pf_altq		*altq;
2780126258Smlaier		u_int32_t		 nr;
2781126258Smlaier
2782223637Sbz#ifdef __FreeBSD__
2783223637Sbz		if (pa->ticket != V_ticket_altqs_active) {
2784223637Sbz#else
2785126258Smlaier		if (pa->ticket != ticket_altqs_active) {
2786223637Sbz#endif
2787126258Smlaier			error = EBUSY;
2788126258Smlaier			break;
2789126258Smlaier		}
2790126258Smlaier		nr = 0;
2791223637Sbz#ifdef __FreeBSD__
2792223637Sbz		altq = TAILQ_FIRST(V_pf_altqs_active);
2793223637Sbz#else
2794126258Smlaier		altq = TAILQ_FIRST(pf_altqs_active);
2795223637Sbz#endif
2796126258Smlaier		while ((altq != NULL) && (nr < pa->nr)) {
2797126258Smlaier			altq = TAILQ_NEXT(altq, entries);
2798126258Smlaier			nr++;
2799126258Smlaier		}
2800126258Smlaier		if (altq == NULL) {
2801126258Smlaier			error = EBUSY;
2802126258Smlaier			break;
2803126258Smlaier		}
2804126258Smlaier		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
2805126258Smlaier		break;
2806126258Smlaier	}
2807126258Smlaier
2808126258Smlaier	case DIOCCHANGEALTQ:
2809126258Smlaier		/* CHANGEALTQ not supported yet! */
2810126258Smlaier		error = ENODEV;
2811126258Smlaier		break;
2812126258Smlaier
2813126258Smlaier	case DIOCGETQSTATS: {
2814126258Smlaier		struct pfioc_qstats	*pq = (struct pfioc_qstats *)addr;
2815126258Smlaier		struct pf_altq		*altq;
2816126258Smlaier		u_int32_t		 nr;
2817126258Smlaier		int			 nbytes;
2818126258Smlaier
2819223637Sbz#ifdef __FreeBSD__
2820223637Sbz		if (pq->ticket != V_ticket_altqs_active) {
2821223637Sbz#else
2822126258Smlaier		if (pq->ticket != ticket_altqs_active) {
2823223637Sbz#endif
2824126258Smlaier			error = EBUSY;
2825126258Smlaier			break;
2826126258Smlaier		}
2827126258Smlaier		nbytes = pq->nbytes;
2828126258Smlaier		nr = 0;
2829223637Sbz#ifdef __FreeBSD__
2830223637Sbz		altq = TAILQ_FIRST(V_pf_altqs_active);
2831223637Sbz#else
2832126258Smlaier		altq = TAILQ_FIRST(pf_altqs_active);
2833223637Sbz#endif
2834126258Smlaier		while ((altq != NULL) && (nr < pq->nr)) {
2835126258Smlaier			altq = TAILQ_NEXT(altq, entries);
2836126258Smlaier			nr++;
2837126258Smlaier		}
2838126258Smlaier		if (altq == NULL) {
2839126258Smlaier			error = EBUSY;
2840126258Smlaier			break;
2841126258Smlaier		}
2842223637Sbz
2843127145Smlaier#ifdef __FreeBSD__
2844177700Smlaier		if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) {
2845177700Smlaier			error = ENXIO;
2846177700Smlaier			break;
2847177700Smlaier		}
2848126261Smlaier		PF_UNLOCK();
2849126261Smlaier#endif
2850126258Smlaier		error = altq_getqstats(altq, pq->buf, &nbytes);
2851127145Smlaier#ifdef __FreeBSD__
2852126261Smlaier		PF_LOCK();
2853126261Smlaier#endif
2854126258Smlaier		if (error == 0) {
2855126258Smlaier			pq->scheduler = altq->scheduler;
2856126258Smlaier			pq->nbytes = nbytes;
2857126258Smlaier		}
2858126258Smlaier		break;
2859126258Smlaier	}
2860126258Smlaier#endif /* ALTQ */
2861126258Smlaier
2862126258Smlaier	case DIOCBEGINADDRS: {
2863126258Smlaier		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2864126258Smlaier
2865223637Sbz#ifdef __FreeBSD__
2866223637Sbz		pf_empty_pool(&V_pf_pabuf);
2867223637Sbz		pp->ticket = ++V_ticket_pabuf;
2868223637Sbz#else
2869126258Smlaier		pf_empty_pool(&pf_pabuf);
2870126258Smlaier		pp->ticket = ++ticket_pabuf;
2871223637Sbz#endif
2872126258Smlaier		break;
2873126258Smlaier	}
2874126258Smlaier
2875126258Smlaier	case DIOCADDADDR: {
2876126258Smlaier		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2877126258Smlaier
2878223637Sbz#ifdef __FreeBSD__
2879223637Sbz		if (pp->ticket != V_ticket_pabuf) {
2880223637Sbz#else
2881149884Smlaier		if (pp->ticket != ticket_pabuf) {
2882223637Sbz#endif
2883149884Smlaier			error = EBUSY;
2884149884Smlaier			break;
2885149884Smlaier		}
2886126258Smlaier#ifndef INET
2887126258Smlaier		if (pp->af == AF_INET) {
2888126258Smlaier			error = EAFNOSUPPORT;
2889126258Smlaier			break;
2890126258Smlaier		}
2891126258Smlaier#endif /* INET */
2892126258Smlaier#ifndef INET6
2893126258Smlaier		if (pp->af == AF_INET6) {
2894126258Smlaier			error = EAFNOSUPPORT;
2895126258Smlaier			break;
2896126258Smlaier		}
2897126258Smlaier#endif /* INET6 */
2898126258Smlaier		if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
2899126258Smlaier		    pp->addr.addr.type != PF_ADDR_DYNIFTL &&
2900126258Smlaier		    pp->addr.addr.type != PF_ADDR_TABLE) {
2901126258Smlaier			error = EINVAL;
2902126258Smlaier			break;
2903126258Smlaier		}
2904223637Sbz#ifdef __FreeBSD__
2905223637Sbz		pa = pool_get(&V_pf_pooladdr_pl, PR_NOWAIT);
2906223637Sbz#else
2907223637Sbz		pa = pool_get(&pf_pooladdr_pl, PR_WAITOK|PR_LIMITFAIL);
2908223637Sbz#endif
2909126258Smlaier		if (pa == NULL) {
2910126258Smlaier			error = ENOMEM;
2911126258Smlaier			break;
2912126258Smlaier		}
2913126258Smlaier		bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
2914126258Smlaier		if (pa->ifname[0]) {
2915171168Smlaier			pa->kif = pfi_kif_get(pa->ifname);
2916130613Smlaier			if (pa->kif == NULL) {
2917223637Sbz#ifdef __FreeBSD__
2918223637Sbz				pool_put(&V_pf_pooladdr_pl, pa);
2919223637Sbz#else
2920126258Smlaier				pool_put(&pf_pooladdr_pl, pa);
2921223637Sbz#endif
2922126258Smlaier				error = EINVAL;
2923126258Smlaier				break;
2924126258Smlaier			}
2925171168Smlaier			pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
2926126258Smlaier		}
2927130613Smlaier		if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
2928130613Smlaier			pfi_dynaddr_remove(&pa->addr);
2929171168Smlaier			pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
2930223637Sbz#ifdef __FreeBSD__
2931223637Sbz			pool_put(&V_pf_pooladdr_pl, pa);
2932223637Sbz#else
2933126258Smlaier			pool_put(&pf_pooladdr_pl, pa);
2934223637Sbz#endif
2935126258Smlaier			error = EINVAL;
2936126258Smlaier			break;
2937126258Smlaier		}
2938223637Sbz#ifdef __FreeBSD__
2939223637Sbz		TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries);
2940223637Sbz#else
2941126258Smlaier		TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
2942223637Sbz#endif
2943126258Smlaier		break;
2944126258Smlaier	}
2945126258Smlaier
2946126258Smlaier	case DIOCGETADDRS: {
2947126258Smlaier		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2948126258Smlaier
2949126258Smlaier		pp->nr = 0;
2950145836Smlaier		pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
2951145836Smlaier		    pp->r_num, 0, 1, 0);
2952126258Smlaier		if (pool == NULL) {
2953126258Smlaier			error = EBUSY;
2954126258Smlaier			break;
2955126258Smlaier		}
2956126258Smlaier		TAILQ_FOREACH(pa, &pool->list, entries)
2957126258Smlaier			pp->nr++;
2958126258Smlaier		break;
2959126258Smlaier	}
2960126258Smlaier
2961126258Smlaier	case DIOCGETADDR: {
2962126258Smlaier		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
2963126258Smlaier		u_int32_t		 nr = 0;
2964126258Smlaier
2965145836Smlaier		pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
2966145836Smlaier		    pp->r_num, 0, 1, 1);
2967126258Smlaier		if (pool == NULL) {
2968126258Smlaier			error = EBUSY;
2969126258Smlaier			break;
2970126258Smlaier		}
2971126258Smlaier		pa = TAILQ_FIRST(&pool->list);
2972126258Smlaier		while ((pa != NULL) && (nr < pp->nr)) {
2973126258Smlaier			pa = TAILQ_NEXT(pa, entries);
2974126258Smlaier			nr++;
2975126258Smlaier		}
2976126258Smlaier		if (pa == NULL) {
2977126258Smlaier			error = EBUSY;
2978126258Smlaier			break;
2979126258Smlaier		}
2980126258Smlaier		bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
2981223637Sbz		pf_addr_copyout(&pp->addr.addr);
2982126258Smlaier		break;
2983126258Smlaier	}
2984126258Smlaier
2985126258Smlaier	case DIOCCHANGEADDR: {
2986126258Smlaier		struct pfioc_pooladdr	*pca = (struct pfioc_pooladdr *)addr;
2987126258Smlaier		struct pf_pooladdr	*oldpa = NULL, *newpa = NULL;
2988126258Smlaier		struct pf_ruleset	*ruleset;
2989126258Smlaier
2990126258Smlaier		if (pca->action < PF_CHANGE_ADD_HEAD ||
2991126258Smlaier		    pca->action > PF_CHANGE_REMOVE) {
2992126258Smlaier			error = EINVAL;
2993126258Smlaier			break;
2994126258Smlaier		}
2995126258Smlaier		if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
2996126258Smlaier		    pca->addr.addr.type != PF_ADDR_DYNIFTL &&
2997126258Smlaier		    pca->addr.addr.type != PF_ADDR_TABLE) {
2998126258Smlaier			error = EINVAL;
2999126258Smlaier			break;
3000126258Smlaier		}
3001126258Smlaier
3002145836Smlaier		ruleset = pf_find_ruleset(pca->anchor);
3003126258Smlaier		if (ruleset == NULL) {
3004126258Smlaier			error = EBUSY;
3005126258Smlaier			break;
3006126258Smlaier		}
3007145836Smlaier		pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
3008145836Smlaier		    pca->r_num, pca->r_last, 1, 1);
3009126258Smlaier		if (pool == NULL) {
3010126258Smlaier			error = EBUSY;
3011126258Smlaier			break;
3012126258Smlaier		}
3013126258Smlaier		if (pca->action != PF_CHANGE_REMOVE) {
3014223637Sbz#ifdef __FreeBSD__
3015223637Sbz			newpa = pool_get(&V_pf_pooladdr_pl,
3016223637Sbz			    PR_NOWAIT);
3017223637Sbz#else
3018223637Sbz			newpa = pool_get(&pf_pooladdr_pl,
3019223637Sbz			    PR_WAITOK|PR_LIMITFAIL);
3020223637Sbz#endif
3021126258Smlaier			if (newpa == NULL) {
3022126258Smlaier				error = ENOMEM;
3023126258Smlaier				break;
3024126258Smlaier			}
3025126258Smlaier			bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
3026126258Smlaier#ifndef INET
3027126258Smlaier			if (pca->af == AF_INET) {
3028223637Sbz#ifdef __FreeBSD__
3029223637Sbz				pool_put(&V_pf_pooladdr_pl, newpa);
3030223637Sbz#else
3031126258Smlaier				pool_put(&pf_pooladdr_pl, newpa);
3032223637Sbz#endif
3033126258Smlaier				error = EAFNOSUPPORT;
3034126258Smlaier				break;
3035126258Smlaier			}
3036126258Smlaier#endif /* INET */
3037126258Smlaier#ifndef INET6
3038126258Smlaier			if (pca->af == AF_INET6) {
3039223637Sbz#ifdef __FreeBSD__
3040223637Sbz				pool_put(&V_pf_pooladdr_pl, newpa);
3041223637Sbz#else
3042126258Smlaier				pool_put(&pf_pooladdr_pl, newpa);
3043223637Sbz#endif
3044126258Smlaier				error = EAFNOSUPPORT;
3045126258Smlaier				break;
3046126258Smlaier			}
3047126258Smlaier#endif /* INET6 */
3048126258Smlaier			if (newpa->ifname[0]) {
3049171168Smlaier				newpa->kif = pfi_kif_get(newpa->ifname);
3050130613Smlaier				if (newpa->kif == NULL) {
3051223637Sbz#ifdef __FreeBSD__
3052223637Sbz					pool_put(&V_pf_pooladdr_pl, newpa);
3053223637Sbz#else
3054126258Smlaier					pool_put(&pf_pooladdr_pl, newpa);
3055223637Sbz#endif
3056126258Smlaier					error = EINVAL;
3057126258Smlaier					break;
3058126258Smlaier				}
3059171168Smlaier				pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
3060126258Smlaier			} else
3061130613Smlaier				newpa->kif = NULL;
3062130613Smlaier			if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
3063126258Smlaier			    pf_tbladdr_setup(ruleset, &newpa->addr)) {
3064130613Smlaier				pfi_dynaddr_remove(&newpa->addr);
3065171168Smlaier				pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
3066223637Sbz#ifdef __FreeBSD__
3067223637Sbz				pool_put(&V_pf_pooladdr_pl, newpa);
3068223637Sbz#else
3069126258Smlaier				pool_put(&pf_pooladdr_pl, newpa);
3070223637Sbz#endif
3071126258Smlaier				error = EINVAL;
3072126258Smlaier				break;
3073126258Smlaier			}
3074126258Smlaier		}
3075126258Smlaier
3076126258Smlaier		if (pca->action == PF_CHANGE_ADD_HEAD)
3077126258Smlaier			oldpa = TAILQ_FIRST(&pool->list);
3078126258Smlaier		else if (pca->action == PF_CHANGE_ADD_TAIL)
3079126258Smlaier			oldpa = TAILQ_LAST(&pool->list, pf_palist);
3080126258Smlaier		else {
3081126258Smlaier			int	i = 0;
3082126258Smlaier
3083126258Smlaier			oldpa = TAILQ_FIRST(&pool->list);
3084126258Smlaier			while ((oldpa != NULL) && (i < pca->nr)) {
3085126258Smlaier				oldpa = TAILQ_NEXT(oldpa, entries);
3086126258Smlaier				i++;
3087126258Smlaier			}
3088126258Smlaier			if (oldpa == NULL) {
3089126258Smlaier				error = EINVAL;
3090126258Smlaier				break;
3091126258Smlaier			}
3092126258Smlaier		}
3093126258Smlaier
3094126258Smlaier		if (pca->action == PF_CHANGE_REMOVE) {
3095126258Smlaier			TAILQ_REMOVE(&pool->list, oldpa, entries);
3096130613Smlaier			pfi_dynaddr_remove(&oldpa->addr);
3097126258Smlaier			pf_tbladdr_remove(&oldpa->addr);
3098171168Smlaier			pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
3099223637Sbz#ifdef __FreeBSD__
3100223637Sbz			pool_put(&V_pf_pooladdr_pl, oldpa);
3101223637Sbz#else
3102126258Smlaier			pool_put(&pf_pooladdr_pl, oldpa);
3103223637Sbz#endif
3104126258Smlaier		} else {
3105126258Smlaier			if (oldpa == NULL)
3106126258Smlaier				TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
3107126258Smlaier			else if (pca->action == PF_CHANGE_ADD_HEAD ||
3108126258Smlaier			    pca->action == PF_CHANGE_ADD_BEFORE)
3109126258Smlaier				TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
3110126258Smlaier			else
3111126258Smlaier				TAILQ_INSERT_AFTER(&pool->list, oldpa,
3112126258Smlaier				    newpa, entries);
3113126258Smlaier		}
3114126258Smlaier
3115126258Smlaier		pool->cur = TAILQ_FIRST(&pool->list);
3116126258Smlaier		PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
3117126258Smlaier		    pca->af);
3118126258Smlaier		break;
3119126258Smlaier	}
3120126258Smlaier
3121126258Smlaier	case DIOCGETRULESETS: {
3122126258Smlaier		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
3123145836Smlaier		struct pf_ruleset	*ruleset;
3124126258Smlaier		struct pf_anchor	*anchor;
3125126258Smlaier
3126145836Smlaier		pr->path[sizeof(pr->path) - 1] = 0;
3127145836Smlaier		if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
3128126258Smlaier			error = EINVAL;
3129126258Smlaier			break;
3130126258Smlaier		}
3131126258Smlaier		pr->nr = 0;
3132145836Smlaier		if (ruleset->anchor == NULL) {
3133145836Smlaier			/* XXX kludge for pf_main_ruleset */
3134223637Sbz#ifdef __FreeBSD__
3135223637Sbz			RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors)
3136223637Sbz#else
3137145836Smlaier			RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
3138223637Sbz#endif
3139145836Smlaier				if (anchor->parent == NULL)
3140145836Smlaier					pr->nr++;
3141145836Smlaier		} else {
3142145836Smlaier			RB_FOREACH(anchor, pf_anchor_node,
3143145836Smlaier			    &ruleset->anchor->children)
3144145836Smlaier				pr->nr++;
3145145836Smlaier		}
3146126258Smlaier		break;
3147126258Smlaier	}
3148126258Smlaier
3149126258Smlaier	case DIOCGETRULESET: {
3150126258Smlaier		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
3151145836Smlaier		struct pf_ruleset	*ruleset;
3152126258Smlaier		struct pf_anchor	*anchor;
3153126258Smlaier		u_int32_t		 nr = 0;
3154126258Smlaier
3155145836Smlaier		pr->path[sizeof(pr->path) - 1] = 0;
3156145836Smlaier		if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
3157126258Smlaier			error = EINVAL;
3158126258Smlaier			break;
3159126258Smlaier		}
3160145836Smlaier		pr->name[0] = 0;
3161145836Smlaier		if (ruleset->anchor == NULL) {
3162145836Smlaier			/* XXX kludge for pf_main_ruleset */
3163223637Sbz#ifdef __FreeBSD__
3164223637Sbz			RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors)
3165223637Sbz#else
3166145836Smlaier			RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
3167223637Sbz#endif
3168145836Smlaier				if (anchor->parent == NULL && nr++ == pr->nr) {
3169145836Smlaier					strlcpy(pr->name, anchor->name,
3170145836Smlaier					    sizeof(pr->name));
3171145836Smlaier					break;
3172145836Smlaier				}
3173145836Smlaier		} else {
3174145836Smlaier			RB_FOREACH(anchor, pf_anchor_node,
3175145836Smlaier			    &ruleset->anchor->children)
3176145836Smlaier				if (nr++ == pr->nr) {
3177145836Smlaier					strlcpy(pr->name, anchor->name,
3178145836Smlaier					    sizeof(pr->name));
3179145836Smlaier					break;
3180145836Smlaier				}
3181126258Smlaier		}
3182145836Smlaier		if (!pr->name[0])
3183126258Smlaier			error = EBUSY;
3184126258Smlaier		break;
3185126258Smlaier	}
3186126258Smlaier
3187126258Smlaier	case DIOCRCLRTABLES: {
3188126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3189126258Smlaier
3190126258Smlaier		if (io->pfrio_esize != 0) {
3191126258Smlaier			error = ENODEV;
3192126258Smlaier			break;
3193126258Smlaier		}
3194126258Smlaier		error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
3195130613Smlaier		    io->pfrio_flags | PFR_FLAG_USERIOCTL);
3196126258Smlaier		break;
3197126258Smlaier	}
3198126258Smlaier
3199126258Smlaier	case DIOCRADDTABLES: {
3200126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3201126258Smlaier
3202126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_table)) {
3203126258Smlaier			error = ENODEV;
3204126258Smlaier			break;
3205126258Smlaier		}
3206126258Smlaier		error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
3207130613Smlaier		    &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3208126258Smlaier		break;
3209126258Smlaier	}
3210126258Smlaier
3211126258Smlaier	case DIOCRDELTABLES: {
3212126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3213126258Smlaier
3214126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_table)) {
3215126258Smlaier			error = ENODEV;
3216126258Smlaier			break;
3217126258Smlaier		}
3218126258Smlaier		error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
3219130613Smlaier		    &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3220126258Smlaier		break;
3221126258Smlaier	}
3222126258Smlaier
3223126258Smlaier	case DIOCRGETTABLES: {
3224126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3225126258Smlaier
3226126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_table)) {
3227126258Smlaier			error = ENODEV;
3228126258Smlaier			break;
3229126258Smlaier		}
3230126258Smlaier		error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
3231130613Smlaier		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3232126258Smlaier		break;
3233126258Smlaier	}
3234126258Smlaier
3235126258Smlaier	case DIOCRGETTSTATS: {
3236126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3237126258Smlaier
3238126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
3239126258Smlaier			error = ENODEV;
3240126258Smlaier			break;
3241126258Smlaier		}
3242126258Smlaier		error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
3243130613Smlaier		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3244126258Smlaier		break;
3245126258Smlaier	}
3246126258Smlaier
3247126258Smlaier	case DIOCRCLRTSTATS: {
3248126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3249126258Smlaier
3250126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_table)) {
3251126258Smlaier			error = ENODEV;
3252126258Smlaier			break;
3253126258Smlaier		}
3254126258Smlaier		error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
3255130613Smlaier		    &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3256126258Smlaier		break;
3257126258Smlaier	}
3258126258Smlaier
3259126258Smlaier	case DIOCRSETTFLAGS: {
3260126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3261126258Smlaier
3262126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_table)) {
3263126258Smlaier			error = ENODEV;
3264126258Smlaier			break;
3265126258Smlaier		}
3266126258Smlaier		error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
3267126258Smlaier		    io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
3268130613Smlaier		    &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3269126258Smlaier		break;
3270126258Smlaier	}
3271126258Smlaier
3272126258Smlaier	case DIOCRCLRADDRS: {
3273126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3274126258Smlaier
3275126258Smlaier		if (io->pfrio_esize != 0) {
3276126258Smlaier			error = ENODEV;
3277126258Smlaier			break;
3278126258Smlaier		}
3279126258Smlaier		error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
3280130613Smlaier		    io->pfrio_flags | PFR_FLAG_USERIOCTL);
3281126258Smlaier		break;
3282126258Smlaier	}
3283126258Smlaier
3284126258Smlaier	case DIOCRADDADDRS: {
3285126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3286126258Smlaier
3287126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3288126258Smlaier			error = ENODEV;
3289126258Smlaier			break;
3290126258Smlaier		}
3291126258Smlaier		error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
3292130613Smlaier		    io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags |
3293130613Smlaier		    PFR_FLAG_USERIOCTL);
3294126258Smlaier		break;
3295126258Smlaier	}
3296126258Smlaier
3297126258Smlaier	case DIOCRDELADDRS: {
3298126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3299126258Smlaier
3300126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3301126258Smlaier			error = ENODEV;
3302126258Smlaier			break;
3303126258Smlaier		}
3304126258Smlaier		error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
3305130613Smlaier		    io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags |
3306130613Smlaier		    PFR_FLAG_USERIOCTL);
3307126258Smlaier		break;
3308126258Smlaier	}
3309126258Smlaier
3310126258Smlaier	case DIOCRSETADDRS: {
3311126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3312126258Smlaier
3313126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3314126258Smlaier			error = ENODEV;
3315126258Smlaier			break;
3316126258Smlaier		}
3317126258Smlaier		error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
3318126258Smlaier		    io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
3319130613Smlaier		    &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
3320171168Smlaier		    PFR_FLAG_USERIOCTL, 0);
3321126258Smlaier		break;
3322126258Smlaier	}
3323126258Smlaier
3324126258Smlaier	case DIOCRGETADDRS: {
3325126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3326126258Smlaier
3327126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3328126258Smlaier			error = ENODEV;
3329126258Smlaier			break;
3330126258Smlaier		}
3331126258Smlaier		error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
3332130613Smlaier		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3333126258Smlaier		break;
3334126258Smlaier	}
3335126258Smlaier
3336126258Smlaier	case DIOCRGETASTATS: {
3337126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3338126258Smlaier
3339126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_astats)) {
3340126258Smlaier			error = ENODEV;
3341126258Smlaier			break;
3342126258Smlaier		}
3343126258Smlaier		error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
3344130613Smlaier		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3345126258Smlaier		break;
3346126258Smlaier	}
3347126258Smlaier
3348126258Smlaier	case DIOCRCLRASTATS: {
3349126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3350126258Smlaier
3351126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3352126258Smlaier			error = ENODEV;
3353126258Smlaier			break;
3354126258Smlaier		}
3355126258Smlaier		error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
3356130613Smlaier		    io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags |
3357130613Smlaier		    PFR_FLAG_USERIOCTL);
3358126258Smlaier		break;
3359126258Smlaier	}
3360126258Smlaier
3361126258Smlaier	case DIOCRTSTADDRS: {
3362126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3363126258Smlaier
3364126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3365126258Smlaier			error = ENODEV;
3366126258Smlaier			break;
3367126258Smlaier		}
3368126258Smlaier		error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
3369130613Smlaier		    io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags |
3370130613Smlaier		    PFR_FLAG_USERIOCTL);
3371126258Smlaier		break;
3372126258Smlaier	}
3373126258Smlaier
3374126258Smlaier	case DIOCRINADEFINE: {
3375126258Smlaier		struct pfioc_table *io = (struct pfioc_table *)addr;
3376126258Smlaier
3377126258Smlaier		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
3378126258Smlaier			error = ENODEV;
3379126258Smlaier			break;
3380126258Smlaier		}
3381126258Smlaier		error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
3382126258Smlaier		    io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
3383130613Smlaier		    io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL);
3384126258Smlaier		break;
3385126258Smlaier	}
3386126258Smlaier
3387126258Smlaier	case DIOCOSFPADD: {
3388126258Smlaier		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
3389126258Smlaier		error = pf_osfp_add(io);
3390126258Smlaier		break;
3391126258Smlaier	}
3392126258Smlaier
3393126258Smlaier	case DIOCOSFPGET: {
3394126258Smlaier		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
3395126258Smlaier		error = pf_osfp_get(io);
3396126258Smlaier		break;
3397126258Smlaier	}
3398126258Smlaier
3399130613Smlaier	case DIOCXBEGIN: {
3400171168Smlaier		struct pfioc_trans	*io = (struct pfioc_trans *)addr;
3401171168Smlaier		struct pfioc_trans_e	*ioe;
3402171168Smlaier		struct pfr_table	*table;
3403171168Smlaier		int			 i;
3404130613Smlaier
3405171168Smlaier		if (io->esize != sizeof(*ioe)) {
3406130613Smlaier			error = ENODEV;
3407130613Smlaier			goto fail;
3408130613Smlaier		}
3409171168Smlaier#ifdef __FreeBSD__
3410171168Smlaier		PF_UNLOCK();
3411171168Smlaier#endif
3412223637Sbz		ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK);
3413223637Sbz		table = malloc(sizeof(*table), M_TEMP, M_WAITOK);
3414171168Smlaier#ifdef __FreeBSD__
3415171168Smlaier		PF_LOCK();
3416171168Smlaier#endif
3417130613Smlaier		for (i = 0; i < io->size; i++) {
3418127145Smlaier#ifdef __FreeBSD__
3419223637Sbz		PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
3420223637Sbz		if (error) {
3421130613Smlaier#else
3422171168Smlaier			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
3423126261Smlaier#endif
3424171168Smlaier				free(table, M_TEMP);
3425171168Smlaier				free(ioe, M_TEMP);
3426130613Smlaier				error = EFAULT;
3427130613Smlaier				goto fail;
3428130613Smlaier			}
3429171168Smlaier			switch (ioe->rs_num) {
3430130613Smlaier#ifdef ALTQ
3431130613Smlaier			case PF_RULESET_ALTQ:
3432171168Smlaier				if (ioe->anchor[0]) {
3433171168Smlaier					free(table, M_TEMP);
3434171168Smlaier					free(ioe, M_TEMP);
3435130613Smlaier					error = EINVAL;
3436130613Smlaier					goto fail;
3437130613Smlaier				}
3438171168Smlaier				if ((error = pf_begin_altq(&ioe->ticket))) {
3439171168Smlaier					free(table, M_TEMP);
3440171168Smlaier					free(ioe, M_TEMP);
3441130613Smlaier					goto fail;
3442171168Smlaier				}
3443130613Smlaier				break;
3444130613Smlaier#endif /* ALTQ */
3445130613Smlaier			case PF_RULESET_TABLE:
3446171168Smlaier				bzero(table, sizeof(*table));
3447171168Smlaier				strlcpy(table->pfrt_anchor, ioe->anchor,
3448171168Smlaier				    sizeof(table->pfrt_anchor));
3449171168Smlaier				if ((error = pfr_ina_begin(table,
3450171168Smlaier				    &ioe->ticket, NULL, 0))) {
3451171168Smlaier					free(table, M_TEMP);
3452171168Smlaier					free(ioe, M_TEMP);
3453130613Smlaier					goto fail;
3454171168Smlaier				}
3455130613Smlaier				break;
3456130613Smlaier			default:
3457171168Smlaier				if ((error = pf_begin_rules(&ioe->ticket,
3458171168Smlaier				    ioe->rs_num, ioe->anchor))) {
3459171168Smlaier					free(table, M_TEMP);
3460171168Smlaier					free(ioe, M_TEMP);
3461130613Smlaier					goto fail;
3462171168Smlaier				}
3463130613Smlaier				break;
3464130613Smlaier			}
3465127145Smlaier#ifdef __FreeBSD__
3466171168Smlaier			PF_COPYOUT(ioe, io->array+i, sizeof(io->array[i]),
3467130613Smlaier			    error);
3468130613Smlaier			if (error) {
3469130613Smlaier#else
3470171168Smlaier			if (copyout(ioe, io->array+i, sizeof(io->array[i]))) {
3471130613Smlaier#endif
3472171168Smlaier				free(table, M_TEMP);
3473171168Smlaier				free(ioe, M_TEMP);
3474130613Smlaier				error = EFAULT;
3475130613Smlaier				goto fail;
3476130613Smlaier			}
3477126261Smlaier		}
3478171168Smlaier		free(table, M_TEMP);
3479171168Smlaier		free(ioe, M_TEMP);
3480130613Smlaier		break;
3481130613Smlaier	}
3482126261Smlaier
3483130613Smlaier	case DIOCXROLLBACK: {
3484171168Smlaier		struct pfioc_trans	*io = (struct pfioc_trans *)addr;
3485171168Smlaier		struct pfioc_trans_e	*ioe;
3486171168Smlaier		struct pfr_table	*table;
3487171168Smlaier		int			 i;
3488126261Smlaier
3489171168Smlaier		if (io->esize != sizeof(*ioe)) {
3490130613Smlaier			error = ENODEV;
3491130613Smlaier			goto fail;
3492126261Smlaier		}
3493171168Smlaier#ifdef __FreeBSD__
3494171168Smlaier		PF_UNLOCK();
3495171168Smlaier#endif
3496223637Sbz		ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK);
3497223637Sbz		table = malloc(sizeof(*table), M_TEMP, M_WAITOK);
3498171168Smlaier#ifdef __FreeBSD__
3499171168Smlaier		PF_LOCK();
3500171168Smlaier#endif
3501130613Smlaier		for (i = 0; i < io->size; i++) {
3502130613Smlaier#ifdef __FreeBSD__
3503171168Smlaier			PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
3504130613Smlaier			if (error) {
3505130613Smlaier#else
3506171168Smlaier			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
3507130613Smlaier#endif
3508171168Smlaier				free(table, M_TEMP);
3509171168Smlaier				free(ioe, M_TEMP);
3510130613Smlaier				error = EFAULT;
3511130613Smlaier				goto fail;
3512130613Smlaier			}
3513171168Smlaier			switch (ioe->rs_num) {
3514130613Smlaier#ifdef ALTQ
3515130613Smlaier			case PF_RULESET_ALTQ:
3516171168Smlaier				if (ioe->anchor[0]) {
3517171168Smlaier					free(table, M_TEMP);
3518171168Smlaier					free(ioe, M_TEMP);
3519130613Smlaier					error = EINVAL;
3520130613Smlaier					goto fail;
3521130613Smlaier				}
3522171168Smlaier				if ((error = pf_rollback_altq(ioe->ticket))) {
3523171168Smlaier					free(table, M_TEMP);
3524171168Smlaier					free(ioe, M_TEMP);
3525130613Smlaier					goto fail; /* really bad */
3526171168Smlaier				}
3527130613Smlaier				break;
3528130613Smlaier#endif /* ALTQ */
3529130613Smlaier			case PF_RULESET_TABLE:
3530171168Smlaier				bzero(table, sizeof(*table));
3531171168Smlaier				strlcpy(table->pfrt_anchor, ioe->anchor,
3532171168Smlaier				    sizeof(table->pfrt_anchor));
3533171168Smlaier				if ((error = pfr_ina_rollback(table,
3534171168Smlaier				    ioe->ticket, NULL, 0))) {
3535171168Smlaier					free(table, M_TEMP);
3536171168Smlaier					free(ioe, M_TEMP);
3537130613Smlaier					goto fail; /* really bad */
3538171168Smlaier				}
3539130613Smlaier				break;
3540130613Smlaier			default:
3541171168Smlaier				if ((error = pf_rollback_rules(ioe->ticket,
3542171168Smlaier				    ioe->rs_num, ioe->anchor))) {
3543171168Smlaier					free(table, M_TEMP);
3544171168Smlaier					free(ioe, M_TEMP);
3545130613Smlaier					goto fail; /* really bad */
3546171168Smlaier				}
3547130613Smlaier				break;
3548130613Smlaier			}
3549126261Smlaier		}
3550171168Smlaier		free(table, M_TEMP);
3551171168Smlaier		free(ioe, M_TEMP);
3552130613Smlaier		break;
3553130613Smlaier	}
3554126261Smlaier
3555130613Smlaier	case DIOCXCOMMIT: {
3556171168Smlaier		struct pfioc_trans	*io = (struct pfioc_trans *)addr;
3557171168Smlaier		struct pfioc_trans_e	*ioe;
3558171168Smlaier		struct pfr_table	*table;
3559171168Smlaier		struct pf_ruleset	*rs;
3560171168Smlaier		int			 i;
3561126261Smlaier
3562171168Smlaier		if (io->esize != sizeof(*ioe)) {
3563130613Smlaier			error = ENODEV;
3564130613Smlaier			goto fail;
3565130613Smlaier		}
3566171168Smlaier#ifdef __FreeBSD__
3567171168Smlaier		PF_UNLOCK();
3568171168Smlaier#endif
3569223637Sbz		ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK);
3570223637Sbz		table = malloc(sizeof(*table), M_TEMP, M_WAITOK);
3571171168Smlaier#ifdef __FreeBSD__
3572171168Smlaier		PF_LOCK();
3573171168Smlaier#endif
3574130613Smlaier		/* first makes sure everything will succeed */
3575130613Smlaier		for (i = 0; i < io->size; i++) {
3576127145Smlaier#ifdef __FreeBSD__
3577171168Smlaier			PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
3578130613Smlaier			if (error) {
3579130613Smlaier#else
3580171168Smlaier			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
3581126261Smlaier#endif
3582171168Smlaier				free(table, M_TEMP);
3583171168Smlaier				free(ioe, M_TEMP);
3584130613Smlaier				error = EFAULT;
3585130613Smlaier				goto fail;
3586130613Smlaier			}
3587171168Smlaier			switch (ioe->rs_num) {
3588130613Smlaier#ifdef ALTQ
3589130613Smlaier			case PF_RULESET_ALTQ:
3590171168Smlaier				if (ioe->anchor[0]) {
3591171168Smlaier					free(table, M_TEMP);
3592171168Smlaier					free(ioe, M_TEMP);
3593130613Smlaier					error = EINVAL;
3594130613Smlaier					goto fail;
3595130613Smlaier				}
3596223637Sbz#ifdef __FreeBSD__
3597223637Sbz				if (!V_altqs_inactive_open || ioe->ticket !=
3598223637Sbz				    V_ticket_altqs_inactive) {
3599223637Sbz#else
3600171168Smlaier				if (!altqs_inactive_open || ioe->ticket !=
3601130613Smlaier				    ticket_altqs_inactive) {
3602223637Sbz#endif
3603171168Smlaier					free(table, M_TEMP);
3604171168Smlaier					free(ioe, M_TEMP);
3605130613Smlaier					error = EBUSY;
3606130613Smlaier					goto fail;
3607130613Smlaier				}
3608130613Smlaier				break;
3609130613Smlaier#endif /* ALTQ */
3610130613Smlaier			case PF_RULESET_TABLE:
3611171168Smlaier				rs = pf_find_ruleset(ioe->anchor);
3612171168Smlaier				if (rs == NULL || !rs->topen || ioe->ticket !=
3613223637Sbz				    rs->tticket) {
3614171168Smlaier					free(table, M_TEMP);
3615171168Smlaier					free(ioe, M_TEMP);
3616130613Smlaier					error = EBUSY;
3617130613Smlaier					goto fail;
3618130613Smlaier				}
3619130613Smlaier				break;
3620130613Smlaier			default:
3621171168Smlaier				if (ioe->rs_num < 0 || ioe->rs_num >=
3622130613Smlaier				    PF_RULESET_MAX) {
3623171168Smlaier					free(table, M_TEMP);
3624171168Smlaier					free(ioe, M_TEMP);
3625130613Smlaier					error = EINVAL;
3626130613Smlaier					goto fail;
3627130613Smlaier				}
3628171168Smlaier				rs = pf_find_ruleset(ioe->anchor);
3629130613Smlaier				if (rs == NULL ||
3630171168Smlaier				    !rs->rules[ioe->rs_num].inactive.open ||
3631171168Smlaier				    rs->rules[ioe->rs_num].inactive.ticket !=
3632171168Smlaier				    ioe->ticket) {
3633171168Smlaier					free(table, M_TEMP);
3634171168Smlaier					free(ioe, M_TEMP);
3635130613Smlaier					error = EBUSY;
3636130613Smlaier					goto fail;
3637130613Smlaier				}
3638130613Smlaier				break;
3639130613Smlaier			}
3640130613Smlaier		}
3641130613Smlaier		/* now do the commit - no errors should happen here */
3642130613Smlaier		for (i = 0; i < io->size; i++) {
3643127145Smlaier#ifdef __FreeBSD__
3644171168Smlaier			PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error);
3645130613Smlaier			if (error) {
3646130613Smlaier#else
3647171168Smlaier			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
3648126261Smlaier#endif
3649171168Smlaier				free(table, M_TEMP);
3650171168Smlaier				free(ioe, M_TEMP);
3651130613Smlaier				error = EFAULT;
3652130613Smlaier				goto fail;
3653130613Smlaier			}
3654171168Smlaier			switch (ioe->rs_num) {
3655130613Smlaier#ifdef ALTQ
3656130613Smlaier			case PF_RULESET_ALTQ:
3657171168Smlaier				if ((error = pf_commit_altq(ioe->ticket))) {
3658171168Smlaier					free(table, M_TEMP);
3659171168Smlaier					free(ioe, M_TEMP);
3660130613Smlaier					goto fail; /* really bad */
3661171168Smlaier				}
3662130613Smlaier				break;
3663130613Smlaier#endif /* ALTQ */
3664130613Smlaier			case PF_RULESET_TABLE:
3665171168Smlaier				bzero(table, sizeof(*table));
3666171168Smlaier				strlcpy(table->pfrt_anchor, ioe->anchor,
3667171168Smlaier				    sizeof(table->pfrt_anchor));
3668171168Smlaier				if ((error = pfr_ina_commit(table, ioe->ticket,
3669171168Smlaier				    NULL, NULL, 0))) {
3670171168Smlaier					free(table, M_TEMP);
3671171168Smlaier					free(ioe, M_TEMP);
3672130613Smlaier					goto fail; /* really bad */
3673171168Smlaier				}
3674130613Smlaier				break;
3675130613Smlaier			default:
3676171168Smlaier				if ((error = pf_commit_rules(ioe->ticket,
3677171168Smlaier				    ioe->rs_num, ioe->anchor))) {
3678171168Smlaier					free(table, M_TEMP);
3679171168Smlaier					free(ioe, M_TEMP);
3680130613Smlaier					goto fail; /* really bad */
3681171168Smlaier				}
3682130613Smlaier				break;
3683130613Smlaier			}
3684126261Smlaier		}
3685171168Smlaier		free(table, M_TEMP);
3686171168Smlaier		free(ioe, M_TEMP);
3687130613Smlaier		break;
3688126261Smlaier	}
3689126261Smlaier
3690130613Smlaier	case DIOCGETSRCNODES: {
3691130613Smlaier		struct pfioc_src_nodes	*psn = (struct pfioc_src_nodes *)addr;
3692171168Smlaier		struct pf_src_node	*n, *p, *pstore;
3693130613Smlaier		u_int32_t		 nr = 0;
3694130613Smlaier		int			 space = psn->psn_len;
3695126261Smlaier
3696130613Smlaier		if (space == 0) {
3697223637Sbz#ifdef __FreeBSD__
3698223637Sbz			RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking)
3699223637Sbz#else
3700130613Smlaier			RB_FOREACH(n, pf_src_tree, &tree_src_tracking)
3701223637Sbz#endif
3702130613Smlaier				nr++;
3703130613Smlaier			psn->psn_len = sizeof(struct pf_src_node) * nr;
3704145836Smlaier			break;
3705126261Smlaier		}
3706126261Smlaier
3707171168Smlaier#ifdef __FreeBSD__
3708171168Smlaier		PF_UNLOCK();
3709171168Smlaier#endif
3710171168Smlaier		pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
3711171168Smlaier#ifdef __FreeBSD__
3712171168Smlaier		PF_LOCK();
3713171168Smlaier#endif
3714130613Smlaier		p = psn->psn_src_nodes;
3715223637Sbz#ifdef __FreeBSD__
3716223637Sbz		RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) {
3717223637Sbz#else
3718130613Smlaier		RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
3719223637Sbz#endif
3720145836Smlaier			int	secs = time_second, diff;
3721126261Smlaier
3722130613Smlaier			if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
3723130613Smlaier				break;
3724130613Smlaier
3725171168Smlaier			bcopy(n, pstore, sizeof(*pstore));
3726130613Smlaier			if (n->rule.ptr != NULL)
3727171168Smlaier				pstore->rule.nr = n->rule.ptr->nr;
3728171168Smlaier			pstore->creation = secs - pstore->creation;
3729171168Smlaier			if (pstore->expire > secs)
3730171168Smlaier				pstore->expire -= secs;
3731130613Smlaier			else
3732171168Smlaier				pstore->expire = 0;
3733145836Smlaier
3734145836Smlaier			/* adjust the connection rate estimate */
3735145836Smlaier			diff = secs - n->conn_rate.last;
3736145836Smlaier			if (diff >= n->conn_rate.seconds)
3737171168Smlaier				pstore->conn_rate.count = 0;
3738145836Smlaier			else
3739171168Smlaier				pstore->conn_rate.count -=
3740145836Smlaier				    n->conn_rate.count * diff /
3741145836Smlaier				    n->conn_rate.seconds;
3742145836Smlaier
3743127145Smlaier#ifdef __FreeBSD__
3744171168Smlaier			PF_COPYOUT(pstore, p, sizeof(*p), error);
3745130613Smlaier#else
3746171168Smlaier			error = copyout(pstore, p, sizeof(*p));
3747126261Smlaier#endif
3748171168Smlaier			if (error) {
3749171168Smlaier				free(pstore, M_TEMP);
3750130613Smlaier				goto fail;
3751171168Smlaier			}
3752130613Smlaier			p++;
3753130613Smlaier			nr++;
3754126261Smlaier		}
3755130613Smlaier		psn->psn_len = sizeof(struct pf_src_node) * nr;
3756171168Smlaier
3757171168Smlaier		free(pstore, M_TEMP);
3758130613Smlaier		break;
3759130613Smlaier	}
3760126261Smlaier
3761130613Smlaier	case DIOCCLRSRCNODES: {
3762130613Smlaier		struct pf_src_node	*n;
3763130613Smlaier		struct pf_state		*state;
3764130613Smlaier
3765223637Sbz#ifdef __FreeBSD__
3766223637Sbz		RB_FOREACH(state, pf_state_tree_id, &V_tree_id) {
3767223637Sbz#else
3768130613Smlaier		RB_FOREACH(state, pf_state_tree_id, &tree_id) {
3769223637Sbz#endif
3770130613Smlaier			state->src_node = NULL;
3771130613Smlaier			state->nat_src_node = NULL;
3772126261Smlaier		}
3773223637Sbz#ifdef __FreeBSD__
3774223637Sbz		RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) {
3775223637Sbz#else
3776130613Smlaier		RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
3777223637Sbz#endif
3778130613Smlaier			n->expire = 1;
3779130613Smlaier			n->states = 0;
3780130613Smlaier		}
3781171168Smlaier		pf_purge_expired_src_nodes(1);
3782223637Sbz#ifdef __FreeBSD__
3783223637Sbz		V_pf_status.src_nodes = 0;
3784223637Sbz#else
3785130613Smlaier		pf_status.src_nodes = 0;
3786223637Sbz#endif
3787130613Smlaier		break;
3788130613Smlaier	}
3789126261Smlaier
3790171168Smlaier	case DIOCKILLSRCNODES: {
3791171168Smlaier		struct pf_src_node	*sn;
3792171168Smlaier		struct pf_state		*s;
3793223637Sbz		struct pfioc_src_node_kill *psnk =
3794223637Sbz		    (struct pfioc_src_node_kill *)addr;
3795223637Sbz		u_int			killed = 0;
3796171168Smlaier
3797223637Sbz#ifdef __FreeBSD__
3798223637Sbz		RB_FOREACH(sn, pf_src_tree, &V_tree_src_tracking) {
3799223637Sbz#else
3800171168Smlaier		RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
3801223637Sbz#endif
3802223637Sbz			if (PF_MATCHA(psnk->psnk_src.neg,
3803223637Sbz				&psnk->psnk_src.addr.v.a.addr,
3804223637Sbz				&psnk->psnk_src.addr.v.a.mask,
3805223637Sbz				&sn->addr, sn->af) &&
3806223637Sbz			    PF_MATCHA(psnk->psnk_dst.neg,
3807223637Sbz				&psnk->psnk_dst.addr.v.a.addr,
3808223637Sbz				&psnk->psnk_dst.addr.v.a.mask,
3809223637Sbz				&sn->raddr, sn->af)) {
3810171168Smlaier				/* Handle state to src_node linkage */
3811171168Smlaier				if (sn->states != 0) {
3812223637Sbz					RB_FOREACH(s, pf_state_tree_id,
3813223637Sbz#ifdef __FreeBSD__
3814223637Sbz					    &V_tree_id) {
3815223637Sbz#else
3816171168Smlaier					    &tree_id) {
3817223637Sbz#endif
3818171168Smlaier						if (s->src_node == sn)
3819171168Smlaier							s->src_node = NULL;
3820171168Smlaier						if (s->nat_src_node == sn)
3821171168Smlaier							s->nat_src_node = NULL;
3822171168Smlaier					}
3823171168Smlaier					sn->states = 0;
3824171168Smlaier				}
3825171168Smlaier				sn->expire = 1;
3826171168Smlaier				killed++;
3827171168Smlaier			}
3828171168Smlaier		}
3829171168Smlaier
3830171168Smlaier		if (killed > 0)
3831171168Smlaier			pf_purge_expired_src_nodes(1);
3832171168Smlaier
3833223637Sbz		psnk->psnk_killed = killed;
3834171168Smlaier		break;
3835171168Smlaier	}
3836171168Smlaier
3837130613Smlaier	case DIOCSETHOSTID: {
3838130613Smlaier		u_int32_t	*hostid = (u_int32_t *)addr;
3839126261Smlaier
3840223637Sbz#ifdef __FreeBSD__
3841145836Smlaier		if (*hostid == 0)
3842223637Sbz			V_pf_status.hostid = arc4random();
3843223637Sbz		else
3844223637Sbz			V_pf_status.hostid = *hostid;
3845223637Sbz#else
3846223637Sbz		if (*hostid == 0)
3847145836Smlaier			pf_status.hostid = arc4random();
3848145836Smlaier		else
3849145836Smlaier			pf_status.hostid = *hostid;
3850223637Sbz#endif
3851130613Smlaier		break;
3852130613Smlaier	}
3853126261Smlaier
3854130613Smlaier	case DIOCOSFPFLUSH:
3855130613Smlaier		pf_osfp_flush();
3856130613Smlaier		break;
3857126261Smlaier
3858130613Smlaier	case DIOCIGETIFACES: {
3859130613Smlaier		struct pfioc_iface *io = (struct pfioc_iface *)addr;
3860130613Smlaier
3861171168Smlaier		if (io->pfiio_esize != sizeof(struct pfi_kif)) {
3862130613Smlaier			error = ENODEV;
3863130613Smlaier			break;
3864130613Smlaier		}
3865130613Smlaier		error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer,
3866171168Smlaier		    &io->pfiio_size);
3867130613Smlaier		break;
3868130613Smlaier	}
3869130613Smlaier
3870145836Smlaier	case DIOCSETIFFLAG: {
3871145836Smlaier		struct pfioc_iface *io = (struct pfioc_iface *)addr;
3872145836Smlaier
3873145836Smlaier		error = pfi_set_flags(io->pfiio_name, io->pfiio_flags);
3874145836Smlaier		break;
3875145836Smlaier	}
3876145836Smlaier
3877145836Smlaier	case DIOCCLRIFFLAG: {
3878145836Smlaier		struct pfioc_iface *io = (struct pfioc_iface *)addr;
3879145836Smlaier
3880145836Smlaier		error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags);
3881145836Smlaier		break;
3882145836Smlaier	}
3883145836Smlaier
3884130613Smlaier	default:
3885130613Smlaier		error = ENODEV;
3886130613Smlaier		break;
3887130613Smlaier	}
3888130613Smlaierfail:
3889130613Smlaier#ifdef __FreeBSD__
3890130613Smlaier	PF_UNLOCK();
3891171168Smlaier
3892171168Smlaier	if (flags & FWRITE)
3893223637Sbz		sx_xunlock(&V_pf_consistency_lock);
3894171168Smlaier	else
3895223637Sbz		sx_sunlock(&V_pf_consistency_lock);
3896145836Smlaier#else
3897145836Smlaier	splx(s);
3898171168Smlaier	if (flags & FWRITE)
3899171168Smlaier		rw_exit_write(&pf_consistency_lock);
3900171168Smlaier	else
3901171168Smlaier		rw_exit_read(&pf_consistency_lock);
3902130613Smlaier#endif
3903223637Sbz
3904223637Sbz	CURVNET_RESTORE();
3905223637Sbz
3906126261Smlaier	return (error);
3907126261Smlaier}
3908126261Smlaier
3909130613Smlaier#ifdef __FreeBSD__
3910223637Sbzvoid
3911223637Sbzpfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
3912223637Sbz{
3913223637Sbz	bzero(sp, sizeof(struct pfsync_state));
3914223637Sbz
3915223637Sbz	/* copy from state key */
3916223637Sbz	sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
3917223637Sbz	sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
3918223637Sbz	sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
3919223637Sbz	sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
3920223637Sbz	sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
3921223637Sbz	sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
3922223637Sbz	sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
3923223637Sbz	sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
3924223637Sbz	sp->proto = st->key[PF_SK_WIRE]->proto;
3925223637Sbz	sp->af = st->key[PF_SK_WIRE]->af;
3926223637Sbz
3927223637Sbz	/* copy from state */
3928223637Sbz	strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
3929223637Sbz	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
3930223637Sbz	sp->creation = htonl(time_second - st->creation);
3931223637Sbz	sp->expire = pf_state_expires(st);
3932223637Sbz	if (sp->expire <= time_second)
3933223637Sbz		sp->expire = htonl(0);
3934223637Sbz	else
3935223637Sbz		sp->expire = htonl(sp->expire - time_second);
3936223637Sbz
3937223637Sbz	sp->direction = st->direction;
3938223637Sbz	sp->log = st->log;
3939223637Sbz	sp->timeout = st->timeout;
3940223637Sbz	sp->state_flags = st->state_flags;
3941223637Sbz	if (st->src_node)
3942223637Sbz		sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
3943223637Sbz	if (st->nat_src_node)
3944223637Sbz		sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
3945223637Sbz
3946223637Sbz	bcopy(&st->id, &sp->id, sizeof(sp->id));
3947223637Sbz	sp->creatorid = st->creatorid;
3948223637Sbz	pf_state_peer_hton(&st->src, &sp->src);
3949223637Sbz	pf_state_peer_hton(&st->dst, &sp->dst);
3950223637Sbz
3951223637Sbz	if (st->rule.ptr == NULL)
3952223637Sbz		sp->rule = htonl(-1);
3953223637Sbz	else
3954223637Sbz		sp->rule = htonl(st->rule.ptr->nr);
3955223637Sbz	if (st->anchor.ptr == NULL)
3956223637Sbz		sp->anchor = htonl(-1);
3957223637Sbz	else
3958223637Sbz		sp->anchor = htonl(st->anchor.ptr->nr);
3959223637Sbz	if (st->nat_rule.ptr == NULL)
3960223637Sbz		sp->nat_rule = htonl(-1);
3961223637Sbz	else
3962223637Sbz		sp->nat_rule = htonl(st->nat_rule.ptr->nr);
3963223637Sbz
3964223637Sbz	pf_state_counter_hton(st->packets[0], sp->packets[0]);
3965223637Sbz	pf_state_counter_hton(st->packets[1], sp->packets[1]);
3966223637Sbz	pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
3967223637Sbz	pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
3968223637Sbz
3969223637Sbz}
3970223637Sbz
3971130613Smlaier/*
3972130613Smlaier * XXX - Check for version missmatch!!!
3973130613Smlaier */
3974126261Smlaierstatic void
3975130613Smlaierpf_clear_states(void)
3976126261Smlaier{
3977223637Sbz	struct pf_state	*state;
3978223637Sbz
3979223637Sbz#ifdef __FreeBSD__
3980223637Sbz	RB_FOREACH(state, pf_state_tree_id, &V_tree_id) {
3981223637Sbz#else
3982130613Smlaier	RB_FOREACH(state, pf_state_tree_id, &tree_id) {
3983223637Sbz#endif
3984130613Smlaier		state->timeout = PFTM_PURGE;
3985130613Smlaier#if NPFSYNC
3986130613Smlaier		/* don't send out individual delete messages */
3987223637Sbz		state->sync_state = PFSTATE_NOSYNC;
3988130613Smlaier#endif
3989171168Smlaier		pf_unlink_state(state);
3990130613Smlaier	}
3991223637Sbz
3992130613Smlaier#if 0 /* NPFSYNC */
3993130613Smlaier/*
3994130613Smlaier * XXX This is called on module unload, we do not want to sync that over? */
3995130613Smlaier */
3996223637Sbz	pfsync_clear_states(V_pf_status.hostid, psk->psk_ifname);
3997130613Smlaier#endif
3998126261Smlaier}
3999126261Smlaier
4000126261Smlaierstatic int
4001130613Smlaierpf_clear_tables(void)
4002126261Smlaier{
4003130613Smlaier	struct pfioc_table io;
4004126261Smlaier	int error;
4005126261Smlaier
4006130613Smlaier	bzero(&io, sizeof(io));
4007126261Smlaier
4008130613Smlaier	error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel,
4009130613Smlaier	    io.pfrio_flags);
4010130613Smlaier
4011126261Smlaier	return (error);
4012126261Smlaier}
4013126261Smlaier
4014130613Smlaierstatic void
4015130613Smlaierpf_clear_srcnodes(void)
4016130613Smlaier{
4017130613Smlaier	struct pf_src_node	*n;
4018130613Smlaier	struct pf_state		*state;
4019130613Smlaier
4020223637Sbz#ifdef __FreeBSD__
4021223637Sbz	RB_FOREACH(state, pf_state_tree_id, &V_tree_id) {
4022223637Sbz#else
4023130613Smlaier	RB_FOREACH(state, pf_state_tree_id, &tree_id) {
4024223637Sbz#endif
4025130613Smlaier		state->src_node = NULL;
4026130613Smlaier		state->nat_src_node = NULL;
4027130613Smlaier	}
4028223637Sbz#ifdef __FreeBSD__
4029223637Sbz	RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) {
4030223637Sbz#else
4031130613Smlaier	RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
4032223637Sbz#endif
4033130613Smlaier		n->expire = 1;
4034130613Smlaier		n->states = 0;
4035130613Smlaier	}
4036130613Smlaier}
4037130613Smlaier/*
4038130613Smlaier * XXX - Check for version missmatch!!!
4039130613Smlaier */
4040130613Smlaier
4041130613Smlaier/*
4042130613Smlaier * Duplicate pfctl -Fa operation to get rid of as much as we can.
4043130613Smlaier */
4044126261Smlaierstatic int
4045126261Smlaiershutdown_pf(void)
4046126261Smlaier{
4047126261Smlaier	int error = 0;
4048130613Smlaier	u_int32_t t[5];
4049130613Smlaier	char nn = '\0';
4050223637Sbz
4051223637Sbz	V_pf_status.running = 0;
4052126261Smlaier	do {
4053145836Smlaier		if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn))
4054145836Smlaier		    != 0) {
4055130613Smlaier			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n"));
4056126261Smlaier			break;
4057126261Smlaier		}
4058145836Smlaier		if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn))
4059145836Smlaier		    != 0) {
4060130613Smlaier			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n"));
4061223637Sbz			break;          /* XXX: rollback? */
4062126261Smlaier		}
4063145836Smlaier		if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn))
4064130613Smlaier		    != 0) {
4065130613Smlaier			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n"));
4066223637Sbz			break;          /* XXX: rollback? */
4067126261Smlaier		}
4068145836Smlaier		if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn))
4069130613Smlaier		    != 0) {
4070130613Smlaier			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n"));
4071223637Sbz			break;          /* XXX: rollback? */
4072126261Smlaier		}
4073145836Smlaier		if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn))
4074130613Smlaier		    != 0) {
4075130613Smlaier			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n"));
4076223637Sbz			break;          /* XXX: rollback? */
4077126261Smlaier		}
4078126261Smlaier
4079130613Smlaier		/* XXX: these should always succeed here */
4080145836Smlaier		pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn);
4081145836Smlaier		pf_commit_rules(t[1], PF_RULESET_FILTER, &nn);
4082145836Smlaier		pf_commit_rules(t[2], PF_RULESET_NAT, &nn);
4083145836Smlaier		pf_commit_rules(t[3], PF_RULESET_BINAT, &nn);
4084145836Smlaier		pf_commit_rules(t[4], PF_RULESET_RDR, &nn);
4085126261Smlaier
4086130613Smlaier		if ((error = pf_clear_tables()) != 0)
4087126261Smlaier			break;
4088126261Smlaier
4089223637Sbz	#ifdef ALTQ
4090130613Smlaier		if ((error = pf_begin_altq(&t[0])) != 0) {
4091130613Smlaier			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n"));
4092126261Smlaier			break;
4093126261Smlaier		}
4094130613Smlaier		pf_commit_altq(t[0]);
4095223637Sbz	#endif
4096126261Smlaier
4097130613Smlaier		pf_clear_states();
4098130613Smlaier
4099130613Smlaier		pf_clear_srcnodes();
4100130613Smlaier
4101130613Smlaier		/* status does not use malloced mem so no need to cleanup */
4102130613Smlaier		/* fingerprints and interfaces have thier own cleanup code */
4103126261Smlaier	} while(0);
4104126261Smlaier
4105223637Sbz	return (error);
4106126261Smlaier}
4107126261Smlaier
4108221132Sbz#ifdef INET
4109126261Smlaierstatic int
4110135920Smlaierpf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
4111135920Smlaier    struct inpcb *inp)
4112126261Smlaier{
4113126261Smlaier	/*
4114126261Smlaier	 * XXX Wed Jul 9 22:03:16 2003 UTC
4115126261Smlaier	 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
4116126261Smlaier	 * in network stack. OpenBSD's network stack have converted
4117126261Smlaier	 * ip_len/ip_off to host byte order frist as FreeBSD.
4118126261Smlaier	 * Now this is not true anymore , so we should convert back to network
4119126261Smlaier	 * byte order.
4120126261Smlaier	 */
4121126261Smlaier	struct ip *h = NULL;
4122126261Smlaier	int chk;
4123126261Smlaier
4124126261Smlaier	if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) {
4125126261Smlaier		/* if m_pkthdr.len is less than ip header, pf will handle. */
4126126261Smlaier		h = mtod(*m, struct ip *);
4127223637Sbz		HTONS(h->ip_len);
4128223637Sbz		HTONS(h->ip_off);
4129126261Smlaier	}
4130223637Sbz	CURVNET_SET(ifp->if_vnet);
4131145836Smlaier	chk = pf_test(PF_IN, ifp, m, NULL, inp);
4132223637Sbz	CURVNET_RESTORE();
4133126261Smlaier	if (chk && *m) {
4134126261Smlaier		m_freem(*m);
4135126261Smlaier		*m = NULL;
4136126261Smlaier	}
4137126261Smlaier	if (*m != NULL) {
4138126261Smlaier		/* pf_test can change ip header location */
4139126261Smlaier		h = mtod(*m, struct ip *);
4140126261Smlaier		NTOHS(h->ip_len);
4141126261Smlaier		NTOHS(h->ip_off);
4142126261Smlaier	}
4143126261Smlaier	return chk;
4144126261Smlaier}
4145126261Smlaier
4146126261Smlaierstatic int
4147135920Smlaierpf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
4148135920Smlaier    struct inpcb *inp)
4149126261Smlaier{
4150126261Smlaier	/*
4151126261Smlaier	 * XXX Wed Jul 9 22:03:16 2003 UTC
4152126261Smlaier	 * OpenBSD has changed its byte ordering convention on ip_len/ip_off
4153126261Smlaier	 * in network stack. OpenBSD's network stack have converted
4154126261Smlaier	 * ip_len/ip_off to host byte order frist as FreeBSD.
4155126261Smlaier	 * Now this is not true anymore , so we should convert back to network
4156126261Smlaier	 * byte order.
4157126261Smlaier	 */
4158126261Smlaier	struct ip *h = NULL;
4159126261Smlaier	int chk;
4160126261Smlaier
4161126261Smlaier	if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) {
4162126261Smlaier		/* if m_pkthdr.len is less than ip header, pf will handle. */
4163126261Smlaier		h = mtod(*m, struct ip *);
4164223637Sbz		HTONS(h->ip_len);
4165223637Sbz		HTONS(h->ip_off);
4166126261Smlaier	}
4167223637Sbz	CURVNET_SET(ifp->if_vnet);
4168145836Smlaier	chk = pf_test(PF_OUT, ifp, m, NULL, inp);
4169223637Sbz	CURVNET_RESTORE();
4170126261Smlaier	if (chk && *m) {
4171126261Smlaier		m_freem(*m);
4172126261Smlaier		*m = NULL;
4173126261Smlaier	}
4174126261Smlaier	if (*m != NULL) {
4175126261Smlaier		/* pf_test can change ip header location */
4176126261Smlaier		h = mtod(*m, struct ip *);
4177126261Smlaier		NTOHS(h->ip_len);
4178126261Smlaier		NTOHS(h->ip_off);
4179126261Smlaier	}
4180126261Smlaier	return chk;
4181126261Smlaier}
4182221132Sbz#endif
4183126261Smlaier
4184126261Smlaier#ifdef INET6
4185126261Smlaierstatic int
4186135920Smlaierpf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
4187135920Smlaier    struct inpcb *inp)
4188126261Smlaier{
4189183550Szec
4190126261Smlaier	/*
4191162069Smlaier	 * IPv6 is not affected by ip_len/ip_off byte order changes.
4192126261Smlaier	 */
4193126261Smlaier	int chk;
4194126261Smlaier
4195162069Smlaier	/*
4196162069Smlaier	 * In case of loopback traffic IPv6 uses the real interface in
4197162069Smlaier	 * order to support scoped addresses. In order to support stateful
4198162069Smlaier	 * filtering we have change this to lo0 as it is the case in IPv4.
4199162069Smlaier	 */
4200223637Sbz	CURVNET_SET(ifp->if_vnet);
4201193274Szec	chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? V_loif : ifp, m,
4202162069Smlaier	    NULL, inp);
4203223637Sbz	CURVNET_RESTORE();
4204126261Smlaier	if (chk && *m) {
4205126261Smlaier		m_freem(*m);
4206126261Smlaier		*m = NULL;
4207126261Smlaier	}
4208126261Smlaier	return chk;
4209126261Smlaier}
4210126261Smlaier
4211126261Smlaierstatic int
4212135920Smlaierpf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
4213135920Smlaier    struct inpcb *inp)
4214126261Smlaier{
4215126261Smlaier	/*
4216126261Smlaier	 * IPv6 does not affected ip_len/ip_off byte order changes.
4217126261Smlaier	 */
4218126261Smlaier	int chk;
4219126261Smlaier
4220223637Sbz	CURVNET_SET(ifp->if_vnet);
4221145836Smlaier	chk = pf_test6(PF_OUT, ifp, m, NULL, inp);
4222223637Sbz	CURVNET_RESTORE();
4223126261Smlaier	if (chk && *m) {
4224126261Smlaier		m_freem(*m);
4225126261Smlaier		*m = NULL;
4226126261Smlaier	}
4227126261Smlaier	return chk;
4228126261Smlaier}
4229126261Smlaier#endif /* INET6 */
4230126261Smlaier
4231126261Smlaierstatic int
4232126261Smlaierhook_pf(void)
4233126261Smlaier{
4234223637Sbz#ifdef INET
4235126261Smlaier	struct pfil_head *pfh_inet;
4236223637Sbz#endif
4237127145Smlaier#ifdef INET6
4238126261Smlaier	struct pfil_head *pfh_inet6;
4239126261Smlaier#endif
4240223637Sbz
4241226801Sglebius	PF_UNLOCK_ASSERT();
4242126261Smlaier
4243223637Sbz	if (V_pf_pfil_hooked)
4244126261Smlaier		return (0);
4245223637Sbz
4246223637Sbz#ifdef INET
4247126261Smlaier	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
4248126261Smlaier	if (pfh_inet == NULL)
4249126261Smlaier		return (ESRCH); /* XXX */
4250126261Smlaier	pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
4251126261Smlaier	pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
4252221132Sbz#endif
4253127145Smlaier#ifdef INET6
4254126261Smlaier	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
4255126261Smlaier	if (pfh_inet6 == NULL) {
4256221132Sbz#ifdef INET
4257126261Smlaier		pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
4258126261Smlaier		    pfh_inet);
4259126261Smlaier		pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
4260126261Smlaier		    pfh_inet);
4261221132Sbz#endif
4262126261Smlaier		return (ESRCH); /* XXX */
4263126261Smlaier	}
4264126261Smlaier	pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
4265126261Smlaier	pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
4266126261Smlaier#endif
4267126261Smlaier
4268223637Sbz	V_pf_pfil_hooked = 1;
4269126261Smlaier	return (0);
4270126261Smlaier}
4271126261Smlaier
4272126261Smlaierstatic int
4273126261Smlaierdehook_pf(void)
4274126261Smlaier{
4275223637Sbz#ifdef INET
4276126261Smlaier	struct pfil_head *pfh_inet;
4277223637Sbz#endif
4278127145Smlaier#ifdef INET6
4279126261Smlaier	struct pfil_head *pfh_inet6;
4280126261Smlaier#endif
4281126261Smlaier
4282226801Sglebius	PF_UNLOCK_ASSERT();
4283126261Smlaier
4284223637Sbz	if (V_pf_pfil_hooked == 0)
4285126261Smlaier		return (0);
4286126261Smlaier
4287223637Sbz#ifdef INET
4288126261Smlaier	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
4289126261Smlaier	if (pfh_inet == NULL)
4290126261Smlaier		return (ESRCH); /* XXX */
4291126261Smlaier	pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
4292126261Smlaier	    pfh_inet);
4293126261Smlaier	pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
4294126261Smlaier	    pfh_inet);
4295221132Sbz#endif
4296127145Smlaier#ifdef INET6
4297126261Smlaier	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
4298126261Smlaier	if (pfh_inet6 == NULL)
4299126261Smlaier		return (ESRCH); /* XXX */
4300126261Smlaier	pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
4301126261Smlaier	    pfh_inet6);
4302126261Smlaier	pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
4303126261Smlaier	    pfh_inet6);
4304126261Smlaier#endif
4305126261Smlaier
4306223637Sbz	V_pf_pfil_hooked = 0;
4307126261Smlaier	return (0);
4308126261Smlaier}
4309126261Smlaier
4310126261Smlaierstatic int
4311230868Sglebiuspf_load(void)
4312223637Sbz{
4313230868Sglebius	VNET_ITERATOR_DECL(vnet_iter);
4314223637Sbz
4315230868Sglebius	VNET_LIST_RLOCK();
4316230868Sglebius	VNET_FOREACH(vnet_iter) {
4317230868Sglebius		CURVNET_SET(vnet_iter);
4318230868Sglebius		V_pf_pfil_hooked = 0;
4319230868Sglebius		V_pf_end_threads = 0;
4320230868Sglebius		V_debug_pfugidhack = 0;
4321230868Sglebius		TAILQ_INIT(&V_pf_tags);
4322230868Sglebius		TAILQ_INIT(&V_pf_qids);
4323230868Sglebius		CURVNET_RESTORE();
4324230868Sglebius	}
4325230868Sglebius	VNET_LIST_RUNLOCK();
4326223637Sbz
4327230868Sglebius	init_pf_mutex();
4328230868Sglebius	pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME);
4329126261Smlaier	init_zone_var();
4330223637Sbz	sx_init(&V_pf_consistency_lock, "pf_statetbl_lock");
4331226801Sglebius	if (pfattach() < 0)
4332126261Smlaier		return (ENOMEM);
4333223637Sbz
4334126261Smlaier	return (0);
4335126261Smlaier}
4336126261Smlaier
4337126261Smlaierstatic int
4338126261Smlaierpf_unload(void)
4339126261Smlaier{
4340126261Smlaier	int error = 0;
4341126261Smlaier
4342126261Smlaier	PF_LOCK();
4343223637Sbz	V_pf_status.running = 0;
4344126261Smlaier	PF_UNLOCK();
4345230868Sglebius	m_addr_chg_pf_p = NULL;
4346126261Smlaier	error = dehook_pf();
4347126261Smlaier	if (error) {
4348126261Smlaier		/*
4349126261Smlaier		 * Should not happen!
4350126261Smlaier		 * XXX Due to error code ESRCH, kldunload will show
4351126261Smlaier		 * a message like 'No such process'.
4352126261Smlaier		 */
4353126261Smlaier		printf("%s : pfil unregisteration fail\n", __FUNCTION__);
4354126261Smlaier		return error;
4355126261Smlaier	}
4356130613Smlaier	PF_LOCK();
4357126261Smlaier	shutdown_pf();
4358223637Sbz	V_pf_end_threads = 1;
4359223637Sbz	while (V_pf_end_threads < 2) {
4360171168Smlaier		wakeup_one(pf_purge_thread);
4361226801Sglebius		msleep(pf_purge_thread, &pf_task_mtx, 0, "pftmo", hz);
4362171168Smlaier	}
4363173822Smlaier	pfi_cleanup();
4364130613Smlaier	pf_osfp_flush();
4365130613Smlaier	pf_osfp_cleanup();
4366126261Smlaier	cleanup_pf_zone();
4367130613Smlaier	PF_UNLOCK();
4368230868Sglebius	destroy_dev(pf_dev);
4369230868Sglebius	destroy_pf_mutex();
4370223637Sbz	sx_destroy(&V_pf_consistency_lock);
4371126261Smlaier	return error;
4372126261Smlaier}
4373126261Smlaier
4374126261Smlaierstatic int
4375126261Smlaierpf_modevent(module_t mod, int type, void *data)
4376126261Smlaier{
4377126261Smlaier	int error = 0;
4378126261Smlaier
4379126261Smlaier	switch(type) {
4380126261Smlaier	case MOD_LOAD:
4381230868Sglebius		error = pf_load();
4382126261Smlaier		break;
4383230868Sglebius	case MOD_QUIESCE:
4384230868Sglebius		/*
4385230868Sglebius		 * Module should not be unloaded due to race conditions.
4386230868Sglebius		 */
4387230868Sglebius		error = EPERM;
4388230868Sglebius		break;
4389126261Smlaier	case MOD_UNLOAD:
4390230868Sglebius		error = pf_unload();
4391126261Smlaier		break;
4392126261Smlaier	default:
4393126261Smlaier		error = EINVAL;
4394126261Smlaier		break;
4395126261Smlaier	}
4396126261Smlaier	return error;
4397126261Smlaier}
4398223637Sbz
4399126261Smlaierstatic moduledata_t pf_mod = {
4400126261Smlaier	"pf",
4401126261Smlaier	pf_modevent,
4402126261Smlaier	0
4403126261Smlaier};
4404126261Smlaier
4405226801SglebiusDECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_FIRST);
4406126261SmlaierMODULE_VERSION(pf, PF_MODVER);
4407223637Sbz#endif /* __FreeBSD__ */
4408