xref: /dragonfly/sys/net/pf/pf_ioctl.c (revision b272101a)
1ed1f0be2SJan Lentfer /*	$OpenBSD: pf_ioctl.c,v 1.209 2008/06/29 08:42:15 mcbride Exp $ */
2ed1f0be2SJan Lentfer /*add $OpenBSD: pf_ioctl.c,v 1.212 2009/02/15 20:42:33 mbalmer Exp $ */
302742ec6SJoerg Sonnenberger 
402742ec6SJoerg Sonnenberger /*
570224baaSJan Lentfer  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
602742ec6SJoerg Sonnenberger  *
702742ec6SJoerg Sonnenberger  * Copyright (c) 2001 Daniel Hartmeier
802742ec6SJoerg Sonnenberger  * Copyright (c) 2002,2003 Henning Brauer
902742ec6SJoerg Sonnenberger  * All rights reserved.
1002742ec6SJoerg Sonnenberger  *
1102742ec6SJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
1202742ec6SJoerg Sonnenberger  * modification, are permitted provided that the following conditions
1302742ec6SJoerg Sonnenberger  * are met:
1402742ec6SJoerg Sonnenberger  *
1502742ec6SJoerg Sonnenberger  *    - Redistributions of source code must retain the above copyright
1602742ec6SJoerg Sonnenberger  *      notice, this list of conditions and the following disclaimer.
1702742ec6SJoerg Sonnenberger  *    - Redistributions in binary form must reproduce the above
1802742ec6SJoerg Sonnenberger  *      copyright notice, this list of conditions and the following
1902742ec6SJoerg Sonnenberger  *      disclaimer in the documentation and/or other materials provided
2002742ec6SJoerg Sonnenberger  *      with the distribution.
2102742ec6SJoerg Sonnenberger  *
2202742ec6SJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2302742ec6SJoerg Sonnenberger  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2402742ec6SJoerg Sonnenberger  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2502742ec6SJoerg Sonnenberger  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2602742ec6SJoerg Sonnenberger  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2702742ec6SJoerg Sonnenberger  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2802742ec6SJoerg Sonnenberger  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2902742ec6SJoerg Sonnenberger  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
3002742ec6SJoerg Sonnenberger  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3102742ec6SJoerg Sonnenberger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3202742ec6SJoerg Sonnenberger  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3302742ec6SJoerg Sonnenberger  * POSSIBILITY OF SUCH DAMAGE.
3402742ec6SJoerg Sonnenberger  *
3502742ec6SJoerg Sonnenberger  * Effort sponsored in part by the Defense Advanced Research Projects
3602742ec6SJoerg Sonnenberger  * Agency (DARPA) and Air Force Research Laboratory, Air Force
3702742ec6SJoerg Sonnenberger  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
3802742ec6SJoerg Sonnenberger  *
3902742ec6SJoerg Sonnenberger  */
4002742ec6SJoerg Sonnenberger 
4102742ec6SJoerg Sonnenberger #include "opt_inet.h"
4202742ec6SJoerg Sonnenberger #include "opt_inet6.h"
4302742ec6SJoerg Sonnenberger 
4402742ec6SJoerg Sonnenberger #include <sys/param.h>
4502742ec6SJoerg Sonnenberger #include <sys/systm.h>
46fef8985eSMatthew Dillon #include <sys/conf.h>
47fef8985eSMatthew Dillon #include <sys/device.h>
4802742ec6SJoerg Sonnenberger #include <sys/mbuf.h>
4902742ec6SJoerg Sonnenberger #include <sys/filio.h>
5002742ec6SJoerg Sonnenberger #include <sys/fcntl.h>
5102742ec6SJoerg Sonnenberger #include <sys/socket.h>
5202742ec6SJoerg Sonnenberger #include <sys/socketvar.h>
5302742ec6SJoerg Sonnenberger #include <sys/kernel.h>
5470224baaSJan Lentfer #include <sys/kthread.h>
5502742ec6SJoerg Sonnenberger #include <sys/time.h>
5670224baaSJan Lentfer #include <sys/proc.h>
5702742ec6SJoerg Sonnenberger #include <sys/malloc.h>
5802742ec6SJoerg Sonnenberger #include <sys/module.h>
5970224baaSJan Lentfer #include <sys/lock.h>
6002742ec6SJoerg Sonnenberger 
61cd8ab232SMatthew Dillon #include <sys/thread2.h>
62cd8ab232SMatthew Dillon 
6302742ec6SJoerg Sonnenberger #include <net/if.h>
6402742ec6SJoerg Sonnenberger #include <net/if_types.h>
6502742ec6SJoerg Sonnenberger #include <net/route.h>
6602742ec6SJoerg Sonnenberger 
6702742ec6SJoerg Sonnenberger #include <netinet/in.h>
6802742ec6SJoerg Sonnenberger #include <netinet/in_var.h>
6902742ec6SJoerg Sonnenberger #include <netinet/in_systm.h>
7002742ec6SJoerg Sonnenberger #include <netinet/ip.h>
7102742ec6SJoerg Sonnenberger #include <netinet/ip_var.h>
7202742ec6SJoerg Sonnenberger #include <netinet/ip_icmp.h>
7302742ec6SJoerg Sonnenberger 
7402742ec6SJoerg Sonnenberger #include <net/pf/pfvar.h>
7570224baaSJan Lentfer #include <sys/md5.h>
7602742ec6SJoerg Sonnenberger 
77cc16352aSSascha Wildner #include <net/pf/if_pflog.h>
7802742ec6SJoerg Sonnenberger #include <net/pf/if_pfsync.h>
7902742ec6SJoerg Sonnenberger 
8002742ec6SJoerg Sonnenberger #ifdef INET6
8102742ec6SJoerg Sonnenberger #include <netinet/ip6.h>
8202742ec6SJoerg Sonnenberger #include <netinet/in_pcb.h>
8302742ec6SJoerg Sonnenberger #endif /* INET6 */
8402742ec6SJoerg Sonnenberger 
8502742ec6SJoerg Sonnenberger #ifdef ALTQ
864d723e5aSJoerg Sonnenberger #include <net/altq/altq.h>
8702742ec6SJoerg Sonnenberger #endif
8802742ec6SJoerg Sonnenberger 
8902742ec6SJoerg Sonnenberger #include <machine/limits.h>
9002742ec6SJoerg Sonnenberger #include <net/pfil.h>
9170224baaSJan Lentfer 
9270224baaSJan Lentfer u_int rt_numfibs = RT_NUMFIBS;
93fef8985eSMatthew Dillon 
941186cbc0SJan Lentfer void			 pfattach(void);
9570224baaSJan Lentfer struct pf_pool		*pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
9670224baaSJan Lentfer 			    u_int8_t, u_int8_t, u_int8_t);
9770224baaSJan Lentfer 
9802742ec6SJoerg Sonnenberger void			 pf_mv_pool(struct pf_palist *, struct pf_palist *);
9902742ec6SJoerg Sonnenberger void			 pf_empty_pool(struct pf_palist *);
10002742ec6SJoerg Sonnenberger #ifdef ALTQ
10102742ec6SJoerg Sonnenberger int			 pf_begin_altq(u_int32_t *);
10202742ec6SJoerg Sonnenberger int			 pf_rollback_altq(u_int32_t);
10302742ec6SJoerg Sonnenberger int			 pf_commit_altq(u_int32_t);
10470224baaSJan Lentfer int			 pf_enable_altq(struct pf_altq *);
10570224baaSJan Lentfer int			 pf_disable_altq(struct pf_altq *);
10602742ec6SJoerg Sonnenberger #endif /* ALTQ */
10770224baaSJan Lentfer int			 pf_begin_rules(u_int32_t *, int, const char *);
10870224baaSJan Lentfer int			 pf_rollback_rules(u_int32_t, int, char *);
10970224baaSJan Lentfer int			 pf_setup_pfsync_matching(struct pf_ruleset *);
11070224baaSJan Lentfer void			 pf_hash_rule(MD5_CTX *, struct pf_rule *);
11170224baaSJan Lentfer void			 pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *);
11270224baaSJan Lentfer int			 pf_commit_rules(u_int32_t, int, char *);
113ed1f0be2SJan Lentfer int			 pf_addr_setup(struct pf_ruleset *,
114ed1f0be2SJan Lentfer 			    struct pf_addr_wrap *, sa_family_t);
115ed1f0be2SJan Lentfer void			 pf_addr_copyout(struct pf_addr_wrap *);
11602742ec6SJoerg Sonnenberger 
11702742ec6SJoerg Sonnenberger struct pf_rule		 pf_default_rule;
11870224baaSJan Lentfer struct lock		 pf_consistency_lock;
11932772c96SMatthew Dillon struct lock		 pf_global_statetbl_lock;
12070224baaSJan Lentfer #ifdef ALTQ
12170224baaSJan Lentfer static int		 pf_altq_running;
12270224baaSJan Lentfer #endif
12302742ec6SJoerg Sonnenberger 
12402742ec6SJoerg Sonnenberger #define	TAGID_MAX	 50000
12502742ec6SJoerg Sonnenberger TAILQ_HEAD(pf_tags, pf_tagname)	pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
12602742ec6SJoerg Sonnenberger 				pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids);
12702742ec6SJoerg Sonnenberger 
12802742ec6SJoerg Sonnenberger #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
12902742ec6SJoerg Sonnenberger #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
13002742ec6SJoerg Sonnenberger #endif
13170224baaSJan Lentfer u_int16_t		 tagname2tag(struct pf_tags *, char *);
13270224baaSJan Lentfer void			 tag2tagname(struct pf_tags *, u_int16_t, char *);
13370224baaSJan Lentfer void			 tag_unref(struct pf_tags *, u_int16_t);
13470224baaSJan Lentfer int			 pf_rtlabel_add(struct pf_addr_wrap *);
13570224baaSJan Lentfer void			 pf_rtlabel_remove(struct pf_addr_wrap *);
13670224baaSJan Lentfer void			 pf_rtlabel_copyout(struct pf_addr_wrap *);
13702742ec6SJoerg Sonnenberger 
1384b1cf444SSascha Wildner #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) kprintf x
13902742ec6SJoerg Sonnenberger 
140b13267a5SMatthew Dillon static cdev_t	pf_dev;
14102742ec6SJoerg Sonnenberger 
1421186cbc0SJan Lentfer static MALLOC_DEFINE(M_PFRULEPL, "pfrulepl", "pf rule pool list");
1431186cbc0SJan Lentfer static MALLOC_DEFINE(M_PFALTQPL, "pfaltqpl", "pf altq pool list");
1441186cbc0SJan Lentfer static MALLOC_DEFINE(M_PFPOOLADDRPL, "pfpooladdrpl", "pf pool address pool list");
1451186cbc0SJan Lentfer static MALLOC_DEFINE(M_PFFRENTPL, "pffrent", "pf frent pool list");
1461186cbc0SJan Lentfer 
147f7c73ea6SMatthew Dillon MALLOC_DEFINE(M_PF, 	  "pf", "pf general");
148f7c73ea6SMatthew Dillon 
1491186cbc0SJan Lentfer 
15002742ec6SJoerg Sonnenberger /*
15102742ec6SJoerg Sonnenberger  * XXX - These are new and need to be checked when moveing to a new version
15202742ec6SJoerg Sonnenberger  */
15302742ec6SJoerg Sonnenberger static void		 pf_clear_states(void);
15402742ec6SJoerg Sonnenberger static int		 pf_clear_tables(void);
15502742ec6SJoerg Sonnenberger static void		 pf_clear_srcnodes(void);
15602742ec6SJoerg Sonnenberger /*
15702742ec6SJoerg Sonnenberger  * XXX - These are new and need to be checked when moveing to a new version
15802742ec6SJoerg Sonnenberger  */
15902742ec6SJoerg Sonnenberger 
16002742ec6SJoerg Sonnenberger /*
16102742ec6SJoerg Sonnenberger  * Wrapper functions for pfil(9) hooks
16202742ec6SJoerg Sonnenberger  */
16302742ec6SJoerg Sonnenberger static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
16402742ec6SJoerg Sonnenberger 		int dir);
16502742ec6SJoerg Sonnenberger static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
16602742ec6SJoerg Sonnenberger 		int dir);
16702742ec6SJoerg Sonnenberger #ifdef INET6
16802742ec6SJoerg Sonnenberger static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
16902742ec6SJoerg Sonnenberger 		int dir);
17002742ec6SJoerg Sonnenberger static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
17102742ec6SJoerg Sonnenberger 		int dir);
17202742ec6SJoerg Sonnenberger #endif
17302742ec6SJoerg Sonnenberger 
17402742ec6SJoerg Sonnenberger static int 		 hook_pf(void);
17502742ec6SJoerg Sonnenberger static int 		 dehook_pf(void);
17602742ec6SJoerg Sonnenberger static int 		 shutdown_pf(void);
17702742ec6SJoerg Sonnenberger static int 		 pf_load(void);
17802742ec6SJoerg Sonnenberger static int 		 pf_unload(void);
17902742ec6SJoerg Sonnenberger 
180fef8985eSMatthew Dillon d_open_t	pfopen;
181fef8985eSMatthew Dillon d_close_t	pfclose;
182fef8985eSMatthew Dillon d_ioctl_t	pfioctl;
183fef8985eSMatthew Dillon 
184fef8985eSMatthew Dillon static struct dev_ops pf_ops = {	    /* XXX convert to port model */
185fef8985eSMatthew Dillon 	{ PF_NAME, 73, 0 },
186fef8985eSMatthew Dillon 	.d_open =	pfopen,
187fef8985eSMatthew Dillon 	.d_close =	pfclose,
188fef8985eSMatthew Dillon 	.d_ioctl =	pfioctl
18902742ec6SJoerg Sonnenberger };
19002742ec6SJoerg Sonnenberger 
19102742ec6SJoerg Sonnenberger static volatile int pf_pfil_hooked = 0;
19270224baaSJan Lentfer int pf_end_threads = 0;
19370224baaSJan Lentfer 
19470224baaSJan Lentfer int debug_pfugidhack = 0;
19570224baaSJan Lentfer SYSCTL_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW, &debug_pfugidhack, 0,
19670224baaSJan Lentfer 	"Enable/disable pf user/group rules mpsafe hack");
19770224baaSJan Lentfer 
19802742ec6SJoerg Sonnenberger void
pfattach(void)19902742ec6SJoerg Sonnenberger pfattach(void)
20002742ec6SJoerg Sonnenberger {
20102742ec6SJoerg Sonnenberger 	u_int32_t *my_timeout = pf_default_rule.timeout;
2023a0038bfSMatthew Dillon 	int nn;
20302742ec6SJoerg Sonnenberger 
204*6823c302SAaron LI 	if (!rn_inithead(&pf_maskhead, NULL, 0)) {
205b4628cf9SSepherosa Ziehau 		kprintf("pf mask radix tree create failed\n");
206d2540711SSascha Wildner 		return;
207b4628cf9SSepherosa Ziehau 	}
2081186cbc0SJan Lentfer 	kmalloc_create(&pf_state_pl, "pf state pool list");
2091186cbc0SJan Lentfer 	kmalloc_raise_limit(pf_state_pl, 0);
2101186cbc0SJan Lentfer 	kmalloc_create(&pf_frent_pl, "pf fragment pool list");
2111186cbc0SJan Lentfer 	kmalloc_raise_limit(pf_frent_pl, 0);
2121186cbc0SJan Lentfer 	kmalloc_create(&pf_cent_pl, "pf cent pool list");
2131186cbc0SJan Lentfer 	kmalloc_raise_limit(pf_cent_pl, 0);
214b4628cf9SSepherosa Ziehau 
215f7c73ea6SMatthew Dillon 	/*
216f7c73ea6SMatthew Dillon 	 * Allocate pcpu array.
217f7c73ea6SMatthew Dillon 	 *
218f7c73ea6SMatthew Dillon 	 * NOTE: The state table also has a global element which we index
219f7c73ea6SMatthew Dillon 	 *	 at [ncpus], so it needs one extra slot.
220f7c73ea6SMatthew Dillon 	 */
221f7c73ea6SMatthew Dillon 	tree_src_tracking = kmalloc(sizeof(*tree_src_tracking) * ncpus,
222f7c73ea6SMatthew Dillon 				M_PF, M_WAITOK | M_ZERO);
223f7c73ea6SMatthew Dillon 	tree_id = kmalloc(sizeof(*tree_id) * ncpus,
224f7c73ea6SMatthew Dillon 				M_PF, M_WAITOK | M_ZERO);
225f7c73ea6SMatthew Dillon 	state_list = kmalloc(sizeof(*state_list) * ncpus,
226f7c73ea6SMatthew Dillon 				M_PF, M_WAITOK | M_ZERO);
227f7c73ea6SMatthew Dillon 	pf_counters = kmalloc(sizeof(*pf_counters) * ncpus,
228f7c73ea6SMatthew Dillon 				M_PF, M_WAITOK | M_ZERO);
229f7c73ea6SMatthew Dillon 	pf_statetbl = kmalloc(sizeof(*pf_statetbl) * (ncpus + 1),
230f7c73ea6SMatthew Dillon 				M_PF, M_WAITOK | M_ZERO);
231f7c73ea6SMatthew Dillon 	purge_cur = kmalloc(sizeof(*purge_cur) * ncpus,
232f7c73ea6SMatthew Dillon 				M_PF, M_WAITOK | M_ZERO);
233f7c73ea6SMatthew Dillon 
23402742ec6SJoerg Sonnenberger 	pfr_initialize();
23502742ec6SJoerg Sonnenberger 	pfi_initialize();
2361186cbc0SJan Lentfer 	pf_osfp_initialize();
23702742ec6SJoerg Sonnenberger 
23802742ec6SJoerg Sonnenberger 	pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl;
23902742ec6SJoerg Sonnenberger 	pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT;
24002742ec6SJoerg Sonnenberger 	pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl;
24102742ec6SJoerg Sonnenberger 	pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT;
24270224baaSJan Lentfer 	if (ctob(physmem) <= 100*1024*1024)
24370224baaSJan Lentfer 		pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
24470224baaSJan Lentfer 		    PFR_KENTRY_HIWAT_SMALL;
245ed1f0be2SJan Lentfer 
2463a0038bfSMatthew Dillon 	for (nn = 0; nn < ncpus; ++nn) {
2473a0038bfSMatthew Dillon 		RB_INIT(&tree_src_tracking[nn]);
2483a0038bfSMatthew Dillon 		RB_INIT(&tree_id[nn]);
2493a0038bfSMatthew Dillon 	}
25070224baaSJan Lentfer 	RB_INIT(&pf_anchors);
25102742ec6SJoerg Sonnenberger 	pf_init_ruleset(&pf_main_ruleset);
25202742ec6SJoerg Sonnenberger 	TAILQ_INIT(&pf_altqs[0]);
25302742ec6SJoerg Sonnenberger 	TAILQ_INIT(&pf_altqs[1]);
25402742ec6SJoerg Sonnenberger 	TAILQ_INIT(&pf_pabuf);
25502742ec6SJoerg Sonnenberger 	pf_altqs_active = &pf_altqs[0];
25602742ec6SJoerg Sonnenberger 	pf_altqs_inactive = &pf_altqs[1];
2573a0038bfSMatthew Dillon 	for (nn = 0; nn < ncpus; ++nn)
2583a0038bfSMatthew Dillon 		TAILQ_INIT(&state_list[nn]);
25902742ec6SJoerg Sonnenberger 
26002742ec6SJoerg Sonnenberger 	/* default rule should never be garbage collected */
26102742ec6SJoerg Sonnenberger 	pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
26202742ec6SJoerg Sonnenberger 	pf_default_rule.action = PF_PASS;
26333040f9eSJoerg Sonnenberger 	pf_default_rule.nr = (uint32_t)(-1);
26470224baaSJan Lentfer 	pf_default_rule.rtableid = -1;
26502742ec6SJoerg Sonnenberger 
26602742ec6SJoerg Sonnenberger 	/* initialize default timeouts */
26702742ec6SJoerg Sonnenberger 	my_timeout[PFTM_TCP_FIRST_PACKET] = 120;	/* First TCP packet */
26802742ec6SJoerg Sonnenberger 	my_timeout[PFTM_TCP_OPENING] = 30; 		/* No response yet */
26902742ec6SJoerg Sonnenberger 	my_timeout[PFTM_TCP_ESTABLISHED] = 24*60*60;	/* Established */
27002742ec6SJoerg Sonnenberger 	my_timeout[PFTM_TCP_CLOSING] = 15 * 60;		/* Half closed */
27102742ec6SJoerg Sonnenberger 	my_timeout[PFTM_TCP_FIN_WAIT] = 45;		/* Got both FINs */
27202742ec6SJoerg Sonnenberger 	my_timeout[PFTM_TCP_CLOSED] = 90;		/* Got a RST */
27302742ec6SJoerg Sonnenberger 	my_timeout[PFTM_UDP_FIRST_PACKET] = 60;		/* First UDP packet */
27402742ec6SJoerg Sonnenberger 	my_timeout[PFTM_UDP_SINGLE] = 30;		/* Unidirectional */
27502742ec6SJoerg Sonnenberger 	my_timeout[PFTM_UDP_MULTIPLE] = 60;		/* Bidirectional */
27602742ec6SJoerg Sonnenberger 	my_timeout[PFTM_ICMP_FIRST_PACKET] = 20;	/* First ICMP packet */
27702742ec6SJoerg Sonnenberger 	my_timeout[PFTM_ICMP_ERROR_REPLY] = 10;		/* Got error response */
27802742ec6SJoerg Sonnenberger 	my_timeout[PFTM_OTHER_FIRST_PACKET] = 60;	/* First packet */
27902742ec6SJoerg Sonnenberger 	my_timeout[PFTM_OTHER_SINGLE] = 30;		/* Unidirectional */
28002742ec6SJoerg Sonnenberger 	my_timeout[PFTM_OTHER_MULTIPLE] = 60;		/* Bidirectional */
28102742ec6SJoerg Sonnenberger 	my_timeout[PFTM_FRAG] = 30;			/* Fragment expire */
28202742ec6SJoerg Sonnenberger 	my_timeout[PFTM_INTERVAL] = 10;			/* Expire interval */
28370224baaSJan Lentfer 	my_timeout[PFTM_SRC_NODE] = 0;			/* Source Tracking */
28470224baaSJan Lentfer 	my_timeout[PFTM_TS_DIFF] = 30;			/* Allowed TS diff */
28570224baaSJan Lentfer 	my_timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
28670224baaSJan Lentfer 	my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
28702742ec6SJoerg Sonnenberger 
28802742ec6SJoerg Sonnenberger 	pf_normalize_init();
28902742ec6SJoerg Sonnenberger 	bzero(&pf_status, sizeof(pf_status));
29002742ec6SJoerg Sonnenberger 	pf_status.debug = PF_DEBUG_URGENT;
29102742ec6SJoerg Sonnenberger 	/* XXX do our best to avoid a conflict */
2920ced1954SMatthew Dillon 	pf_status.hostid = karc4random();
29302742ec6SJoerg Sonnenberger 
29470224baaSJan Lentfer 	if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge"))
29570224baaSJan Lentfer 		panic("pfpurge thread");
29670224baaSJan Lentfer }
29770224baaSJan Lentfer 
29802742ec6SJoerg Sonnenberger int
pfopen(struct dev_open_args * ap)299fef8985eSMatthew Dillon pfopen(struct dev_open_args *ap)
30002742ec6SJoerg Sonnenberger {
3012a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
302b13267a5SMatthew Dillon 	cdev_t dev = ap->a_head.a_dev;
3032a7a2b1cSJan Lentfer 	if (minor(dev) >= 1) {
3042a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
30502742ec6SJoerg Sonnenberger 		return (ENXIO);
3062a7a2b1cSJan Lentfer 	}
3072a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
30802742ec6SJoerg Sonnenberger 	return (0);
30902742ec6SJoerg Sonnenberger }
31002742ec6SJoerg Sonnenberger 
31102742ec6SJoerg Sonnenberger int
pfclose(struct dev_close_args * ap)312fef8985eSMatthew Dillon pfclose(struct dev_close_args *ap)
31302742ec6SJoerg Sonnenberger {
3142a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
315b13267a5SMatthew Dillon 	cdev_t dev = ap->a_head.a_dev;
3162a7a2b1cSJan Lentfer 	if (minor(dev) >= 1) {
3172a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
31802742ec6SJoerg Sonnenberger 		return (ENXIO);
3192a7a2b1cSJan Lentfer 	}
3202a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
32102742ec6SJoerg Sonnenberger 	return (0);
32202742ec6SJoerg Sonnenberger }
32302742ec6SJoerg Sonnenberger 
32402742ec6SJoerg Sonnenberger struct pf_pool *
pf_get_pool(char * anchor,u_int32_t ticket,u_int8_t rule_action,u_int32_t rule_number,u_int8_t r_last,u_int8_t active,u_int8_t check_ticket)32570224baaSJan Lentfer pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
32670224baaSJan Lentfer     u_int32_t rule_number, u_int8_t r_last, u_int8_t active,
32770224baaSJan Lentfer     u_int8_t check_ticket)
32802742ec6SJoerg Sonnenberger {
32902742ec6SJoerg Sonnenberger 	struct pf_ruleset	*ruleset;
33002742ec6SJoerg Sonnenberger 	struct pf_rule		*rule;
33102742ec6SJoerg Sonnenberger 	int			 rs_num;
33202742ec6SJoerg Sonnenberger 
33370224baaSJan Lentfer 	ruleset = pf_find_ruleset(anchor);
33402742ec6SJoerg Sonnenberger 	if (ruleset == NULL)
33502742ec6SJoerg Sonnenberger 		return (NULL);
33602742ec6SJoerg Sonnenberger 	rs_num = pf_get_ruleset_number(rule_action);
33702742ec6SJoerg Sonnenberger 	if (rs_num >= PF_RULESET_MAX)
33802742ec6SJoerg Sonnenberger 		return (NULL);
33902742ec6SJoerg Sonnenberger 	if (active) {
34002742ec6SJoerg Sonnenberger 		if (check_ticket && ticket !=
34102742ec6SJoerg Sonnenberger 		    ruleset->rules[rs_num].active.ticket)
34202742ec6SJoerg Sonnenberger 			return (NULL);
34302742ec6SJoerg Sonnenberger 		if (r_last)
34402742ec6SJoerg Sonnenberger 			rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
34502742ec6SJoerg Sonnenberger 			    pf_rulequeue);
34602742ec6SJoerg Sonnenberger 		else
34702742ec6SJoerg Sonnenberger 			rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
34802742ec6SJoerg Sonnenberger 	} else {
34902742ec6SJoerg Sonnenberger 		if (check_ticket && ticket !=
35002742ec6SJoerg Sonnenberger 		    ruleset->rules[rs_num].inactive.ticket)
35102742ec6SJoerg Sonnenberger 			return (NULL);
35202742ec6SJoerg Sonnenberger 		if (r_last)
35302742ec6SJoerg Sonnenberger 			rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
35402742ec6SJoerg Sonnenberger 			    pf_rulequeue);
35502742ec6SJoerg Sonnenberger 		else
35602742ec6SJoerg Sonnenberger 			rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
35702742ec6SJoerg Sonnenberger 	}
35802742ec6SJoerg Sonnenberger 	if (!r_last) {
35902742ec6SJoerg Sonnenberger 		while ((rule != NULL) && (rule->nr != rule_number))
36002742ec6SJoerg Sonnenberger 			rule = TAILQ_NEXT(rule, entries);
36102742ec6SJoerg Sonnenberger 	}
36202742ec6SJoerg Sonnenberger 	if (rule == NULL)
36302742ec6SJoerg Sonnenberger 		return (NULL);
36402742ec6SJoerg Sonnenberger 
36502742ec6SJoerg Sonnenberger 	return (&rule->rpool);
36602742ec6SJoerg Sonnenberger }
36702742ec6SJoerg Sonnenberger 
36802742ec6SJoerg Sonnenberger void
pf_mv_pool(struct pf_palist * poola,struct pf_palist * poolb)36902742ec6SJoerg Sonnenberger pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
37002742ec6SJoerg Sonnenberger {
37102742ec6SJoerg Sonnenberger 	struct pf_pooladdr	*mv_pool_pa;
37202742ec6SJoerg Sonnenberger 
37302742ec6SJoerg Sonnenberger 	while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
37402742ec6SJoerg Sonnenberger 		TAILQ_REMOVE(poola, mv_pool_pa, entries);
37502742ec6SJoerg Sonnenberger 		TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
37602742ec6SJoerg Sonnenberger 	}
37702742ec6SJoerg Sonnenberger }
37802742ec6SJoerg Sonnenberger 
37902742ec6SJoerg Sonnenberger void
pf_empty_pool(struct pf_palist * poola)38002742ec6SJoerg Sonnenberger pf_empty_pool(struct pf_palist *poola)
38102742ec6SJoerg Sonnenberger {
38202742ec6SJoerg Sonnenberger 	struct pf_pooladdr	*empty_pool_pa;
38302742ec6SJoerg Sonnenberger 
38402742ec6SJoerg Sonnenberger 	while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
38502742ec6SJoerg Sonnenberger 		pfi_dynaddr_remove(&empty_pool_pa->addr);
38602742ec6SJoerg Sonnenberger 		pf_tbladdr_remove(&empty_pool_pa->addr);
38770224baaSJan Lentfer 		pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
38802742ec6SJoerg Sonnenberger 		TAILQ_REMOVE(poola, empty_pool_pa, entries);
3891186cbc0SJan Lentfer 		kfree(empty_pool_pa, M_PFPOOLADDRPL);
39002742ec6SJoerg Sonnenberger 	}
39102742ec6SJoerg Sonnenberger }
39202742ec6SJoerg Sonnenberger 
39302742ec6SJoerg Sonnenberger void
pf_rm_rule(struct pf_rulequeue * rulequeue,struct pf_rule * rule)39402742ec6SJoerg Sonnenberger pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
39502742ec6SJoerg Sonnenberger {
39602742ec6SJoerg Sonnenberger 	if (rulequeue != NULL) {
397ed1f0be2SJan Lentfer 		if (rule->states_cur <= 0) {
39802742ec6SJoerg Sonnenberger 			/*
39902742ec6SJoerg Sonnenberger 			 * XXX - we need to remove the table *before* detaching
40002742ec6SJoerg Sonnenberger 			 * the rule to make sure the table code does not delete
40102742ec6SJoerg Sonnenberger 			 * the anchor under our feet.
40202742ec6SJoerg Sonnenberger 			 */
40302742ec6SJoerg Sonnenberger 			pf_tbladdr_remove(&rule->src.addr);
40402742ec6SJoerg Sonnenberger 			pf_tbladdr_remove(&rule->dst.addr);
40570224baaSJan Lentfer 			if (rule->overload_tbl)
40670224baaSJan Lentfer 				pfr_detach_table(rule->overload_tbl);
40702742ec6SJoerg Sonnenberger 		}
40802742ec6SJoerg Sonnenberger 		TAILQ_REMOVE(rulequeue, rule, entries);
40902742ec6SJoerg Sonnenberger 		rule->entries.tqe_prev = NULL;
41070224baaSJan Lentfer 		rule->nr = -1;
41102742ec6SJoerg Sonnenberger 	}
41202742ec6SJoerg Sonnenberger 
413ed1f0be2SJan Lentfer 	if (rule->states_cur > 0 || rule->src_nodes > 0 ||
41402742ec6SJoerg Sonnenberger 	    rule->entries.tqe_prev != NULL)
41502742ec6SJoerg Sonnenberger 		return;
41602742ec6SJoerg Sonnenberger 	pf_tag_unref(rule->tag);
41702742ec6SJoerg Sonnenberger 	pf_tag_unref(rule->match_tag);
41802742ec6SJoerg Sonnenberger #ifdef ALTQ
41902742ec6SJoerg Sonnenberger 	if (rule->pqid != rule->qid)
42002742ec6SJoerg Sonnenberger 		pf_qid_unref(rule->pqid);
42102742ec6SJoerg Sonnenberger 	pf_qid_unref(rule->qid);
42202742ec6SJoerg Sonnenberger #endif
42370224baaSJan Lentfer 	pf_rtlabel_remove(&rule->src.addr);
42470224baaSJan Lentfer 	pf_rtlabel_remove(&rule->dst.addr);
42502742ec6SJoerg Sonnenberger 	pfi_dynaddr_remove(&rule->src.addr);
42602742ec6SJoerg Sonnenberger 	pfi_dynaddr_remove(&rule->dst.addr);
42702742ec6SJoerg Sonnenberger 	if (rulequeue == NULL) {
42802742ec6SJoerg Sonnenberger 		pf_tbladdr_remove(&rule->src.addr);
42902742ec6SJoerg Sonnenberger 		pf_tbladdr_remove(&rule->dst.addr);
43070224baaSJan Lentfer 		if (rule->overload_tbl)
43170224baaSJan Lentfer 			pfr_detach_table(rule->overload_tbl);
43202742ec6SJoerg Sonnenberger 	}
43370224baaSJan Lentfer 	pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
43470224baaSJan Lentfer 	pf_anchor_remove(rule);
43502742ec6SJoerg Sonnenberger 	pf_empty_pool(&rule->rpool.list);
4361186cbc0SJan Lentfer 	kfree(rule, M_PFRULEPL);
43702742ec6SJoerg Sonnenberger }
43802742ec6SJoerg Sonnenberger 
43970224baaSJan Lentfer u_int16_t
tagname2tag(struct pf_tags * head,char * tagname)44002742ec6SJoerg Sonnenberger tagname2tag(struct pf_tags *head, char *tagname)
44102742ec6SJoerg Sonnenberger {
44202742ec6SJoerg Sonnenberger 	struct pf_tagname	*tag, *p = NULL;
44302742ec6SJoerg Sonnenberger 	u_int16_t		 new_tagid = 1;
44402742ec6SJoerg Sonnenberger 
44502742ec6SJoerg Sonnenberger 	TAILQ_FOREACH(tag, head, entries)
44602742ec6SJoerg Sonnenberger 		if (strcmp(tagname, tag->name) == 0) {
44702742ec6SJoerg Sonnenberger 			tag->ref++;
44802742ec6SJoerg Sonnenberger 			return (tag->tag);
44902742ec6SJoerg Sonnenberger 		}
45002742ec6SJoerg Sonnenberger 
45102742ec6SJoerg Sonnenberger 	/*
45202742ec6SJoerg Sonnenberger 	 * to avoid fragmentation, we do a linear search from the beginning
45302742ec6SJoerg Sonnenberger 	 * and take the first free slot we find. if there is none or the list
45402742ec6SJoerg Sonnenberger 	 * is empty, append a new entry at the end.
45502742ec6SJoerg Sonnenberger 	 */
45602742ec6SJoerg Sonnenberger 
45702742ec6SJoerg Sonnenberger 	/* new entry */
45802742ec6SJoerg Sonnenberger 	if (!TAILQ_EMPTY(head))
45902742ec6SJoerg Sonnenberger 		for (p = TAILQ_FIRST(head); p != NULL &&
46002742ec6SJoerg Sonnenberger 		    p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
46102742ec6SJoerg Sonnenberger 			new_tagid = p->tag + 1;
46202742ec6SJoerg Sonnenberger 
46302742ec6SJoerg Sonnenberger 	if (new_tagid > TAGID_MAX)
46402742ec6SJoerg Sonnenberger 		return (0);
46502742ec6SJoerg Sonnenberger 
46602742ec6SJoerg Sonnenberger 	/* allocate and fill new struct pf_tagname */
467ed1f0be2SJan Lentfer 	tag = kmalloc(sizeof(*tag), M_TEMP, M_WAITOK);
46802742ec6SJoerg Sonnenberger 	strlcpy(tag->name, tagname, sizeof(tag->name));
46902742ec6SJoerg Sonnenberger 	tag->tag = new_tagid;
47002742ec6SJoerg Sonnenberger 	tag->ref++;
47102742ec6SJoerg Sonnenberger 
47202742ec6SJoerg Sonnenberger 	if (p != NULL)	/* insert new entry before p */
47302742ec6SJoerg Sonnenberger 		TAILQ_INSERT_BEFORE(p, tag, entries);
47402742ec6SJoerg Sonnenberger 	else	/* either list empty or no free slot in between */
47502742ec6SJoerg Sonnenberger 		TAILQ_INSERT_TAIL(head, tag, entries);
47602742ec6SJoerg Sonnenberger 
47702742ec6SJoerg Sonnenberger 	return (tag->tag);
47802742ec6SJoerg Sonnenberger }
47902742ec6SJoerg Sonnenberger 
48070224baaSJan Lentfer void
tag2tagname(struct pf_tags * head,u_int16_t tagid,char * p)48102742ec6SJoerg Sonnenberger tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
48202742ec6SJoerg Sonnenberger {
48302742ec6SJoerg Sonnenberger 	struct pf_tagname	*tag;
48402742ec6SJoerg Sonnenberger 
48502742ec6SJoerg Sonnenberger 	TAILQ_FOREACH(tag, head, entries)
48602742ec6SJoerg Sonnenberger 		if (tag->tag == tagid) {
48702742ec6SJoerg Sonnenberger 			strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
48802742ec6SJoerg Sonnenberger 			return;
48902742ec6SJoerg Sonnenberger 		}
49002742ec6SJoerg Sonnenberger }
49102742ec6SJoerg Sonnenberger 
49270224baaSJan Lentfer void
tag_unref(struct pf_tags * head,u_int16_t tag)49302742ec6SJoerg Sonnenberger tag_unref(struct pf_tags *head, u_int16_t tag)
49402742ec6SJoerg Sonnenberger {
49502742ec6SJoerg Sonnenberger 	struct pf_tagname	*p, *next;
49602742ec6SJoerg Sonnenberger 
49702742ec6SJoerg Sonnenberger 	if (tag == 0)
49802742ec6SJoerg Sonnenberger 		return;
49902742ec6SJoerg Sonnenberger 
50002742ec6SJoerg Sonnenberger 	for (p = TAILQ_FIRST(head); p != NULL; p = next) {
50102742ec6SJoerg Sonnenberger 		next = TAILQ_NEXT(p, entries);
50202742ec6SJoerg Sonnenberger 		if (tag == p->tag) {
50302742ec6SJoerg Sonnenberger 			if (--p->ref == 0) {
50402742ec6SJoerg Sonnenberger 				TAILQ_REMOVE(head, p, entries);
505efda3bd0SMatthew Dillon 				kfree(p, M_TEMP);
50602742ec6SJoerg Sonnenberger 			}
50702742ec6SJoerg Sonnenberger 			break;
50802742ec6SJoerg Sonnenberger 		}
50902742ec6SJoerg Sonnenberger 	}
51002742ec6SJoerg Sonnenberger }
51102742ec6SJoerg Sonnenberger 
51202742ec6SJoerg Sonnenberger u_int16_t
pf_tagname2tag(char * tagname)51302742ec6SJoerg Sonnenberger pf_tagname2tag(char *tagname)
51402742ec6SJoerg Sonnenberger {
51502742ec6SJoerg Sonnenberger 	return (tagname2tag(&pf_tags, tagname));
51602742ec6SJoerg Sonnenberger }
51702742ec6SJoerg Sonnenberger 
51802742ec6SJoerg Sonnenberger void
pf_tag2tagname(u_int16_t tagid,char * p)51902742ec6SJoerg Sonnenberger pf_tag2tagname(u_int16_t tagid, char *p)
52002742ec6SJoerg Sonnenberger {
52170224baaSJan Lentfer 	tag2tagname(&pf_tags, tagid, p);
52270224baaSJan Lentfer }
52370224baaSJan Lentfer 
52470224baaSJan Lentfer void
pf_tag_ref(u_int16_t tag)52570224baaSJan Lentfer pf_tag_ref(u_int16_t tag)
52670224baaSJan Lentfer {
52770224baaSJan Lentfer 	struct pf_tagname *t;
52870224baaSJan Lentfer 
52970224baaSJan Lentfer 	TAILQ_FOREACH(t, &pf_tags, entries)
53070224baaSJan Lentfer 		if (t->tag == tag)
53170224baaSJan Lentfer 			break;
53270224baaSJan Lentfer 	if (t != NULL)
53370224baaSJan Lentfer 		t->ref++;
53402742ec6SJoerg Sonnenberger }
53502742ec6SJoerg Sonnenberger 
53602742ec6SJoerg Sonnenberger void
pf_tag_unref(u_int16_t tag)53702742ec6SJoerg Sonnenberger pf_tag_unref(u_int16_t tag)
53802742ec6SJoerg Sonnenberger {
53970224baaSJan Lentfer 	tag_unref(&pf_tags, tag);
54070224baaSJan Lentfer }
54170224baaSJan Lentfer 
54270224baaSJan Lentfer int
pf_rtlabel_add(struct pf_addr_wrap * a)54370224baaSJan Lentfer pf_rtlabel_add(struct pf_addr_wrap *a)
54470224baaSJan Lentfer {
54570224baaSJan Lentfer 	return (0);
54670224baaSJan Lentfer }
54770224baaSJan Lentfer 
54870224baaSJan Lentfer void
pf_rtlabel_remove(struct pf_addr_wrap * a)54970224baaSJan Lentfer pf_rtlabel_remove(struct pf_addr_wrap *a)
55070224baaSJan Lentfer {
55170224baaSJan Lentfer }
55270224baaSJan Lentfer 
55370224baaSJan Lentfer void
pf_rtlabel_copyout(struct pf_addr_wrap * a)55470224baaSJan Lentfer pf_rtlabel_copyout(struct pf_addr_wrap *a)
55570224baaSJan Lentfer {
55670224baaSJan Lentfer 	if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel)
55770224baaSJan Lentfer 		strlcpy(a->v.rtlabelname, "?", sizeof(a->v.rtlabelname));
55802742ec6SJoerg Sonnenberger }
55902742ec6SJoerg Sonnenberger 
56002742ec6SJoerg Sonnenberger #ifdef ALTQ
56102742ec6SJoerg Sonnenberger u_int32_t
pf_qname2qid(char * qname)56202742ec6SJoerg Sonnenberger pf_qname2qid(char *qname)
56302742ec6SJoerg Sonnenberger {
56402742ec6SJoerg Sonnenberger 	return ((u_int32_t)tagname2tag(&pf_qids, qname));
56502742ec6SJoerg Sonnenberger }
56602742ec6SJoerg Sonnenberger 
56702742ec6SJoerg Sonnenberger void
pf_qid2qname(u_int32_t qid,char * p)56802742ec6SJoerg Sonnenberger pf_qid2qname(u_int32_t qid, char *p)
56902742ec6SJoerg Sonnenberger {
57070224baaSJan Lentfer 	tag2tagname(&pf_qids, (u_int16_t)qid, p);
57102742ec6SJoerg Sonnenberger }
57202742ec6SJoerg Sonnenberger 
57302742ec6SJoerg Sonnenberger void
pf_qid_unref(u_int32_t qid)57402742ec6SJoerg Sonnenberger pf_qid_unref(u_int32_t qid)
57502742ec6SJoerg Sonnenberger {
57670224baaSJan Lentfer 	tag_unref(&pf_qids, (u_int16_t)qid);
57702742ec6SJoerg Sonnenberger }
57802742ec6SJoerg Sonnenberger 
57902742ec6SJoerg Sonnenberger int
pf_begin_altq(u_int32_t * ticket)58002742ec6SJoerg Sonnenberger pf_begin_altq(u_int32_t *ticket)
58102742ec6SJoerg Sonnenberger {
58202742ec6SJoerg Sonnenberger 	struct pf_altq	*altq;
58302742ec6SJoerg Sonnenberger 	int		 error = 0;
58402742ec6SJoerg Sonnenberger 
58502742ec6SJoerg Sonnenberger 	/* Purge the old altq list */
58602742ec6SJoerg Sonnenberger 	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
58702742ec6SJoerg Sonnenberger 		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
588d15093b9SAaron LI 		if (altq->qname[0] == 0) {
58902742ec6SJoerg Sonnenberger 			/* detach and destroy the discipline */
59002742ec6SJoerg Sonnenberger 			error = altq_remove(altq);
59102742ec6SJoerg Sonnenberger 		} else
59202742ec6SJoerg Sonnenberger 			pf_qid_unref(altq->qid);
5931186cbc0SJan Lentfer 		kfree(altq, M_PFALTQPL);
59402742ec6SJoerg Sonnenberger 	}
59502742ec6SJoerg Sonnenberger 	if (error)
59602742ec6SJoerg Sonnenberger 		return (error);
59702742ec6SJoerg Sonnenberger 	*ticket = ++ticket_altqs_inactive;
59802742ec6SJoerg Sonnenberger 	altqs_inactive_open = 1;
59902742ec6SJoerg Sonnenberger 	return (0);
60002742ec6SJoerg Sonnenberger }
60102742ec6SJoerg Sonnenberger 
60202742ec6SJoerg Sonnenberger int
pf_rollback_altq(u_int32_t ticket)60302742ec6SJoerg Sonnenberger pf_rollback_altq(u_int32_t ticket)
60402742ec6SJoerg Sonnenberger {
60502742ec6SJoerg Sonnenberger 	struct pf_altq	*altq;
60602742ec6SJoerg Sonnenberger 	int		 error = 0;
60702742ec6SJoerg Sonnenberger 
60802742ec6SJoerg Sonnenberger 	if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
60902742ec6SJoerg Sonnenberger 		return (0);
61002742ec6SJoerg Sonnenberger 	/* Purge the old altq list */
61102742ec6SJoerg Sonnenberger 	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
61202742ec6SJoerg Sonnenberger 		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
613d15093b9SAaron LI 		if (altq->qname[0] == 0) {
61402742ec6SJoerg Sonnenberger 			/* detach and destroy the discipline */
61502742ec6SJoerg Sonnenberger 			error = altq_remove(altq);
61602742ec6SJoerg Sonnenberger 		} else
61702742ec6SJoerg Sonnenberger 			pf_qid_unref(altq->qid);
6181186cbc0SJan Lentfer 		kfree(altq, M_PFALTQPL);
61902742ec6SJoerg Sonnenberger 	}
62002742ec6SJoerg Sonnenberger 	altqs_inactive_open = 0;
62102742ec6SJoerg Sonnenberger 	return (error);
62202742ec6SJoerg Sonnenberger }
62302742ec6SJoerg Sonnenberger 
62402742ec6SJoerg Sonnenberger int
pf_commit_altq(u_int32_t ticket)62502742ec6SJoerg Sonnenberger pf_commit_altq(u_int32_t ticket)
62602742ec6SJoerg Sonnenberger {
62702742ec6SJoerg Sonnenberger 	struct pf_altqqueue	*old_altqs;
62802742ec6SJoerg Sonnenberger 	struct pf_altq		*altq;
629cc6e5672SJoerg Sonnenberger 	int			 err, error = 0;
63002742ec6SJoerg Sonnenberger 
63102742ec6SJoerg Sonnenberger 	if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
63202742ec6SJoerg Sonnenberger 		return (EBUSY);
63302742ec6SJoerg Sonnenberger 
63402742ec6SJoerg Sonnenberger 	/* swap altqs, keep the old. */
635cc6e5672SJoerg Sonnenberger 	crit_enter();
63602742ec6SJoerg Sonnenberger 	old_altqs = pf_altqs_active;
63702742ec6SJoerg Sonnenberger 	pf_altqs_active = pf_altqs_inactive;
63802742ec6SJoerg Sonnenberger 	pf_altqs_inactive = old_altqs;
63902742ec6SJoerg Sonnenberger 	ticket_altqs_active = ticket_altqs_inactive;
64002742ec6SJoerg Sonnenberger 
64102742ec6SJoerg Sonnenberger 	/* Attach new disciplines */
64202742ec6SJoerg Sonnenberger 	TAILQ_FOREACH(altq, pf_altqs_active, entries) {
643d15093b9SAaron LI 		if (altq->qname[0] == 0) {
64402742ec6SJoerg Sonnenberger 			/* attach the discipline */
64502742ec6SJoerg Sonnenberger 			error = altq_pfattach(altq);
64602742ec6SJoerg Sonnenberger 			if (error) {
647cc6e5672SJoerg Sonnenberger 				crit_exit();
64802742ec6SJoerg Sonnenberger 				return (error);
64902742ec6SJoerg Sonnenberger 			}
65002742ec6SJoerg Sonnenberger 		}
65102742ec6SJoerg Sonnenberger 	}
65202742ec6SJoerg Sonnenberger 
65302742ec6SJoerg Sonnenberger 	/* Purge the old altq list */
65402742ec6SJoerg Sonnenberger 	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
65502742ec6SJoerg Sonnenberger 		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
656d15093b9SAaron LI 		if (altq->qname[0] == 0) {
65702742ec6SJoerg Sonnenberger 			/* detach and destroy the discipline */
65870224baaSJan Lentfer 			if (pf_altq_running)
65970224baaSJan Lentfer 				error = pf_disable_altq(altq);
66002742ec6SJoerg Sonnenberger 			err = altq_pfdetach(altq);
66102742ec6SJoerg Sonnenberger 			if (err != 0 && error == 0)
66202742ec6SJoerg Sonnenberger 				error = err;
66302742ec6SJoerg Sonnenberger 			err = altq_remove(altq);
66402742ec6SJoerg Sonnenberger 			if (err != 0 && error == 0)
66502742ec6SJoerg Sonnenberger 				error = err;
66602742ec6SJoerg Sonnenberger 		} else
66702742ec6SJoerg Sonnenberger 			pf_qid_unref(altq->qid);
6681186cbc0SJan Lentfer 		kfree(altq, M_PFALTQPL);
66902742ec6SJoerg Sonnenberger 	}
670cc6e5672SJoerg Sonnenberger 	crit_exit();
67102742ec6SJoerg Sonnenberger 
67202742ec6SJoerg Sonnenberger 	altqs_inactive_open = 0;
67302742ec6SJoerg Sonnenberger 	return (error);
67402742ec6SJoerg Sonnenberger }
67570224baaSJan Lentfer 
67670224baaSJan Lentfer int
pf_enable_altq(struct pf_altq * altq)67770224baaSJan Lentfer pf_enable_altq(struct pf_altq *altq)
67870224baaSJan Lentfer {
67970224baaSJan Lentfer 	struct ifnet		*ifp;
68070224baaSJan Lentfer 	struct tb_profile	 tb;
68170224baaSJan Lentfer 	int			 error = 0;
68270224baaSJan Lentfer 
683b4051e25SSepherosa Ziehau 	ifnet_lock();
6840a887f91SAaron LI 
685d15093b9SAaron LI 	if ((ifp = ifunit(altq->ifname)) == NULL) {
686d15093b9SAaron LI 		ifnet_unlock();
68770224baaSJan Lentfer 		return (EINVAL);
688d15093b9SAaron LI 	}
68970224baaSJan Lentfer 
69070224baaSJan Lentfer 	if (ifp->if_snd.altq_type != ALTQT_NONE)
69170224baaSJan Lentfer 		error = altq_enable(&ifp->if_snd);
69270224baaSJan Lentfer 
69370224baaSJan Lentfer 	/* set tokenbucket regulator */
69470224baaSJan Lentfer 	if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
69570224baaSJan Lentfer 		tb.rate = altq->ifbandwidth;
69670224baaSJan Lentfer 		tb.depth = altq->tbrsize;
69770224baaSJan Lentfer 		crit_enter();
69870224baaSJan Lentfer 		error = tbr_set(&ifp->if_snd, &tb);
69970224baaSJan Lentfer 		crit_exit();
70070224baaSJan Lentfer 	}
70170224baaSJan Lentfer 
702d15093b9SAaron LI 	ifnet_unlock();
70370224baaSJan Lentfer 	return (error);
70470224baaSJan Lentfer }
70570224baaSJan Lentfer 
70670224baaSJan Lentfer int
pf_disable_altq(struct pf_altq * altq)70770224baaSJan Lentfer pf_disable_altq(struct pf_altq *altq)
70870224baaSJan Lentfer {
70970224baaSJan Lentfer 	struct ifnet		*ifp;
71070224baaSJan Lentfer 	struct tb_profile	 tb;
71170224baaSJan Lentfer 	int			 error;
71270224baaSJan Lentfer 
713b4051e25SSepherosa Ziehau 	ifnet_lock();
7140a887f91SAaron LI 
715d15093b9SAaron LI 	if ((ifp = ifunit(altq->ifname)) == NULL) {
716d15093b9SAaron LI 		ifnet_unlock();
71770224baaSJan Lentfer 		return (EINVAL);
718d15093b9SAaron LI 	}
71970224baaSJan Lentfer 
72070224baaSJan Lentfer 	/*
72170224baaSJan Lentfer 	 * when the discipline is no longer referenced, it was overridden
72270224baaSJan Lentfer 	 * by a new one.  if so, just return.
72370224baaSJan Lentfer 	 */
724d15093b9SAaron LI 	if (altq->altq_disc != ifp->if_snd.altq_disc) {
725d15093b9SAaron LI 		ifnet_unlock();
72670224baaSJan Lentfer 		return (0);
727d15093b9SAaron LI 	}
72870224baaSJan Lentfer 
72970224baaSJan Lentfer 	error = altq_disable(&ifp->if_snd);
73070224baaSJan Lentfer 
73170224baaSJan Lentfer 	if (error == 0) {
73270224baaSJan Lentfer 		/* clear tokenbucket regulator */
73370224baaSJan Lentfer 		tb.rate = 0;
73470224baaSJan Lentfer 		crit_enter();
73570224baaSJan Lentfer 		error = tbr_set(&ifp->if_snd, &tb);
73670224baaSJan Lentfer 		crit_exit();
73770224baaSJan Lentfer 	}
73870224baaSJan Lentfer 
7390a887f91SAaron LI 	ifnet_unlock();
740d15093b9SAaron LI 	return (error);
7410a887f91SAaron LI }
74202742ec6SJoerg Sonnenberger #endif /* ALTQ */
74302742ec6SJoerg Sonnenberger 
74402742ec6SJoerg Sonnenberger int
pf_begin_rules(u_int32_t * ticket,int rs_num,const char * anchor)74570224baaSJan Lentfer pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
74602742ec6SJoerg Sonnenberger {
74702742ec6SJoerg Sonnenberger 	struct pf_ruleset	*rs;
74802742ec6SJoerg Sonnenberger 	struct pf_rule		*rule;
74902742ec6SJoerg Sonnenberger 
75002742ec6SJoerg Sonnenberger 	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
75102742ec6SJoerg Sonnenberger 		return (EINVAL);
75270224baaSJan Lentfer 	rs = pf_find_or_create_ruleset(anchor);
75302742ec6SJoerg Sonnenberger 	if (rs == NULL)
75402742ec6SJoerg Sonnenberger 		return (EINVAL);
75570224baaSJan Lentfer 	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
75602742ec6SJoerg Sonnenberger 		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
75770224baaSJan Lentfer 		rs->rules[rs_num].inactive.rcount--;
75870224baaSJan Lentfer 	}
75902742ec6SJoerg Sonnenberger 	*ticket = ++rs->rules[rs_num].inactive.ticket;
76002742ec6SJoerg Sonnenberger 	rs->rules[rs_num].inactive.open = 1;
76102742ec6SJoerg Sonnenberger 	return (0);
76202742ec6SJoerg Sonnenberger }
76302742ec6SJoerg Sonnenberger 
76402742ec6SJoerg Sonnenberger int
pf_rollback_rules(u_int32_t ticket,int rs_num,char * anchor)76570224baaSJan Lentfer pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
76602742ec6SJoerg Sonnenberger {
76702742ec6SJoerg Sonnenberger 	struct pf_ruleset	*rs;
76802742ec6SJoerg Sonnenberger 	struct pf_rule		*rule;
76902742ec6SJoerg Sonnenberger 
77002742ec6SJoerg Sonnenberger 	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
77102742ec6SJoerg Sonnenberger 		return (EINVAL);
77270224baaSJan Lentfer 	rs = pf_find_ruleset(anchor);
77302742ec6SJoerg Sonnenberger 	if (rs == NULL || !rs->rules[rs_num].inactive.open ||
77402742ec6SJoerg Sonnenberger 	    rs->rules[rs_num].inactive.ticket != ticket)
77502742ec6SJoerg Sonnenberger 		return (0);
77670224baaSJan Lentfer 	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
77702742ec6SJoerg Sonnenberger 		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
77870224baaSJan Lentfer 		rs->rules[rs_num].inactive.rcount--;
77970224baaSJan Lentfer 	}
78002742ec6SJoerg Sonnenberger 	rs->rules[rs_num].inactive.open = 0;
78102742ec6SJoerg Sonnenberger 	return (0);
78202742ec6SJoerg Sonnenberger }
78302742ec6SJoerg Sonnenberger 
78470224baaSJan Lentfer #define PF_MD5_UPD(st, elm)						\
78570224baaSJan Lentfer 		MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm))
78670224baaSJan Lentfer 
78770224baaSJan Lentfer #define PF_MD5_UPD_STR(st, elm)						\
78870224baaSJan Lentfer 		MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm))
78970224baaSJan Lentfer 
79070224baaSJan Lentfer #define PF_MD5_UPD_HTONL(st, elm, stor) do {				\
79170224baaSJan Lentfer 		(stor) = htonl((st)->elm);				\
79270224baaSJan Lentfer 		MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\
79370224baaSJan Lentfer } while (0)
79470224baaSJan Lentfer 
79570224baaSJan Lentfer #define PF_MD5_UPD_HTONS(st, elm, stor) do {				\
79670224baaSJan Lentfer 		(stor) = htons((st)->elm);				\
79770224baaSJan Lentfer 		MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\
79870224baaSJan Lentfer } while (0)
79970224baaSJan Lentfer 
80070224baaSJan Lentfer void
pf_hash_rule_addr(MD5_CTX * ctx,struct pf_rule_addr * pfr)80170224baaSJan Lentfer pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
80270224baaSJan Lentfer {
80370224baaSJan Lentfer 	PF_MD5_UPD(pfr, addr.type);
80470224baaSJan Lentfer 	switch (pfr->addr.type) {
80570224baaSJan Lentfer 		case PF_ADDR_DYNIFTL:
80670224baaSJan Lentfer 			PF_MD5_UPD(pfr, addr.v.ifname);
80770224baaSJan Lentfer 			PF_MD5_UPD(pfr, addr.iflags);
80870224baaSJan Lentfer 			break;
80970224baaSJan Lentfer 		case PF_ADDR_TABLE:
81070224baaSJan Lentfer 			PF_MD5_UPD(pfr, addr.v.tblname);
81170224baaSJan Lentfer 			break;
81270224baaSJan Lentfer 		case PF_ADDR_ADDRMASK:
81370224baaSJan Lentfer 			/* XXX ignore af? */
81470224baaSJan Lentfer 			PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
81570224baaSJan Lentfer 			PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
81670224baaSJan Lentfer 			break;
81770224baaSJan Lentfer 		case PF_ADDR_RTLABEL:
81870224baaSJan Lentfer 			PF_MD5_UPD(pfr, addr.v.rtlabelname);
81970224baaSJan Lentfer 			break;
82070224baaSJan Lentfer 	}
82170224baaSJan Lentfer 
82270224baaSJan Lentfer 	PF_MD5_UPD(pfr, port[0]);
82370224baaSJan Lentfer 	PF_MD5_UPD(pfr, port[1]);
82470224baaSJan Lentfer 	PF_MD5_UPD(pfr, neg);
82570224baaSJan Lentfer 	PF_MD5_UPD(pfr, port_op);
82670224baaSJan Lentfer }
82770224baaSJan Lentfer 
82870224baaSJan Lentfer void
pf_hash_rule(MD5_CTX * ctx,struct pf_rule * rule)82970224baaSJan Lentfer pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
83070224baaSJan Lentfer {
83170224baaSJan Lentfer 	u_int16_t x;
83270224baaSJan Lentfer 	u_int32_t y;
83370224baaSJan Lentfer 
83470224baaSJan Lentfer 	pf_hash_rule_addr(ctx, &rule->src);
83570224baaSJan Lentfer 	pf_hash_rule_addr(ctx, &rule->dst);
83670224baaSJan Lentfer 	PF_MD5_UPD_STR(rule, label);
83770224baaSJan Lentfer 	PF_MD5_UPD_STR(rule, ifname);
83870224baaSJan Lentfer 	PF_MD5_UPD_STR(rule, match_tagname);
83970224baaSJan Lentfer 	PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
84070224baaSJan Lentfer 	PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
84170224baaSJan Lentfer 	PF_MD5_UPD_HTONL(rule, prob, y);
84270224baaSJan Lentfer 	PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
84370224baaSJan Lentfer 	PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
84470224baaSJan Lentfer 	PF_MD5_UPD(rule, uid.op);
84570224baaSJan Lentfer 	PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
84670224baaSJan Lentfer 	PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
84770224baaSJan Lentfer 	PF_MD5_UPD(rule, gid.op);
84870224baaSJan Lentfer 	PF_MD5_UPD_HTONL(rule, rule_flag, y);
84970224baaSJan Lentfer 	PF_MD5_UPD(rule, action);
85070224baaSJan Lentfer 	PF_MD5_UPD(rule, direction);
85170224baaSJan Lentfer 	PF_MD5_UPD(rule, af);
85270224baaSJan Lentfer 	PF_MD5_UPD(rule, quick);
85370224baaSJan Lentfer 	PF_MD5_UPD(rule, ifnot);
85470224baaSJan Lentfer 	PF_MD5_UPD(rule, match_tag_not);
85570224baaSJan Lentfer 	PF_MD5_UPD(rule, natpass);
85670224baaSJan Lentfer 	PF_MD5_UPD(rule, keep_state);
85770224baaSJan Lentfer 	PF_MD5_UPD(rule, proto);
85870224baaSJan Lentfer 	PF_MD5_UPD(rule, type);
85970224baaSJan Lentfer 	PF_MD5_UPD(rule, code);
86070224baaSJan Lentfer 	PF_MD5_UPD(rule, flags);
86170224baaSJan Lentfer 	PF_MD5_UPD(rule, flagset);
86270224baaSJan Lentfer 	PF_MD5_UPD(rule, allow_opts);
86370224baaSJan Lentfer 	PF_MD5_UPD(rule, rt);
86470224baaSJan Lentfer 	PF_MD5_UPD(rule, tos);
86570224baaSJan Lentfer }
86670224baaSJan Lentfer 
86702742ec6SJoerg Sonnenberger int
pf_commit_rules(u_int32_t ticket,int rs_num,char * anchor)86870224baaSJan Lentfer pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
86902742ec6SJoerg Sonnenberger {
87002742ec6SJoerg Sonnenberger 	struct pf_ruleset	*rs;
87170224baaSJan Lentfer 	struct pf_rule		*rule, **old_array;
87202742ec6SJoerg Sonnenberger 	struct pf_rulequeue	*old_rules;
87370224baaSJan Lentfer 	int			 error;
87470224baaSJan Lentfer 	u_int32_t		 old_rcount;
87502742ec6SJoerg Sonnenberger 
87602742ec6SJoerg Sonnenberger 	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
87702742ec6SJoerg Sonnenberger 		return (EINVAL);
87870224baaSJan Lentfer 	rs = pf_find_ruleset(anchor);
87902742ec6SJoerg Sonnenberger 	if (rs == NULL || !rs->rules[rs_num].inactive.open ||
88002742ec6SJoerg Sonnenberger 	    ticket != rs->rules[rs_num].inactive.ticket)
88102742ec6SJoerg Sonnenberger 		return (EBUSY);
88202742ec6SJoerg Sonnenberger 
88370224baaSJan Lentfer 	/* Calculate checksum for the main ruleset */
88470224baaSJan Lentfer 	if (rs == &pf_main_ruleset) {
88570224baaSJan Lentfer 		error = pf_setup_pfsync_matching(rs);
88670224baaSJan Lentfer 		if (error != 0)
88770224baaSJan Lentfer 			return (error);
88870224baaSJan Lentfer 	}
88970224baaSJan Lentfer 
89002742ec6SJoerg Sonnenberger 	/* Swap rules, keep the old. */
891cc6e5672SJoerg Sonnenberger 	crit_enter();
89202742ec6SJoerg Sonnenberger 	old_rules = rs->rules[rs_num].active.ptr;
89370224baaSJan Lentfer 	old_rcount = rs->rules[rs_num].active.rcount;
89470224baaSJan Lentfer 	old_array = rs->rules[rs_num].active.ptr_array;
89570224baaSJan Lentfer 
89602742ec6SJoerg Sonnenberger 	rs->rules[rs_num].active.ptr =
89702742ec6SJoerg Sonnenberger 	    rs->rules[rs_num].inactive.ptr;
89870224baaSJan Lentfer 	rs->rules[rs_num].active.ptr_array =
89970224baaSJan Lentfer 	    rs->rules[rs_num].inactive.ptr_array;
90070224baaSJan Lentfer 	rs->rules[rs_num].active.rcount =
90170224baaSJan Lentfer 	    rs->rules[rs_num].inactive.rcount;
90202742ec6SJoerg Sonnenberger 	rs->rules[rs_num].inactive.ptr = old_rules;
90370224baaSJan Lentfer 	rs->rules[rs_num].inactive.ptr_array = old_array;
90470224baaSJan Lentfer 	rs->rules[rs_num].inactive.rcount = old_rcount;
90570224baaSJan Lentfer 
90602742ec6SJoerg Sonnenberger 	rs->rules[rs_num].active.ticket =
90702742ec6SJoerg Sonnenberger 	    rs->rules[rs_num].inactive.ticket;
90802742ec6SJoerg Sonnenberger 	pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
90902742ec6SJoerg Sonnenberger 
91070224baaSJan Lentfer 
91102742ec6SJoerg Sonnenberger 	/* Purge the old rule list. */
91202742ec6SJoerg Sonnenberger 	while ((rule = TAILQ_FIRST(old_rules)) != NULL)
91302742ec6SJoerg Sonnenberger 		pf_rm_rule(old_rules, rule);
91470224baaSJan Lentfer 	if (rs->rules[rs_num].inactive.ptr_array)
91570224baaSJan Lentfer 		kfree(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
91670224baaSJan Lentfer 	rs->rules[rs_num].inactive.ptr_array = NULL;
91770224baaSJan Lentfer 	rs->rules[rs_num].inactive.rcount = 0;
91802742ec6SJoerg Sonnenberger 	rs->rules[rs_num].inactive.open = 0;
91902742ec6SJoerg Sonnenberger 	pf_remove_if_empty_ruleset(rs);
920cc6e5672SJoerg Sonnenberger 	crit_exit();
92102742ec6SJoerg Sonnenberger 	return (0);
92202742ec6SJoerg Sonnenberger }
92302742ec6SJoerg Sonnenberger 
92402742ec6SJoerg Sonnenberger int
pf_setup_pfsync_matching(struct pf_ruleset * rs)92570224baaSJan Lentfer pf_setup_pfsync_matching(struct pf_ruleset *rs)
92670224baaSJan Lentfer {
92770224baaSJan Lentfer 	MD5_CTX			 ctx;
92870224baaSJan Lentfer 	struct pf_rule		*rule;
92970224baaSJan Lentfer 	int			 rs_cnt;
93070224baaSJan Lentfer 	u_int8_t		 digest[PF_MD5_DIGEST_LENGTH];
93170224baaSJan Lentfer 
93270224baaSJan Lentfer 	MD5Init(&ctx);
93370224baaSJan Lentfer 	for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
93470224baaSJan Lentfer 		/* XXX PF_RULESET_SCRUB as well? */
93570224baaSJan Lentfer 		if (rs_cnt == PF_RULESET_SCRUB)
93670224baaSJan Lentfer 			continue;
93770224baaSJan Lentfer 
93870224baaSJan Lentfer 		if (rs->rules[rs_cnt].inactive.ptr_array)
93970224baaSJan Lentfer 			kfree(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
94070224baaSJan Lentfer 		rs->rules[rs_cnt].inactive.ptr_array = NULL;
94170224baaSJan Lentfer 
94270224baaSJan Lentfer 		if (rs->rules[rs_cnt].inactive.rcount) {
94370224baaSJan Lentfer 			rs->rules[rs_cnt].inactive.ptr_array =
94470224baaSJan Lentfer 			    kmalloc(sizeof(caddr_t) *
94570224baaSJan Lentfer 				    rs->rules[rs_cnt].inactive.rcount,
94670224baaSJan Lentfer 				    M_TEMP, M_WAITOK);
94770224baaSJan Lentfer 		}
94870224baaSJan Lentfer 
94970224baaSJan Lentfer 		TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
95070224baaSJan Lentfer 		    entries) {
95170224baaSJan Lentfer 			pf_hash_rule(&ctx, rule);
95270224baaSJan Lentfer 			(rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
95370224baaSJan Lentfer 		}
95470224baaSJan Lentfer 	}
95570224baaSJan Lentfer 
95670224baaSJan Lentfer 	MD5Final(digest, &ctx);
95770224baaSJan Lentfer 	memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
95870224baaSJan Lentfer 	return (0);
95970224baaSJan Lentfer }
96070224baaSJan Lentfer 
96170224baaSJan Lentfer int
pf_addr_setup(struct pf_ruleset * ruleset,struct pf_addr_wrap * addr,sa_family_t af)962ed1f0be2SJan Lentfer pf_addr_setup(struct pf_ruleset *ruleset, struct pf_addr_wrap *addr,
963ed1f0be2SJan Lentfer     sa_family_t af)
964ed1f0be2SJan Lentfer {
965ed1f0be2SJan Lentfer 	if (pfi_dynaddr_setup(addr, af) ||
966ed1f0be2SJan Lentfer 	    pf_tbladdr_setup(ruleset, addr))
967ed1f0be2SJan Lentfer 		return (EINVAL);
968ed1f0be2SJan Lentfer 
969ed1f0be2SJan Lentfer 	return (0);
970ed1f0be2SJan Lentfer }
971ed1f0be2SJan Lentfer 
972ed1f0be2SJan Lentfer void
pf_addr_copyout(struct pf_addr_wrap * addr)973ed1f0be2SJan Lentfer pf_addr_copyout(struct pf_addr_wrap *addr)
974ed1f0be2SJan Lentfer {
975ed1f0be2SJan Lentfer 	pfi_dynaddr_copyout(addr);
976ed1f0be2SJan Lentfer 	pf_tbladdr_copyout(addr);
977ed1f0be2SJan Lentfer 	pf_rtlabel_copyout(addr);
978ed1f0be2SJan Lentfer }
979ed1f0be2SJan Lentfer 
980ed1f0be2SJan Lentfer int
pfioctl(struct dev_ioctl_args * ap)981fef8985eSMatthew Dillon pfioctl(struct dev_ioctl_args *ap)
98202742ec6SJoerg Sonnenberger {
983fef8985eSMatthew Dillon 	u_long cmd = ap->a_cmd;
984fef8985eSMatthew Dillon 	caddr_t addr = ap->a_data;
98502742ec6SJoerg Sonnenberger 	struct pf_pooladdr	*pa = NULL;
98602742ec6SJoerg Sonnenberger 	struct pf_pool		*pool = NULL;
98702742ec6SJoerg Sonnenberger 	int			 error = 0;
98802742ec6SJoerg Sonnenberger 
9892a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
9902a7a2b1cSJan Lentfer 
99102742ec6SJoerg Sonnenberger 	/* XXX keep in sync with switch() below */
9923a0038bfSMatthew Dillon 	if (securelevel > 1) {
99302742ec6SJoerg Sonnenberger 		switch (cmd) {
99402742ec6SJoerg Sonnenberger 		case DIOCGETRULES:
99502742ec6SJoerg Sonnenberger 		case DIOCGETRULE:
99602742ec6SJoerg Sonnenberger 		case DIOCGETADDRS:
99702742ec6SJoerg Sonnenberger 		case DIOCGETADDR:
99802742ec6SJoerg Sonnenberger 		case DIOCGETSTATE:
99902742ec6SJoerg Sonnenberger 		case DIOCSETSTATUSIF:
100002742ec6SJoerg Sonnenberger 		case DIOCGETSTATUS:
100102742ec6SJoerg Sonnenberger 		case DIOCCLRSTATUS:
100202742ec6SJoerg Sonnenberger 		case DIOCNATLOOK:
100302742ec6SJoerg Sonnenberger 		case DIOCSETDEBUG:
100402742ec6SJoerg Sonnenberger 		case DIOCGETSTATES:
100502742ec6SJoerg Sonnenberger 		case DIOCGETTIMEOUT:
100602742ec6SJoerg Sonnenberger 		case DIOCCLRRULECTRS:
100702742ec6SJoerg Sonnenberger 		case DIOCGETLIMIT:
100802742ec6SJoerg Sonnenberger 		case DIOCGETALTQS:
100902742ec6SJoerg Sonnenberger 		case DIOCGETALTQ:
101002742ec6SJoerg Sonnenberger 		case DIOCGETQSTATS:
101102742ec6SJoerg Sonnenberger 		case DIOCGETRULESETS:
101202742ec6SJoerg Sonnenberger 		case DIOCGETRULESET:
101302742ec6SJoerg Sonnenberger 		case DIOCRGETTABLES:
101402742ec6SJoerg Sonnenberger 		case DIOCRGETTSTATS:
101502742ec6SJoerg Sonnenberger 		case DIOCRCLRTSTATS:
101602742ec6SJoerg Sonnenberger 		case DIOCRCLRADDRS:
101702742ec6SJoerg Sonnenberger 		case DIOCRADDADDRS:
101802742ec6SJoerg Sonnenberger 		case DIOCRDELADDRS:
101902742ec6SJoerg Sonnenberger 		case DIOCRSETADDRS:
102002742ec6SJoerg Sonnenberger 		case DIOCRGETADDRS:
102102742ec6SJoerg Sonnenberger 		case DIOCRGETASTATS:
102202742ec6SJoerg Sonnenberger 		case DIOCRCLRASTATS:
102302742ec6SJoerg Sonnenberger 		case DIOCRTSTADDRS:
102402742ec6SJoerg Sonnenberger 		case DIOCOSFPGET:
102502742ec6SJoerg Sonnenberger 		case DIOCGETSRCNODES:
102602742ec6SJoerg Sonnenberger 		case DIOCCLRSRCNODES:
102702742ec6SJoerg Sonnenberger 		case DIOCIGETIFACES:
102870224baaSJan Lentfer 		case DIOCSETIFFLAG:
102970224baaSJan Lentfer 		case DIOCCLRIFFLAG:
103002742ec6SJoerg Sonnenberger 		case DIOCGIFSPEED:
103102742ec6SJoerg Sonnenberger 			break;
103202742ec6SJoerg Sonnenberger 		case DIOCRCLRTABLES:
103302742ec6SJoerg Sonnenberger 		case DIOCRADDTABLES:
103402742ec6SJoerg Sonnenberger 		case DIOCRDELTABLES:
103502742ec6SJoerg Sonnenberger 		case DIOCRSETTFLAGS:
103602742ec6SJoerg Sonnenberger 			if (((struct pfioc_table *)addr)->pfrio_flags &
103702742ec6SJoerg Sonnenberger 			    PFR_FLAG_DUMMY)
103802742ec6SJoerg Sonnenberger 				break; /* dummy operation ok */
10392a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
104002742ec6SJoerg Sonnenberger 			return (EPERM);
104102742ec6SJoerg Sonnenberger 		default:
10422a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
104302742ec6SJoerg Sonnenberger 			return (EPERM);
104402742ec6SJoerg Sonnenberger 		}
10453a0038bfSMatthew Dillon 	}
104602742ec6SJoerg Sonnenberger 
10473a0038bfSMatthew Dillon 	if (!(ap->a_fflag & FWRITE)) {
104802742ec6SJoerg Sonnenberger 		switch (cmd) {
104902742ec6SJoerg Sonnenberger 		case DIOCGETRULES:
105002742ec6SJoerg Sonnenberger 		case DIOCGETADDRS:
105102742ec6SJoerg Sonnenberger 		case DIOCGETADDR:
105202742ec6SJoerg Sonnenberger 		case DIOCGETSTATE:
105302742ec6SJoerg Sonnenberger 		case DIOCGETSTATUS:
105402742ec6SJoerg Sonnenberger 		case DIOCGETSTATES:
105502742ec6SJoerg Sonnenberger 		case DIOCGETTIMEOUT:
105602742ec6SJoerg Sonnenberger 		case DIOCGETLIMIT:
105702742ec6SJoerg Sonnenberger 		case DIOCGETALTQS:
105802742ec6SJoerg Sonnenberger 		case DIOCGETALTQ:
105902742ec6SJoerg Sonnenberger 		case DIOCGETQSTATS:
106002742ec6SJoerg Sonnenberger 		case DIOCGETRULESETS:
106102742ec6SJoerg Sonnenberger 		case DIOCGETRULESET:
106270224baaSJan Lentfer 		case DIOCNATLOOK:
106302742ec6SJoerg Sonnenberger 		case DIOCRGETTABLES:
106402742ec6SJoerg Sonnenberger 		case DIOCRGETTSTATS:
106502742ec6SJoerg Sonnenberger 		case DIOCRGETADDRS:
106602742ec6SJoerg Sonnenberger 		case DIOCRGETASTATS:
106702742ec6SJoerg Sonnenberger 		case DIOCRTSTADDRS:
106802742ec6SJoerg Sonnenberger 		case DIOCOSFPGET:
106902742ec6SJoerg Sonnenberger 		case DIOCGETSRCNODES:
107002742ec6SJoerg Sonnenberger 		case DIOCIGETIFACES:
107102742ec6SJoerg Sonnenberger 		case DIOCGIFSPEED:
107202742ec6SJoerg Sonnenberger 			break;
107302742ec6SJoerg Sonnenberger 		case DIOCRCLRTABLES:
107402742ec6SJoerg Sonnenberger 		case DIOCRADDTABLES:
107502742ec6SJoerg Sonnenberger 		case DIOCRDELTABLES:
107602742ec6SJoerg Sonnenberger 		case DIOCRCLRTSTATS:
107702742ec6SJoerg Sonnenberger 		case DIOCRCLRADDRS:
107802742ec6SJoerg Sonnenberger 		case DIOCRADDADDRS:
107902742ec6SJoerg Sonnenberger 		case DIOCRDELADDRS:
108002742ec6SJoerg Sonnenberger 		case DIOCRSETADDRS:
108102742ec6SJoerg Sonnenberger 		case DIOCRSETTFLAGS:
108202742ec6SJoerg Sonnenberger 			if (((struct pfioc_table *)addr)->pfrio_flags &
108302742ec6SJoerg Sonnenberger 			    PFR_FLAG_DUMMY)
108402742ec6SJoerg Sonnenberger 				break; /* dummy operation ok */
10852a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
108602742ec6SJoerg Sonnenberger 			return (EACCES);
108770224baaSJan Lentfer 		case DIOCGETRULE:
1088ed1f0be2SJan Lentfer 			if (((struct pfioc_rule *)addr)->action ==
1089ed1f0be2SJan Lentfer 			    PF_GET_CLR_CNTR) {
10902a7a2b1cSJan Lentfer 				lwkt_reltoken(&pf_token);
109170224baaSJan Lentfer 				return (EACCES);
10922a7a2b1cSJan Lentfer 			}
109370224baaSJan Lentfer 			break;
109402742ec6SJoerg Sonnenberger 		default:
10952a7a2b1cSJan Lentfer 			lwkt_reltoken(&pf_token);
109602742ec6SJoerg Sonnenberger 			return (EACCES);
109702742ec6SJoerg Sonnenberger 		}
10983a0038bfSMatthew Dillon 	}
109902742ec6SJoerg Sonnenberger 
110002742ec6SJoerg Sonnenberger 	switch (cmd) {
110102742ec6SJoerg Sonnenberger 	case DIOCSTART:
110202742ec6SJoerg Sonnenberger 		if (pf_status.running)
110302742ec6SJoerg Sonnenberger 			error = EEXIST;
110402742ec6SJoerg Sonnenberger 		else {
110502742ec6SJoerg Sonnenberger 			error = hook_pf();
110602742ec6SJoerg Sonnenberger 			if (error) {
110702742ec6SJoerg Sonnenberger 				DPFPRINTF(PF_DEBUG_MISC,
11083f625015SSascha Wildner 				    ("pf: pfil registration fail\n"));
110902742ec6SJoerg Sonnenberger 				break;
111002742ec6SJoerg Sonnenberger 			}
111102742ec6SJoerg Sonnenberger 			pf_status.running = 1;
111202742ec6SJoerg Sonnenberger 			pf_status.since = time_second;
111302742ec6SJoerg Sonnenberger 			if (pf_status.stateid == 0) {
111402742ec6SJoerg Sonnenberger 				pf_status.stateid = time_second;
111502742ec6SJoerg Sonnenberger 				pf_status.stateid = pf_status.stateid << 32;
111602742ec6SJoerg Sonnenberger 			}
111702742ec6SJoerg Sonnenberger 			DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
111802742ec6SJoerg Sonnenberger 		}
111902742ec6SJoerg Sonnenberger 		break;
112002742ec6SJoerg Sonnenberger 
112102742ec6SJoerg Sonnenberger 	case DIOCSTOP:
112202742ec6SJoerg Sonnenberger 		if (!pf_status.running)
112302742ec6SJoerg Sonnenberger 			error = ENOENT;
112402742ec6SJoerg Sonnenberger 		else {
112502742ec6SJoerg Sonnenberger 			pf_status.running = 0;
112602742ec6SJoerg Sonnenberger 			error = dehook_pf();
112702742ec6SJoerg Sonnenberger 			if (error) {
112802742ec6SJoerg Sonnenberger 				pf_status.running = 1;
112902742ec6SJoerg Sonnenberger 				DPFPRINTF(PF_DEBUG_MISC,
11303f625015SSascha Wildner 					("pf: pfil unregistration failed\n"));
113102742ec6SJoerg Sonnenberger 			}
113202742ec6SJoerg Sonnenberger 			pf_status.since = time_second;
113302742ec6SJoerg Sonnenberger 			DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
113402742ec6SJoerg Sonnenberger 		}
113502742ec6SJoerg Sonnenberger 		break;
113602742ec6SJoerg Sonnenberger 
113702742ec6SJoerg Sonnenberger 	case DIOCADDRULE: {
113802742ec6SJoerg Sonnenberger 		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
113902742ec6SJoerg Sonnenberger 		struct pf_ruleset	*ruleset;
114002742ec6SJoerg Sonnenberger 		struct pf_rule		*rule, *tail;
114102742ec6SJoerg Sonnenberger 		struct pf_pooladdr	*pa;
114202742ec6SJoerg Sonnenberger 		int			 rs_num;
114302742ec6SJoerg Sonnenberger 
114470224baaSJan Lentfer 		pr->anchor[sizeof(pr->anchor) - 1] = 0;
114570224baaSJan Lentfer 		ruleset = pf_find_ruleset(pr->anchor);
114602742ec6SJoerg Sonnenberger 		if (ruleset == NULL) {
114702742ec6SJoerg Sonnenberger 			error = EINVAL;
114802742ec6SJoerg Sonnenberger 			break;
114902742ec6SJoerg Sonnenberger 		}
115002742ec6SJoerg Sonnenberger 		rs_num = pf_get_ruleset_number(pr->rule.action);
115102742ec6SJoerg Sonnenberger 		if (rs_num >= PF_RULESET_MAX) {
115202742ec6SJoerg Sonnenberger 			error = EINVAL;
115302742ec6SJoerg Sonnenberger 			break;
115402742ec6SJoerg Sonnenberger 		}
115502742ec6SJoerg Sonnenberger 		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
115602742ec6SJoerg Sonnenberger 			error = EINVAL;
115702742ec6SJoerg Sonnenberger 			break;
115802742ec6SJoerg Sonnenberger 		}
115902742ec6SJoerg Sonnenberger 		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
116002742ec6SJoerg Sonnenberger 			error = EBUSY;
116102742ec6SJoerg Sonnenberger 			break;
116202742ec6SJoerg Sonnenberger 		}
116302742ec6SJoerg Sonnenberger 		if (pr->pool_ticket != ticket_pabuf) {
116402742ec6SJoerg Sonnenberger 			error = EBUSY;
116502742ec6SJoerg Sonnenberger 			break;
116602742ec6SJoerg Sonnenberger 		}
11671186cbc0SJan Lentfer 		rule = kmalloc(sizeof(struct pf_rule), M_PFRULEPL, M_WAITOK);
116802742ec6SJoerg Sonnenberger 		bcopy(&pr->rule, rule, sizeof(struct pf_rule));
116970224baaSJan Lentfer 		rule->cuid = ap->a_cred->cr_ruid;
11708542fb09SSascha Wildner 		rule->cpid = 0;
117102742ec6SJoerg Sonnenberger 		rule->anchor = NULL;
117202742ec6SJoerg Sonnenberger 		rule->kif = NULL;
117302742ec6SJoerg Sonnenberger 		TAILQ_INIT(&rule->rpool.list);
117402742ec6SJoerg Sonnenberger 		/* initialize refcounting */
1175ed1f0be2SJan Lentfer 		rule->states_cur = 0;
117602742ec6SJoerg Sonnenberger 		rule->src_nodes = 0;
117702742ec6SJoerg Sonnenberger 		rule->entries.tqe_prev = NULL;
117802742ec6SJoerg Sonnenberger #ifndef INET
117902742ec6SJoerg Sonnenberger 		if (rule->af == AF_INET) {
11801186cbc0SJan Lentfer 			kfree(rule, M_PFRULEPL);
118102742ec6SJoerg Sonnenberger 			error = EAFNOSUPPORT;
118202742ec6SJoerg Sonnenberger 			break;
118302742ec6SJoerg Sonnenberger 		}
118402742ec6SJoerg Sonnenberger #endif /* INET */
118502742ec6SJoerg Sonnenberger #ifndef INET6
118602742ec6SJoerg Sonnenberger 		if (rule->af == AF_INET6) {
11871186cbc0SJan Lentfer 			kfree(rule, M_PFRULEPL);
118802742ec6SJoerg Sonnenberger 			error = EAFNOSUPPORT;
118902742ec6SJoerg Sonnenberger 			break;
119002742ec6SJoerg Sonnenberger 		}
119102742ec6SJoerg Sonnenberger #endif /* INET6 */
119202742ec6SJoerg Sonnenberger 		tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
119302742ec6SJoerg Sonnenberger 		    pf_rulequeue);
119402742ec6SJoerg Sonnenberger 		if (tail)
119502742ec6SJoerg Sonnenberger 			rule->nr = tail->nr + 1;
119602742ec6SJoerg Sonnenberger 		else
119702742ec6SJoerg Sonnenberger 			rule->nr = 0;
119802742ec6SJoerg Sonnenberger 		if (rule->ifname[0]) {
119970224baaSJan Lentfer 			rule->kif = pfi_kif_get(rule->ifname);
120002742ec6SJoerg Sonnenberger 			if (rule->kif == NULL) {
12011186cbc0SJan Lentfer 				kfree(rule, M_PFRULEPL);
120202742ec6SJoerg Sonnenberger 				error = EINVAL;
120302742ec6SJoerg Sonnenberger 				break;
120402742ec6SJoerg Sonnenberger 			}
120570224baaSJan Lentfer 			pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
120602742ec6SJoerg Sonnenberger 		}
120702742ec6SJoerg Sonnenberger 
120870224baaSJan Lentfer 		if (rule->rtableid > 0 && rule->rtableid > rt_numfibs)
120970224baaSJan Lentfer 			error = EBUSY;
121070224baaSJan Lentfer 
121102742ec6SJoerg Sonnenberger #ifdef ALTQ
121202742ec6SJoerg Sonnenberger 		/* set queue IDs */
121302742ec6SJoerg Sonnenberger 		if (rule->qname[0] != 0) {
121402742ec6SJoerg Sonnenberger 			if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
121502742ec6SJoerg Sonnenberger 				error = EBUSY;
121602742ec6SJoerg Sonnenberger 			else if (rule->pqname[0] != 0) {
121702742ec6SJoerg Sonnenberger 				if ((rule->pqid =
121802742ec6SJoerg Sonnenberger 				    pf_qname2qid(rule->pqname)) == 0)
121902742ec6SJoerg Sonnenberger 					error = EBUSY;
122002742ec6SJoerg Sonnenberger 			} else
122102742ec6SJoerg Sonnenberger 				rule->pqid = rule->qid;
122202742ec6SJoerg Sonnenberger 		}
122302742ec6SJoerg Sonnenberger #endif
122402742ec6SJoerg Sonnenberger 		if (rule->tagname[0])
122502742ec6SJoerg Sonnenberger 			if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
122602742ec6SJoerg Sonnenberger 				error = EBUSY;
122702742ec6SJoerg Sonnenberger 		if (rule->match_tagname[0])
122802742ec6SJoerg Sonnenberger 			if ((rule->match_tag =
122902742ec6SJoerg Sonnenberger 			    pf_tagname2tag(rule->match_tagname)) == 0)
123002742ec6SJoerg Sonnenberger 				error = EBUSY;
123102742ec6SJoerg Sonnenberger 		if (rule->rt && !rule->direction)
123202742ec6SJoerg Sonnenberger 			error = EINVAL;
123370224baaSJan Lentfer #if NPFLOG > 0
1234315a7da3SJan Lentfer 		if (!rule->log)
1235315a7da3SJan Lentfer 			rule->logif = 0;
123670224baaSJan Lentfer 		if (rule->logif >= PFLOGIFS_MAX)
123770224baaSJan Lentfer 			error = EINVAL;
123870224baaSJan Lentfer #endif
123970224baaSJan Lentfer 		if (pf_rtlabel_add(&rule->src.addr) ||
124070224baaSJan Lentfer 		    pf_rtlabel_add(&rule->dst.addr))
124170224baaSJan Lentfer 			error = EBUSY;
1242ed1f0be2SJan Lentfer 		if (pf_addr_setup(ruleset, &rule->src.addr, rule->af))
124302742ec6SJoerg Sonnenberger 			error = EINVAL;
1244ed1f0be2SJan Lentfer 		if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af))
124502742ec6SJoerg Sonnenberger 			error = EINVAL;
124670224baaSJan Lentfer 		if (pf_anchor_setup(rule, ruleset, pr->anchor_call))
124770224baaSJan Lentfer 			error = EINVAL;
124802742ec6SJoerg Sonnenberger 		TAILQ_FOREACH(pa, &pf_pabuf, entries)
124902742ec6SJoerg Sonnenberger 			if (pf_tbladdr_setup(ruleset, &pa->addr))
125002742ec6SJoerg Sonnenberger 				error = EINVAL;
125102742ec6SJoerg Sonnenberger 
125270224baaSJan Lentfer 		if (rule->overload_tblname[0]) {
125370224baaSJan Lentfer 			if ((rule->overload_tbl = pfr_attach_table(ruleset,
125470224baaSJan Lentfer 			    rule->overload_tblname)) == NULL)
125570224baaSJan Lentfer 				error = EINVAL;
125670224baaSJan Lentfer 			else
125770224baaSJan Lentfer 				rule->overload_tbl->pfrkt_flags |=
125870224baaSJan Lentfer 				    PFR_TFLAG_ACTIVE;
125970224baaSJan Lentfer 		}
126070224baaSJan Lentfer 
126102742ec6SJoerg Sonnenberger 		pf_mv_pool(&pf_pabuf, &rule->rpool.list);
126202742ec6SJoerg Sonnenberger 		if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
126370224baaSJan Lentfer 		    (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
126402742ec6SJoerg Sonnenberger 		    (rule->rt > PF_FASTROUTE)) &&
126502742ec6SJoerg Sonnenberger 		    (TAILQ_FIRST(&rule->rpool.list) == NULL))
126602742ec6SJoerg Sonnenberger 			error = EINVAL;
126702742ec6SJoerg Sonnenberger 
126802742ec6SJoerg Sonnenberger 		if (error) {
126902742ec6SJoerg Sonnenberger 			pf_rm_rule(NULL, rule);
127002742ec6SJoerg Sonnenberger 			break;
127102742ec6SJoerg Sonnenberger 		}
127202742ec6SJoerg Sonnenberger 		rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
127370224baaSJan Lentfer 		rule->evaluations = rule->packets[0] = rule->packets[1] =
127470224baaSJan Lentfer 		    rule->bytes[0] = rule->bytes[1] = 0;
127502742ec6SJoerg Sonnenberger 		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
127602742ec6SJoerg Sonnenberger 		    rule, entries);
127770224baaSJan Lentfer 		ruleset->rules[rs_num].inactive.rcount++;
127802742ec6SJoerg Sonnenberger 		break;
127902742ec6SJoerg Sonnenberger 	}
128002742ec6SJoerg Sonnenberger 
128102742ec6SJoerg Sonnenberger 	case DIOCGETRULES: {
128202742ec6SJoerg Sonnenberger 		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
128302742ec6SJoerg Sonnenberger 		struct pf_ruleset	*ruleset;
128402742ec6SJoerg Sonnenberger 		struct pf_rule		*tail;
128502742ec6SJoerg Sonnenberger 		int			 rs_num;
128602742ec6SJoerg Sonnenberger 
128770224baaSJan Lentfer 		pr->anchor[sizeof(pr->anchor) - 1] = 0;
128870224baaSJan Lentfer 		ruleset = pf_find_ruleset(pr->anchor);
128902742ec6SJoerg Sonnenberger 		if (ruleset == NULL) {
129002742ec6SJoerg Sonnenberger 			error = EINVAL;
129102742ec6SJoerg Sonnenberger 			break;
129202742ec6SJoerg Sonnenberger 		}
129302742ec6SJoerg Sonnenberger 		rs_num = pf_get_ruleset_number(pr->rule.action);
129402742ec6SJoerg Sonnenberger 		if (rs_num >= PF_RULESET_MAX) {
129502742ec6SJoerg Sonnenberger 			error = EINVAL;
129602742ec6SJoerg Sonnenberger 			break;
129702742ec6SJoerg Sonnenberger 		}
129802742ec6SJoerg Sonnenberger 		tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
129902742ec6SJoerg Sonnenberger 		    pf_rulequeue);
130002742ec6SJoerg Sonnenberger 		if (tail)
130102742ec6SJoerg Sonnenberger 			pr->nr = tail->nr + 1;
130202742ec6SJoerg Sonnenberger 		else
130302742ec6SJoerg Sonnenberger 			pr->nr = 0;
130402742ec6SJoerg Sonnenberger 		pr->ticket = ruleset->rules[rs_num].active.ticket;
130502742ec6SJoerg Sonnenberger 		break;
130602742ec6SJoerg Sonnenberger 	}
130702742ec6SJoerg Sonnenberger 
130802742ec6SJoerg Sonnenberger 	case DIOCGETRULE: {
130902742ec6SJoerg Sonnenberger 		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;
131002742ec6SJoerg Sonnenberger 		struct pf_ruleset	*ruleset;
131102742ec6SJoerg Sonnenberger 		struct pf_rule		*rule;
131202742ec6SJoerg Sonnenberger 		int			 rs_num, i;
131302742ec6SJoerg Sonnenberger 
131470224baaSJan Lentfer 		pr->anchor[sizeof(pr->anchor) - 1] = 0;
131570224baaSJan Lentfer 		ruleset = pf_find_ruleset(pr->anchor);
131602742ec6SJoerg Sonnenberger 		if (ruleset == NULL) {
131702742ec6SJoerg Sonnenberger 			error = EINVAL;
131802742ec6SJoerg Sonnenberger 			break;
131902742ec6SJoerg Sonnenberger 		}
132002742ec6SJoerg Sonnenberger 		rs_num = pf_get_ruleset_number(pr->rule.action);
132102742ec6SJoerg Sonnenberger 		if (rs_num >= PF_RULESET_MAX) {
132202742ec6SJoerg Sonnenberger 			error = EINVAL;
132302742ec6SJoerg Sonnenberger 			break;
132402742ec6SJoerg Sonnenberger 		}
132502742ec6SJoerg Sonnenberger 		if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
132602742ec6SJoerg Sonnenberger 			error = EBUSY;
132702742ec6SJoerg Sonnenberger 			break;
132802742ec6SJoerg Sonnenberger 		}
132902742ec6SJoerg Sonnenberger 		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
133002742ec6SJoerg Sonnenberger 		while ((rule != NULL) && (rule->nr != pr->nr))
133102742ec6SJoerg Sonnenberger 			rule = TAILQ_NEXT(rule, entries);
133202742ec6SJoerg Sonnenberger 		if (rule == NULL) {
133302742ec6SJoerg Sonnenberger 			error = EBUSY;
133402742ec6SJoerg Sonnenberger 			break;
133502742ec6SJoerg Sonnenberger 		}
133602742ec6SJoerg Sonnenberger 		bcopy(rule, &pr->rule, sizeof(struct pf_rule));
133770224baaSJan Lentfer 		if (pf_anchor_copyout(ruleset, rule, pr)) {
133870224baaSJan Lentfer 			error = EBUSY;
133970224baaSJan Lentfer 			break;
134070224baaSJan Lentfer 		}
1341ed1f0be2SJan Lentfer 		pf_addr_copyout(&pr->rule.src.addr);
1342ed1f0be2SJan Lentfer 		pf_addr_copyout(&pr->rule.dst.addr);
134302742ec6SJoerg Sonnenberger 		for (i = 0; i < PF_SKIP_COUNT; ++i)
134402742ec6SJoerg Sonnenberger 			if (rule->skip[i].ptr == NULL)
134533040f9eSJoerg Sonnenberger 				pr->rule.skip[i].nr = (uint32_t)(-1);
134602742ec6SJoerg Sonnenberger 			else
134702742ec6SJoerg Sonnenberger 				pr->rule.skip[i].nr =
134802742ec6SJoerg Sonnenberger 				    rule->skip[i].ptr->nr;
134970224baaSJan Lentfer 
135070224baaSJan Lentfer 		if (pr->action == PF_GET_CLR_CNTR) {
135170224baaSJan Lentfer 			rule->evaluations = 0;
135270224baaSJan Lentfer 			rule->packets[0] = rule->packets[1] = 0;
135370224baaSJan Lentfer 			rule->bytes[0] = rule->bytes[1] = 0;
1354ed1f0be2SJan Lentfer 			rule->states_tot = 0;
135570224baaSJan Lentfer 		}
135602742ec6SJoerg Sonnenberger 		break;
135702742ec6SJoerg Sonnenberger 	}
135802742ec6SJoerg Sonnenberger 
135902742ec6SJoerg Sonnenberger 	case DIOCCHANGERULE: {
136002742ec6SJoerg Sonnenberger 		struct pfioc_rule	*pcr = (struct pfioc_rule *)addr;
136102742ec6SJoerg Sonnenberger 		struct pf_ruleset	*ruleset;
136202742ec6SJoerg Sonnenberger 		struct pf_rule		*oldrule = NULL, *newrule = NULL;
136302742ec6SJoerg Sonnenberger 		u_int32_t		 nr = 0;
136402742ec6SJoerg Sonnenberger 		int			 rs_num;
136502742ec6SJoerg Sonnenberger 
136602742ec6SJoerg Sonnenberger 		if (!(pcr->action == PF_CHANGE_REMOVE ||
136702742ec6SJoerg Sonnenberger 		    pcr->action == PF_CHANGE_GET_TICKET) &&
136802742ec6SJoerg Sonnenberger 		    pcr->pool_ticket != ticket_pabuf) {
136902742ec6SJoerg Sonnenberger 			error = EBUSY;
137002742ec6SJoerg Sonnenberger 			break;
137102742ec6SJoerg Sonnenberger 		}
137202742ec6SJoerg Sonnenberger 
137302742ec6SJoerg Sonnenberger 		if (pcr->action < PF_CHANGE_ADD_HEAD ||
137402742ec6SJoerg Sonnenberger 		    pcr->action > PF_CHANGE_GET_TICKET) {
137502742ec6SJoerg Sonnenberger 			error = EINVAL;
137602742ec6SJoerg Sonnenberger 			break;
137702742ec6SJoerg Sonnenberger 		}
137870224baaSJan Lentfer 		ruleset = pf_find_ruleset(pcr->anchor);
137902742ec6SJoerg Sonnenberger 		if (ruleset == NULL) {
138002742ec6SJoerg Sonnenberger 			error = EINVAL;
138102742ec6SJoerg Sonnenberger 			break;
138202742ec6SJoerg Sonnenberger 		}
138302742ec6SJoerg Sonnenberger 		rs_num = pf_get_ruleset_number(pcr->rule.action);
138402742ec6SJoerg Sonnenberger 		if (rs_num >= PF_RULESET_MAX) {
138502742ec6SJoerg Sonnenberger 			error = EINVAL;
138602742ec6SJoerg Sonnenberger 			break;
138702742ec6SJoerg Sonnenberger 		}
138802742ec6SJoerg Sonnenberger 
138902742ec6SJoerg Sonnenberger 		if (pcr->action == PF_CHANGE_GET_TICKET) {
139002742ec6SJoerg Sonnenberger 			pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
139102742ec6SJoerg Sonnenberger 			break;
139202742ec6SJoerg Sonnenberger 		} else {
139302742ec6SJoerg Sonnenberger 			if (pcr->ticket !=
139402742ec6SJoerg Sonnenberger 			    ruleset->rules[rs_num].active.ticket) {
139502742ec6SJoerg Sonnenberger 				error = EINVAL;
139602742ec6SJoerg Sonnenberger 				break;
139702742ec6SJoerg Sonnenberger 			}
139802742ec6SJoerg Sonnenberger 			if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
139902742ec6SJoerg Sonnenberger 				error = EINVAL;
140002742ec6SJoerg Sonnenberger 				break;
140102742ec6SJoerg Sonnenberger 			}
140202742ec6SJoerg Sonnenberger 		}
140302742ec6SJoerg Sonnenberger 
140402742ec6SJoerg Sonnenberger 		if (pcr->action != PF_CHANGE_REMOVE) {
14051186cbc0SJan Lentfer 			newrule = kmalloc(sizeof(struct pf_rule), M_PFRULEPL, M_WAITOK|M_NULLOK);
140602742ec6SJoerg Sonnenberger 			if (newrule == NULL) {
140702742ec6SJoerg Sonnenberger 				error = ENOMEM;
140802742ec6SJoerg Sonnenberger 				break;
140902742ec6SJoerg Sonnenberger 			}
141002742ec6SJoerg Sonnenberger 			bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
141170224baaSJan Lentfer 			newrule->cuid = ap->a_cred->cr_ruid;
14128542fb09SSascha Wildner 			newrule->cpid = 0;
141302742ec6SJoerg Sonnenberger 			TAILQ_INIT(&newrule->rpool.list);
141402742ec6SJoerg Sonnenberger 			/* initialize refcounting */
1415ed1f0be2SJan Lentfer 			newrule->states_cur = 0;
141602742ec6SJoerg Sonnenberger 			newrule->entries.tqe_prev = NULL;
141702742ec6SJoerg Sonnenberger #ifndef INET
141802742ec6SJoerg Sonnenberger 			if (newrule->af == AF_INET) {
14191186cbc0SJan Lentfer 				kfree(newrule, M_PFRULEPL);
142002742ec6SJoerg Sonnenberger 				error = EAFNOSUPPORT;
142102742ec6SJoerg Sonnenberger 				break;
142202742ec6SJoerg Sonnenberger 			}
142302742ec6SJoerg Sonnenberger #endif /* INET */
142402742ec6SJoerg Sonnenberger #ifndef INET6
142502742ec6SJoerg Sonnenberger 			if (newrule->af == AF_INET6) {
14261186cbc0SJan Lentfer 				kfree(newrule, M_PFRULEPL);
142702742ec6SJoerg Sonnenberger 				error = EAFNOSUPPORT;
142802742ec6SJoerg Sonnenberger 				break;
142902742ec6SJoerg Sonnenberger 			}
143002742ec6SJoerg Sonnenberger #endif /* INET6 */
143102742ec6SJoerg Sonnenberger 			if (newrule->ifname[0]) {
143270224baaSJan Lentfer 				newrule->kif = pfi_kif_get(newrule->ifname);
143302742ec6SJoerg Sonnenberger 				if (newrule->kif == NULL) {
14341186cbc0SJan Lentfer 					kfree(newrule, M_PFRULEPL);
143502742ec6SJoerg Sonnenberger 					error = EINVAL;
143602742ec6SJoerg Sonnenberger 					break;
143702742ec6SJoerg Sonnenberger 				}
143870224baaSJan Lentfer 				pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
143902742ec6SJoerg Sonnenberger 			} else
144002742ec6SJoerg Sonnenberger 				newrule->kif = NULL;
144102742ec6SJoerg Sonnenberger 
144270224baaSJan Lentfer 			if (newrule->rtableid > 0 &&
144370224baaSJan Lentfer 			    newrule->rtableid > rt_numfibs)
144470224baaSJan Lentfer 				error = EBUSY;
144570224baaSJan Lentfer 
144602742ec6SJoerg Sonnenberger #ifdef ALTQ
144702742ec6SJoerg Sonnenberger 			/* set queue IDs */
144802742ec6SJoerg Sonnenberger 			if (newrule->qname[0] != 0) {
144902742ec6SJoerg Sonnenberger 				if ((newrule->qid =
145002742ec6SJoerg Sonnenberger 				    pf_qname2qid(newrule->qname)) == 0)
145102742ec6SJoerg Sonnenberger 					error = EBUSY;
145202742ec6SJoerg Sonnenberger 				else if (newrule->pqname[0] != 0) {
145302742ec6SJoerg Sonnenberger 					if ((newrule->pqid =
145402742ec6SJoerg Sonnenberger 					    pf_qname2qid(newrule->pqname)) == 0)
145502742ec6SJoerg Sonnenberger 						error = EBUSY;
145602742ec6SJoerg Sonnenberger 				} else
145702742ec6SJoerg Sonnenberger 					newrule->pqid = newrule->qid;
145802742ec6SJoerg Sonnenberger 			}
145970224baaSJan Lentfer #endif /* ALTQ */
146002742ec6SJoerg Sonnenberger 			if (newrule->tagname[0])
146102742ec6SJoerg Sonnenberger 				if ((newrule->tag =
146202742ec6SJoerg Sonnenberger 				    pf_tagname2tag(newrule->tagname)) == 0)
146302742ec6SJoerg Sonnenberger 					error = EBUSY;
146402742ec6SJoerg Sonnenberger 			if (newrule->match_tagname[0])
146502742ec6SJoerg Sonnenberger 				if ((newrule->match_tag = pf_tagname2tag(
146602742ec6SJoerg Sonnenberger 				    newrule->match_tagname)) == 0)
146702742ec6SJoerg Sonnenberger 					error = EBUSY;
146802742ec6SJoerg Sonnenberger 			if (newrule->rt && !newrule->direction)
146902742ec6SJoerg Sonnenberger 				error = EINVAL;
1470315a7da3SJan Lentfer #if NPFLOG > 0
1471315a7da3SJan Lentfer 			if (!newrule->log)
1472315a7da3SJan Lentfer 				newrule->logif = 0;
1473315a7da3SJan Lentfer 			if (newrule->logif >= PFLOGIFS_MAX)
1474315a7da3SJan Lentfer 				error = EINVAL;
1475315a7da3SJan Lentfer #endif
147670224baaSJan Lentfer 			if (pf_rtlabel_add(&newrule->src.addr) ||
147770224baaSJan Lentfer 			    pf_rtlabel_add(&newrule->dst.addr))
147870224baaSJan Lentfer 				error = EBUSY;
1479ed1f0be2SJan Lentfer 			if (pf_addr_setup(ruleset, &newrule->src.addr, newrule->af))
148002742ec6SJoerg Sonnenberger 				error = EINVAL;
1481ed1f0be2SJan Lentfer 			if (pf_addr_setup(ruleset, &newrule->dst.addr, newrule->af))
148202742ec6SJoerg Sonnenberger 				error = EINVAL;
148370224baaSJan Lentfer 			if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call))
148470224baaSJan Lentfer 				error = EINVAL;
148570224baaSJan Lentfer 			TAILQ_FOREACH(pa, &pf_pabuf, entries)
148670224baaSJan Lentfer 				if (pf_tbladdr_setup(ruleset, &pa->addr))
148770224baaSJan Lentfer 					error = EINVAL;
148870224baaSJan Lentfer 
148970224baaSJan Lentfer 			if (newrule->overload_tblname[0]) {
149070224baaSJan Lentfer 				if ((newrule->overload_tbl = pfr_attach_table(
149170224baaSJan Lentfer 				    ruleset, newrule->overload_tblname)) ==
149270224baaSJan Lentfer 				    NULL)
149370224baaSJan Lentfer 					error = EINVAL;
149470224baaSJan Lentfer 				else
149570224baaSJan Lentfer 					newrule->overload_tbl->pfrkt_flags |=
149670224baaSJan Lentfer 					    PFR_TFLAG_ACTIVE;
149770224baaSJan Lentfer 			}
149802742ec6SJoerg Sonnenberger 
149902742ec6SJoerg Sonnenberger 			pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
150002742ec6SJoerg Sonnenberger 			if (((((newrule->action == PF_NAT) ||
150102742ec6SJoerg Sonnenberger 			    (newrule->action == PF_RDR) ||
150202742ec6SJoerg Sonnenberger 			    (newrule->action == PF_BINAT) ||
150302742ec6SJoerg Sonnenberger 			    (newrule->rt > PF_FASTROUTE)) &&
150470224baaSJan Lentfer 			    !newrule->anchor)) &&
150502742ec6SJoerg Sonnenberger 			    (TAILQ_FIRST(&newrule->rpool.list) == NULL))
150602742ec6SJoerg Sonnenberger 				error = EINVAL;
150702742ec6SJoerg Sonnenberger 
150802742ec6SJoerg Sonnenberger 			if (error) {
150902742ec6SJoerg Sonnenberger 				pf_rm_rule(NULL, newrule);
151002742ec6SJoerg Sonnenberger 				break;
151102742ec6SJoerg Sonnenberger 			}
151202742ec6SJoerg Sonnenberger 			newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
151370224baaSJan Lentfer 			newrule->evaluations = 0;
151470224baaSJan Lentfer 			newrule->packets[0] = newrule->packets[1] = 0;
151570224baaSJan Lentfer 			newrule->bytes[0] = newrule->bytes[1] = 0;
151602742ec6SJoerg Sonnenberger 		}
151702742ec6SJoerg Sonnenberger 		pf_empty_pool(&pf_pabuf);
151802742ec6SJoerg Sonnenberger 
151902742ec6SJoerg Sonnenberger 		if (pcr->action == PF_CHANGE_ADD_HEAD)
152002742ec6SJoerg Sonnenberger 			oldrule = TAILQ_FIRST(
152102742ec6SJoerg Sonnenberger 			    ruleset->rules[rs_num].active.ptr);
152202742ec6SJoerg Sonnenberger 		else if (pcr->action == PF_CHANGE_ADD_TAIL)
152302742ec6SJoerg Sonnenberger 			oldrule = TAILQ_LAST(
152402742ec6SJoerg Sonnenberger 			    ruleset->rules[rs_num].active.ptr, pf_rulequeue);
152502742ec6SJoerg Sonnenberger 		else {
152602742ec6SJoerg Sonnenberger 			oldrule = TAILQ_FIRST(
152702742ec6SJoerg Sonnenberger 			    ruleset->rules[rs_num].active.ptr);
152802742ec6SJoerg Sonnenberger 			while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
152902742ec6SJoerg Sonnenberger 				oldrule = TAILQ_NEXT(oldrule, entries);
153002742ec6SJoerg Sonnenberger 			if (oldrule == NULL) {
153170224baaSJan Lentfer 				if (newrule != NULL)
153202742ec6SJoerg Sonnenberger 					pf_rm_rule(NULL, newrule);
153302742ec6SJoerg Sonnenberger 				error = EINVAL;
153402742ec6SJoerg Sonnenberger 				break;
153502742ec6SJoerg Sonnenberger 			}
153602742ec6SJoerg Sonnenberger 		}
153702742ec6SJoerg Sonnenberger 
153870224baaSJan Lentfer 		if (pcr->action == PF_CHANGE_REMOVE) {
153902742ec6SJoerg Sonnenberger 			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
154070224baaSJan Lentfer 			ruleset->rules[rs_num].active.rcount--;
154170224baaSJan Lentfer 		} else {
154202742ec6SJoerg Sonnenberger 			if (oldrule == NULL)
154302742ec6SJoerg Sonnenberger 				TAILQ_INSERT_TAIL(
154402742ec6SJoerg Sonnenberger 				    ruleset->rules[rs_num].active.ptr,
154502742ec6SJoerg Sonnenberger 				    newrule, entries);
154602742ec6SJoerg Sonnenberger 			else if (pcr->action == PF_CHANGE_ADD_HEAD ||
154702742ec6SJoerg Sonnenberger 			    pcr->action == PF_CHANGE_ADD_BEFORE)
154802742ec6SJoerg Sonnenberger 				TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
154902742ec6SJoerg Sonnenberger 			else
155002742ec6SJoerg Sonnenberger 				TAILQ_INSERT_AFTER(
155102742ec6SJoerg Sonnenberger 				    ruleset->rules[rs_num].active.ptr,
155202742ec6SJoerg Sonnenberger 				    oldrule, newrule, entries);
155370224baaSJan Lentfer 			ruleset->rules[rs_num].active.rcount++;
155402742ec6SJoerg Sonnenberger 		}
155502742ec6SJoerg Sonnenberger 
155602742ec6SJoerg Sonnenberger 		nr = 0;
155702742ec6SJoerg Sonnenberger 		TAILQ_FOREACH(oldrule,
155802742ec6SJoerg Sonnenberger 		    ruleset->rules[rs_num].active.ptr, entries)
155902742ec6SJoerg Sonnenberger 			oldrule->nr = nr++;
156002742ec6SJoerg Sonnenberger 
156170224baaSJan Lentfer 		ruleset->rules[rs_num].active.ticket++;
156270224baaSJan Lentfer 
156302742ec6SJoerg Sonnenberger 		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
156402742ec6SJoerg Sonnenberger 		pf_remove_if_empty_ruleset(ruleset);
156502742ec6SJoerg Sonnenberger 
156602742ec6SJoerg Sonnenberger 		break;
156702742ec6SJoerg Sonnenberger 	}
156802742ec6SJoerg Sonnenberger 
156902742ec6SJoerg Sonnenberger 	case DIOCCLRSTATES: {
1570315a7da3SJan Lentfer 		struct pf_state		*s, *nexts;
157102742ec6SJoerg Sonnenberger 		struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
1572ed1f0be2SJan Lentfer 		u_int			 killed = 0;
15733a0038bfSMatthew Dillon 		globaldata_t save_gd = mycpu;
15743a0038bfSMatthew Dillon 		int nn;
157502742ec6SJoerg Sonnenberger 
15763a0038bfSMatthew Dillon 		for (nn = 0; nn < ncpus; ++nn) {
15773a0038bfSMatthew Dillon 			lwkt_setcpu_self(globaldata_find(nn));
15783a0038bfSMatthew Dillon 			for (s = RB_MIN(pf_state_tree_id, &tree_id[nn]);
15793a0038bfSMatthew Dillon 			     s; s = nexts) {
15803a0038bfSMatthew Dillon 				nexts = RB_NEXT(pf_state_tree_id,
15813a0038bfSMatthew Dillon 						&tree_id[nn], s);
158270224baaSJan Lentfer 
15833a0038bfSMatthew Dillon 				if (!psk->psk_ifname[0] ||
15843a0038bfSMatthew Dillon 				    !strcmp(psk->psk_ifname,
1585315a7da3SJan Lentfer 					    s->kif->pfik_name)) {
15863a0038bfSMatthew Dillon 					/*
15873a0038bfSMatthew Dillon 					 * don't send out individual
15883a0038bfSMatthew Dillon 					 * delete messages
15893a0038bfSMatthew Dillon 					 */
1590315a7da3SJan Lentfer 					s->sync_flags = PFSTATE_NOSYNC;
1591315a7da3SJan Lentfer 					pf_unlink_state(s);
159202742ec6SJoerg Sonnenberger 					killed++;
159302742ec6SJoerg Sonnenberger 				}
159402742ec6SJoerg Sonnenberger 			}
15953a0038bfSMatthew Dillon 		}
15963a0038bfSMatthew Dillon 		lwkt_setcpu_self(save_gd);
1597ed1f0be2SJan Lentfer 		psk->psk_killed = killed;
159802742ec6SJoerg Sonnenberger 		pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
159902742ec6SJoerg Sonnenberger 		break;
160002742ec6SJoerg Sonnenberger 	}
160102742ec6SJoerg Sonnenberger 
160202742ec6SJoerg Sonnenberger 	case DIOCKILLSTATES: {
1603315a7da3SJan Lentfer 		struct pf_state		*s, *nexts;
1604315a7da3SJan Lentfer 		struct pf_state_key	*sk;
1605ed1f0be2SJan Lentfer 		struct pf_addr		*srcaddr, *dstaddr;
1606ed1f0be2SJan Lentfer 		u_int16_t		 srcport, dstport;
160702742ec6SJoerg Sonnenberger 		struct pfioc_state_kill	*psk = (struct pfioc_state_kill *)addr;
1608ed1f0be2SJan Lentfer 		u_int			 killed = 0;
16093a0038bfSMatthew Dillon 		globaldata_t save_gd = mycpu;
16103a0038bfSMatthew Dillon 		int nn;
1611ed1f0be2SJan Lentfer 
1612ed1f0be2SJan Lentfer 		if (psk->psk_pfcmp.id) {
1613ed1f0be2SJan Lentfer 			if (psk->psk_pfcmp.creatorid == 0)
1614ed1f0be2SJan Lentfer 				psk->psk_pfcmp.creatorid = pf_status.hostid;
16153a0038bfSMatthew Dillon 			for (nn = 0; nn < ncpus; ++nn) {
16163a0038bfSMatthew Dillon 				lwkt_setcpu_self(globaldata_find(nn));
1617ed1f0be2SJan Lentfer 				if ((s = pf_find_state_byid(&psk->psk_pfcmp))) {
1618ed1f0be2SJan Lentfer 					/* send immediate delete of state */
1619ed1f0be2SJan Lentfer 					pfsync_delete_state(s);
1620ed1f0be2SJan Lentfer 					s->sync_flags |= PFSTATE_NOSYNC;
1621ed1f0be2SJan Lentfer 					pf_unlink_state(s);
16223a0038bfSMatthew Dillon 					++psk->psk_killed;
1623ed1f0be2SJan Lentfer 				}
16243a0038bfSMatthew Dillon 			}
16253a0038bfSMatthew Dillon 			lwkt_setcpu_self(save_gd);
1626ed1f0be2SJan Lentfer 			break;
1627ed1f0be2SJan Lentfer 		}
162802742ec6SJoerg Sonnenberger 
16293a0038bfSMatthew Dillon 		for (nn = 0; nn < ncpus; ++nn) {
16303a0038bfSMatthew Dillon 		    lwkt_setcpu_self(globaldata_find(nn));
16313a0038bfSMatthew Dillon 		    for (s = RB_MIN(pf_state_tree_id, &tree_id[nn]);
16323a0038bfSMatthew Dillon 			 s; s = nexts) {
16333a0038bfSMatthew Dillon 			    nexts = RB_NEXT(pf_state_tree_id, &tree_id[nn], s);
1634ed1f0be2SJan Lentfer 			    sk = s->key[PF_SK_WIRE];
163570224baaSJan Lentfer 
1636ed1f0be2SJan Lentfer 			    if (s->direction == PF_OUT) {
1637ed1f0be2SJan Lentfer 				    srcaddr = &sk->addr[1];
1638ed1f0be2SJan Lentfer 				    dstaddr = &sk->addr[0];
1639ed1f0be2SJan Lentfer 				    srcport = sk->port[0];
1640ed1f0be2SJan Lentfer 				    dstport = sk->port[0];
164170224baaSJan Lentfer 			    } else {
1642ed1f0be2SJan Lentfer 				    srcaddr = &sk->addr[0];
1643ed1f0be2SJan Lentfer 				    dstaddr = &sk->addr[1];
1644ed1f0be2SJan Lentfer 				    srcport = sk->port[0];
1645ed1f0be2SJan Lentfer 				    dstport = sk->port[0];
164670224baaSJan Lentfer 			    }
1647315a7da3SJan Lentfer 			    if ((!psk->psk_af || sk->af == psk->psk_af)
164802742ec6SJoerg Sonnenberger 				&& (!psk->psk_proto || psk->psk_proto ==
1649315a7da3SJan Lentfer 						       sk->proto) &&
165070224baaSJan Lentfer 				PF_MATCHA(psk->psk_src.neg,
165102742ec6SJoerg Sonnenberger 					  &psk->psk_src.addr.v.a.addr,
165202742ec6SJoerg Sonnenberger 					  &psk->psk_src.addr.v.a.mask,
1653ed1f0be2SJan Lentfer 					  srcaddr, sk->af) &&
165470224baaSJan Lentfer 				PF_MATCHA(psk->psk_dst.neg,
165502742ec6SJoerg Sonnenberger 					  &psk->psk_dst.addr.v.a.addr,
165602742ec6SJoerg Sonnenberger 					  &psk->psk_dst.addr.v.a.mask,
1657ed1f0be2SJan Lentfer 					  dstaddr, sk->af) &&
165802742ec6SJoerg Sonnenberger 				(psk->psk_src.port_op == 0 ||
165902742ec6SJoerg Sonnenberger 				 pf_match_port(psk->psk_src.port_op,
16603a0038bfSMatthew Dillon 					       psk->psk_src.port[0],
16613a0038bfSMatthew Dillon 					       psk->psk_src.port[1],
1662ed1f0be2SJan Lentfer 					       srcport)) &&
166302742ec6SJoerg Sonnenberger 				(psk->psk_dst.port_op == 0 ||
166402742ec6SJoerg Sonnenberger 				 pf_match_port(psk->psk_dst.port_op,
16653a0038bfSMatthew Dillon 					       psk->psk_dst.port[0],
16663a0038bfSMatthew Dillon 					       psk->psk_dst.port[1],
1667ed1f0be2SJan Lentfer 					       dstport)) &&
16683a0038bfSMatthew Dillon 				(!psk->psk_label[0] ||
16693a0038bfSMatthew Dillon 				 (s->rule.ptr->label[0] &&
1670ed1f0be2SJan Lentfer 				  !strcmp(psk->psk_label, s->rule.ptr->label))) &&
16713a0038bfSMatthew Dillon 				(!psk->psk_ifname[0] ||
16723a0038bfSMatthew Dillon 				 !strcmp(psk->psk_ifname, s->kif->pfik_name))) {
167370224baaSJan Lentfer 				    /* send immediate delete of state */
1674315a7da3SJan Lentfer 				    pfsync_delete_state(s);
1675315a7da3SJan Lentfer 				    s->sync_flags |= PFSTATE_NOSYNC;
1676315a7da3SJan Lentfer 				    pf_unlink_state(s);
167702742ec6SJoerg Sonnenberger 				    killed++;
167802742ec6SJoerg Sonnenberger 			    }
167902742ec6SJoerg Sonnenberger 		    }
16803a0038bfSMatthew Dillon 		}
16813a0038bfSMatthew Dillon 		lwkt_setcpu_self(save_gd);
1682ed1f0be2SJan Lentfer 		psk->psk_killed = killed;
168302742ec6SJoerg Sonnenberger 		break;
168402742ec6SJoerg Sonnenberger 	}
168502742ec6SJoerg Sonnenberger 
168602742ec6SJoerg Sonnenberger 	case DIOCADDSTATE: {
168702742ec6SJoerg Sonnenberger 		struct pfioc_state	*ps = (struct pfioc_state *)addr;
1688ed1f0be2SJan Lentfer 		struct pfsync_state	*sp = &ps->state;
168902742ec6SJoerg Sonnenberger 
1690315a7da3SJan Lentfer 		if (sp->timeout >= PFTM_MAX &&
1691315a7da3SJan Lentfer 		    sp->timeout != PFTM_UNTIL_PACKET) {
169202742ec6SJoerg Sonnenberger 			error = EINVAL;
169302742ec6SJoerg Sonnenberger 			break;
169402742ec6SJoerg Sonnenberger 		}
1695ed1f0be2SJan Lentfer 		error = pfsync_state_import(sp, PFSYNC_SI_IOCTL);
169602742ec6SJoerg Sonnenberger 		break;
169702742ec6SJoerg Sonnenberger 	}
169802742ec6SJoerg Sonnenberger 
169902742ec6SJoerg Sonnenberger 	case DIOCGETSTATE: {
170002742ec6SJoerg Sonnenberger 		struct pfioc_state	*ps = (struct pfioc_state *)addr;
1701315a7da3SJan Lentfer 		struct pf_state		*s;
1702ed1f0be2SJan Lentfer 		struct pf_state_cmp	 id_key;
17033a0038bfSMatthew Dillon 		globaldata_t save_gd = mycpu;
17043a0038bfSMatthew Dillon 		int nn;
170502742ec6SJoerg Sonnenberger 
1706ed1f0be2SJan Lentfer 		bcopy(ps->state.id, &id_key.id, sizeof(id_key.id));
1707ed1f0be2SJan Lentfer 		id_key.creatorid = ps->state.creatorid;
17083a0038bfSMatthew Dillon 		s = NULL;
17093a0038bfSMatthew Dillon 		for (nn = 0; nn < ncpus; ++nn) {
17103a0038bfSMatthew Dillon 			lwkt_setcpu_self(globaldata_find(nn));
1711ed1f0be2SJan Lentfer 			s = pf_find_state_byid(&id_key);
17123a0038bfSMatthew Dillon 			if (s)
171302742ec6SJoerg Sonnenberger 				break;
171402742ec6SJoerg Sonnenberger 		}
17153a0038bfSMatthew Dillon 		if (s) {
1716ed1f0be2SJan Lentfer 			pfsync_state_export(&ps->state, s);
17173a0038bfSMatthew Dillon 		} else {
17183a0038bfSMatthew Dillon 			error = ENOENT;
17193a0038bfSMatthew Dillon 		}
17203a0038bfSMatthew Dillon 		lwkt_setcpu_self(save_gd);
172102742ec6SJoerg Sonnenberger 		break;
172202742ec6SJoerg Sonnenberger 	}
172302742ec6SJoerg Sonnenberger 
172402742ec6SJoerg Sonnenberger 	case DIOCGETSTATES: {
172502742ec6SJoerg Sonnenberger 		struct pfioc_states	*ps = (struct pfioc_states *)addr;
172602742ec6SJoerg Sonnenberger 		struct pf_state		*state;
1727315a7da3SJan Lentfer 		struct pfsync_state	*p, *pstore;
172802742ec6SJoerg Sonnenberger 		u_int32_t		 nr = 0;
17293a0038bfSMatthew Dillon 		globaldata_t save_gd = mycpu;
17303a0038bfSMatthew Dillon 		int nn;
173102742ec6SJoerg Sonnenberger 
1732315a7da3SJan Lentfer 		if (ps->ps_len == 0) {
173370224baaSJan Lentfer 			nr = pf_status.states;
1734315a7da3SJan Lentfer 			ps->ps_len = sizeof(struct pfsync_state) * nr;
173570224baaSJan Lentfer 			break;
173602742ec6SJoerg Sonnenberger 		}
173702742ec6SJoerg Sonnenberger 
173870224baaSJan Lentfer 		pstore = kmalloc(sizeof(*pstore), M_TEMP, M_WAITOK);
173970224baaSJan Lentfer 
174002742ec6SJoerg Sonnenberger 		p = ps->ps_states;
174170224baaSJan Lentfer 
17423a0038bfSMatthew Dillon 		for (nn = 0; nn < ncpus; ++nn) {
17433a0038bfSMatthew Dillon 			lwkt_setcpu_self(globaldata_find(nn));
17443a0038bfSMatthew Dillon 			state = TAILQ_FIRST(&state_list[nn]);
174570224baaSJan Lentfer 			while (state) {
174670224baaSJan Lentfer 				if (state->timeout != PFTM_UNLINKED) {
17473a0038bfSMatthew Dillon 					if ((nr + 1) * sizeof(*p) >
17483a0038bfSMatthew Dillon 					    (unsigned)ps->ps_len) {
174902742ec6SJoerg Sonnenberger 						break;
17503a0038bfSMatthew Dillon 					}
1751ed1f0be2SJan Lentfer 					pfsync_state_export(pstore, state);
175270224baaSJan Lentfer 					error = copyout(pstore, p, sizeof(*p));
175302742ec6SJoerg Sonnenberger 					if (error) {
175470224baaSJan Lentfer 						kfree(pstore, M_TEMP);
17553a0038bfSMatthew Dillon 						lwkt_setcpu_self(save_gd);
175602742ec6SJoerg Sonnenberger 						goto fail;
175702742ec6SJoerg Sonnenberger 					}
175802742ec6SJoerg Sonnenberger 					p++;
175902742ec6SJoerg Sonnenberger 					nr++;
176002742ec6SJoerg Sonnenberger 				}
1761315a7da3SJan Lentfer 				state = TAILQ_NEXT(state, entry_list);
176270224baaSJan Lentfer 			}
17633a0038bfSMatthew Dillon 		}
17643a0038bfSMatthew Dillon 		lwkt_setcpu_self(save_gd);
1765315a7da3SJan Lentfer 		ps->ps_len = sizeof(struct pfsync_state) * nr;
176670224baaSJan Lentfer 		kfree(pstore, M_TEMP);
176702742ec6SJoerg Sonnenberger 		break;
176802742ec6SJoerg Sonnenberger 	}
176902742ec6SJoerg Sonnenberger 
177002742ec6SJoerg Sonnenberger 	case DIOCGETSTATUS: {
1771f7c73ea6SMatthew Dillon 		/*
1772f7c73ea6SMatthew Dillon 		 * Retrieve pf_status, merge pcpu counters into pf_status
1773f7c73ea6SMatthew Dillon 		 * for user consumption.
1774f7c73ea6SMatthew Dillon 		 */
177502742ec6SJoerg Sonnenberger 		struct pf_status *s = (struct pf_status *)addr;
1776f7c73ea6SMatthew Dillon 		struct pf_counters *pfc;
1777f7c73ea6SMatthew Dillon 		int n;
1778f7c73ea6SMatthew Dillon 		int i;
1779f7c73ea6SMatthew Dillon 
178002742ec6SJoerg Sonnenberger 		bcopy(&pf_status, s, sizeof(struct pf_status));
1781f7c73ea6SMatthew Dillon 		for (n = 0; n < ncpus; ++n) {
1782f7c73ea6SMatthew Dillon 			pfc = &pf_counters[n];
1783f7c73ea6SMatthew Dillon 			for (i = 0; i < PFRES_MAX; ++i)
1784f7c73ea6SMatthew Dillon 				s->counters[i] += pfc->counters[i];
1785f7c73ea6SMatthew Dillon 			for (i = 0; i < LCNT_MAX; ++i)
1786f7c73ea6SMatthew Dillon 				s->lcounters[i] += pfc->lcounters[i];
1787f7c73ea6SMatthew Dillon 			for (i = 0; i < FCNT_MAX; ++i)
1788f7c73ea6SMatthew Dillon 				s->fcounters[i] += pfc->fcounters[i];
1789f7c73ea6SMatthew Dillon 			for (i = 0; i < SCNT_MAX; ++i)
1790f7c73ea6SMatthew Dillon 				s->scounters[i] += pfc->scounters[i];
1791f7c73ea6SMatthew Dillon 		}
1792ed1f0be2SJan Lentfer 		pfi_update_status(s->ifname, s);
179302742ec6SJoerg Sonnenberger 		break;
179402742ec6SJoerg Sonnenberger 	}
179502742ec6SJoerg Sonnenberger 
179602742ec6SJoerg Sonnenberger 	case DIOCSETSTATUSIF: {
179702742ec6SJoerg Sonnenberger 		struct pfioc_if	*pi = (struct pfioc_if *)addr;
179802742ec6SJoerg Sonnenberger 
179902742ec6SJoerg Sonnenberger 		if (pi->ifname[0] == 0) {
180002742ec6SJoerg Sonnenberger 			bzero(pf_status.ifname, IFNAMSIZ);
180102742ec6SJoerg Sonnenberger 			break;
180202742ec6SJoerg Sonnenberger 		}
180302742ec6SJoerg Sonnenberger 		strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ);
180402742ec6SJoerg Sonnenberger 		break;
180502742ec6SJoerg Sonnenberger 	}
180602742ec6SJoerg Sonnenberger 
180702742ec6SJoerg Sonnenberger 	case DIOCCLRSTATUS: {
1808f7c73ea6SMatthew Dillon 		int i;
1809f7c73ea6SMatthew Dillon 
181002742ec6SJoerg Sonnenberger 		bzero(pf_status.counters, sizeof(pf_status.counters));
181102742ec6SJoerg Sonnenberger 		bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
181202742ec6SJoerg Sonnenberger 		bzero(pf_status.scounters, sizeof(pf_status.scounters));
1813f7c73ea6SMatthew Dillon 		for (i = 0; i < ncpus; ++i) {
1814f7c73ea6SMatthew Dillon 			bzero(pf_counters[i].counters, sizeof(pf_counters[0].counters));
1815f7c73ea6SMatthew Dillon 			bzero(pf_counters[i].fcounters, sizeof(pf_counters[0].fcounters));
1816f7c73ea6SMatthew Dillon 			bzero(pf_counters[i].scounters, sizeof(pf_counters[0].scounters));
1817f7c73ea6SMatthew Dillon 		}
1818f7c73ea6SMatthew Dillon 
181970224baaSJan Lentfer 		pf_status.since = time_second;
182002742ec6SJoerg Sonnenberger 		if (*pf_status.ifname)
1821ed1f0be2SJan Lentfer 			pfi_update_status(pf_status.ifname, NULL);
182202742ec6SJoerg Sonnenberger 		break;
182302742ec6SJoerg Sonnenberger 	}
182402742ec6SJoerg Sonnenberger 
182502742ec6SJoerg Sonnenberger 	case DIOCNATLOOK: {
182602742ec6SJoerg Sonnenberger 		struct pfioc_natlook	*pnl = (struct pfioc_natlook *)addr;
1827315a7da3SJan Lentfer 		struct pf_state_key	*sk;
182802742ec6SJoerg Sonnenberger 		struct pf_state		*state;
1829315a7da3SJan Lentfer 		struct pf_state_key_cmp	 key;
183002742ec6SJoerg Sonnenberger 		int			 m = 0, direction = pnl->direction;
1831ed1f0be2SJan Lentfer 		int			 sidx, didx;
18323a0038bfSMatthew Dillon 		globaldata_t save_gd = mycpu;
18333a0038bfSMatthew Dillon 		int nn;
183402742ec6SJoerg Sonnenberger 
1835ed1f0be2SJan Lentfer 		/* NATLOOK src and dst are reversed, so reverse sidx/didx */
1836ed1f0be2SJan Lentfer 		sidx = (direction == PF_IN) ? 1 : 0;
1837ed1f0be2SJan Lentfer 		didx = (direction == PF_IN) ? 0 : 1;
183802742ec6SJoerg Sonnenberger 
183902742ec6SJoerg Sonnenberger 		if (!pnl->proto ||
184002742ec6SJoerg Sonnenberger 		    PF_AZERO(&pnl->saddr, pnl->af) ||
184102742ec6SJoerg Sonnenberger 		    PF_AZERO(&pnl->daddr, pnl->af) ||
184270224baaSJan Lentfer 		    ((pnl->proto == IPPROTO_TCP ||
184370224baaSJan Lentfer 		    pnl->proto == IPPROTO_UDP) &&
184470224baaSJan Lentfer 		    (!pnl->dport || !pnl->sport)))
184502742ec6SJoerg Sonnenberger 			error = EINVAL;
184602742ec6SJoerg Sonnenberger 		else {
1847ed1f0be2SJan Lentfer 			key.af = pnl->af;
1848ed1f0be2SJan Lentfer 			key.proto = pnl->proto;
1849ed1f0be2SJan Lentfer 			PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af);
1850ed1f0be2SJan Lentfer 			key.port[sidx] = pnl->sport;
1851ed1f0be2SJan Lentfer 			PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af);
1852ed1f0be2SJan Lentfer 			key.port[didx] = pnl->dport;
1853ed1f0be2SJan Lentfer 
18543a0038bfSMatthew Dillon 			state = NULL;
18553a0038bfSMatthew Dillon 			for (nn = 0; nn < ncpus; ++nn) {
18563a0038bfSMatthew Dillon 				lwkt_setcpu_self(globaldata_find(nn));
1857ed1f0be2SJan Lentfer 				state = pf_find_state_all(&key, direction, &m);
18583a0038bfSMatthew Dillon 				if (state || m > 1)
18593a0038bfSMatthew Dillon 					break;
18603a0038bfSMatthew Dillon 				m = 0;
18613a0038bfSMatthew Dillon 			}
1862ed1f0be2SJan Lentfer 
18633a0038bfSMatthew Dillon 			if (m > 1) {
186402742ec6SJoerg Sonnenberger 				error = E2BIG;	/* more than one state */
18653a0038bfSMatthew Dillon 			} else if (state != NULL) {
1866ed1f0be2SJan Lentfer 				sk = state->key[sidx];
1867ed1f0be2SJan Lentfer 				PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af);
1868ed1f0be2SJan Lentfer 				pnl->rsport = sk->port[sidx];
1869ed1f0be2SJan Lentfer 				PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af);
1870ed1f0be2SJan Lentfer 				pnl->rdport = sk->port[didx];
18713a0038bfSMatthew Dillon 			} else {
187202742ec6SJoerg Sonnenberger 				error = ENOENT;
187302742ec6SJoerg Sonnenberger 			}
18743a0038bfSMatthew Dillon 			lwkt_setcpu_self(save_gd);
18753a0038bfSMatthew Dillon 		}
187602742ec6SJoerg Sonnenberger 		break;
187702742ec6SJoerg Sonnenberger 	}
187802742ec6SJoerg Sonnenberger 
187902742ec6SJoerg Sonnenberger 	case DIOCSETTIMEOUT: {
188002742ec6SJoerg Sonnenberger 		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
188102742ec6SJoerg Sonnenberger 		int		 old;
188202742ec6SJoerg Sonnenberger 
188302742ec6SJoerg Sonnenberger 		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
188402742ec6SJoerg Sonnenberger 		    pt->seconds < 0) {
188502742ec6SJoerg Sonnenberger 			error = EINVAL;
188602742ec6SJoerg Sonnenberger 			goto fail;
188702742ec6SJoerg Sonnenberger 		}
188802742ec6SJoerg Sonnenberger 		old = pf_default_rule.timeout[pt->timeout];
188970224baaSJan Lentfer 		if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
189070224baaSJan Lentfer 			pt->seconds = 1;
189102742ec6SJoerg Sonnenberger 		pf_default_rule.timeout[pt->timeout] = pt->seconds;
189270224baaSJan Lentfer 		if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
189370224baaSJan Lentfer 			wakeup(pf_purge_thread);
189402742ec6SJoerg Sonnenberger 		pt->seconds = old;
189502742ec6SJoerg Sonnenberger 		break;
189602742ec6SJoerg Sonnenberger 	}
189702742ec6SJoerg Sonnenberger 
189802742ec6SJoerg Sonnenberger 	case DIOCGETTIMEOUT: {
189902742ec6SJoerg Sonnenberger 		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;
190002742ec6SJoerg Sonnenberger 
190102742ec6SJoerg Sonnenberger 		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
190202742ec6SJoerg Sonnenberger 			error = EINVAL;
190302742ec6SJoerg Sonnenberger 			goto fail;
190402742ec6SJoerg Sonnenberger 		}
190502742ec6SJoerg Sonnenberger 		pt->seconds = pf_default_rule.timeout[pt->timeout];
190602742ec6SJoerg Sonnenberger 		break;
190702742ec6SJoerg Sonnenberger 	}
190802742ec6SJoerg Sonnenberger 
190902742ec6SJoerg Sonnenberger 	case DIOCGETLIMIT: {
191002742ec6SJoerg Sonnenberger 		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
191102742ec6SJoerg Sonnenberger 
191202742ec6SJoerg Sonnenberger 		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
191302742ec6SJoerg Sonnenberger 			error = EINVAL;
191402742ec6SJoerg Sonnenberger 			goto fail;
191502742ec6SJoerg Sonnenberger 		}
191602742ec6SJoerg Sonnenberger 		pl->limit = pf_pool_limits[pl->index].limit;
191702742ec6SJoerg Sonnenberger 		break;
191802742ec6SJoerg Sonnenberger 	}
191902742ec6SJoerg Sonnenberger 
192002742ec6SJoerg Sonnenberger 	case DIOCSETLIMIT: {
192102742ec6SJoerg Sonnenberger 		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;
192202742ec6SJoerg Sonnenberger 		int			 old_limit;
192302742ec6SJoerg Sonnenberger 
192402742ec6SJoerg Sonnenberger 		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
192502742ec6SJoerg Sonnenberger 		    pf_pool_limits[pl->index].pp == NULL) {
192602742ec6SJoerg Sonnenberger 			error = EINVAL;
192702742ec6SJoerg Sonnenberger 			goto fail;
192802742ec6SJoerg Sonnenberger 		}
192902742ec6SJoerg Sonnenberger 
193002742ec6SJoerg Sonnenberger 		/* XXX Get an API to set limits on the zone/pool */
193102742ec6SJoerg Sonnenberger 		old_limit = pf_pool_limits[pl->index].limit;
193202742ec6SJoerg Sonnenberger 		pf_pool_limits[pl->index].limit = pl->limit;
193302742ec6SJoerg Sonnenberger 		pl->limit = old_limit;
193402742ec6SJoerg Sonnenberger 		break;
193502742ec6SJoerg Sonnenberger 	}
193602742ec6SJoerg Sonnenberger 
193702742ec6SJoerg Sonnenberger 	case DIOCSETDEBUG: {
193802742ec6SJoerg Sonnenberger 		u_int32_t	*level = (u_int32_t *)addr;
193902742ec6SJoerg Sonnenberger 
194002742ec6SJoerg Sonnenberger 		pf_status.debug = *level;
194102742ec6SJoerg Sonnenberger 		break;
194202742ec6SJoerg Sonnenberger 	}
194302742ec6SJoerg Sonnenberger 
194402742ec6SJoerg Sonnenberger 	case DIOCCLRRULECTRS: {
194570224baaSJan Lentfer 		/* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
194602742ec6SJoerg Sonnenberger 		struct pf_ruleset	*ruleset = &pf_main_ruleset;
194702742ec6SJoerg Sonnenberger 		struct pf_rule		*rule;
194802742ec6SJoerg Sonnenberger 
194902742ec6SJoerg Sonnenberger 		TAILQ_FOREACH(rule,
195070224baaSJan Lentfer 		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
195170224baaSJan Lentfer 			rule->evaluations = 0;
195270224baaSJan Lentfer 			rule->packets[0] = rule->packets[1] = 0;
195370224baaSJan Lentfer 			rule->bytes[0] = rule->bytes[1] = 0;
195470224baaSJan Lentfer 		}
195502742ec6SJoerg Sonnenberger 		break;
195602742ec6SJoerg Sonnenberger 	}
195702742ec6SJoerg Sonnenberger 
195802742ec6SJoerg Sonnenberger 	case DIOCGIFSPEED: {
195902742ec6SJoerg Sonnenberger 		struct pf_ifspeed	*psp = (struct pf_ifspeed *)addr;
196002742ec6SJoerg Sonnenberger 		struct pf_ifspeed	ps;
196102742ec6SJoerg Sonnenberger 		struct ifnet		*ifp;
196202742ec6SJoerg Sonnenberger 
196302742ec6SJoerg Sonnenberger 		if (psp->ifname[0] != 0) {
196402742ec6SJoerg Sonnenberger 			/* Can we completely trust user-land? */
196502742ec6SJoerg Sonnenberger 			strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
1966b4051e25SSepherosa Ziehau 			ifnet_lock();
196702742ec6SJoerg Sonnenberger 			ifp = ifunit(ps.ifname);
196802742ec6SJoerg Sonnenberger 			if (ifp )
196902742ec6SJoerg Sonnenberger 				psp->baudrate = ifp->if_baudrate;
197002742ec6SJoerg Sonnenberger 			else
197102742ec6SJoerg Sonnenberger 				error = EINVAL;
1972d15093b9SAaron LI 			ifnet_unlock();
197302742ec6SJoerg Sonnenberger 		} else
197402742ec6SJoerg Sonnenberger 			error = EINVAL;
197502742ec6SJoerg Sonnenberger 		break;
197602742ec6SJoerg Sonnenberger 	}
197702742ec6SJoerg Sonnenberger #ifdef ALTQ
197802742ec6SJoerg Sonnenberger 	case DIOCSTARTALTQ: {
197902742ec6SJoerg Sonnenberger 		struct pf_altq		*altq;
198002742ec6SJoerg Sonnenberger 
198102742ec6SJoerg Sonnenberger 		/* enable all altq interfaces on active list */
198202742ec6SJoerg Sonnenberger 		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1983d15093b9SAaron LI 			if (altq->qname[0] == 0) {
198470224baaSJan Lentfer 				error = pf_enable_altq(altq);
198502742ec6SJoerg Sonnenberger 				if (error != 0)
198602742ec6SJoerg Sonnenberger 					break;
198702742ec6SJoerg Sonnenberger 			}
198802742ec6SJoerg Sonnenberger 		}
198970224baaSJan Lentfer 		if (error == 0)
199070224baaSJan Lentfer 			pf_altq_running = 1;
199102742ec6SJoerg Sonnenberger 		DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
199202742ec6SJoerg Sonnenberger 		break;
199302742ec6SJoerg Sonnenberger 	}
199402742ec6SJoerg Sonnenberger 
199502742ec6SJoerg Sonnenberger 	case DIOCSTOPALTQ: {
199602742ec6SJoerg Sonnenberger 		struct pf_altq		*altq;
199702742ec6SJoerg Sonnenberger 
199802742ec6SJoerg Sonnenberger 		/* disable all altq interfaces on active list */
199902742ec6SJoerg Sonnenberger 		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2000d15093b9SAaron LI 			if (altq->qname[0] == 0) {
200170224baaSJan Lentfer 				error = pf_disable_altq(altq);
200270224baaSJan Lentfer 				if (error != 0)
200302742ec6SJoerg Sonnenberger 					break;
200402742ec6SJoerg Sonnenberger 			}
200502742ec6SJoerg Sonnenberger 		}
200670224baaSJan Lentfer 		if (error == 0)
200770224baaSJan Lentfer 			pf_altq_running = 0;
200802742ec6SJoerg Sonnenberger 		DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
200902742ec6SJoerg Sonnenberger 		break;
201002742ec6SJoerg Sonnenberger 	}
201102742ec6SJoerg Sonnenberger 
201202742ec6SJoerg Sonnenberger 	case DIOCADDALTQ: {
201302742ec6SJoerg Sonnenberger 		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
201402742ec6SJoerg Sonnenberger 		struct pf_altq		*altq, *a;
201502742ec6SJoerg Sonnenberger 
201602742ec6SJoerg Sonnenberger 		if (pa->ticket != ticket_altqs_inactive) {
201702742ec6SJoerg Sonnenberger 			error = EBUSY;
201802742ec6SJoerg Sonnenberger 			break;
201902742ec6SJoerg Sonnenberger 		}
20201186cbc0SJan Lentfer 		altq = kmalloc(sizeof(struct pf_altq), M_PFALTQPL, M_WAITOK|M_NULLOK);
202102742ec6SJoerg Sonnenberger 		if (altq == NULL) {
202202742ec6SJoerg Sonnenberger 			error = ENOMEM;
202302742ec6SJoerg Sonnenberger 			break;
202402742ec6SJoerg Sonnenberger 		}
202502742ec6SJoerg Sonnenberger 		bcopy(&pa->altq, altq, sizeof(struct pf_altq));
202602742ec6SJoerg Sonnenberger 
202702742ec6SJoerg Sonnenberger 		/*
202802742ec6SJoerg Sonnenberger 		 * if this is for a queue, find the discipline and
202902742ec6SJoerg Sonnenberger 		 * copy the necessary fields
203002742ec6SJoerg Sonnenberger 		 */
203102742ec6SJoerg Sonnenberger 		if (altq->qname[0] != 0) {
203202742ec6SJoerg Sonnenberger 			if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {
203302742ec6SJoerg Sonnenberger 				error = EBUSY;
20341186cbc0SJan Lentfer 				kfree(altq, M_PFALTQPL);
203502742ec6SJoerg Sonnenberger 				break;
203602742ec6SJoerg Sonnenberger 			}
2037ed1f0be2SJan Lentfer 			altq->altq_disc = NULL;
203802742ec6SJoerg Sonnenberger 			TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
203902742ec6SJoerg Sonnenberger 				if (strncmp(a->ifname, altq->ifname,
204002742ec6SJoerg Sonnenberger 				    IFNAMSIZ) == 0 && a->qname[0] == 0) {
204102742ec6SJoerg Sonnenberger 					altq->altq_disc = a->altq_disc;
204202742ec6SJoerg Sonnenberger 					break;
204302742ec6SJoerg Sonnenberger 				}
204402742ec6SJoerg Sonnenberger 			}
204502742ec6SJoerg Sonnenberger 		}
204602742ec6SJoerg Sonnenberger 
204702742ec6SJoerg Sonnenberger 		error = altq_add(altq);
204802742ec6SJoerg Sonnenberger 		if (error) {
20491186cbc0SJan Lentfer 			kfree(altq, M_PFALTQPL);
205002742ec6SJoerg Sonnenberger 			break;
205102742ec6SJoerg Sonnenberger 		}
205202742ec6SJoerg Sonnenberger 
205302742ec6SJoerg Sonnenberger 		TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
205402742ec6SJoerg Sonnenberger 		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
205502742ec6SJoerg Sonnenberger 		break;
205602742ec6SJoerg Sonnenberger 	}
205702742ec6SJoerg Sonnenberger 
205802742ec6SJoerg Sonnenberger 	case DIOCGETALTQS: {
205902742ec6SJoerg Sonnenberger 		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
206002742ec6SJoerg Sonnenberger 		struct pf_altq		*altq;
206102742ec6SJoerg Sonnenberger 
206202742ec6SJoerg Sonnenberger 		pa->nr = 0;
206302742ec6SJoerg Sonnenberger 		TAILQ_FOREACH(altq, pf_altqs_active, entries)
206402742ec6SJoerg Sonnenberger 			pa->nr++;
206502742ec6SJoerg Sonnenberger 		pa->ticket = ticket_altqs_active;
206602742ec6SJoerg Sonnenberger 		break;
206702742ec6SJoerg Sonnenberger 	}
206802742ec6SJoerg Sonnenberger 
206902742ec6SJoerg Sonnenberger 	case DIOCGETALTQ: {
207002742ec6SJoerg Sonnenberger 		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;
207102742ec6SJoerg Sonnenberger 		struct pf_altq		*altq;
207202742ec6SJoerg Sonnenberger 		u_int32_t		 nr;
207302742ec6SJoerg Sonnenberger 
207402742ec6SJoerg Sonnenberger 		if (pa->ticket != ticket_altqs_active) {
207502742ec6SJoerg Sonnenberger 			error = EBUSY;
207602742ec6SJoerg Sonnenberger 			break;
207702742ec6SJoerg Sonnenberger 		}
207802742ec6SJoerg Sonnenberger 		nr = 0;
207902742ec6SJoerg Sonnenberger 		altq = TAILQ_FIRST(pf_altqs_active);
208002742ec6SJoerg Sonnenberger 		while ((altq != NULL) && (nr < pa->nr)) {
208102742ec6SJoerg Sonnenberger 			altq = TAILQ_NEXT(altq, entries);
208202742ec6SJoerg Sonnenberger 			nr++;
208302742ec6SJoerg Sonnenberger 		}
208402742ec6SJoerg Sonnenberger 		if (altq == NULL) {
208502742ec6SJoerg Sonnenberger 			error = EBUSY;
208602742ec6SJoerg Sonnenberger 			break;
208702742ec6SJoerg Sonnenberger 		}
208802742ec6SJoerg Sonnenberger 		bcopy(altq, &pa->altq, sizeof(struct pf_altq));
208902742ec6SJoerg Sonnenberger 		break;
209002742ec6SJoerg Sonnenberger 	}
209102742ec6SJoerg Sonnenberger 
209202742ec6SJoerg Sonnenberger 	case DIOCCHANGEALTQ:
209302742ec6SJoerg Sonnenberger 		/* CHANGEALTQ not supported yet! */
209402742ec6SJoerg Sonnenberger 		error = ENODEV;
209502742ec6SJoerg Sonnenberger 		break;
209602742ec6SJoerg Sonnenberger 
209702742ec6SJoerg Sonnenberger 	case DIOCGETQSTATS: {
209802742ec6SJoerg Sonnenberger 		struct pfioc_qstats	*pq = (struct pfioc_qstats *)addr;
209902742ec6SJoerg Sonnenberger 		struct pf_altq		*altq;
210002742ec6SJoerg Sonnenberger 		u_int32_t		 nr;
210102742ec6SJoerg Sonnenberger 		int			 nbytes;
210202742ec6SJoerg Sonnenberger 
210302742ec6SJoerg Sonnenberger 		if (pq->ticket != ticket_altqs_active) {
210402742ec6SJoerg Sonnenberger 			error = EBUSY;
210502742ec6SJoerg Sonnenberger 			break;
210602742ec6SJoerg Sonnenberger 		}
210702742ec6SJoerg Sonnenberger 		nbytes = pq->nbytes;
210802742ec6SJoerg Sonnenberger 		nr = 0;
210902742ec6SJoerg Sonnenberger 		altq = TAILQ_FIRST(pf_altqs_active);
211002742ec6SJoerg Sonnenberger 		while ((altq != NULL) && (nr < pq->nr)) {
211102742ec6SJoerg Sonnenberger 			altq = TAILQ_NEXT(altq, entries);
211202742ec6SJoerg Sonnenberger 			nr++;
211302742ec6SJoerg Sonnenberger 		}
211402742ec6SJoerg Sonnenberger 		if (altq == NULL) {
211502742ec6SJoerg Sonnenberger 			error = EBUSY;
211602742ec6SJoerg Sonnenberger 			break;
211702742ec6SJoerg Sonnenberger 		}
211802742ec6SJoerg Sonnenberger 		error = altq_getqstats(altq, pq->buf, &nbytes);
211902742ec6SJoerg Sonnenberger 		if (error == 0) {
212002742ec6SJoerg Sonnenberger 			pq->scheduler = altq->scheduler;
212102742ec6SJoerg Sonnenberger 			pq->nbytes = nbytes;
212202742ec6SJoerg Sonnenberger 		}
212302742ec6SJoerg Sonnenberger 		break;
212402742ec6SJoerg Sonnenberger 	}
212502742ec6SJoerg Sonnenberger #endif /* ALTQ */
212602742ec6SJoerg Sonnenberger 
212702742ec6SJoerg Sonnenberger 	case DIOCBEGINADDRS: {
212802742ec6SJoerg Sonnenberger 		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
212902742ec6SJoerg Sonnenberger 
213002742ec6SJoerg Sonnenberger 		pf_empty_pool(&pf_pabuf);
213102742ec6SJoerg Sonnenberger 		pp->ticket = ++ticket_pabuf;
213202742ec6SJoerg Sonnenberger 		break;
213302742ec6SJoerg Sonnenberger 	}
213402742ec6SJoerg Sonnenberger 
213502742ec6SJoerg Sonnenberger 	case DIOCADDADDR: {
213602742ec6SJoerg Sonnenberger 		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
213702742ec6SJoerg Sonnenberger 
213870224baaSJan Lentfer 		if (pp->ticket != ticket_pabuf) {
213970224baaSJan Lentfer 			error = EBUSY;
214070224baaSJan Lentfer 			break;
214170224baaSJan Lentfer 		}
214202742ec6SJoerg Sonnenberger #ifndef INET
214302742ec6SJoerg Sonnenberger 		if (pp->af == AF_INET) {
214402742ec6SJoerg Sonnenberger 			error = EAFNOSUPPORT;
214502742ec6SJoerg Sonnenberger 			break;
214602742ec6SJoerg Sonnenberger 		}
214702742ec6SJoerg Sonnenberger #endif /* INET */
214802742ec6SJoerg Sonnenberger #ifndef INET6
214902742ec6SJoerg Sonnenberger 		if (pp->af == AF_INET6) {
215002742ec6SJoerg Sonnenberger 			error = EAFNOSUPPORT;
215102742ec6SJoerg Sonnenberger 			break;
215202742ec6SJoerg Sonnenberger 		}
215302742ec6SJoerg Sonnenberger #endif /* INET6 */
215402742ec6SJoerg Sonnenberger 		if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
215502742ec6SJoerg Sonnenberger 		    pp->addr.addr.type != PF_ADDR_DYNIFTL &&
215602742ec6SJoerg Sonnenberger 		    pp->addr.addr.type != PF_ADDR_TABLE) {
215702742ec6SJoerg Sonnenberger 			error = EINVAL;
215802742ec6SJoerg Sonnenberger 			break;
215902742ec6SJoerg Sonnenberger 		}
21601186cbc0SJan Lentfer 		pa = kmalloc(sizeof(struct pf_altq), M_PFPOOLADDRPL, M_WAITOK|M_NULLOK);
216102742ec6SJoerg Sonnenberger 		if (pa == NULL) {
216202742ec6SJoerg Sonnenberger 			error = ENOMEM;
216302742ec6SJoerg Sonnenberger 			break;
216402742ec6SJoerg Sonnenberger 		}
216502742ec6SJoerg Sonnenberger 		bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
216602742ec6SJoerg Sonnenberger 		if (pa->ifname[0]) {
216770224baaSJan Lentfer 			pa->kif = pfi_kif_get(pa->ifname);
216802742ec6SJoerg Sonnenberger 			if (pa->kif == NULL) {
21691186cbc0SJan Lentfer 				kfree(ap, M_PFPOOLADDRPL);
217002742ec6SJoerg Sonnenberger 				error = EINVAL;
217102742ec6SJoerg Sonnenberger 				break;
217202742ec6SJoerg Sonnenberger 			}
217370224baaSJan Lentfer 			pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
217402742ec6SJoerg Sonnenberger 		}
217502742ec6SJoerg Sonnenberger 		if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
217602742ec6SJoerg Sonnenberger 			pfi_dynaddr_remove(&pa->addr);
217770224baaSJan Lentfer 			pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
21781186cbc0SJan Lentfer 			kfree(pa, M_PFPOOLADDRPL);
217902742ec6SJoerg Sonnenberger 			error = EINVAL;
218002742ec6SJoerg Sonnenberger 			break;
218102742ec6SJoerg Sonnenberger 		}
218202742ec6SJoerg Sonnenberger 		TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
218302742ec6SJoerg Sonnenberger 		break;
218402742ec6SJoerg Sonnenberger 	}
218502742ec6SJoerg Sonnenberger 
218602742ec6SJoerg Sonnenberger 	case DIOCGETADDRS: {
218702742ec6SJoerg Sonnenberger 		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
218802742ec6SJoerg Sonnenberger 
218902742ec6SJoerg Sonnenberger 		pp->nr = 0;
219070224baaSJan Lentfer 		pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
219170224baaSJan Lentfer 		    pp->r_num, 0, 1, 0);
219202742ec6SJoerg Sonnenberger 		if (pool == NULL) {
219302742ec6SJoerg Sonnenberger 			error = EBUSY;
219402742ec6SJoerg Sonnenberger 			break;
219502742ec6SJoerg Sonnenberger 		}
219602742ec6SJoerg Sonnenberger 		TAILQ_FOREACH(pa, &pool->list, entries)
219702742ec6SJoerg Sonnenberger 			pp->nr++;
219802742ec6SJoerg Sonnenberger 		break;
219902742ec6SJoerg Sonnenberger 	}
220002742ec6SJoerg Sonnenberger 
220102742ec6SJoerg Sonnenberger 	case DIOCGETADDR: {
220202742ec6SJoerg Sonnenberger 		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;
220302742ec6SJoerg Sonnenberger 		u_int32_t		 nr = 0;
220402742ec6SJoerg Sonnenberger 
220570224baaSJan Lentfer 		pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
220670224baaSJan Lentfer 		    pp->r_num, 0, 1, 1);
220702742ec6SJoerg Sonnenberger 		if (pool == NULL) {
220802742ec6SJoerg Sonnenberger 			error = EBUSY;
220902742ec6SJoerg Sonnenberger 			break;
221002742ec6SJoerg Sonnenberger 		}
221102742ec6SJoerg Sonnenberger 		pa = TAILQ_FIRST(&pool->list);
221202742ec6SJoerg Sonnenberger 		while ((pa != NULL) && (nr < pp->nr)) {
221302742ec6SJoerg Sonnenberger 			pa = TAILQ_NEXT(pa, entries);
221402742ec6SJoerg Sonnenberger 			nr++;
221502742ec6SJoerg Sonnenberger 		}
221602742ec6SJoerg Sonnenberger 		if (pa == NULL) {
221702742ec6SJoerg Sonnenberger 			error = EBUSY;
221802742ec6SJoerg Sonnenberger 			break;
221902742ec6SJoerg Sonnenberger 		}
222002742ec6SJoerg Sonnenberger 		bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
2221ed1f0be2SJan Lentfer 		pf_addr_copyout(&pp->addr.addr);
222202742ec6SJoerg Sonnenberger 		break;
222302742ec6SJoerg Sonnenberger 	}
222402742ec6SJoerg Sonnenberger 
222502742ec6SJoerg Sonnenberger 	case DIOCCHANGEADDR: {
222602742ec6SJoerg Sonnenberger 		struct pfioc_pooladdr	*pca = (struct pfioc_pooladdr *)addr;
222702742ec6SJoerg Sonnenberger 		struct pf_pooladdr	*oldpa = NULL, *newpa = NULL;
222802742ec6SJoerg Sonnenberger 		struct pf_ruleset	*ruleset;
222902742ec6SJoerg Sonnenberger 
223002742ec6SJoerg Sonnenberger 		if (pca->action < PF_CHANGE_ADD_HEAD ||
223102742ec6SJoerg Sonnenberger 		    pca->action > PF_CHANGE_REMOVE) {
223202742ec6SJoerg Sonnenberger 			error = EINVAL;
223302742ec6SJoerg Sonnenberger 			break;
223402742ec6SJoerg Sonnenberger 		}
223502742ec6SJoerg Sonnenberger 		if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
223602742ec6SJoerg Sonnenberger 		    pca->addr.addr.type != PF_ADDR_DYNIFTL &&
223702742ec6SJoerg Sonnenberger 		    pca->addr.addr.type != PF_ADDR_TABLE) {
223802742ec6SJoerg Sonnenberger 			error = EINVAL;
223902742ec6SJoerg Sonnenberger 			break;
224002742ec6SJoerg Sonnenberger 		}
224102742ec6SJoerg Sonnenberger 
224270224baaSJan Lentfer 		ruleset = pf_find_ruleset(pca->anchor);
224302742ec6SJoerg Sonnenberger 		if (ruleset == NULL) {
224402742ec6SJoerg Sonnenberger 			error = EBUSY;
224502742ec6SJoerg Sonnenberger 			break;
224602742ec6SJoerg Sonnenberger 		}
224770224baaSJan Lentfer 		pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
224870224baaSJan Lentfer 		    pca->r_num, pca->r_last, 1, 1);
224902742ec6SJoerg Sonnenberger 		if (pool == NULL) {
225002742ec6SJoerg Sonnenberger 			error = EBUSY;
225102742ec6SJoerg Sonnenberger 			break;
225202742ec6SJoerg Sonnenberger 		}
225302742ec6SJoerg Sonnenberger 		if (pca->action != PF_CHANGE_REMOVE) {
22541186cbc0SJan Lentfer 			newpa = kmalloc(sizeof(struct pf_pooladdr),
22551186cbc0SJan Lentfer 				M_PFPOOLADDRPL, M_WAITOK|M_NULLOK);
225602742ec6SJoerg Sonnenberger 			if (newpa == NULL) {
225702742ec6SJoerg Sonnenberger 				error = ENOMEM;
225802742ec6SJoerg Sonnenberger 				break;
225902742ec6SJoerg Sonnenberger 			}
226002742ec6SJoerg Sonnenberger 			bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
226102742ec6SJoerg Sonnenberger #ifndef INET
226202742ec6SJoerg Sonnenberger 			if (pca->af == AF_INET) {
22631186cbc0SJan Lentfer 				kfree(newpa, M_PFPOOLADDRPL);
226402742ec6SJoerg Sonnenberger 				error = EAFNOSUPPORT;
226502742ec6SJoerg Sonnenberger 				break;
226602742ec6SJoerg Sonnenberger 			}
226702742ec6SJoerg Sonnenberger #endif /* INET */
226802742ec6SJoerg Sonnenberger #ifndef INET6
226902742ec6SJoerg Sonnenberger 			if (pca->af == AF_INET6) {
22701186cbc0SJan Lentfer 				kfree(newpa, M_PFPOOLADDRPL);
227102742ec6SJoerg Sonnenberger 				error = EAFNOSUPPORT;
227202742ec6SJoerg Sonnenberger 				break;
227302742ec6SJoerg Sonnenberger 			}
227402742ec6SJoerg Sonnenberger #endif /* INET6 */
227502742ec6SJoerg Sonnenberger 			if (newpa->ifname[0]) {
227670224baaSJan Lentfer 				newpa->kif = pfi_kif_get(newpa->ifname);
227702742ec6SJoerg Sonnenberger 				if (newpa->kif == NULL) {
22781186cbc0SJan Lentfer 					kfree(newpa, M_PFPOOLADDRPL);
227902742ec6SJoerg Sonnenberger 					error = EINVAL;
228002742ec6SJoerg Sonnenberger 					break;
228102742ec6SJoerg Sonnenberger 				}
228270224baaSJan Lentfer 				pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
228302742ec6SJoerg Sonnenberger 			} else
228402742ec6SJoerg Sonnenberger 				newpa->kif = NULL;
228502742ec6SJoerg Sonnenberger 			if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
228602742ec6SJoerg Sonnenberger 			    pf_tbladdr_setup(ruleset, &newpa->addr)) {
228702742ec6SJoerg Sonnenberger 				pfi_dynaddr_remove(&newpa->addr);
228870224baaSJan Lentfer 				pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
22891186cbc0SJan Lentfer 				kfree(newpa, M_PFPOOLADDRPL);
229002742ec6SJoerg Sonnenberger 				error = EINVAL;
229102742ec6SJoerg Sonnenberger 				break;
229202742ec6SJoerg Sonnenberger 			}
229302742ec6SJoerg Sonnenberger 		}
229402742ec6SJoerg Sonnenberger 
229502742ec6SJoerg Sonnenberger 		if (pca->action == PF_CHANGE_ADD_HEAD)
229602742ec6SJoerg Sonnenberger 			oldpa = TAILQ_FIRST(&pool->list);
229702742ec6SJoerg Sonnenberger 		else if (pca->action == PF_CHANGE_ADD_TAIL)
229802742ec6SJoerg Sonnenberger 			oldpa = TAILQ_LAST(&pool->list, pf_palist);
229902742ec6SJoerg Sonnenberger 		else {
230002742ec6SJoerg Sonnenberger 			int	i = 0;
230102742ec6SJoerg Sonnenberger 
230202742ec6SJoerg Sonnenberger 			oldpa = TAILQ_FIRST(&pool->list);
230302742ec6SJoerg Sonnenberger 			while ((oldpa != NULL) && (i < pca->nr)) {
230402742ec6SJoerg Sonnenberger 				oldpa = TAILQ_NEXT(oldpa, entries);
230502742ec6SJoerg Sonnenberger 				i++;
230602742ec6SJoerg Sonnenberger 			}
230702742ec6SJoerg Sonnenberger 			if (oldpa == NULL) {
230802742ec6SJoerg Sonnenberger 				error = EINVAL;
230902742ec6SJoerg Sonnenberger 				break;
231002742ec6SJoerg Sonnenberger 			}
231102742ec6SJoerg Sonnenberger 		}
231202742ec6SJoerg Sonnenberger 
231302742ec6SJoerg Sonnenberger 		if (pca->action == PF_CHANGE_REMOVE) {
231402742ec6SJoerg Sonnenberger 			TAILQ_REMOVE(&pool->list, oldpa, entries);
231502742ec6SJoerg Sonnenberger 			pfi_dynaddr_remove(&oldpa->addr);
231602742ec6SJoerg Sonnenberger 			pf_tbladdr_remove(&oldpa->addr);
231770224baaSJan Lentfer 			pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
23181186cbc0SJan Lentfer 			kfree(oldpa, M_PFPOOLADDRPL);
231902742ec6SJoerg Sonnenberger 		} else {
232002742ec6SJoerg Sonnenberger 			if (oldpa == NULL)
232102742ec6SJoerg Sonnenberger 				TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
232202742ec6SJoerg Sonnenberger 			else if (pca->action == PF_CHANGE_ADD_HEAD ||
232302742ec6SJoerg Sonnenberger 			    pca->action == PF_CHANGE_ADD_BEFORE)
232402742ec6SJoerg Sonnenberger 				TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
232502742ec6SJoerg Sonnenberger 			else
232602742ec6SJoerg Sonnenberger 				TAILQ_INSERT_AFTER(&pool->list, oldpa,
232702742ec6SJoerg Sonnenberger 				    newpa, entries);
232802742ec6SJoerg Sonnenberger 		}
232902742ec6SJoerg Sonnenberger 
233002742ec6SJoerg Sonnenberger 		pool->cur = TAILQ_FIRST(&pool->list);
233102742ec6SJoerg Sonnenberger 		PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
233202742ec6SJoerg Sonnenberger 		    pca->af);
233302742ec6SJoerg Sonnenberger 		break;
233402742ec6SJoerg Sonnenberger 	}
233502742ec6SJoerg Sonnenberger 
233602742ec6SJoerg Sonnenberger 	case DIOCGETRULESETS: {
233702742ec6SJoerg Sonnenberger 		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
233802742ec6SJoerg Sonnenberger 		struct pf_ruleset	*ruleset;
233970224baaSJan Lentfer 		struct pf_anchor	*anchor;
234002742ec6SJoerg Sonnenberger 
234170224baaSJan Lentfer 		pr->path[sizeof(pr->path) - 1] = 0;
234270224baaSJan Lentfer 		if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
234302742ec6SJoerg Sonnenberger 			error = EINVAL;
234402742ec6SJoerg Sonnenberger 			break;
234502742ec6SJoerg Sonnenberger 		}
234602742ec6SJoerg Sonnenberger 		pr->nr = 0;
234770224baaSJan Lentfer 		if (ruleset->anchor == NULL) {
234870224baaSJan Lentfer 			/* XXX kludge for pf_main_ruleset */
234970224baaSJan Lentfer 			RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
235070224baaSJan Lentfer 				if (anchor->parent == NULL)
235102742ec6SJoerg Sonnenberger 					pr->nr++;
235270224baaSJan Lentfer 		} else {
235370224baaSJan Lentfer 			RB_FOREACH(anchor, pf_anchor_node,
235470224baaSJan Lentfer 			    &ruleset->anchor->children)
235570224baaSJan Lentfer 				pr->nr++;
235670224baaSJan Lentfer 		}
235702742ec6SJoerg Sonnenberger 		break;
235802742ec6SJoerg Sonnenberger 	}
235902742ec6SJoerg Sonnenberger 
236002742ec6SJoerg Sonnenberger 	case DIOCGETRULESET: {
236102742ec6SJoerg Sonnenberger 		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;
236202742ec6SJoerg Sonnenberger 		struct pf_ruleset	*ruleset;
236370224baaSJan Lentfer 		struct pf_anchor	*anchor;
236402742ec6SJoerg Sonnenberger 		u_int32_t		 nr = 0;
236502742ec6SJoerg Sonnenberger 
236670224baaSJan Lentfer 		pr->path[sizeof(pr->path) - 1] = 0;
236770224baaSJan Lentfer 		if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
236802742ec6SJoerg Sonnenberger 			error = EINVAL;
236902742ec6SJoerg Sonnenberger 			break;
237002742ec6SJoerg Sonnenberger 		}
237170224baaSJan Lentfer 		pr->name[0] = 0;
237270224baaSJan Lentfer 		if (ruleset->anchor == NULL) {
237370224baaSJan Lentfer 			/* XXX kludge for pf_main_ruleset */
237470224baaSJan Lentfer 			RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
237570224baaSJan Lentfer 				if (anchor->parent == NULL && nr++ == pr->nr) {
237670224baaSJan Lentfer 					strlcpy(pr->name, anchor->name,
237770224baaSJan Lentfer 					    sizeof(pr->name));
237870224baaSJan Lentfer 					break;
237902742ec6SJoerg Sonnenberger 				}
238070224baaSJan Lentfer 		} else {
238170224baaSJan Lentfer 			RB_FOREACH(anchor, pf_anchor_node,
238270224baaSJan Lentfer 			    &ruleset->anchor->children)
238370224baaSJan Lentfer 				if (nr++ == pr->nr) {
238470224baaSJan Lentfer 					strlcpy(pr->name, anchor->name,
238570224baaSJan Lentfer 					    sizeof(pr->name));
238670224baaSJan Lentfer 					break;
238770224baaSJan Lentfer 				}
238870224baaSJan Lentfer 		}
238970224baaSJan Lentfer 		if (!pr->name[0])
239002742ec6SJoerg Sonnenberger 			error = EBUSY;
239102742ec6SJoerg Sonnenberger 		break;
239202742ec6SJoerg Sonnenberger 	}
239302742ec6SJoerg Sonnenberger 
239402742ec6SJoerg Sonnenberger 	case DIOCRCLRTABLES: {
239502742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
239602742ec6SJoerg Sonnenberger 
239702742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != 0) {
239802742ec6SJoerg Sonnenberger 			error = ENODEV;
239902742ec6SJoerg Sonnenberger 			break;
240002742ec6SJoerg Sonnenberger 		}
240102742ec6SJoerg Sonnenberger 		error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
240202742ec6SJoerg Sonnenberger 		    io->pfrio_flags | PFR_FLAG_USERIOCTL);
240302742ec6SJoerg Sonnenberger 		break;
240402742ec6SJoerg Sonnenberger 	}
240502742ec6SJoerg Sonnenberger 
240602742ec6SJoerg Sonnenberger 	case DIOCRADDTABLES: {
240702742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
240802742ec6SJoerg Sonnenberger 
240902742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
241002742ec6SJoerg Sonnenberger 			error = ENODEV;
241102742ec6SJoerg Sonnenberger 			break;
241202742ec6SJoerg Sonnenberger 		}
241302742ec6SJoerg Sonnenberger 		error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
241402742ec6SJoerg Sonnenberger 		    &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL);
241502742ec6SJoerg Sonnenberger 		break;
241602742ec6SJoerg Sonnenberger 	}
241702742ec6SJoerg Sonnenberger 
241802742ec6SJoerg Sonnenberger 	case DIOCRDELTABLES: {
241902742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
242002742ec6SJoerg Sonnenberger 
242102742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
242202742ec6SJoerg Sonnenberger 			error = ENODEV;
242302742ec6SJoerg Sonnenberger 			break;
242402742ec6SJoerg Sonnenberger 		}
242502742ec6SJoerg Sonnenberger 		error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
242602742ec6SJoerg Sonnenberger 		    &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
242702742ec6SJoerg Sonnenberger 		break;
242802742ec6SJoerg Sonnenberger 	}
242902742ec6SJoerg Sonnenberger 
243002742ec6SJoerg Sonnenberger 	case DIOCRGETTABLES: {
243102742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
243202742ec6SJoerg Sonnenberger 
243302742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
243402742ec6SJoerg Sonnenberger 			error = ENODEV;
243502742ec6SJoerg Sonnenberger 			break;
243602742ec6SJoerg Sonnenberger 		}
243702742ec6SJoerg Sonnenberger 		error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
243802742ec6SJoerg Sonnenberger 		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
243902742ec6SJoerg Sonnenberger 		break;
244002742ec6SJoerg Sonnenberger 	}
244102742ec6SJoerg Sonnenberger 
244202742ec6SJoerg Sonnenberger 	case DIOCRGETTSTATS: {
244302742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
244402742ec6SJoerg Sonnenberger 
244502742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
244602742ec6SJoerg Sonnenberger 			error = ENODEV;
244702742ec6SJoerg Sonnenberger 			break;
244802742ec6SJoerg Sonnenberger 		}
244902742ec6SJoerg Sonnenberger 		error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
245002742ec6SJoerg Sonnenberger 		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
245102742ec6SJoerg Sonnenberger 		break;
245202742ec6SJoerg Sonnenberger 	}
245302742ec6SJoerg Sonnenberger 
245402742ec6SJoerg Sonnenberger 	case DIOCRCLRTSTATS: {
245502742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
245602742ec6SJoerg Sonnenberger 
245702742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
245802742ec6SJoerg Sonnenberger 			error = ENODEV;
245902742ec6SJoerg Sonnenberger 			break;
246002742ec6SJoerg Sonnenberger 		}
246102742ec6SJoerg Sonnenberger 		error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
246202742ec6SJoerg Sonnenberger 		    &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL);
246302742ec6SJoerg Sonnenberger 		break;
246402742ec6SJoerg Sonnenberger 	}
246502742ec6SJoerg Sonnenberger 
246602742ec6SJoerg Sonnenberger 	case DIOCRSETTFLAGS: {
246702742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
246802742ec6SJoerg Sonnenberger 
246902742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_table)) {
247002742ec6SJoerg Sonnenberger 			error = ENODEV;
247102742ec6SJoerg Sonnenberger 			break;
247202742ec6SJoerg Sonnenberger 		}
247302742ec6SJoerg Sonnenberger 		error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
247402742ec6SJoerg Sonnenberger 		    io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
247502742ec6SJoerg Sonnenberger 		    &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
247602742ec6SJoerg Sonnenberger 		break;
247702742ec6SJoerg Sonnenberger 	}
247802742ec6SJoerg Sonnenberger 
247902742ec6SJoerg Sonnenberger 	case DIOCRCLRADDRS: {
248002742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
248102742ec6SJoerg Sonnenberger 
248202742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != 0) {
248302742ec6SJoerg Sonnenberger 			error = ENODEV;
248402742ec6SJoerg Sonnenberger 			break;
248502742ec6SJoerg Sonnenberger 		}
248602742ec6SJoerg Sonnenberger 		error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
248702742ec6SJoerg Sonnenberger 		    io->pfrio_flags | PFR_FLAG_USERIOCTL);
248802742ec6SJoerg Sonnenberger 		break;
248902742ec6SJoerg Sonnenberger 	}
249002742ec6SJoerg Sonnenberger 
249102742ec6SJoerg Sonnenberger 	case DIOCRADDADDRS: {
249202742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
249302742ec6SJoerg Sonnenberger 
249402742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
249502742ec6SJoerg Sonnenberger 			error = ENODEV;
249602742ec6SJoerg Sonnenberger 			break;
249702742ec6SJoerg Sonnenberger 		}
249802742ec6SJoerg Sonnenberger 		error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
249902742ec6SJoerg Sonnenberger 		    io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags |
250002742ec6SJoerg Sonnenberger 		    PFR_FLAG_USERIOCTL);
250102742ec6SJoerg Sonnenberger 		break;
250202742ec6SJoerg Sonnenberger 	}
250302742ec6SJoerg Sonnenberger 
250402742ec6SJoerg Sonnenberger 	case DIOCRDELADDRS: {
250502742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
250602742ec6SJoerg Sonnenberger 
250702742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
250802742ec6SJoerg Sonnenberger 			error = ENODEV;
250902742ec6SJoerg Sonnenberger 			break;
251002742ec6SJoerg Sonnenberger 		}
251102742ec6SJoerg Sonnenberger 		error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
251202742ec6SJoerg Sonnenberger 		    io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags |
251302742ec6SJoerg Sonnenberger 		    PFR_FLAG_USERIOCTL);
251402742ec6SJoerg Sonnenberger 		break;
251502742ec6SJoerg Sonnenberger 	}
251602742ec6SJoerg Sonnenberger 
251702742ec6SJoerg Sonnenberger 	case DIOCRSETADDRS: {
251802742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
251902742ec6SJoerg Sonnenberger 
252002742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
252102742ec6SJoerg Sonnenberger 			error = ENODEV;
252202742ec6SJoerg Sonnenberger 			break;
252302742ec6SJoerg Sonnenberger 		}
252402742ec6SJoerg Sonnenberger 		error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
252502742ec6SJoerg Sonnenberger 		    io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
252602742ec6SJoerg Sonnenberger 		    &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
252770224baaSJan Lentfer 		    PFR_FLAG_USERIOCTL, 0);
252802742ec6SJoerg Sonnenberger 		break;
252902742ec6SJoerg Sonnenberger 	}
253002742ec6SJoerg Sonnenberger 
253102742ec6SJoerg Sonnenberger 	case DIOCRGETADDRS: {
253202742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
253302742ec6SJoerg Sonnenberger 
253402742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
253502742ec6SJoerg Sonnenberger 			error = ENODEV;
253602742ec6SJoerg Sonnenberger 			break;
253702742ec6SJoerg Sonnenberger 		}
253802742ec6SJoerg Sonnenberger 		error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
253902742ec6SJoerg Sonnenberger 		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
254002742ec6SJoerg Sonnenberger 		break;
254102742ec6SJoerg Sonnenberger 	}
254202742ec6SJoerg Sonnenberger 
254302742ec6SJoerg Sonnenberger 	case DIOCRGETASTATS: {
254402742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
254502742ec6SJoerg Sonnenberger 
254602742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_astats)) {
254702742ec6SJoerg Sonnenberger 			error = ENODEV;
254802742ec6SJoerg Sonnenberger 			break;
254902742ec6SJoerg Sonnenberger 		}
255002742ec6SJoerg Sonnenberger 		error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
255102742ec6SJoerg Sonnenberger 		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
255202742ec6SJoerg Sonnenberger 		break;
255302742ec6SJoerg Sonnenberger 	}
255402742ec6SJoerg Sonnenberger 
255502742ec6SJoerg Sonnenberger 	case DIOCRCLRASTATS: {
255602742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
255702742ec6SJoerg Sonnenberger 
255802742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
255902742ec6SJoerg Sonnenberger 			error = ENODEV;
256002742ec6SJoerg Sonnenberger 			break;
256102742ec6SJoerg Sonnenberger 		}
256202742ec6SJoerg Sonnenberger 		error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
256302742ec6SJoerg Sonnenberger 		    io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags |
256402742ec6SJoerg Sonnenberger 		    PFR_FLAG_USERIOCTL);
256502742ec6SJoerg Sonnenberger 		break;
256602742ec6SJoerg Sonnenberger 	}
256702742ec6SJoerg Sonnenberger 
256802742ec6SJoerg Sonnenberger 	case DIOCRTSTADDRS: {
256902742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
257002742ec6SJoerg Sonnenberger 
257102742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
257202742ec6SJoerg Sonnenberger 			error = ENODEV;
257302742ec6SJoerg Sonnenberger 			break;
257402742ec6SJoerg Sonnenberger 		}
257502742ec6SJoerg Sonnenberger 		error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
257602742ec6SJoerg Sonnenberger 		    io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags |
257702742ec6SJoerg Sonnenberger 		    PFR_FLAG_USERIOCTL);
257802742ec6SJoerg Sonnenberger 		break;
257902742ec6SJoerg Sonnenberger 	}
258002742ec6SJoerg Sonnenberger 
258102742ec6SJoerg Sonnenberger 	case DIOCRINADEFINE: {
258202742ec6SJoerg Sonnenberger 		struct pfioc_table *io = (struct pfioc_table *)addr;
258302742ec6SJoerg Sonnenberger 
258402742ec6SJoerg Sonnenberger 		if (io->pfrio_esize != sizeof(struct pfr_addr)) {
258502742ec6SJoerg Sonnenberger 			error = ENODEV;
258602742ec6SJoerg Sonnenberger 			break;
258702742ec6SJoerg Sonnenberger 		}
258802742ec6SJoerg Sonnenberger 		error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
258902742ec6SJoerg Sonnenberger 		    io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
259002742ec6SJoerg Sonnenberger 		    io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL);
259102742ec6SJoerg Sonnenberger 		break;
259202742ec6SJoerg Sonnenberger 	}
259302742ec6SJoerg Sonnenberger 
259402742ec6SJoerg Sonnenberger 	case DIOCOSFPADD: {
259502742ec6SJoerg Sonnenberger 		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
259602742ec6SJoerg Sonnenberger 		error = pf_osfp_add(io);
259702742ec6SJoerg Sonnenberger 		break;
259802742ec6SJoerg Sonnenberger 	}
259902742ec6SJoerg Sonnenberger 
260002742ec6SJoerg Sonnenberger 	case DIOCOSFPGET: {
260102742ec6SJoerg Sonnenberger 		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
260202742ec6SJoerg Sonnenberger 		error = pf_osfp_get(io);
260302742ec6SJoerg Sonnenberger 		break;
260402742ec6SJoerg Sonnenberger 	}
260502742ec6SJoerg Sonnenberger 
260602742ec6SJoerg Sonnenberger 	case DIOCXBEGIN: {
260702742ec6SJoerg Sonnenberger 		struct pfioc_trans	*io = (struct pfioc_trans *)addr;
260870224baaSJan Lentfer 		struct pfioc_trans_e	*ioe;
260970224baaSJan Lentfer 		struct pfr_table	*table;
261002742ec6SJoerg Sonnenberger 		int			 i;
261102742ec6SJoerg Sonnenberger 
261270224baaSJan Lentfer 		if (io->esize != sizeof(*ioe)) {
261302742ec6SJoerg Sonnenberger 			error = ENODEV;
261402742ec6SJoerg Sonnenberger 			goto fail;
261502742ec6SJoerg Sonnenberger 		}
2616ed1f0be2SJan Lentfer 		ioe = kmalloc(sizeof(*ioe), M_TEMP, M_WAITOK);
2617ed1f0be2SJan Lentfer 		table = kmalloc(sizeof(*table), M_TEMP, M_WAITOK);
261802742ec6SJoerg Sonnenberger 		for (i = 0; i < io->size; i++) {
261970224baaSJan Lentfer 			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
262070224baaSJan Lentfer 				kfree(table, M_TEMP);
262170224baaSJan Lentfer 				kfree(ioe, M_TEMP);
262202742ec6SJoerg Sonnenberger 				error = EFAULT;
262302742ec6SJoerg Sonnenberger 				goto fail;
262402742ec6SJoerg Sonnenberger 			}
262570224baaSJan Lentfer 			switch (ioe->rs_num) {
262602742ec6SJoerg Sonnenberger #ifdef ALTQ
262702742ec6SJoerg Sonnenberger 			case PF_RULESET_ALTQ:
262870224baaSJan Lentfer 				if (ioe->anchor[0]) {
262970224baaSJan Lentfer 					kfree(table, M_TEMP);
263070224baaSJan Lentfer 					kfree(ioe, M_TEMP);
263102742ec6SJoerg Sonnenberger 					error = EINVAL;
263202742ec6SJoerg Sonnenberger 					goto fail;
263302742ec6SJoerg Sonnenberger 				}
263470224baaSJan Lentfer 				if ((error = pf_begin_altq(&ioe->ticket))) {
263570224baaSJan Lentfer 					kfree(table, M_TEMP);
263670224baaSJan Lentfer 					kfree(ioe, M_TEMP);
263702742ec6SJoerg Sonnenberger 					goto fail;
263870224baaSJan Lentfer 				}
263902742ec6SJoerg Sonnenberger 				break;
264002742ec6SJoerg Sonnenberger #endif /* ALTQ */
264102742ec6SJoerg Sonnenberger 			case PF_RULESET_TABLE:
264270224baaSJan Lentfer 				bzero(table, sizeof(*table));
264370224baaSJan Lentfer 				strlcpy(table->pfrt_anchor, ioe->anchor,
264470224baaSJan Lentfer 				    sizeof(table->pfrt_anchor));
264570224baaSJan Lentfer 				if ((error = pfr_ina_begin(table,
264670224baaSJan Lentfer 				    &ioe->ticket, NULL, 0))) {
264770224baaSJan Lentfer 					kfree(table, M_TEMP);
264870224baaSJan Lentfer 					kfree(ioe, M_TEMP);
264902742ec6SJoerg Sonnenberger 					goto fail;
265070224baaSJan Lentfer 				}
265102742ec6SJoerg Sonnenberger 				break;
265202742ec6SJoerg Sonnenberger 			default:
265370224baaSJan Lentfer 				if ((error = pf_begin_rules(&ioe->ticket,
265470224baaSJan Lentfer 				    ioe->rs_num, ioe->anchor))) {
265570224baaSJan Lentfer 					kfree(table, M_TEMP);
265670224baaSJan Lentfer 					kfree(ioe, M_TEMP);
265702742ec6SJoerg Sonnenberger 					goto fail;
265870224baaSJan Lentfer 				}
265902742ec6SJoerg Sonnenberger 				break;
266002742ec6SJoerg Sonnenberger 			}
266170224baaSJan Lentfer 			if (copyout(ioe, io->array+i, sizeof(io->array[i]))) {
266270224baaSJan Lentfer 				kfree(table, M_TEMP);
266370224baaSJan Lentfer 				kfree(ioe, M_TEMP);
266402742ec6SJoerg Sonnenberger 				error = EFAULT;
266502742ec6SJoerg Sonnenberger 				goto fail;
266602742ec6SJoerg Sonnenberger 			}
266702742ec6SJoerg Sonnenberger 		}
266870224baaSJan Lentfer 		kfree(table, M_TEMP);
266970224baaSJan Lentfer 		kfree(ioe, M_TEMP);
267002742ec6SJoerg Sonnenberger 		break;
267102742ec6SJoerg Sonnenberger 	}
267202742ec6SJoerg Sonnenberger 
267302742ec6SJoerg Sonnenberger 	case DIOCXROLLBACK: {
267402742ec6SJoerg Sonnenberger 		struct pfioc_trans	*io = (struct pfioc_trans *)addr;
267570224baaSJan Lentfer 		struct pfioc_trans_e	*ioe;
267670224baaSJan Lentfer 		struct pfr_table	*table;
267702742ec6SJoerg Sonnenberger 		int			 i;
267802742ec6SJoerg Sonnenberger 
267970224baaSJan Lentfer 		if (io->esize != sizeof(*ioe)) {
268002742ec6SJoerg Sonnenberger 			error = ENODEV;
268102742ec6SJoerg Sonnenberger 			goto fail;
268202742ec6SJoerg Sonnenberger 		}
2683ed1f0be2SJan Lentfer 		ioe = kmalloc(sizeof(*ioe), M_TEMP, M_WAITOK);
2684ed1f0be2SJan Lentfer 		table = kmalloc(sizeof(*table), M_TEMP, M_WAITOK);
268502742ec6SJoerg Sonnenberger 		for (i = 0; i < io->size; i++) {
268670224baaSJan Lentfer 			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
268770224baaSJan Lentfer 				kfree(table, M_TEMP);
268870224baaSJan Lentfer 				kfree(ioe, M_TEMP);
268902742ec6SJoerg Sonnenberger 				error = EFAULT;
269002742ec6SJoerg Sonnenberger 				goto fail;
269102742ec6SJoerg Sonnenberger 			}
269270224baaSJan Lentfer 			switch (ioe->rs_num) {
269302742ec6SJoerg Sonnenberger #ifdef ALTQ
269402742ec6SJoerg Sonnenberger 			case PF_RULESET_ALTQ:
269570224baaSJan Lentfer 				if (ioe->anchor[0]) {
269670224baaSJan Lentfer 					kfree(table, M_TEMP);
269770224baaSJan Lentfer 					kfree(ioe, M_TEMP);
269802742ec6SJoerg Sonnenberger 					error = EINVAL;
269902742ec6SJoerg Sonnenberger 					goto fail;
270002742ec6SJoerg Sonnenberger 				}
270170224baaSJan Lentfer 				if ((error = pf_rollback_altq(ioe->ticket))) {
270270224baaSJan Lentfer 					kfree(table, M_TEMP);
270370224baaSJan Lentfer 					kfree(ioe, M_TEMP);
270402742ec6SJoerg Sonnenberger 					goto fail; /* really bad */
270570224baaSJan Lentfer 				}
270602742ec6SJoerg Sonnenberger 				break;
270702742ec6SJoerg Sonnenberger #endif /* ALTQ */
270802742ec6SJoerg Sonnenberger 			case PF_RULESET_TABLE:
270970224baaSJan Lentfer 				bzero(table, sizeof(*table));
271070224baaSJan Lentfer 				strlcpy(table->pfrt_anchor, ioe->anchor,
271170224baaSJan Lentfer 				    sizeof(table->pfrt_anchor));
271270224baaSJan Lentfer 				if ((error = pfr_ina_rollback(table,
271370224baaSJan Lentfer 				    ioe->ticket, NULL, 0))) {
271470224baaSJan Lentfer 					kfree(table, M_TEMP);
271570224baaSJan Lentfer 					kfree(ioe, M_TEMP);
271602742ec6SJoerg Sonnenberger 					goto fail; /* really bad */
271770224baaSJan Lentfer 				}
271802742ec6SJoerg Sonnenberger 				break;
271902742ec6SJoerg Sonnenberger 			default:
272070224baaSJan Lentfer 				if ((error = pf_rollback_rules(ioe->ticket,
272170224baaSJan Lentfer 				    ioe->rs_num, ioe->anchor))) {
272270224baaSJan Lentfer 					kfree(table, M_TEMP);
272370224baaSJan Lentfer 					kfree(ioe, M_TEMP);
272402742ec6SJoerg Sonnenberger 					goto fail; /* really bad */
272570224baaSJan Lentfer 				}
272602742ec6SJoerg Sonnenberger 				break;
272702742ec6SJoerg Sonnenberger 			}
272802742ec6SJoerg Sonnenberger 		}
272970224baaSJan Lentfer 		kfree(table, M_TEMP);
273070224baaSJan Lentfer 		kfree(ioe, M_TEMP);
273102742ec6SJoerg Sonnenberger 		break;
273202742ec6SJoerg Sonnenberger 	}
273302742ec6SJoerg Sonnenberger 
273402742ec6SJoerg Sonnenberger 	case DIOCXCOMMIT: {
273502742ec6SJoerg Sonnenberger 		struct pfioc_trans	*io = (struct pfioc_trans *)addr;
273670224baaSJan Lentfer 		struct pfioc_trans_e	*ioe;
273770224baaSJan Lentfer 		struct pfr_table	*table;
273802742ec6SJoerg Sonnenberger 		struct pf_ruleset	*rs;
273902742ec6SJoerg Sonnenberger 		int			 i;
274002742ec6SJoerg Sonnenberger 
274170224baaSJan Lentfer 		if (io->esize != sizeof(*ioe)) {
274202742ec6SJoerg Sonnenberger 			error = ENODEV;
274302742ec6SJoerg Sonnenberger 			goto fail;
274402742ec6SJoerg Sonnenberger 		}
2745ed1f0be2SJan Lentfer 		ioe = kmalloc(sizeof(*ioe), M_TEMP, M_WAITOK);
2746ed1f0be2SJan Lentfer 		table = kmalloc(sizeof(*table), M_TEMP, M_WAITOK);
274702742ec6SJoerg Sonnenberger 		/* first makes sure everything will succeed */
274802742ec6SJoerg Sonnenberger 		for (i = 0; i < io->size; i++) {
274970224baaSJan Lentfer 			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
275070224baaSJan Lentfer 				kfree(table, M_TEMP);
275170224baaSJan Lentfer 				kfree(ioe, M_TEMP);
275202742ec6SJoerg Sonnenberger 				error = EFAULT;
275302742ec6SJoerg Sonnenberger 				goto fail;
275402742ec6SJoerg Sonnenberger 			}
275570224baaSJan Lentfer 			switch (ioe->rs_num) {
275602742ec6SJoerg Sonnenberger #ifdef ALTQ
275702742ec6SJoerg Sonnenberger 			case PF_RULESET_ALTQ:
275870224baaSJan Lentfer 				if (ioe->anchor[0]) {
275970224baaSJan Lentfer 					kfree(table, M_TEMP);
276070224baaSJan Lentfer 					kfree(ioe, M_TEMP);
276102742ec6SJoerg Sonnenberger 					error = EINVAL;
276202742ec6SJoerg Sonnenberger 					goto fail;
276302742ec6SJoerg Sonnenberger 				}
276470224baaSJan Lentfer 				if (!altqs_inactive_open || ioe->ticket !=
276502742ec6SJoerg Sonnenberger 				    ticket_altqs_inactive) {
276670224baaSJan Lentfer 					kfree(table, M_TEMP);
276770224baaSJan Lentfer 					kfree(ioe, M_TEMP);
276802742ec6SJoerg Sonnenberger 					error = EBUSY;
276902742ec6SJoerg Sonnenberger 					goto fail;
277002742ec6SJoerg Sonnenberger 				}
277102742ec6SJoerg Sonnenberger 				break;
277202742ec6SJoerg Sonnenberger #endif /* ALTQ */
277302742ec6SJoerg Sonnenberger 			case PF_RULESET_TABLE:
277470224baaSJan Lentfer 				rs = pf_find_ruleset(ioe->anchor);
277570224baaSJan Lentfer 				if (rs == NULL || !rs->topen || ioe->ticket !=
277602742ec6SJoerg Sonnenberger 				     rs->tticket) {
277770224baaSJan Lentfer 					kfree(table, M_TEMP);
277870224baaSJan Lentfer 					kfree(ioe, M_TEMP);
277902742ec6SJoerg Sonnenberger 					error = EBUSY;
278002742ec6SJoerg Sonnenberger 					goto fail;
278102742ec6SJoerg Sonnenberger 				}
278202742ec6SJoerg Sonnenberger 				break;
278302742ec6SJoerg Sonnenberger 			default:
278470224baaSJan Lentfer 				if (ioe->rs_num < 0 || ioe->rs_num >=
278502742ec6SJoerg Sonnenberger 				    PF_RULESET_MAX) {
278670224baaSJan Lentfer 					kfree(table, M_TEMP);
278770224baaSJan Lentfer 					kfree(ioe, M_TEMP);
278802742ec6SJoerg Sonnenberger 					error = EINVAL;
278902742ec6SJoerg Sonnenberger 					goto fail;
279002742ec6SJoerg Sonnenberger 				}
279170224baaSJan Lentfer 				rs = pf_find_ruleset(ioe->anchor);
279202742ec6SJoerg Sonnenberger 				if (rs == NULL ||
279370224baaSJan Lentfer 				    !rs->rules[ioe->rs_num].inactive.open ||
279470224baaSJan Lentfer 				    rs->rules[ioe->rs_num].inactive.ticket !=
279570224baaSJan Lentfer 				    ioe->ticket) {
279670224baaSJan Lentfer 					kfree(table, M_TEMP);
279770224baaSJan Lentfer 					kfree(ioe, M_TEMP);
279802742ec6SJoerg Sonnenberger 					error = EBUSY;
279902742ec6SJoerg Sonnenberger 					goto fail;
280002742ec6SJoerg Sonnenberger 				}
280102742ec6SJoerg Sonnenberger 				break;
280202742ec6SJoerg Sonnenberger 			}
280302742ec6SJoerg Sonnenberger 		}
280402742ec6SJoerg Sonnenberger 		/* now do the commit - no errors should happen here */
280502742ec6SJoerg Sonnenberger 		for (i = 0; i < io->size; i++) {
280670224baaSJan Lentfer 			if (copyin(io->array+i, ioe, sizeof(*ioe))) {
280770224baaSJan Lentfer 				kfree(table, M_TEMP);
280870224baaSJan Lentfer 				kfree(ioe, M_TEMP);
280902742ec6SJoerg Sonnenberger 				error = EFAULT;
281002742ec6SJoerg Sonnenberger 				goto fail;
281102742ec6SJoerg Sonnenberger 			}
281270224baaSJan Lentfer 			switch (ioe->rs_num) {
281302742ec6SJoerg Sonnenberger #ifdef ALTQ
281402742ec6SJoerg Sonnenberger 			case PF_RULESET_ALTQ:
281570224baaSJan Lentfer 				if ((error = pf_commit_altq(ioe->ticket))) {
281670224baaSJan Lentfer 					kfree(table, M_TEMP);
281770224baaSJan Lentfer 					kfree(ioe, M_TEMP);
281802742ec6SJoerg Sonnenberger 					goto fail; /* really bad */
281970224baaSJan Lentfer 				}
282002742ec6SJoerg Sonnenberger 				break;
282102742ec6SJoerg Sonnenberger #endif /* ALTQ */
282202742ec6SJoerg Sonnenberger 			case PF_RULESET_TABLE:
282370224baaSJan Lentfer 				bzero(table, sizeof(*table));
282470224baaSJan Lentfer 				strlcpy(table->pfrt_anchor, ioe->anchor,
282570224baaSJan Lentfer 				    sizeof(table->pfrt_anchor));
282670224baaSJan Lentfer 				if ((error = pfr_ina_commit(table, ioe->ticket,
282770224baaSJan Lentfer 				    NULL, NULL, 0))) {
282870224baaSJan Lentfer 					kfree(table, M_TEMP);
282970224baaSJan Lentfer 					kfree(ioe, M_TEMP);
283002742ec6SJoerg Sonnenberger 					goto fail; /* really bad */
283170224baaSJan Lentfer 				}
283202742ec6SJoerg Sonnenberger 				break;
283302742ec6SJoerg Sonnenberger 			default:
283470224baaSJan Lentfer 				if ((error = pf_commit_rules(ioe->ticket,
283570224baaSJan Lentfer 				    ioe->rs_num, ioe->anchor))) {
283670224baaSJan Lentfer 					kfree(table, M_TEMP);
283770224baaSJan Lentfer 					kfree(ioe, M_TEMP);
283802742ec6SJoerg Sonnenberger 					goto fail; /* really bad */
283970224baaSJan Lentfer 				}
284002742ec6SJoerg Sonnenberger 				break;
284102742ec6SJoerg Sonnenberger 			}
284202742ec6SJoerg Sonnenberger 		}
284370224baaSJan Lentfer 		kfree(table, M_TEMP);
284470224baaSJan Lentfer 		kfree(ioe, M_TEMP);
284502742ec6SJoerg Sonnenberger 		break;
284602742ec6SJoerg Sonnenberger 	}
284702742ec6SJoerg Sonnenberger 
284802742ec6SJoerg Sonnenberger 	case DIOCGETSRCNODES: {
284902742ec6SJoerg Sonnenberger 		struct pfioc_src_nodes	*psn = (struct pfioc_src_nodes *)addr;
285070224baaSJan Lentfer 		struct pf_src_node	*n, *p, *pstore;
285102742ec6SJoerg Sonnenberger 		u_int32_t nr = 0;
285202742ec6SJoerg Sonnenberger 		int	space = psn->psn_len;
28533a0038bfSMatthew Dillon 		int	nn;
285402742ec6SJoerg Sonnenberger 
285502742ec6SJoerg Sonnenberger 		if (space == 0) {
28563a0038bfSMatthew Dillon 			for (nn = 0; nn < ncpus; ++nn) {
28573a0038bfSMatthew Dillon 				RB_FOREACH(n, pf_src_tree,
28583a0038bfSMatthew Dillon 					   &tree_src_tracking[nn]) {
285902742ec6SJoerg Sonnenberger 					nr++;
28603a0038bfSMatthew Dillon 				}
28613a0038bfSMatthew Dillon 			}
286202742ec6SJoerg Sonnenberger 			psn->psn_len = sizeof(struct pf_src_node) * nr;
286370224baaSJan Lentfer 			break;
286402742ec6SJoerg Sonnenberger 		}
286502742ec6SJoerg Sonnenberger 
286670224baaSJan Lentfer 		pstore = kmalloc(sizeof(*pstore), M_TEMP, M_WAITOK);
286770224baaSJan Lentfer 
286802742ec6SJoerg Sonnenberger 		p = psn->psn_src_nodes;
28693a0038bfSMatthew Dillon 
28703a0038bfSMatthew Dillon 		/*
28713a0038bfSMatthew Dillon 		 * WARNING: We are not switching cpus so we cannot call
28723a0038bfSMatthew Dillon 		 *	    nominal pf.c support routines for cpu-specific
28733a0038bfSMatthew Dillon 		 *	    data.
28743a0038bfSMatthew Dillon 		 */
28753a0038bfSMatthew Dillon 		for (nn = 0; nn < ncpus; ++nn) {
28763a0038bfSMatthew Dillon 			RB_FOREACH(n, pf_src_tree, &tree_src_tracking[nn]) {
287770224baaSJan Lentfer 				int	secs = time_second, diff;
287802742ec6SJoerg Sonnenberger 
28793a0038bfSMatthew Dillon 				if ((nr + 1) * sizeof(*p) >
28803a0038bfSMatthew Dillon 				    (unsigned)psn->psn_len) {
288102742ec6SJoerg Sonnenberger 					break;
28823a0038bfSMatthew Dillon 				}
288302742ec6SJoerg Sonnenberger 
288470224baaSJan Lentfer 				bcopy(n, pstore, sizeof(*pstore));
288502742ec6SJoerg Sonnenberger 				if (n->rule.ptr != NULL)
288670224baaSJan Lentfer 					pstore->rule.nr = n->rule.ptr->nr;
288770224baaSJan Lentfer 				pstore->creation = secs - pstore->creation;
288870224baaSJan Lentfer 				if (pstore->expire > secs)
288970224baaSJan Lentfer 					pstore->expire -= secs;
289002742ec6SJoerg Sonnenberger 				else
289170224baaSJan Lentfer 					pstore->expire = 0;
289270224baaSJan Lentfer 
289370224baaSJan Lentfer 				/* adjust the connection rate estimate */
289470224baaSJan Lentfer 				diff = secs - n->conn_rate.last;
289570224baaSJan Lentfer 				if (diff >= n->conn_rate.seconds)
289670224baaSJan Lentfer 					pstore->conn_rate.count = 0;
289770224baaSJan Lentfer 				else
289870224baaSJan Lentfer 					pstore->conn_rate.count -=
289970224baaSJan Lentfer 					    n->conn_rate.count * diff /
290070224baaSJan Lentfer 					    n->conn_rate.seconds;
290170224baaSJan Lentfer 
290270224baaSJan Lentfer 				error = copyout(pstore, p, sizeof(*p));
290302742ec6SJoerg Sonnenberger 				if (error) {
290470224baaSJan Lentfer 					kfree(pstore, M_TEMP);
290502742ec6SJoerg Sonnenberger 					goto fail;
290602742ec6SJoerg Sonnenberger 				}
290702742ec6SJoerg Sonnenberger 				p++;
290802742ec6SJoerg Sonnenberger 				nr++;
290902742ec6SJoerg Sonnenberger 			}
29103a0038bfSMatthew Dillon 		}
291102742ec6SJoerg Sonnenberger 		psn->psn_len = sizeof(struct pf_src_node) * nr;
291270224baaSJan Lentfer 		kfree(pstore, M_TEMP);
291302742ec6SJoerg Sonnenberger 		break;
291402742ec6SJoerg Sonnenberger 	}
291502742ec6SJoerg Sonnenberger 
291602742ec6SJoerg Sonnenberger 	case DIOCCLRSRCNODES: {
291702742ec6SJoerg Sonnenberger 		struct pf_src_node	*n;
291802742ec6SJoerg Sonnenberger 		struct pf_state		*state;
29193a0038bfSMatthew Dillon 		globaldata_t save_gd = mycpu;
29203a0038bfSMatthew Dillon 		int nn;
292102742ec6SJoerg Sonnenberger 
29223a0038bfSMatthew Dillon 		/*
29233a0038bfSMatthew Dillon 		 * WARNING: We are not switching cpus so we cannot call
29243a0038bfSMatthew Dillon 		 *	    nominal pf.c support routines for cpu-specific
29253a0038bfSMatthew Dillon 		 *	    data.
29263a0038bfSMatthew Dillon 		 */
29273a0038bfSMatthew Dillon 		for (nn = 0; nn < ncpus; ++nn) {
29283a0038bfSMatthew Dillon 			RB_FOREACH(state, pf_state_tree_id, &tree_id[nn]) {
292902742ec6SJoerg Sonnenberger 				state->src_node = NULL;
293002742ec6SJoerg Sonnenberger 				state->nat_src_node = NULL;
293102742ec6SJoerg Sonnenberger 			}
29323a0038bfSMatthew Dillon 			RB_FOREACH(n, pf_src_tree, &tree_src_tracking[nn]) {
293302742ec6SJoerg Sonnenberger 				n->expire = 1;
293402742ec6SJoerg Sonnenberger 				n->states = 0;
293502742ec6SJoerg Sonnenberger 			}
29363a0038bfSMatthew Dillon 		}
29373a0038bfSMatthew Dillon 
29383a0038bfSMatthew Dillon 		/*
29393a0038bfSMatthew Dillon 		 * WARNING: Must move to the target cpu for nominal calls
29403a0038bfSMatthew Dillon 		 *	    into pf.c
29413a0038bfSMatthew Dillon 		 */
29423a0038bfSMatthew Dillon 		for (nn = 0; nn < ncpus; ++nn) {
29433a0038bfSMatthew Dillon 			lwkt_setcpu_self(globaldata_find(nn));
294470224baaSJan Lentfer 			pf_purge_expired_src_nodes(1);
29453a0038bfSMatthew Dillon 		}
29463a0038bfSMatthew Dillon 		lwkt_setcpu_self(save_gd);
294702742ec6SJoerg Sonnenberger 		pf_status.src_nodes = 0;
294870224baaSJan Lentfer 		break;
294970224baaSJan Lentfer 	}
295070224baaSJan Lentfer 
295170224baaSJan Lentfer 	case DIOCKILLSRCNODES: {
295270224baaSJan Lentfer 		struct pf_src_node	*sn;
295370224baaSJan Lentfer 		struct pf_state		*s;
2954ed1f0be2SJan Lentfer 		struct pfioc_src_node_kill *psnk =
295570224baaSJan Lentfer 		    (struct pfioc_src_node_kill *)addr;
2956ed1f0be2SJan Lentfer 		u_int			killed = 0;
29573a0038bfSMatthew Dillon 		globaldata_t save_gd = mycpu;
29583a0038bfSMatthew Dillon 		int nn;
295970224baaSJan Lentfer 
29603a0038bfSMatthew Dillon 		/*
29613a0038bfSMatthew Dillon 		 * WARNING: We are not switching cpus so we cannot call
29623a0038bfSMatthew Dillon 		 *	    nominal pf.c support routines for cpu-specific
29633a0038bfSMatthew Dillon 		 *	    data.
29643a0038bfSMatthew Dillon 		 */
29653a0038bfSMatthew Dillon 		for (nn = 0; nn < ncpus; ++nn) {
29663a0038bfSMatthew Dillon 		    RB_FOREACH(sn, pf_src_tree, &tree_src_tracking[nn]) {
2967ed1f0be2SJan Lentfer 			if (PF_MATCHA(psnk->psnk_src.neg,
2968ed1f0be2SJan Lentfer 				&psnk->psnk_src.addr.v.a.addr,
2969ed1f0be2SJan Lentfer 				&psnk->psnk_src.addr.v.a.mask,
297070224baaSJan Lentfer 				&sn->addr, sn->af) &&
2971ed1f0be2SJan Lentfer 			    PF_MATCHA(psnk->psnk_dst.neg,
2972ed1f0be2SJan Lentfer 				&psnk->psnk_dst.addr.v.a.addr,
2973ed1f0be2SJan Lentfer 				&psnk->psnk_dst.addr.v.a.mask,
297470224baaSJan Lentfer 				&sn->raddr, sn->af)) {
297570224baaSJan Lentfer 				/* Handle state to src_node linkage */
297670224baaSJan Lentfer 				if (sn->states != 0) {
297770224baaSJan Lentfer 					RB_FOREACH(s, pf_state_tree_id,
29783a0038bfSMatthew Dillon 					    &tree_id[nn]) {
297970224baaSJan Lentfer 						if (s->src_node == sn)
298070224baaSJan Lentfer 							s->src_node = NULL;
298170224baaSJan Lentfer 						if (s->nat_src_node == sn)
298270224baaSJan Lentfer 							s->nat_src_node = NULL;
298370224baaSJan Lentfer 					}
298470224baaSJan Lentfer 					sn->states = 0;
298570224baaSJan Lentfer 				}
298670224baaSJan Lentfer 				sn->expire = 1;
298770224baaSJan Lentfer 				killed++;
298870224baaSJan Lentfer 			}
298970224baaSJan Lentfer 		    }
29903a0038bfSMatthew Dillon 		}
29913a0038bfSMatthew Dillon 		if (killed > 0) {
29923a0038bfSMatthew Dillon 			for (nn = 0; nn < ncpus; ++nn) {
29933a0038bfSMatthew Dillon 				lwkt_setcpu_self(globaldata_find(nn));
299470224baaSJan Lentfer 				pf_purge_expired_src_nodes(1);
29953a0038bfSMatthew Dillon 			}
29963a0038bfSMatthew Dillon 			lwkt_setcpu_self(save_gd);
29973a0038bfSMatthew Dillon 		}
299870224baaSJan Lentfer 
2999ed1f0be2SJan Lentfer 		psnk->psnk_killed = killed;
300002742ec6SJoerg Sonnenberger 		break;
300102742ec6SJoerg Sonnenberger 	}
300202742ec6SJoerg Sonnenberger 
300302742ec6SJoerg Sonnenberger 	case DIOCSETHOSTID: {
300402742ec6SJoerg Sonnenberger 		u_int32_t	*hostid = (u_int32_t *)addr;
300502742ec6SJoerg Sonnenberger 
300670224baaSJan Lentfer 		if (*hostid == 0)
300770224baaSJan Lentfer 			pf_status.hostid = karc4random();
300870224baaSJan Lentfer 		else
300902742ec6SJoerg Sonnenberger 			pf_status.hostid = *hostid;
301002742ec6SJoerg Sonnenberger 		break;
301102742ec6SJoerg Sonnenberger 	}
301202742ec6SJoerg Sonnenberger 
301302742ec6SJoerg Sonnenberger 	case DIOCOSFPFLUSH:
3014cc6e5672SJoerg Sonnenberger 		crit_enter();
301502742ec6SJoerg Sonnenberger 		pf_osfp_flush();
3016cc6e5672SJoerg Sonnenberger 		crit_exit();
301702742ec6SJoerg Sonnenberger 		break;
301802742ec6SJoerg Sonnenberger 
301902742ec6SJoerg Sonnenberger 	case DIOCIGETIFACES: {
302002742ec6SJoerg Sonnenberger 		struct pfioc_iface *io = (struct pfioc_iface *)addr;
302102742ec6SJoerg Sonnenberger 
302270224baaSJan Lentfer 		if (io->pfiio_esize != sizeof(struct pfi_kif)) {
302302742ec6SJoerg Sonnenberger 			error = ENODEV;
302402742ec6SJoerg Sonnenberger 			break;
302502742ec6SJoerg Sonnenberger 		}
302602742ec6SJoerg Sonnenberger 		error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer,
302770224baaSJan Lentfer 		    &io->pfiio_size);
302802742ec6SJoerg Sonnenberger 		break;
302902742ec6SJoerg Sonnenberger 	}
303002742ec6SJoerg Sonnenberger 
303170224baaSJan Lentfer 	case DIOCSETIFFLAG: {
303202742ec6SJoerg Sonnenberger 		struct pfioc_iface *io = (struct pfioc_iface *)addr;
303302742ec6SJoerg Sonnenberger 
303470224baaSJan Lentfer 		error = pfi_set_flags(io->pfiio_name, io->pfiio_flags);
303570224baaSJan Lentfer 		break;
303670224baaSJan Lentfer 	}
303770224baaSJan Lentfer 
303870224baaSJan Lentfer 	case DIOCCLRIFFLAG: {
303970224baaSJan Lentfer 		struct pfioc_iface *io = (struct pfioc_iface *)addr;
304070224baaSJan Lentfer 
304170224baaSJan Lentfer 		error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags);
304202742ec6SJoerg Sonnenberger 		break;
304302742ec6SJoerg Sonnenberger 	}
304402742ec6SJoerg Sonnenberger 
304502742ec6SJoerg Sonnenberger 	default:
304602742ec6SJoerg Sonnenberger 		error = ENODEV;
304702742ec6SJoerg Sonnenberger 		break;
304802742ec6SJoerg Sonnenberger 	}
304902742ec6SJoerg Sonnenberger fail:
30502a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
305102742ec6SJoerg Sonnenberger 	return (error);
305202742ec6SJoerg Sonnenberger }
305302742ec6SJoerg Sonnenberger 
305402742ec6SJoerg Sonnenberger /*
305502742ec6SJoerg Sonnenberger  * XXX - Check for version missmatch!!!
305602742ec6SJoerg Sonnenberger  */
305702742ec6SJoerg Sonnenberger static void
pf_clear_states(void)305802742ec6SJoerg Sonnenberger pf_clear_states(void)
305902742ec6SJoerg Sonnenberger {
30601186cbc0SJan Lentfer 	struct pf_state		*s, *nexts;
30613a0038bfSMatthew Dillon 	globaldata_t save_gd = mycpu;
30623a0038bfSMatthew Dillon 	int nn;
306302742ec6SJoerg Sonnenberger 
30643a0038bfSMatthew Dillon 	for (nn = 0; nn < ncpus; ++nn) {
30653a0038bfSMatthew Dillon 		lwkt_setcpu_self(globaldata_find(nn));
30663a0038bfSMatthew Dillon 		for (s = RB_MIN(pf_state_tree_id, &tree_id[nn]); s; s = nexts) {
30673a0038bfSMatthew Dillon 			nexts = RB_NEXT(pf_state_tree_id, &tree_id[nn], s);
30681186cbc0SJan Lentfer 
306902742ec6SJoerg Sonnenberger 			/* don't send out individual delete messages */
30701186cbc0SJan Lentfer 			s->sync_flags = PFSTATE_NOSYNC;
30711186cbc0SJan Lentfer 			pf_unlink_state(s);
30723a0038bfSMatthew Dillon 		}
30731186cbc0SJan Lentfer 
307402742ec6SJoerg Sonnenberger 	}
30753a0038bfSMatthew Dillon 	lwkt_setcpu_self(save_gd);
30761186cbc0SJan Lentfer 
3077ed1f0be2SJan Lentfer #if 0 /* PFSYNC */
307802742ec6SJoerg Sonnenberger /*
307902742ec6SJoerg Sonnenberger  * XXX This is called on module unload, we do not want to sync that over? */
308002742ec6SJoerg Sonnenberger  */
308102742ec6SJoerg Sonnenberger 	pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
308202742ec6SJoerg Sonnenberger #endif
308302742ec6SJoerg Sonnenberger }
308402742ec6SJoerg Sonnenberger 
308502742ec6SJoerg Sonnenberger static int
pf_clear_tables(void)308602742ec6SJoerg Sonnenberger pf_clear_tables(void)
308702742ec6SJoerg Sonnenberger {
308802742ec6SJoerg Sonnenberger 	struct pfioc_table io;
308902742ec6SJoerg Sonnenberger 	int error;
309002742ec6SJoerg Sonnenberger 
309102742ec6SJoerg Sonnenberger 	bzero(&io, sizeof(io));
309202742ec6SJoerg Sonnenberger 
309302742ec6SJoerg Sonnenberger 	error = pfr_clr_tables(&io.pfrio_table, &io.pfrio_ndel,
309402742ec6SJoerg Sonnenberger 	    io.pfrio_flags);
309502742ec6SJoerg Sonnenberger 
309602742ec6SJoerg Sonnenberger 	return (error);
309702742ec6SJoerg Sonnenberger }
309802742ec6SJoerg Sonnenberger 
309902742ec6SJoerg Sonnenberger static void
pf_clear_srcnodes(void)310002742ec6SJoerg Sonnenberger pf_clear_srcnodes(void)
310102742ec6SJoerg Sonnenberger {
310202742ec6SJoerg Sonnenberger 	struct pf_src_node	*n;
310302742ec6SJoerg Sonnenberger 	struct pf_state		*state;
31043a0038bfSMatthew Dillon 	globaldata_t save_gd = mycpu;
31053a0038bfSMatthew Dillon 	int nn;
310602742ec6SJoerg Sonnenberger 
31073a0038bfSMatthew Dillon 	for (nn = 0; nn < ncpus; ++nn) {
31083a0038bfSMatthew Dillon 		lwkt_setcpu_self(globaldata_find(nn));
31093a0038bfSMatthew Dillon 		RB_FOREACH(state, pf_state_tree_id, &tree_id[nn]) {
311002742ec6SJoerg Sonnenberger 			state->src_node = NULL;
311102742ec6SJoerg Sonnenberger 			state->nat_src_node = NULL;
311202742ec6SJoerg Sonnenberger 		}
31133a0038bfSMatthew Dillon 		RB_FOREACH(n, pf_src_tree, &tree_src_tracking[nn]) {
311402742ec6SJoerg Sonnenberger 			n->expire = 1;
311502742ec6SJoerg Sonnenberger 			n->states = 0;
311602742ec6SJoerg Sonnenberger 		}
311770224baaSJan Lentfer 		pf_purge_expired_src_nodes(0);
31183a0038bfSMatthew Dillon 	}
31193a0038bfSMatthew Dillon 	lwkt_setcpu_self(save_gd);
31203a0038bfSMatthew Dillon 
312102742ec6SJoerg Sonnenberger 	pf_status.src_nodes = 0;
312202742ec6SJoerg Sonnenberger }
31231186cbc0SJan Lentfer 
312402742ec6SJoerg Sonnenberger /*
312502742ec6SJoerg Sonnenberger  * XXX - Check for version missmatch!!!
312602742ec6SJoerg Sonnenberger  */
312702742ec6SJoerg Sonnenberger 
312802742ec6SJoerg Sonnenberger /*
312902742ec6SJoerg Sonnenberger  * Duplicate pfctl -Fa operation to get rid of as much as we can.
313002742ec6SJoerg Sonnenberger  */
313102742ec6SJoerg Sonnenberger static int
shutdown_pf(void)313202742ec6SJoerg Sonnenberger shutdown_pf(void)
313302742ec6SJoerg Sonnenberger {
313402742ec6SJoerg Sonnenberger 	int error = 0;
313502742ec6SJoerg Sonnenberger 	u_int32_t t[5];
313602742ec6SJoerg Sonnenberger 	char nn = '\0';
313702742ec6SJoerg Sonnenberger 
3138ed1f0be2SJan Lentfer 
313902742ec6SJoerg Sonnenberger 	pf_status.running = 0;
31401186cbc0SJan Lentfer 	error = dehook_pf();
31411186cbc0SJan Lentfer 	if (error) {
31421186cbc0SJan Lentfer 		pf_status.running = 1;
31431186cbc0SJan Lentfer 		DPFPRINTF(PF_DEBUG_MISC,
31441186cbc0SJan Lentfer 		    ("pf: pfil unregistration failed\n"));
31451186cbc0SJan Lentfer 		return(error);
31461186cbc0SJan Lentfer 	}
314702742ec6SJoerg Sonnenberger 	do {
314870224baaSJan Lentfer 		if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn)) != 0) {
314902742ec6SJoerg Sonnenberger 			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: SCRUB\n"));
315002742ec6SJoerg Sonnenberger 			break;
315102742ec6SJoerg Sonnenberger 		}
315270224baaSJan Lentfer 		if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn)) != 0) {
315302742ec6SJoerg Sonnenberger 			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n"));
315402742ec6SJoerg Sonnenberger 			break;		/* XXX: rollback? */
315502742ec6SJoerg Sonnenberger 		}
315670224baaSJan Lentfer 		if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn))    != 0) {
315702742ec6SJoerg Sonnenberger 			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n"));
315802742ec6SJoerg Sonnenberger 			break;		/* XXX: rollback? */
315902742ec6SJoerg Sonnenberger 		}
316070224baaSJan Lentfer 		if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn))
316102742ec6SJoerg Sonnenberger 		    != 0) {
316202742ec6SJoerg Sonnenberger 			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n"));
316302742ec6SJoerg Sonnenberger 			break;		/* XXX: rollback? */
316402742ec6SJoerg Sonnenberger 		}
316570224baaSJan Lentfer 		if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn))
316602742ec6SJoerg Sonnenberger 		    != 0) {
316702742ec6SJoerg Sonnenberger 			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n"));
316802742ec6SJoerg Sonnenberger 			break;		/* XXX: rollback? */
316902742ec6SJoerg Sonnenberger 		}
317002742ec6SJoerg Sonnenberger 
317102742ec6SJoerg Sonnenberger 		/* XXX: these should always succeed here */
317270224baaSJan Lentfer 		pf_commit_rules(t[0], PF_RULESET_SCRUB, &nn);
317370224baaSJan Lentfer 		pf_commit_rules(t[1], PF_RULESET_FILTER, &nn);
317470224baaSJan Lentfer 		pf_commit_rules(t[2], PF_RULESET_NAT, &nn);
317570224baaSJan Lentfer 		pf_commit_rules(t[3], PF_RULESET_BINAT, &nn);
317670224baaSJan Lentfer 		pf_commit_rules(t[4], PF_RULESET_RDR, &nn);
317702742ec6SJoerg Sonnenberger 
317802742ec6SJoerg Sonnenberger 		if ((error = pf_clear_tables()) != 0)
317902742ec6SJoerg Sonnenberger 			break;
318002742ec6SJoerg Sonnenberger #ifdef ALTQ
318102742ec6SJoerg Sonnenberger 		if ((error = pf_begin_altq(&t[0])) != 0) {
318202742ec6SJoerg Sonnenberger 			DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n"));
318302742ec6SJoerg Sonnenberger 			break;
318402742ec6SJoerg Sonnenberger 		}
318502742ec6SJoerg Sonnenberger 		pf_commit_altq(t[0]);
318602742ec6SJoerg Sonnenberger #endif
318702742ec6SJoerg Sonnenberger 		pf_clear_states();
318802742ec6SJoerg Sonnenberger 		pf_clear_srcnodes();
318902742ec6SJoerg Sonnenberger 
319002742ec6SJoerg Sonnenberger 		/* status does not use malloced mem so no need to cleanup */
319102742ec6SJoerg Sonnenberger 		/* fingerprints and interfaces have their own cleanup code */
319202742ec6SJoerg Sonnenberger 	} while (0);
31932949c680SAaron LI 
319402742ec6SJoerg Sonnenberger 	return (error);
319502742ec6SJoerg Sonnenberger }
319602742ec6SJoerg Sonnenberger 
319702742ec6SJoerg Sonnenberger static int
pf_check_in(void * arg,struct mbuf ** m,struct ifnet * ifp,int dir)319802742ec6SJoerg Sonnenberger pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
319902742ec6SJoerg Sonnenberger {
320002742ec6SJoerg Sonnenberger 	/*
32018a93af2aSMatthew Dillon 	 * NOTE: ip_len and ip_off are left in network byte order
320202742ec6SJoerg Sonnenberger 	 */
320302742ec6SJoerg Sonnenberger 	int chk;
320402742ec6SJoerg Sonnenberger 
32053a0038bfSMatthew Dillon 	lwkt_gettoken_shared(&pf_token);
32062a7a2b1cSJan Lentfer 
320770224baaSJan Lentfer 	chk = pf_test(PF_IN, ifp, m, NULL, NULL);
320802742ec6SJoerg Sonnenberger 	if (chk && *m) {
320902742ec6SJoerg Sonnenberger 		m_freem(*m);
321002742ec6SJoerg Sonnenberger 		*m = NULL;
321102742ec6SJoerg Sonnenberger 	}
32122a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
321302742ec6SJoerg Sonnenberger 	return chk;
321402742ec6SJoerg Sonnenberger }
321502742ec6SJoerg Sonnenberger 
321602742ec6SJoerg Sonnenberger static int
pf_check_out(void * arg,struct mbuf ** m,struct ifnet * ifp,int dir)321702742ec6SJoerg Sonnenberger pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
321802742ec6SJoerg Sonnenberger {
321902742ec6SJoerg Sonnenberger 	/*
32208a93af2aSMatthew Dillon 	 * NOTE: ip_len and ip_off are left in network byte order
322102742ec6SJoerg Sonnenberger 	 */
322202742ec6SJoerg Sonnenberger 	int chk;
322302742ec6SJoerg Sonnenberger 
32243a0038bfSMatthew Dillon 	lwkt_gettoken_shared(&pf_token);
32252a7a2b1cSJan Lentfer 
322602742ec6SJoerg Sonnenberger 	/* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
322702742ec6SJoerg Sonnenberger 	if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
322802742ec6SJoerg Sonnenberger 		in_delayed_cksum(*m);
322902742ec6SJoerg Sonnenberger 		(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
323002742ec6SJoerg Sonnenberger 	}
323170224baaSJan Lentfer 	chk = pf_test(PF_OUT, ifp, m, NULL, NULL);
323202742ec6SJoerg Sonnenberger 	if (chk && *m) {
323302742ec6SJoerg Sonnenberger 		m_freem(*m);
323402742ec6SJoerg Sonnenberger 		*m = NULL;
323502742ec6SJoerg Sonnenberger 	}
32362a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
323702742ec6SJoerg Sonnenberger 	return chk;
323802742ec6SJoerg Sonnenberger }
323902742ec6SJoerg Sonnenberger 
324002742ec6SJoerg Sonnenberger #ifdef INET6
324102742ec6SJoerg Sonnenberger static int
pf_check6_in(void * arg,struct mbuf ** m,struct ifnet * ifp,int dir)324202742ec6SJoerg Sonnenberger pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
324302742ec6SJoerg Sonnenberger {
324402742ec6SJoerg Sonnenberger 	int chk;
324502742ec6SJoerg Sonnenberger 
32463a0038bfSMatthew Dillon 	lwkt_gettoken_shared(&pf_token);
32472a7a2b1cSJan Lentfer 
324870224baaSJan Lentfer 	chk = pf_test6(PF_IN, ifp, m, NULL, NULL);
324902742ec6SJoerg Sonnenberger 	if (chk && *m) {
325002742ec6SJoerg Sonnenberger 		m_freem(*m);
325102742ec6SJoerg Sonnenberger 		*m = NULL;
325202742ec6SJoerg Sonnenberger 	}
32532a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
325402742ec6SJoerg Sonnenberger 	return chk;
325502742ec6SJoerg Sonnenberger }
325602742ec6SJoerg Sonnenberger 
325702742ec6SJoerg Sonnenberger static int
pf_check6_out(void * arg,struct mbuf ** m,struct ifnet * ifp,int dir)325802742ec6SJoerg Sonnenberger pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
325902742ec6SJoerg Sonnenberger {
326002742ec6SJoerg Sonnenberger 	int chk;
326102742ec6SJoerg Sonnenberger 
32623a0038bfSMatthew Dillon 	lwkt_gettoken_shared(&pf_token);
32632a7a2b1cSJan Lentfer 
326402742ec6SJoerg Sonnenberger 	/* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
326502742ec6SJoerg Sonnenberger 	if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
326602742ec6SJoerg Sonnenberger 		in_delayed_cksum(*m);
326702742ec6SJoerg Sonnenberger 		(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
326802742ec6SJoerg Sonnenberger 	}
326970224baaSJan Lentfer 	chk = pf_test6(PF_OUT, ifp, m, NULL, NULL);
327002742ec6SJoerg Sonnenberger 	if (chk && *m) {
327102742ec6SJoerg Sonnenberger 		m_freem(*m);
327202742ec6SJoerg Sonnenberger 		*m = NULL;
327302742ec6SJoerg Sonnenberger 	}
32742a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
327502742ec6SJoerg Sonnenberger 	return chk;
327602742ec6SJoerg Sonnenberger }
327702742ec6SJoerg Sonnenberger #endif /* INET6 */
327802742ec6SJoerg Sonnenberger 
327902742ec6SJoerg Sonnenberger static int
hook_pf(void)328002742ec6SJoerg Sonnenberger hook_pf(void)
328102742ec6SJoerg Sonnenberger {
328202742ec6SJoerg Sonnenberger 	struct pfil_head *pfh_inet;
328302742ec6SJoerg Sonnenberger #ifdef INET6
328402742ec6SJoerg Sonnenberger 	struct pfil_head *pfh_inet6;
328502742ec6SJoerg Sonnenberger #endif
328602742ec6SJoerg Sonnenberger 
32872a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
32882a7a2b1cSJan Lentfer 
32892a7a2b1cSJan Lentfer 	if (pf_pfil_hooked) {
32902a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
329102742ec6SJoerg Sonnenberger 		return (0);
32922a7a2b1cSJan Lentfer 	}
329302742ec6SJoerg Sonnenberger 
329402742ec6SJoerg Sonnenberger 	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
32952a7a2b1cSJan Lentfer 	if (pfh_inet == NULL) {
32962a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
3297e4fc90e8SMatthew Dillon 		return (ENODEV);
32982a7a2b1cSJan Lentfer 	}
329948e93b2fSMatthew Dillon 	pfil_add_hook(pf_check_in, NULL, PFIL_IN, pfh_inet);
330048e93b2fSMatthew Dillon 	pfil_add_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet);
330102742ec6SJoerg Sonnenberger #ifdef INET6
330202742ec6SJoerg Sonnenberger 	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
330302742ec6SJoerg Sonnenberger 	if (pfh_inet6 == NULL) {
330401dfc40dSSepherosa Ziehau 		pfil_remove_hook(pf_check_in, NULL, PFIL_IN, pfh_inet);
330501dfc40dSSepherosa Ziehau 		pfil_remove_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet);
33062a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
330702742ec6SJoerg Sonnenberger 		return (ENODEV);
330802742ec6SJoerg Sonnenberger 	}
330948e93b2fSMatthew Dillon 	pfil_add_hook(pf_check6_in, NULL, PFIL_IN, pfh_inet6);
331048e93b2fSMatthew Dillon 	pfil_add_hook(pf_check6_out, NULL, PFIL_OUT, pfh_inet6);
331102742ec6SJoerg Sonnenberger #endif
331202742ec6SJoerg Sonnenberger 
331302742ec6SJoerg Sonnenberger 	pf_pfil_hooked = 1;
33142a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
331502742ec6SJoerg Sonnenberger 	return (0);
331602742ec6SJoerg Sonnenberger }
331702742ec6SJoerg Sonnenberger 
331802742ec6SJoerg Sonnenberger static int
dehook_pf(void)331902742ec6SJoerg Sonnenberger dehook_pf(void)
332002742ec6SJoerg Sonnenberger {
332102742ec6SJoerg Sonnenberger 	struct pfil_head *pfh_inet;
332202742ec6SJoerg Sonnenberger #ifdef INET6
332302742ec6SJoerg Sonnenberger 	struct pfil_head *pfh_inet6;
332402742ec6SJoerg Sonnenberger #endif
332502742ec6SJoerg Sonnenberger 
33262a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
33272a7a2b1cSJan Lentfer 
33282a7a2b1cSJan Lentfer 	if (pf_pfil_hooked == 0) {
33292a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
333002742ec6SJoerg Sonnenberger 		return (0);
33312a7a2b1cSJan Lentfer 	}
333202742ec6SJoerg Sonnenberger 
333302742ec6SJoerg Sonnenberger 	pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
33342a7a2b1cSJan Lentfer 	if (pfh_inet == NULL) {
33352a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
333602742ec6SJoerg Sonnenberger 		return (ENODEV);
33372a7a2b1cSJan Lentfer 	}
333801dfc40dSSepherosa Ziehau 	pfil_remove_hook(pf_check_in, NULL, PFIL_IN, pfh_inet);
333901dfc40dSSepherosa Ziehau 	pfil_remove_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet);
334002742ec6SJoerg Sonnenberger #ifdef INET6
334102742ec6SJoerg Sonnenberger 	pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
33422a7a2b1cSJan Lentfer 	if (pfh_inet6 == NULL) {
33432a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
334402742ec6SJoerg Sonnenberger 		return (ENODEV);
33452a7a2b1cSJan Lentfer 	}
334601dfc40dSSepherosa Ziehau 	pfil_remove_hook(pf_check6_in, NULL, PFIL_IN, pfh_inet6);
334701dfc40dSSepherosa Ziehau 	pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT, pfh_inet6);
334802742ec6SJoerg Sonnenberger #endif
334902742ec6SJoerg Sonnenberger 
335002742ec6SJoerg Sonnenberger 	pf_pfil_hooked = 0;
33512a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
335202742ec6SJoerg Sonnenberger 	return (0);
335302742ec6SJoerg Sonnenberger }
335402742ec6SJoerg Sonnenberger 
335502742ec6SJoerg Sonnenberger static int
pf_load(void)335602742ec6SJoerg Sonnenberger pf_load(void)
335702742ec6SJoerg Sonnenberger {
33582a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
33592a7a2b1cSJan Lentfer 
3360c686757eSAaron LI 	pf_dev = make_dev(&pf_ops, 0, UID_ROOT, GID_WHEEL, 0600, PF_NAME);
33611186cbc0SJan Lentfer 	pfattach();
336270224baaSJan Lentfer 	lockinit(&pf_consistency_lock, "pfconslck", 0, LK_CANRECURSE);
336332772c96SMatthew Dillon 	lockinit(&pf_global_statetbl_lock, "pfglstlk", 0, 0);
33642a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
336502742ec6SJoerg Sonnenberger 	return (0);
336602742ec6SJoerg Sonnenberger }
336702742ec6SJoerg Sonnenberger 
336802742ec6SJoerg Sonnenberger static int
pf_unload(void)336902742ec6SJoerg Sonnenberger pf_unload(void)
337002742ec6SJoerg Sonnenberger {
337102742ec6SJoerg Sonnenberger 	int error;
337202742ec6SJoerg Sonnenberger 	pf_status.running = 0;
33732a7a2b1cSJan Lentfer 
33742a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
33752a7a2b1cSJan Lentfer 
337602742ec6SJoerg Sonnenberger 	error = dehook_pf();
337702742ec6SJoerg Sonnenberger 	if (error) {
337802742ec6SJoerg Sonnenberger 		/*
337902742ec6SJoerg Sonnenberger 		 * Should not happen!
338002742ec6SJoerg Sonnenberger 		 * XXX Due to error code ESRCH, kldunload will show
338102742ec6SJoerg Sonnenberger 		 * a message like 'No such process'.
338202742ec6SJoerg Sonnenberger 		 */
33833f625015SSascha Wildner 		kprintf("pfil unregistration fail\n");
33842a7a2b1cSJan Lentfer 		lwkt_reltoken(&pf_token);
338502742ec6SJoerg Sonnenberger 		return error;
338602742ec6SJoerg Sonnenberger 	}
3387f7c73ea6SMatthew Dillon 	kprintf("PF shutdown\n");
338870224baaSJan Lentfer 	pf_end_threads = 1;
3389f7c73ea6SMatthew Dillon 	shutdown_pf();
339070224baaSJan Lentfer 	while (pf_end_threads < 2) {
339170224baaSJan Lentfer 		wakeup_one(pf_purge_thread);
3392f7c73ea6SMatthew Dillon 		tsleep(pf_purge_thread, 0, "pftmo", hz / 10);
339370224baaSJan Lentfer 	}
339402742ec6SJoerg Sonnenberger 	pfi_cleanup();
339502742ec6SJoerg Sonnenberger 	pf_osfp_flush();
3396cd29885aSMatthew Dillon 	dev_ops_remove_all(&pf_ops);
339770224baaSJan Lentfer 	lockuninit(&pf_consistency_lock);
33982a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
3399b4628cf9SSepherosa Ziehau 
3400f7c73ea6SMatthew Dillon 	pf_normalize_unload();
3401b4628cf9SSepherosa Ziehau 	if (pf_maskhead != NULL) {
34020d7b85c8SAaron LI 		rn_flush(pf_maskhead, rn_freemask);
34030d7b85c8SAaron LI 		rn_freehead(pf_maskhead);
340414dd43dcSMatthew Dillon 		pf_maskhead = NULL;
3405b4628cf9SSepherosa Ziehau 	}
34061186cbc0SJan Lentfer 	kmalloc_destroy(&pf_state_pl);
34071186cbc0SJan Lentfer 	kmalloc_destroy(&pf_frent_pl);
34081186cbc0SJan Lentfer 	kmalloc_destroy(&pf_cent_pl);
3409f7c73ea6SMatthew Dillon 
3410f7c73ea6SMatthew Dillon 	kfree(tree_src_tracking, M_PF);
3411f7c73ea6SMatthew Dillon 	kfree(tree_id, M_PF);
3412f7c73ea6SMatthew Dillon 	kfree(state_list, M_PF);
3413f7c73ea6SMatthew Dillon 	kfree(pf_counters, M_PF);
3414f7c73ea6SMatthew Dillon 	kfree(pf_statetbl, M_PF);
3415f7c73ea6SMatthew Dillon 	kfree(purge_cur, M_PF);
3416f7c73ea6SMatthew Dillon 
341702742ec6SJoerg Sonnenberger 	return 0;
341802742ec6SJoerg Sonnenberger }
341902742ec6SJoerg Sonnenberger 
342002742ec6SJoerg Sonnenberger static int
pf_modevent(module_t mod,int type,void * data __unused)3421c686757eSAaron LI pf_modevent(module_t mod, int type, void *data __unused)
342202742ec6SJoerg Sonnenberger {
342302742ec6SJoerg Sonnenberger 	int error = 0;
342402742ec6SJoerg Sonnenberger 
34252a7a2b1cSJan Lentfer 	lwkt_gettoken(&pf_token);
34262a7a2b1cSJan Lentfer 
342702742ec6SJoerg Sonnenberger 	switch(type) {
342802742ec6SJoerg Sonnenberger 	case MOD_LOAD:
342902742ec6SJoerg Sonnenberger 		error = pf_load();
343002742ec6SJoerg Sonnenberger 		break;
343102742ec6SJoerg Sonnenberger 
343202742ec6SJoerg Sonnenberger 	case MOD_UNLOAD:
343302742ec6SJoerg Sonnenberger 		error = pf_unload();
343402742ec6SJoerg Sonnenberger 		break;
343502742ec6SJoerg Sonnenberger 	default:
343602742ec6SJoerg Sonnenberger 		error = EINVAL;
343702742ec6SJoerg Sonnenberger 		break;
343802742ec6SJoerg Sonnenberger 	}
34392a7a2b1cSJan Lentfer 	lwkt_reltoken(&pf_token);
344002742ec6SJoerg Sonnenberger 	return error;
344102742ec6SJoerg Sonnenberger }
344202742ec6SJoerg Sonnenberger 
344302742ec6SJoerg Sonnenberger static moduledata_t pf_mod = {
344402742ec6SJoerg Sonnenberger 	"pf",
344502742ec6SJoerg Sonnenberger 	pf_modevent,
344602742ec6SJoerg Sonnenberger 	0
344702742ec6SJoerg Sonnenberger };
3448c686757eSAaron LI 
344902742ec6SJoerg Sonnenberger DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_FIRST);
345002742ec6SJoerg Sonnenberger MODULE_VERSION(pf, PF_MODVER);
3451