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