xref: /openbsd-src/sys/net/pf_table.c (revision d40c63659aefc32359b6396f35c7bc9a9ae8f265)
1*d40c6365Ssashan /*	$OpenBSD: pf_table.c,v 1.145 2023/08/10 16:44:04 sashan Exp $	*/
26ee9b743Scedric 
36ee9b743Scedric /*
46ee9b743Scedric  * Copyright (c) 2002 Cedric Berger
56ee9b743Scedric  * All rights reserved.
66ee9b743Scedric  *
76ee9b743Scedric  * Redistribution and use in source and binary forms, with or without
86ee9b743Scedric  * modification, are permitted provided that the following conditions
96ee9b743Scedric  * are met:
106ee9b743Scedric  *
116ee9b743Scedric  *    - Redistributions of source code must retain the above copyright
126ee9b743Scedric  *      notice, this list of conditions and the following disclaimer.
136ee9b743Scedric  *    - Redistributions in binary form must reproduce the above
146ee9b743Scedric  *      copyright notice, this list of conditions and the following
156ee9b743Scedric  *      disclaimer in the documentation and/or other materials provided
166ee9b743Scedric  *      with the distribution.
176ee9b743Scedric  *
186ee9b743Scedric  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
196ee9b743Scedric  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
206ee9b743Scedric  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
216ee9b743Scedric  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
226ee9b743Scedric  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
236ee9b743Scedric  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
246ee9b743Scedric  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
256ee9b743Scedric  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
266ee9b743Scedric  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
276ee9b743Scedric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
286ee9b743Scedric  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296ee9b743Scedric  * POSSIBILITY OF SUCH DAMAGE.
306ee9b743Scedric  *
316ee9b743Scedric  */
326ee9b743Scedric 
336ee9b743Scedric #include <sys/param.h>
346ee9b743Scedric #include <sys/systm.h>
356ee9b743Scedric #include <sys/socket.h>
366ee9b743Scedric #include <sys/mbuf.h>
378efe75c5Shenning #include <sys/pool.h>
38a2fdc13dSmcbride #include <sys/syslog.h>
39d49b1212Smpi #include <sys/proc.h>
406ee9b743Scedric 
416ee9b743Scedric #include <net/if.h>
42ab417b3aSbluhm 
436ee9b743Scedric #include <netinet/in.h>
44ab417b3aSbluhm #include <netinet/ip.h>
456ee9b743Scedric #include <netinet/ip_ipsp.h>
46ab417b3aSbluhm #include <netinet/ip_icmp.h>
47ab417b3aSbluhm #include <netinet/tcp.h>
48ab417b3aSbluhm #include <netinet/udp.h>
49ab417b3aSbluhm 
50ab417b3aSbluhm #ifdef INET6
51ab417b3aSbluhm #include <netinet/ip6.h>
52ab417b3aSbluhm #include <netinet/icmp6.h>
53ab417b3aSbluhm #endif /* INET6 */
54ab417b3aSbluhm 
556ee9b743Scedric #include <net/pfvar.h>
56ab417b3aSbluhm #include <net/pfvar_priv.h>
576ee9b743Scedric 
5896d425afSmickey #define ACCEPT_FLAGS(flags, oklist)		\
596ee9b743Scedric 	do {					\
606ee9b743Scedric 		if ((flags & ~(oklist)) &	\
616ee9b743Scedric 		    PFR_FLAG_ALLMASK)		\
626ee9b743Scedric 			return (EINVAL);	\
636ee9b743Scedric 	} while (0)
646ee9b743Scedric 
6596d425afSmickey #define COPYIN(from, to, size, flags)		\
66ec359bd5Scedric 	((flags & PFR_FLAG_USERIOCTL) ?		\
67ec359bd5Scedric 	copyin((from), (to), (size)) :		\
68ec359bd5Scedric 	(bcopy((from), (to), (size)), 0))
69ec359bd5Scedric 
7096d425afSmickey #define COPYOUT(from, to, size, flags)		\
71ec359bd5Scedric 	((flags & PFR_FLAG_USERIOCTL) ?		\
72ec359bd5Scedric 	copyout((from), (to), (size)) :		\
73ec359bd5Scedric 	(bcopy((from), (to), (size)), 0))
74ec359bd5Scedric 
75ac7813e4Ssashan #define YIELD(ok)				\
76ac7813e4Ssashan 	do {					\
77ac7813e4Ssashan 		if (ok)				\
78ac7813e4Ssashan 			sched_pause(preempt);	\
79ac7813e4Ssashan 	} while (0)
80636c1edeStedu 
816ee9b743Scedric #define	FILLIN_SIN(sin, addr)			\
826ee9b743Scedric 	do {					\
836ee9b743Scedric 		(sin).sin_len = sizeof(sin);	\
846ee9b743Scedric 		(sin).sin_family = AF_INET;	\
856ee9b743Scedric 		(sin).sin_addr = (addr);	\
866ee9b743Scedric 	} while (0)
876ee9b743Scedric 
886ee9b743Scedric #define	FILLIN_SIN6(sin6, addr)			\
896ee9b743Scedric 	do {					\
906ee9b743Scedric 		(sin6).sin6_len = sizeof(sin6);	\
916ee9b743Scedric 		(sin6).sin6_family = AF_INET6;	\
926ee9b743Scedric 		(sin6).sin6_addr = (addr);	\
936ee9b743Scedric 	} while (0)
946ee9b743Scedric 
95c06aa877Scedric #define SWAP(type, a1, a2)			\
96c06aa877Scedric 	do {					\
97c06aa877Scedric 		type tmp = a1;			\
98c06aa877Scedric 		a1 = a2;			\
99c06aa877Scedric 		a2 = tmp;			\
100c06aa877Scedric 	} while (0)
101c06aa877Scedric 
102b47e54c9Scedric #define SUNION2PF(su, af) (((af)==AF_INET) ?	\
103b47e54c9Scedric     (struct pf_addr *)&(su)->sin.sin_addr :	\
104b47e54c9Scedric     (struct pf_addr *)&(su)->sin6.sin6_addr)
105b47e54c9Scedric 
1066ee9b743Scedric #define	AF_BITS(af)		(((af)==AF_INET)?32:128)
1076ee9b743Scedric #define	ADDR_NETWORK(ad)	((ad)->pfra_net < AF_BITS((ad)->pfra_af))
1086ee9b743Scedric #define	KENTRY_NETWORK(ke)	((ke)->pfrke_net < AF_BITS((ke)->pfrke_af))
10968bca9d0Scedric 
110c06aa877Scedric #define NO_ADDRESSES		(-1)
11168bca9d0Scedric #define ENQUEUE_UNMARKED_ONLY	(1)
11268bca9d0Scedric #define INVERT_NEG_FLAG		(1)
1136ee9b743Scedric 
1146ee9b743Scedric struct pfr_walktree {
1156ee9b743Scedric 	enum pfrw_op {
1166ee9b743Scedric 		PFRW_MARK,
1176ee9b743Scedric 		PFRW_SWEEP,
1186ee9b743Scedric 		PFRW_ENQUEUE,
1196ee9b743Scedric 		PFRW_GET_ADDRS,
120b47e54c9Scedric 		PFRW_GET_ASTATS,
121ec359bd5Scedric 		PFRW_POOL_GET,
122ec359bd5Scedric 		PFRW_DYNADDR_UPDATE
1236ee9b743Scedric 	}	 pfrw_op;
1246ee9b743Scedric 	union {
1256ee9b743Scedric 		struct pfr_addr		*pfrw1_addr;
1266ee9b743Scedric 		struct pfr_astats	*pfrw1_astats;
1276ee9b743Scedric 		struct pfr_kentryworkq	*pfrw1_workq;
128b47e54c9Scedric 		struct pfr_kentry	*pfrw1_kentry;
129ec359bd5Scedric 		struct pfi_dynaddr	*pfrw1_dyn;
1306ee9b743Scedric 	}	 pfrw_1;
1316ee9b743Scedric 	int	 pfrw_free;
132ec359bd5Scedric 	int	 pfrw_flags;
1336ee9b743Scedric };
1346ee9b743Scedric #define pfrw_addr	pfrw_1.pfrw1_addr
1356ee9b743Scedric #define pfrw_astats	pfrw_1.pfrw1_astats
1366ee9b743Scedric #define pfrw_workq	pfrw_1.pfrw1_workq
137b47e54c9Scedric #define pfrw_kentry	pfrw_1.pfrw1_kentry
138ec359bd5Scedric #define pfrw_dyn	pfrw_1.pfrw1_dyn
1396ee9b743Scedric #define pfrw_cnt	pfrw_free
1406ee9b743Scedric 
1416ee9b743Scedric #define senderr(e)	do { rv = (e); goto _bad; } while (0)
1426ee9b743Scedric 
1436ee9b743Scedric struct pool		 pfr_ktable_pl;
14436754172Smcbride struct pool		 pfr_kentry_pl[PFRKE_MAX];
1455f03a6e1Smcbride struct pool		 pfr_kcounters_pl;
146b47e54c9Scedric union sockaddr_union	 pfr_mask;
147b47e54c9Scedric struct pf_addr		 pfr_ffaddr;
1486ee9b743Scedric 
149cbdc262eSmcbride int			 pfr_gcd(int, int);
150c06aa877Scedric void			 pfr_copyout_addr(struct pfr_addr *,
151c06aa877Scedric 			    struct pfr_kentry *ke);
1526ee9b743Scedric int			 pfr_validate_addr(struct pfr_addr *);
153c06aa877Scedric void			 pfr_enqueue_addrs(struct pfr_ktable *,
154c06aa877Scedric 			    struct pfr_kentryworkq *, int *, int);
155c06aa877Scedric void			 pfr_mark_addrs(struct pfr_ktable *);
1566ee9b743Scedric struct pfr_kentry	*pfr_lookup_addr(struct pfr_ktable *,
1576ee9b743Scedric 			    struct pfr_addr *, int);
158999a6f61Ssashan struct pfr_kentry	*pfr_lookup_kentry(struct pfr_ktable *,
159999a6f61Ssashan 			    struct pfr_kentry *, int);
160f7f76181Smikeb struct pfr_kentry	*pfr_create_kentry(struct pfr_addr *);
161999a6f61Ssashan struct pfr_kentry 	*pfr_create_kentry_unlocked(struct pfr_addr *, int);
162999a6f61Ssashan void			 pfr_kentry_kif_ref(struct pfr_kentry *);
1636ee9b743Scedric void			 pfr_destroy_kentries(struct pfr_kentryworkq *);
164999a6f61Ssashan void			 pfr_destroy_ioq(struct pfr_kentryworkq *, int);
1654e905526Scedric void			 pfr_destroy_kentry(struct pfr_kentry *);
166e82ca249Scedric void			 pfr_insert_kentries(struct pfr_ktable *,
16726ca2c15Sguenther 			    struct pfr_kentryworkq *, time_t);
1686ee9b743Scedric void			 pfr_remove_kentries(struct pfr_ktable *,
1696ee9b743Scedric 			    struct pfr_kentryworkq *);
17026ca2c15Sguenther void			 pfr_clstats_kentries(struct pfr_kentryworkq *, time_t,
171c06aa877Scedric 			    int);
172ec359bd5Scedric void			 pfr_reset_feedback(struct pfr_addr *, int, int);
1736ee9b743Scedric void			 pfr_prepare_network(union sockaddr_union *, int, int);
1746ee9b743Scedric int			 pfr_route_kentry(struct pfr_ktable *,
1756ee9b743Scedric 			    struct pfr_kentry *);
1766ee9b743Scedric int			 pfr_unroute_kentry(struct pfr_ktable *,
1776ee9b743Scedric 			    struct pfr_kentry *);
178dcabaadaSclaudio int			 pfr_walktree(struct radix_node *, void *, u_int);
179ec359bd5Scedric int			 pfr_validate_table(struct pfr_table *, int, int);
180f560c95aSjaredy int			 pfr_fix_anchor(char *);
18126ca2c15Sguenther void			 pfr_commit_ktable(struct pfr_ktable *, time_t);
1826ee9b743Scedric void			 pfr_insert_ktables(struct pfr_ktableworkq *);
183c06aa877Scedric void			 pfr_insert_ktable(struct pfr_ktable *);
1842c9e9fd6Scedric void			 pfr_setflags_ktables(struct pfr_ktableworkq *);
1852c9e9fd6Scedric void			 pfr_setflags_ktable(struct pfr_ktable *, int);
18626ca2c15Sguenther void			 pfr_clstats_ktables(struct pfr_ktableworkq *, time_t,
1876ee9b743Scedric 			    int);
18826ca2c15Sguenther void			 pfr_clstats_ktable(struct pfr_ktable *, time_t, int);
18926ca2c15Sguenther struct pfr_ktable	*pfr_create_ktable(struct pfr_table *, time_t, int,
19026ca2c15Sguenther 			    int);
191c06aa877Scedric void			 pfr_destroy_ktables(struct pfr_ktableworkq *, int);
192de97784bSsashan void			 pfr_destroy_ktables_aux(struct pfr_ktableworkq *);
193c06aa877Scedric void			 pfr_destroy_ktable(struct pfr_ktable *, int);
194342c264fSdlg int			 pfr_ktable_compare(struct pfr_ktable *,
195342c264fSdlg 			    struct pfr_ktable *);
196cbdc262eSmcbride void			 pfr_ktable_winfo_update(struct pfr_ktable *,
197cbdc262eSmcbride 			    struct pfr_kentry *);
1986ee9b743Scedric struct pfr_ktable	*pfr_lookup_table(struct pfr_table *);
199dd94896cScedric void			 pfr_clean_node_mask(struct pfr_ktable *,
200dd94896cScedric 			    struct pfr_kentryworkq *);
201a9b90787Scedric int			 pfr_table_count(struct pfr_table *, int);
202a9b90787Scedric int			 pfr_skip_table(struct pfr_table *,
203a9b90787Scedric 			    struct pfr_ktable *, int);
204b47e54c9Scedric struct pfr_kentry	*pfr_kentry_byidx(struct pfr_ktable *, int, int);
2052b27abb2Smarkus int			 pfr_islinklocal(sa_family_t, struct pf_addr *);
2066ee9b743Scedric 
207342c264fSdlg RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
208342c264fSdlg RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
2096ee9b743Scedric 
2106ee9b743Scedric struct pfr_ktablehead	 pfr_ktables;
2119977d1daScedric struct pfr_table	 pfr_nulltable;
2126ee9b743Scedric int			 pfr_ktable_cnt;
2136ee9b743Scedric 
214cbdc262eSmcbride int
pfr_gcd(int m,int n)215cbdc262eSmcbride pfr_gcd(int m, int n)
216cbdc262eSmcbride {
217cbdc262eSmcbride        int t;
218cbdc262eSmcbride 
219cbdc262eSmcbride        while (m > 0) {
220cbdc262eSmcbride 	       t = n % m;
221cbdc262eSmcbride 	       n = m;
222cbdc262eSmcbride 	       m = t;
223cbdc262eSmcbride        }
224cbdc262eSmcbride        return (n);
225cbdc262eSmcbride }
226cbdc262eSmcbride 
2277b0f80e3Scedric void
pfr_initialize(void)2287b0f80e3Scedric pfr_initialize(void)
2297b0f80e3Scedric {
23098afcbd2Smpi 	rn_init(sizeof(struct sockaddr_in6));
23198afcbd2Smpi 
2321378bae2Sdlg 	pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable),
2331378bae2Sdlg 	    0, IPL_SOFTNET, 0, "pfrktable", NULL);
23436754172Smcbride 	pool_init(&pfr_kentry_pl[PFRKE_PLAIN], sizeof(struct pfr_kentry),
2351378bae2Sdlg 	    0, IPL_SOFTNET, 0, "pfrke_plain", NULL);
23636754172Smcbride 	pool_init(&pfr_kentry_pl[PFRKE_ROUTE], sizeof(struct pfr_kentry_route),
2371378bae2Sdlg 	    0, IPL_SOFTNET, 0, "pfrke_route", NULL);
238bcb11948Szinke 	pool_init(&pfr_kentry_pl[PFRKE_COST], sizeof(struct pfr_kentry_cost),
2391378bae2Sdlg 	    0, IPL_SOFTNET, 0, "pfrke_cost", NULL);
24036754172Smcbride 	pool_init(&pfr_kcounters_pl, sizeof(struct pfr_kcounters),
2411378bae2Sdlg 	    0, IPL_SOFTNET, 0, "pfrkcounters", NULL);
2427b0f80e3Scedric 
243b47e54c9Scedric 	memset(&pfr_ffaddr, 0xff, sizeof(pfr_ffaddr));
2447b0f80e3Scedric }
2457b0f80e3Scedric 
2466ee9b743Scedric int
pfr_clr_addrs(struct pfr_table * tbl,int * ndel,int flags)2476ee9b743Scedric pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
2486ee9b743Scedric {
2496ee9b743Scedric 	struct pfr_ktable	*kt;
2506ee9b743Scedric 	struct pfr_kentryworkq	 workq;
2516ee9b743Scedric 
2521bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
253ec359bd5Scedric 	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
2544e905526Scedric 		return (EINVAL);
2556ee9b743Scedric 	kt = pfr_lookup_table(tbl);
256bb75ae08Sdhartmei 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2576ee9b743Scedric 		return (ESRCH);
258c06aa877Scedric 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
259c06aa877Scedric 		return (EPERM);
260c06aa877Scedric 	pfr_enqueue_addrs(kt, &workq, ndel, 0);
2616ee9b743Scedric 
2626ee9b743Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
2636ee9b743Scedric 		pfr_remove_kentries(kt, &workq);
2646ee9b743Scedric 		if (kt->pfrkt_cnt) {
2652551ddbaSmcbride 			DPFPRINTF(LOG_NOTICE,
2662551ddbaSmcbride 			    "pfr_clr_addrs: corruption detected (%d).",
267c06aa877Scedric 			    kt->pfrkt_cnt);
2686ee9b743Scedric 			kt->pfrkt_cnt = 0;
2696ee9b743Scedric 		}
2706ee9b743Scedric 	}
2716ee9b743Scedric 	return (0);
2726ee9b743Scedric }
2736ee9b743Scedric 
274999a6f61Ssashan void
pfr_fill_feedback(struct pfr_kentry_all * ke,struct pfr_addr * ad)275999a6f61Ssashan pfr_fill_feedback(struct pfr_kentry_all *ke, struct pfr_addr *ad)
276999a6f61Ssashan {
277999a6f61Ssashan 	ad->pfra_type = ke->pfrke_type;
278999a6f61Ssashan 
279999a6f61Ssashan 	switch (ke->pfrke_type) {
280999a6f61Ssashan 	case PFRKE_PLAIN:
281999a6f61Ssashan 		break;
282999a6f61Ssashan 	case PFRKE_COST:
283999a6f61Ssashan 		((struct pfr_kentry_cost *)ke)->weight = ad->pfra_weight;
284999a6f61Ssashan 		/* FALLTHROUGH */
285999a6f61Ssashan 	case PFRKE_ROUTE:
286999a6f61Ssashan 		if (ke->pfrke_rifname[0])
287999a6f61Ssashan 			strlcpy(ad->pfra_ifname, ke->pfrke_rifname, IFNAMSIZ);
288999a6f61Ssashan 		break;
289999a6f61Ssashan 	}
290999a6f61Ssashan 
291999a6f61Ssashan 	switch (ke->pfrke_af) {
292999a6f61Ssashan 	case AF_INET:
293999a6f61Ssashan 		ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr;
294999a6f61Ssashan 		break;
295999a6f61Ssashan #ifdef	INET6
296999a6f61Ssashan 	case AF_INET6:
297999a6f61Ssashan 		ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr;
298999a6f61Ssashan 		break;
299999a6f61Ssashan #endif	/* INET6 */
300999a6f61Ssashan 	default:
301999a6f61Ssashan 		unhandled_af(ke->pfrke_af);
302999a6f61Ssashan 	}
303999a6f61Ssashan 	ad->pfra_weight = ((struct pfr_kentry_cost *)ke)->weight;
304999a6f61Ssashan 	ad->pfra_af = ke->pfrke_af;
305999a6f61Ssashan 	ad->pfra_net = ke->pfrke_net;
306999a6f61Ssashan 	if (ke->pfrke_flags & PFRKE_FLAG_NOT)
307999a6f61Ssashan 		ad->pfra_not = 1;
308999a6f61Ssashan 	ad->pfra_fback = ke->pfrke_fb;
309999a6f61Ssashan }
310999a6f61Ssashan 
3116ee9b743Scedric int
pfr_add_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int flags)3126ee9b743Scedric pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
3136ee9b743Scedric     int *nadd, int flags)
3146ee9b743Scedric {
3159977d1daScedric 	struct pfr_ktable	*kt, *tmpkt;
316999a6f61Ssashan 	struct pfr_kentryworkq	 workq, ioq;
317999a6f61Ssashan 	struct pfr_kentry	*p, *q, *ke;
3186ee9b743Scedric 	struct pfr_addr		 ad;
3191bdebab7Stedu 	int			 i, rv, xadd = 0;
3203209772dScheloha 	time_t			 tzero = gettime();
3216ee9b743Scedric 
3221bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK);
323ec359bd5Scedric 	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
3244e905526Scedric 		return (EINVAL);
3254b397724Smikeb 	tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0,
32630d709c8Smbuhl 	    (flags & PFR_FLAG_USERIOCTL? PR_WAITOK : PR_NOWAIT));
3279977d1daScedric 	if (tmpkt == NULL)
3289977d1daScedric 		return (ENOMEM);
3296ee9b743Scedric 	SLIST_INIT(&workq);
330999a6f61Ssashan 	SLIST_INIT(&ioq);
3316ee9b743Scedric 	for (i = 0; i < size; i++) {
332ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
33396d425afSmickey 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
3346ee9b743Scedric 			senderr(EFAULT);
3356ee9b743Scedric 		if (pfr_validate_addr(&ad))
336b20a6e9cScedric 			senderr(EINVAL);
337999a6f61Ssashan 
338999a6f61Ssashan 		ke = pfr_create_kentry_unlocked(&ad, flags);
339999a6f61Ssashan 		if (ke == NULL)
340999a6f61Ssashan 			senderr(ENOMEM);
341999a6f61Ssashan 		ke->pfrke_fb = PFR_FB_NONE;
342999a6f61Ssashan 		SLIST_INSERT_HEAD(&ioq, ke, pfrke_ioq);
343999a6f61Ssashan 	}
344999a6f61Ssashan 
345999a6f61Ssashan 	NET_LOCK();
346999a6f61Ssashan 	PF_LOCK();
347999a6f61Ssashan 	kt = pfr_lookup_table(tbl);
348999a6f61Ssashan 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
349999a6f61Ssashan 		PF_UNLOCK();
350999a6f61Ssashan 		NET_UNLOCK();
351999a6f61Ssashan 		senderr(ESRCH);
352999a6f61Ssashan 	}
353ac7c051cSjsg 	if (kt->pfrkt_flags & PFR_TFLAG_CONST) {
354ac7c051cSjsg 		PF_UNLOCK();
355ac7c051cSjsg 		NET_UNLOCK();
356ac7c051cSjsg 		senderr(EPERM);
357ac7c051cSjsg 	}
358999a6f61Ssashan 	SLIST_FOREACH(ke, &ioq, pfrke_ioq) {
359999a6f61Ssashan 		pfr_kentry_kif_ref(ke);
360999a6f61Ssashan 		p = pfr_lookup_kentry(kt, ke, 1);
361999a6f61Ssashan 		q = pfr_lookup_kentry(tmpkt, ke, 1);
3626ee9b743Scedric 		if (flags & PFR_FLAG_FEEDBACK) {
363b8802620Scedric 			if (q != NULL)
364999a6f61Ssashan 				ke->pfrke_fb = PFR_FB_DUPLICATE;
365b8802620Scedric 			else if (p == NULL)
366999a6f61Ssashan 				ke->pfrke_fb = PFR_FB_ADDED;
36736754172Smcbride 			else if ((p->pfrke_flags & PFRKE_FLAG_NOT) !=
368999a6f61Ssashan 			    (ke->pfrke_flags & PFRKE_FLAG_NOT))
369999a6f61Ssashan 				ke->pfrke_fb = PFR_FB_CONFLICT;
370b8802620Scedric 			else
371999a6f61Ssashan 				ke->pfrke_fb = PFR_FB_NONE;
3726ee9b743Scedric 		}
3734e905526Scedric 		if (p == NULL && q == NULL) {
374999a6f61Ssashan 			if (pfr_route_kentry(tmpkt, ke)) {
375999a6f61Ssashan 				/* defer destroy after feedback is processed */
376999a6f61Ssashan 				ke->pfrke_fb = PFR_FB_NONE;
3774e905526Scedric 			} else {
378999a6f61Ssashan 				/*
379999a6f61Ssashan 				 * mark entry as added to table, so we won't
380999a6f61Ssashan 				 * kill it with rest of the ioq
381999a6f61Ssashan 				 */
382999a6f61Ssashan 				ke->pfrke_fb = PFR_FB_ADDED;
383999a6f61Ssashan 				SLIST_INSERT_HEAD(&workq, ke, pfrke_workq);
3846ee9b743Scedric 				xadd++;
385b8802620Scedric 			}
3866ee9b743Scedric 		}
387999a6f61Ssashan 	}
388999a6f61Ssashan 	/* remove entries, which we will insert from tmpkt */
389999a6f61Ssashan 	pfr_clean_node_mask(tmpkt, &workq);
390999a6f61Ssashan 	if (!(flags & PFR_FLAG_DUMMY))
391999a6f61Ssashan 		pfr_insert_kentries(kt, &workq, tzero);
392999a6f61Ssashan 
393999a6f61Ssashan 	PF_UNLOCK();
394999a6f61Ssashan 	NET_UNLOCK();
395999a6f61Ssashan 
396999a6f61Ssashan 	if (flags & PFR_FLAG_FEEDBACK) {
397999a6f61Ssashan 		i = 0;
398999a6f61Ssashan 		while ((ke = SLIST_FIRST(&ioq)) != NULL) {
399999a6f61Ssashan 			YIELD(flags & PFR_FLAG_USERIOCTL);
400999a6f61Ssashan 			pfr_fill_feedback((struct pfr_kentry_all *)ke, &ad);
40196d425afSmickey 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
4024e905526Scedric 				senderr(EFAULT);
403999a6f61Ssashan 			i++;
404999a6f61Ssashan 			SLIST_REMOVE_HEAD(&ioq, pfrke_ioq);
405999a6f61Ssashan 			switch (ke->pfrke_fb) {
406999a6f61Ssashan 			case PFR_FB_CONFLICT:
407999a6f61Ssashan 			case PFR_FB_DUPLICATE:
408999a6f61Ssashan 			case PFR_FB_NONE:
409999a6f61Ssashan 				pfr_destroy_kentry(ke);
410999a6f61Ssashan 				break;
411999a6f61Ssashan 			case PFR_FB_ADDED:
412999a6f61Ssashan 				if (flags & PFR_FLAG_DUMMY)
413999a6f61Ssashan 					pfr_destroy_kentry(ke);
4144e905526Scedric 			}
415999a6f61Ssashan 		}
4167b74eda2Scedric 	} else
417999a6f61Ssashan 		pfr_destroy_ioq(&ioq, flags);
418999a6f61Ssashan 
4196ee9b743Scedric 	if (nadd != NULL)
4206ee9b743Scedric 		*nadd = xadd;
421999a6f61Ssashan 
422c06aa877Scedric 	pfr_destroy_ktable(tmpkt, 0);
4236ee9b743Scedric 	return (0);
4246ee9b743Scedric _bad:
425999a6f61Ssashan 	pfr_destroy_ioq(&ioq, flags);
4266ee9b743Scedric 	if (flags & PFR_FLAG_FEEDBACK)
427ec359bd5Scedric 		pfr_reset_feedback(addr, size, flags);
428c06aa877Scedric 	pfr_destroy_ktable(tmpkt, 0);
4296ee9b743Scedric 	return (rv);
4306ee9b743Scedric }
4316ee9b743Scedric 
4326ee9b743Scedric int
pfr_del_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * ndel,int flags)4336ee9b743Scedric pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
4346ee9b743Scedric     int *ndel, int flags)
4356ee9b743Scedric {
4366ee9b743Scedric 	struct pfr_ktable	*kt;
4376ee9b743Scedric 	struct pfr_kentryworkq	 workq;
4386ee9b743Scedric 	struct pfr_kentry	*p;
4396ee9b743Scedric 	struct pfr_addr		 ad;
4401bdebab7Stedu 	int			 i, rv, xdel = 0, log = 1;
4416ee9b743Scedric 
4421bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK);
443ec359bd5Scedric 	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
4444e905526Scedric 		return (EINVAL);
4456ee9b743Scedric 	kt = pfr_lookup_table(tbl);
446bb75ae08Sdhartmei 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
4476ee9b743Scedric 		return (ESRCH);
448c06aa877Scedric 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
449c06aa877Scedric 		return (EPERM);
450fb2081aeScedric 	/*
451fb2081aeScedric 	 * there are two algorithms to choose from here.
452fb2081aeScedric 	 * with:
453fb2081aeScedric 	 *   n: number of addresses to delete
454fb2081aeScedric 	 *   N: number of addresses in the table
455fb2081aeScedric 	 *
456fb2081aeScedric 	 * one is O(N) and is better for large 'n'
457fb2081aeScedric 	 * one is O(n*LOG(N)) and is better for small 'n'
458fb2081aeScedric 	 *
459fb2081aeScedric 	 * following code try to decide which one is best.
460fb2081aeScedric 	 */
461fb2081aeScedric 	for (i = kt->pfrkt_cnt; i > 0; i >>= 1)
462fb2081aeScedric 		log++;
463fb2081aeScedric 	if (size > kt->pfrkt_cnt/log) {
464fb2081aeScedric 		/* full table scan */
465c06aa877Scedric 		pfr_mark_addrs(kt);
466fb2081aeScedric 	} else {
467fb2081aeScedric 		/* iterate over addresses to delete */
468fb2081aeScedric 		for (i = 0; i < size; i++) {
469ac7813e4Ssashan 			YIELD(flags & PFR_FLAG_USERIOCTL);
47096d425afSmickey 			if (COPYIN(addr+i, &ad, sizeof(ad), flags))
471fb2081aeScedric 				return (EFAULT);
472fb2081aeScedric 			if (pfr_validate_addr(&ad))
473fb2081aeScedric 				return (EINVAL);
474fb2081aeScedric 			p = pfr_lookup_addr(kt, &ad, 1);
475fb2081aeScedric 			if (p != NULL)
47636754172Smcbride 				p->pfrke_flags &= ~PFRKE_FLAG_MARK;
477fb2081aeScedric 		}
478fb2081aeScedric 	}
4796ee9b743Scedric 	SLIST_INIT(&workq);
4806ee9b743Scedric 	for (i = 0; i < size; i++) {
481ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
48296d425afSmickey 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
4836ee9b743Scedric 			senderr(EFAULT);
4846ee9b743Scedric 		if (pfr_validate_addr(&ad))
4856ee9b743Scedric 			senderr(EINVAL);
4866ee9b743Scedric 		p = pfr_lookup_addr(kt, &ad, 1);
4876ee9b743Scedric 		if (flags & PFR_FLAG_FEEDBACK) {
488b8802620Scedric 			if (p == NULL)
489b8802620Scedric 				ad.pfra_fback = PFR_FB_NONE;
49036754172Smcbride 			else if ((p->pfrke_flags & PFRKE_FLAG_NOT) !=
49136754172Smcbride 			    ad.pfra_not)
492b8802620Scedric 				ad.pfra_fback = PFR_FB_CONFLICT;
49336754172Smcbride 			else if (p->pfrke_flags & PFRKE_FLAG_MARK)
494b8802620Scedric 				ad.pfra_fback = PFR_FB_DUPLICATE;
495b8802620Scedric 			else
496b8802620Scedric 				ad.pfra_fback = PFR_FB_DELETED;
4976ee9b743Scedric 		}
49836754172Smcbride 		if (p != NULL &&
49936754172Smcbride 		    (p->pfrke_flags & PFRKE_FLAG_NOT) == ad.pfra_not &&
50036754172Smcbride 		    !(p->pfrke_flags & PFRKE_FLAG_MARK)) {
50136754172Smcbride 			p->pfrke_flags |= PFRKE_FLAG_MARK;
5026ee9b743Scedric 			SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
5036ee9b743Scedric 			xdel++;
5046ee9b743Scedric 		}
5054e905526Scedric 		if (flags & PFR_FLAG_FEEDBACK)
50696d425afSmickey 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
5074e905526Scedric 				senderr(EFAULT);
5086ee9b743Scedric 	}
5096ee9b743Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
5106ee9b743Scedric 		pfr_remove_kentries(kt, &workq);
5116ee9b743Scedric 	}
5126ee9b743Scedric 	if (ndel != NULL)
5136ee9b743Scedric 		*ndel = xdel;
5146ee9b743Scedric 	return (0);
5156ee9b743Scedric _bad:
5166ee9b743Scedric 	if (flags & PFR_FLAG_FEEDBACK)
517ec359bd5Scedric 		pfr_reset_feedback(addr, size, flags);
5186ee9b743Scedric 	return (rv);
5196ee9b743Scedric }
5206ee9b743Scedric 
5216ee9b743Scedric int
pfr_set_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * size2,int * nadd,int * ndel,int * nchange,int flags,u_int32_t ignore_pfrt_flags)5226ee9b743Scedric pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
52356966508Spascoe     int *size2, int *nadd, int *ndel, int *nchange, int flags,
52456966508Spascoe     u_int32_t ignore_pfrt_flags)
5256ee9b743Scedric {
5269977d1daScedric 	struct pfr_ktable	*kt, *tmpkt;
5276ee9b743Scedric 	struct pfr_kentryworkq	 addq, delq, changeq;
5289977d1daScedric 	struct pfr_kentry	*p, *q;
5296ee9b743Scedric 	struct pfr_addr		 ad;
5301bdebab7Stedu 	int			 i, rv, xadd = 0, xdel = 0, xchange = 0;
5313209772dScheloha 	time_t			 tzero = gettime();
5326ee9b743Scedric 
5331bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK);
53456966508Spascoe 	if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
53556966508Spascoe 	    PFR_FLAG_USERIOCTL))
5364e905526Scedric 		return (EINVAL);
5376ee9b743Scedric 	kt = pfr_lookup_table(tbl);
538bb75ae08Sdhartmei 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
5396ee9b743Scedric 		return (ESRCH);
540c06aa877Scedric 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
541c06aa877Scedric 		return (EPERM);
5424b397724Smikeb 	tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0,
54330d709c8Smbuhl 	    (flags & PFR_FLAG_USERIOCTL? PR_WAITOK : PR_NOWAIT));
5449977d1daScedric 	if (tmpkt == NULL)
5459977d1daScedric 		return (ENOMEM);
546c06aa877Scedric 	pfr_mark_addrs(kt);
5476ee9b743Scedric 	SLIST_INIT(&addq);
5486ee9b743Scedric 	SLIST_INIT(&delq);
5496ee9b743Scedric 	SLIST_INIT(&changeq);
5506ee9b743Scedric 	for (i = 0; i < size; i++) {
551ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
55296d425afSmickey 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
5536ee9b743Scedric 			senderr(EFAULT);
5546ee9b743Scedric 		if (pfr_validate_addr(&ad))
5556ee9b743Scedric 			senderr(EINVAL);
5564e905526Scedric 		ad.pfra_fback = PFR_FB_NONE;
5576ee9b743Scedric 		p = pfr_lookup_addr(kt, &ad, 1);
5586ee9b743Scedric 		if (p != NULL) {
55936754172Smcbride 			if (p->pfrke_flags & PFRKE_FLAG_MARK) {
5609977d1daScedric 				ad.pfra_fback = PFR_FB_DUPLICATE;
5619977d1daScedric 				goto _skip;
5629977d1daScedric 			}
56336754172Smcbride 			p->pfrke_flags |= PFRKE_FLAG_MARK;
56436754172Smcbride 			if ((p->pfrke_flags & PFRKE_FLAG_NOT) != ad.pfra_not) {
5656ee9b743Scedric 				SLIST_INSERT_HEAD(&changeq, p, pfrke_workq);
5666ee9b743Scedric 				ad.pfra_fback = PFR_FB_CHANGED;
5676ee9b743Scedric 				xchange++;
5684e905526Scedric 			}
5696ee9b743Scedric 		} else {
5709977d1daScedric 			q = pfr_lookup_addr(tmpkt, &ad, 1);
5719977d1daScedric 			if (q != NULL) {
5729977d1daScedric 				ad.pfra_fback = PFR_FB_DUPLICATE;
5739977d1daScedric 				goto _skip;
5749977d1daScedric 			}
575f7f76181Smikeb 			p = pfr_create_kentry(&ad);
5766ee9b743Scedric 			if (p == NULL)
5776ee9b743Scedric 				senderr(ENOMEM);
5784e905526Scedric 			if (pfr_route_kentry(tmpkt, p)) {
5794e905526Scedric 				pfr_destroy_kentry(p);
5804e905526Scedric 				ad.pfra_fback = PFR_FB_NONE;
581d07f096bSsashan 				goto _skip;
582d07f096bSsashan 			}
5836ee9b743Scedric 			SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
5846ee9b743Scedric 			ad.pfra_fback = PFR_FB_ADDED;
5856ee9b743Scedric 			xadd++;
586cbdc262eSmcbride 			if (p->pfrke_type == PFRKE_COST)
587cbdc262eSmcbride 				kt->pfrkt_refcntcost++;
588cbdc262eSmcbride 			pfr_ktable_winfo_update(kt, p);
5894e905526Scedric 		}
5909977d1daScedric _skip:
5916ee9b743Scedric 		if (flags & PFR_FLAG_FEEDBACK)
59296d425afSmickey 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
5936ee9b743Scedric 				senderr(EFAULT);
5946ee9b743Scedric 	}
59568bca9d0Scedric 	pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
5966ee9b743Scedric 	if ((flags & PFR_FLAG_FEEDBACK) && *size2) {
5976ee9b743Scedric 		if (*size2 < size+xdel) {
5986ee9b743Scedric 			*size2 = size+xdel;
5996ee9b743Scedric 			senderr(0);
6006ee9b743Scedric 		}
6016ee9b743Scedric 		i = 0;
6026ee9b743Scedric 		SLIST_FOREACH(p, &delq, pfrke_workq) {
6036ee9b743Scedric 			pfr_copyout_addr(&ad, p);
6046ee9b743Scedric 			ad.pfra_fback = PFR_FB_DELETED;
60596d425afSmickey 			if (COPYOUT(&ad, addr+size+i, sizeof(ad), flags))
6066ee9b743Scedric 				senderr(EFAULT);
6076ee9b743Scedric 			i++;
6086ee9b743Scedric 		}
6096ee9b743Scedric 	}
610dd94896cScedric 	pfr_clean_node_mask(tmpkt, &addq);
6116ee9b743Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
612c06aa877Scedric 		pfr_insert_kentries(kt, &addq, tzero);
6136ee9b743Scedric 		pfr_remove_kentries(kt, &delq);
61468bca9d0Scedric 		pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
6157b74eda2Scedric 	} else
6167b74eda2Scedric 		pfr_destroy_kentries(&addq);
6176ee9b743Scedric 	if (nadd != NULL)
6186ee9b743Scedric 		*nadd = xadd;
6196ee9b743Scedric 	if (ndel != NULL)
6206ee9b743Scedric 		*ndel = xdel;
6216ee9b743Scedric 	if (nchange != NULL)
6226ee9b743Scedric 		*nchange = xchange;
623ec359bd5Scedric 	if ((flags & PFR_FLAG_FEEDBACK) && size2)
6246ee9b743Scedric 		*size2 = size+xdel;
625c06aa877Scedric 	pfr_destroy_ktable(tmpkt, 0);
6266ee9b743Scedric 	return (0);
6276ee9b743Scedric _bad:
628dd94896cScedric 	pfr_clean_node_mask(tmpkt, &addq);
6296ee9b743Scedric 	pfr_destroy_kentries(&addq);
6306ee9b743Scedric 	if (flags & PFR_FLAG_FEEDBACK)
631ec359bd5Scedric 		pfr_reset_feedback(addr, size, flags);
632c06aa877Scedric 	pfr_destroy_ktable(tmpkt, 0);
6336ee9b743Scedric 	return (rv);
6346ee9b743Scedric }
6356ee9b743Scedric 
6366ee9b743Scedric int
pfr_tst_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nmatch,int flags)6376ee9b743Scedric pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
638e82ca249Scedric 	int *nmatch, int flags)
6396ee9b743Scedric {
6406ee9b743Scedric 	struct pfr_ktable	*kt;
6416ee9b743Scedric 	struct pfr_kentry	*p;
6426ee9b743Scedric 	struct pfr_addr		 ad;
643e82ca249Scedric 	int			 i, xmatch = 0;
6446ee9b743Scedric 
64596d425afSmickey 	ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE);
646ec359bd5Scedric 	if (pfr_validate_table(tbl, 0, 0))
6474e905526Scedric 		return (EINVAL);
6486ee9b743Scedric 	kt = pfr_lookup_table(tbl);
649bb75ae08Sdhartmei 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
6506ee9b743Scedric 		return (ESRCH);
6516ee9b743Scedric 
6526ee9b743Scedric 	for (i = 0; i < size; i++) {
653ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
65496d425afSmickey 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
6556ee9b743Scedric 			return (EFAULT);
6566ee9b743Scedric 		if (pfr_validate_addr(&ad))
6576ee9b743Scedric 			return (EINVAL);
6586ee9b743Scedric 		if (ADDR_NETWORK(&ad))
6596ee9b743Scedric 			return (EINVAL);
6606ee9b743Scedric 		p = pfr_lookup_addr(kt, &ad, 0);
661e82ca249Scedric 		if (flags & PFR_FLAG_REPLACE)
662e82ca249Scedric 			pfr_copyout_addr(&ad, p);
663e82ca249Scedric 		ad.pfra_fback = (p == NULL) ? PFR_FB_NONE :
66436754172Smcbride 		    ((p->pfrke_flags & PFRKE_FLAG_NOT) ?
66536754172Smcbride 		    PFR_FB_NOTMATCH : PFR_FB_MATCH);
66636754172Smcbride 		if (p != NULL && !(p->pfrke_flags & PFRKE_FLAG_NOT))
667e82ca249Scedric 			xmatch++;
66896d425afSmickey 		if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
6696ee9b743Scedric 			return (EFAULT);
6706ee9b743Scedric 	}
671e82ca249Scedric 	if (nmatch != NULL)
672e82ca249Scedric 		*nmatch = xmatch;
6736ee9b743Scedric 	return (0);
6746ee9b743Scedric }
6756ee9b743Scedric 
6766ee9b743Scedric int
pfr_get_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int * size,int flags)6776ee9b743Scedric pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
6786ee9b743Scedric 	int flags)
6796ee9b743Scedric {
6806ee9b743Scedric 	struct pfr_ktable	*kt;
6816ee9b743Scedric 	struct pfr_walktree	 w;
6826ee9b743Scedric 	int			 rv;
6836ee9b743Scedric 
68496d425afSmickey 	ACCEPT_FLAGS(flags, 0);
685ec359bd5Scedric 	if (pfr_validate_table(tbl, 0, 0))
6864e905526Scedric 		return (EINVAL);
6876ee9b743Scedric 	kt = pfr_lookup_table(tbl);
6885f46ddbaShenning 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
6896ee9b743Scedric 		return (ESRCH);
6906ee9b743Scedric 	if (kt->pfrkt_cnt > *size) {
6916ee9b743Scedric 		*size = kt->pfrkt_cnt;
6926ee9b743Scedric 		return (0);
6936ee9b743Scedric 	}
6946ee9b743Scedric 
6956ee9b743Scedric 	bzero(&w, sizeof(w));
6966ee9b743Scedric 	w.pfrw_op = PFRW_GET_ADDRS;
6976ee9b743Scedric 	w.pfrw_addr = addr;
6986ee9b743Scedric 	w.pfrw_free = kt->pfrkt_cnt;
699ec359bd5Scedric 	w.pfrw_flags = flags;
7006ee9b743Scedric 	rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
7016ee9b743Scedric 	if (!rv)
7026ee9b743Scedric 		rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
7036ee9b743Scedric 	if (rv)
7046ee9b743Scedric 		return (rv);
7056ee9b743Scedric 
7066ee9b743Scedric 	if (w.pfrw_free) {
7072551ddbaSmcbride 		DPFPRINTF(LOG_ERR,
7082551ddbaSmcbride 		    "pfr_get_addrs: corruption detected (%d)", w.pfrw_free);
7096ee9b743Scedric 		return (ENOTTY);
7106ee9b743Scedric 	}
7116ee9b743Scedric 	*size = kt->pfrkt_cnt;
7126ee9b743Scedric 	return (0);
7136ee9b743Scedric }
7146ee9b743Scedric 
7156ee9b743Scedric int
pfr_get_astats(struct pfr_table * tbl,struct pfr_astats * addr,int * size,int flags)7166ee9b743Scedric pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
7176ee9b743Scedric 	int flags)
7186ee9b743Scedric {
7196ee9b743Scedric 	struct pfr_ktable	*kt;
7206ee9b743Scedric 	struct pfr_walktree	 w;
7216ee9b743Scedric 	struct pfr_kentryworkq	 workq;
7221bdebab7Stedu 	int			 rv;
7233209772dScheloha 	time_t			 tzero = gettime();
7246ee9b743Scedric 
725ec359bd5Scedric 	if (pfr_validate_table(tbl, 0, 0))
7264e905526Scedric 		return (EINVAL);
7276ee9b743Scedric 	kt = pfr_lookup_table(tbl);
728bb75ae08Sdhartmei 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
7296ee9b743Scedric 		return (ESRCH);
7306ee9b743Scedric 	if (kt->pfrkt_cnt > *size) {
7316ee9b743Scedric 		*size = kt->pfrkt_cnt;
7326ee9b743Scedric 		return (0);
7336ee9b743Scedric 	}
7346ee9b743Scedric 
7356ee9b743Scedric 	bzero(&w, sizeof(w));
7366ee9b743Scedric 	w.pfrw_op = PFRW_GET_ASTATS;
7376ee9b743Scedric 	w.pfrw_astats = addr;
7386ee9b743Scedric 	w.pfrw_free = kt->pfrkt_cnt;
739ec359bd5Scedric 	w.pfrw_flags = flags;
7406ee9b743Scedric 	rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
7416ee9b743Scedric 	if (!rv)
7426ee9b743Scedric 		rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
7436ee9b743Scedric 	if (!rv && (flags & PFR_FLAG_CLSTATS)) {
744c06aa877Scedric 		pfr_enqueue_addrs(kt, &workq, NULL, 0);
745c06aa877Scedric 		pfr_clstats_kentries(&workq, tzero, 0);
7466ee9b743Scedric 	}
7476ee9b743Scedric 	if (rv)
7486ee9b743Scedric 		return (rv);
7496ee9b743Scedric 
7506ee9b743Scedric 	if (w.pfrw_free) {
7512551ddbaSmcbride 		DPFPRINTF(LOG_ERR,
7522551ddbaSmcbride 		    "pfr_get_astats: corruption detected (%d)", w.pfrw_free);
7536ee9b743Scedric 		return (ENOTTY);
7546ee9b743Scedric 	}
7556ee9b743Scedric 	*size = kt->pfrkt_cnt;
7566ee9b743Scedric 	return (0);
7576ee9b743Scedric }
7586ee9b743Scedric 
7596ee9b743Scedric int
pfr_clr_astats(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nzero,int flags)7606ee9b743Scedric pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
7616ee9b743Scedric     int *nzero, int flags)
7626ee9b743Scedric {
7636ee9b743Scedric 	struct pfr_ktable	*kt;
7646ee9b743Scedric 	struct pfr_kentryworkq	 workq;
7656ee9b743Scedric 	struct pfr_kentry	*p;
7666ee9b743Scedric 	struct pfr_addr		 ad;
7671bdebab7Stedu 	int			 i, rv, xzero = 0;
7686ee9b743Scedric 
7691bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK);
770ec359bd5Scedric 	if (pfr_validate_table(tbl, 0, 0))
7714e905526Scedric 		return (EINVAL);
7726ee9b743Scedric 	kt = pfr_lookup_table(tbl);
773bb75ae08Sdhartmei 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
7746ee9b743Scedric 		return (ESRCH);
7756ee9b743Scedric 	SLIST_INIT(&workq);
7766ee9b743Scedric 	for (i = 0; i < size; i++) {
777ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
77896d425afSmickey 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
7796ee9b743Scedric 			senderr(EFAULT);
7806ee9b743Scedric 		if (pfr_validate_addr(&ad))
7816ee9b743Scedric 			senderr(EINVAL);
7826ee9b743Scedric 		p = pfr_lookup_addr(kt, &ad, 1);
7836ee9b743Scedric 		if (flags & PFR_FLAG_FEEDBACK) {
7846ee9b743Scedric 			ad.pfra_fback = (p != NULL) ?
7856ee9b743Scedric 			    PFR_FB_CLEARED : PFR_FB_NONE;
78696d425afSmickey 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
7876ee9b743Scedric 				senderr(EFAULT);
7886ee9b743Scedric 		}
7896ee9b743Scedric 		if (p != NULL) {
7906ee9b743Scedric 			SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
7916ee9b743Scedric 			xzero++;
7926ee9b743Scedric 		}
7936ee9b743Scedric 	}
7946ee9b743Scedric 
7956ee9b743Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
7963209772dScheloha 		pfr_clstats_kentries(&workq, gettime(), 0);
7976ee9b743Scedric 	}
7986ee9b743Scedric 	if (nzero != NULL)
7996ee9b743Scedric 		*nzero = xzero;
8006ee9b743Scedric 	return (0);
8016ee9b743Scedric _bad:
8026ee9b743Scedric 	if (flags & PFR_FLAG_FEEDBACK)
803ec359bd5Scedric 		pfr_reset_feedback(addr, size, flags);
8046ee9b743Scedric 	return (rv);
8056ee9b743Scedric }
8066ee9b743Scedric 
8076ee9b743Scedric int
pfr_validate_addr(struct pfr_addr * ad)8086ee9b743Scedric pfr_validate_addr(struct pfr_addr *ad)
8096ee9b743Scedric {
8104e905526Scedric 	int i;
8114e905526Scedric 
8126ee9b743Scedric 	switch (ad->pfra_af) {
8136ee9b743Scedric 	case AF_INET:
8144e905526Scedric 		if (ad->pfra_net > 32)
8156ee9b743Scedric 			return (-1);
8164e905526Scedric 		break;
8177d37faf6Spb #ifdef INET6
8186ee9b743Scedric 	case AF_INET6:
8194e905526Scedric 		if (ad->pfra_net > 128)
8206ee9b743Scedric 			return (-1);
8214e905526Scedric 		break;
8227d37faf6Spb #endif /* INET6 */
8236ee9b743Scedric 	default:
8246ee9b743Scedric 		return (-1);
8256ee9b743Scedric 	}
8264e905526Scedric 	if (ad->pfra_net < 128 &&
8274e905526Scedric 		(((caddr_t)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8))))
8284e905526Scedric 			return (-1);
8294e905526Scedric 	for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++)
8304e905526Scedric 		if (((caddr_t)ad)[i])
8314e905526Scedric 			return (-1);
8324e905526Scedric 	if (ad->pfra_not && ad->pfra_not != 1)
8334e905526Scedric 		return (-1);
834ab23e671Skn 	if (ad->pfra_fback != PFR_FB_NONE)
8354e905526Scedric 		return (-1);
8362a9429a8Smikeb 	if (ad->pfra_type >= PFRKE_MAX)
8372a9429a8Smikeb 		return (-1);
8384e905526Scedric 	return (0);
8396ee9b743Scedric }
8406ee9b743Scedric 
841c06aa877Scedric void
pfr_enqueue_addrs(struct pfr_ktable * kt,struct pfr_kentryworkq * workq,int * naddr,int sweep)8426ee9b743Scedric pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq,
843c06aa877Scedric 	int *naddr, int sweep)
8446ee9b743Scedric {
8456ee9b743Scedric 	struct pfr_walktree	w;
8466ee9b743Scedric 
8476ee9b743Scedric 	SLIST_INIT(workq);
8486ee9b743Scedric 	bzero(&w, sizeof(w));
849c06aa877Scedric 	w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE;
8506ee9b743Scedric 	w.pfrw_workq = workq;
851c06aa877Scedric 	if (kt->pfrkt_ip4 != NULL)
852c06aa877Scedric 		if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
8532551ddbaSmcbride 			DPFPRINTF(LOG_ERR,
8542551ddbaSmcbride 			    "pfr_enqueue_addrs: IPv4 walktree failed.");
855c06aa877Scedric 	if (kt->pfrkt_ip6 != NULL)
856c06aa877Scedric 		if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
8572551ddbaSmcbride 			DPFPRINTF(LOG_ERR,
8582551ddbaSmcbride 			    "pfr_enqueue_addrs: IPv6 walktree failed.");
8596ee9b743Scedric 	if (naddr != NULL)
8606ee9b743Scedric 		*naddr = w.pfrw_cnt;
8616ee9b743Scedric }
8626ee9b743Scedric 
863c06aa877Scedric void
pfr_mark_addrs(struct pfr_ktable * kt)864c06aa877Scedric pfr_mark_addrs(struct pfr_ktable *kt)
865c06aa877Scedric {
866c06aa877Scedric 	struct pfr_walktree	w;
867c06aa877Scedric 
868c06aa877Scedric 	bzero(&w, sizeof(w));
869c06aa877Scedric 	w.pfrw_op = PFRW_MARK;
870c06aa877Scedric 	if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
8712551ddbaSmcbride 		DPFPRINTF(LOG_ERR,
8722551ddbaSmcbride 		    "pfr_mark_addrs: IPv4 walktree failed.");
873c06aa877Scedric 	if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
8742551ddbaSmcbride 		DPFPRINTF(LOG_ERR,
8752551ddbaSmcbride 		    "pfr_mark_addrs: IPv6 walktree failed.");
876c06aa877Scedric }
877c06aa877Scedric 
878c06aa877Scedric 
8796ee9b743Scedric struct pfr_kentry *
pfr_lookup_addr(struct pfr_ktable * kt,struct pfr_addr * ad,int exact)8806ee9b743Scedric pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
8816ee9b743Scedric {
8826ee9b743Scedric 	union sockaddr_union	 sa, mask;
8836ee9b743Scedric 	struct radix_node_head	*head;
8846ee9b743Scedric 	struct pfr_kentry	*ke;
8856ee9b743Scedric 
8866ee9b743Scedric 	bzero(&sa, sizeof(sa));
887ba413839Sjsg 	switch (ad->pfra_af) {
888ba413839Sjsg 	case AF_INET:
8896ee9b743Scedric 		FILLIN_SIN(sa.sin, ad->pfra_ip4addr);
8906ee9b743Scedric 		head = kt->pfrkt_ip4;
891ba413839Sjsg 		break;
8929b00340fSsashan #ifdef	INET6
893ba413839Sjsg 	case AF_INET6:
8946ee9b743Scedric 		FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr);
8956ee9b743Scedric 		head = kt->pfrkt_ip6;
896ba413839Sjsg 		break;
8979b00340fSsashan #endif	/* INET6 */
898ba413839Sjsg 	default:
899ba413839Sjsg 		unhandled_af(ad->pfra_af);
9006ee9b743Scedric 	}
9016ee9b743Scedric 	if (ADDR_NETWORK(ad)) {
9026ee9b743Scedric 		pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net);
9036ee9b743Scedric 		ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head);
9046ee9b743Scedric 	} else {
9056ee9b743Scedric 		ke = (struct pfr_kentry *)rn_match(&sa, head);
9066ee9b743Scedric 		if (exact && ke && KENTRY_NETWORK(ke))
9076ee9b743Scedric 			ke = NULL;
9086ee9b743Scedric 	}
9096ee9b743Scedric 	return (ke);
9106ee9b743Scedric }
9116ee9b743Scedric 
9126ee9b743Scedric struct pfr_kentry *
pfr_lookup_kentry(struct pfr_ktable * kt,struct pfr_kentry * key,int exact)913999a6f61Ssashan pfr_lookup_kentry(struct pfr_ktable *kt, struct pfr_kentry *key, int exact)
914999a6f61Ssashan {
915999a6f61Ssashan 	union sockaddr_union	 mask;
916999a6f61Ssashan 	struct radix_node_head	*head;
917999a6f61Ssashan 	struct pfr_kentry	*ke;
918999a6f61Ssashan 
919999a6f61Ssashan 	switch (key->pfrke_af) {
920999a6f61Ssashan 	case AF_INET:
921999a6f61Ssashan 		head = kt->pfrkt_ip4;
922999a6f61Ssashan 		break;
923999a6f61Ssashan #ifdef	INET6
924999a6f61Ssashan 	case AF_INET6:
925999a6f61Ssashan 		head = kt->pfrkt_ip6;
926999a6f61Ssashan 		break;
927999a6f61Ssashan #endif	/* INET6 */
928999a6f61Ssashan 	default:
929999a6f61Ssashan 		unhandled_af(key->pfrke_af);
930999a6f61Ssashan 	}
931999a6f61Ssashan 	if (KENTRY_NETWORK(key)) {
932999a6f61Ssashan 		pfr_prepare_network(&mask, key->pfrke_af, key->pfrke_net);
933999a6f61Ssashan 		ke = (struct pfr_kentry *)rn_lookup(&key->pfrke_sa, &mask,
934999a6f61Ssashan 		    head);
935999a6f61Ssashan 	} else {
936999a6f61Ssashan 		ke = (struct pfr_kentry *)rn_match(&key->pfrke_sa, head);
937999a6f61Ssashan 		if (exact && ke && KENTRY_NETWORK(ke))
938999a6f61Ssashan 			ke = NULL;
939999a6f61Ssashan 	}
940999a6f61Ssashan 	return (ke);
941999a6f61Ssashan }
942999a6f61Ssashan 
943999a6f61Ssashan struct pfr_kentry *
pfr_create_kentry(struct pfr_addr * ad)944f7f76181Smikeb pfr_create_kentry(struct pfr_addr *ad)
9456ee9b743Scedric {
94636754172Smcbride 	struct pfr_kentry_all	*ke;
9476ee9b743Scedric 
9482a9429a8Smikeb 	if (ad->pfra_type >= PFRKE_MAX)
9492a9429a8Smikeb 		panic("unknown pfra_type %d", ad->pfra_type);
9502a9429a8Smikeb 
95136754172Smcbride 	ke = pool_get(&pfr_kentry_pl[ad->pfra_type], PR_NOWAIT | PR_ZERO);
9526ee9b743Scedric 	if (ke == NULL)
9536ee9b743Scedric 		return (NULL);
9546ee9b743Scedric 
95536754172Smcbride 	ke->pfrke_type = ad->pfra_type;
95636754172Smcbride 
957cbdc262eSmcbride 	/* set weight allowing implicit weights */
958cbdc262eSmcbride 	if (ad->pfra_weight == 0)
959cbdc262eSmcbride 		ad->pfra_weight = 1;
960cbdc262eSmcbride 
96136754172Smcbride 	switch (ke->pfrke_type) {
962cbdc262eSmcbride 	case PFRKE_PLAIN:
963cbdc262eSmcbride 		break;
964bcb11948Szinke 	case PFRKE_COST:
965cbdc262eSmcbride 		((struct pfr_kentry_cost *)ke)->weight = ad->pfra_weight;
966cbdc262eSmcbride 		/* FALLTHROUGH */
967cbdc262eSmcbride 	case PFRKE_ROUTE:
968cbdc262eSmcbride 		if (ad->pfra_ifname[0])
969c97e8838Ssashan 			ke->pfrke_rkif = pfi_kif_get(ad->pfra_ifname, NULL);
97036754172Smcbride 		if (ke->pfrke_rkif)
97136754172Smcbride 			pfi_kif_ref(ke->pfrke_rkif, PFI_KIF_REF_ROUTE);
97236754172Smcbride 		break;
97336754172Smcbride 	}
97436754172Smcbride 
9759b00340fSsashan 	switch (ad->pfra_af) {
9769b00340fSsashan 	case AF_INET:
9776ee9b743Scedric 		FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr);
9789b00340fSsashan 		break;
9799b00340fSsashan #ifdef	INET6
9809b00340fSsashan 	case AF_INET6:
9816ee9b743Scedric 		FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr);
9829b00340fSsashan 		break;
9839b00340fSsashan #endif	/* INET6 */
9849b00340fSsashan 	default:
9853f22add7Ssashan 		unhandled_af(ad->pfra_af);
9869b00340fSsashan 	}
9876ee9b743Scedric 	ke->pfrke_af = ad->pfra_af;
9886ee9b743Scedric 	ke->pfrke_net = ad->pfra_net;
98936754172Smcbride 	if (ad->pfra_not)
99036754172Smcbride 		ke->pfrke_flags |= PFRKE_FLAG_NOT;
99136754172Smcbride 	return ((struct pfr_kentry *)ke);
9926ee9b743Scedric }
9936ee9b743Scedric 
994999a6f61Ssashan struct pfr_kentry *
pfr_create_kentry_unlocked(struct pfr_addr * ad,int flags)995999a6f61Ssashan pfr_create_kentry_unlocked(struct pfr_addr *ad, int flags)
996999a6f61Ssashan {
997999a6f61Ssashan 	struct pfr_kentry_all	*ke;
998999a6f61Ssashan 	int mflags = PR_ZERO;
999999a6f61Ssashan 
1000999a6f61Ssashan 	if (ad->pfra_type >= PFRKE_MAX)
1001999a6f61Ssashan 		panic("unknown pfra_type %d", ad->pfra_type);
1002999a6f61Ssashan 
1003999a6f61Ssashan 	if (flags & PFR_FLAG_USERIOCTL)
1004999a6f61Ssashan 		mflags |= PR_WAITOK;
1005999a6f61Ssashan 	else
1006999a6f61Ssashan 		mflags |= PR_NOWAIT;
1007999a6f61Ssashan 
1008999a6f61Ssashan 	ke = pool_get(&pfr_kentry_pl[ad->pfra_type], mflags);
1009999a6f61Ssashan 	if (ke == NULL)
1010999a6f61Ssashan 		return (NULL);
1011999a6f61Ssashan 
1012999a6f61Ssashan 	ke->pfrke_type = ad->pfra_type;
1013999a6f61Ssashan 
1014999a6f61Ssashan 	/* set weight allowing implicit weights */
1015999a6f61Ssashan 	if (ad->pfra_weight == 0)
1016999a6f61Ssashan 		ad->pfra_weight = 1;
1017999a6f61Ssashan 
1018999a6f61Ssashan 	switch (ke->pfrke_type) {
1019999a6f61Ssashan 	case PFRKE_PLAIN:
1020999a6f61Ssashan 		break;
1021999a6f61Ssashan 	case PFRKE_COST:
1022999a6f61Ssashan 		((struct pfr_kentry_cost *)ke)->weight = ad->pfra_weight;
1023999a6f61Ssashan 		/* FALLTHROUGH */
1024999a6f61Ssashan 	case PFRKE_ROUTE:
1025999a6f61Ssashan 		if (ad->pfra_ifname[0])
1026999a6f61Ssashan 			(void) strlcpy(ke->pfrke_rifname, ad->pfra_ifname,
1027999a6f61Ssashan 			    IFNAMSIZ);
1028999a6f61Ssashan 		break;
1029999a6f61Ssashan 	}
1030999a6f61Ssashan 
1031999a6f61Ssashan 	switch (ad->pfra_af) {
1032999a6f61Ssashan 	case AF_INET:
1033999a6f61Ssashan 		FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr);
1034999a6f61Ssashan 		break;
1035999a6f61Ssashan #ifdef	INET6
1036999a6f61Ssashan 	case AF_INET6:
1037999a6f61Ssashan 		FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr);
1038999a6f61Ssashan 		break;
1039999a6f61Ssashan #endif	/* INET6 */
1040999a6f61Ssashan 	default:
1041999a6f61Ssashan 		unhandled_af(ad->pfra_af);
1042999a6f61Ssashan 	}
1043999a6f61Ssashan 	ke->pfrke_af = ad->pfra_af;
1044999a6f61Ssashan 	ke->pfrke_net = ad->pfra_net;
1045999a6f61Ssashan 	if (ad->pfra_not)
1046999a6f61Ssashan 		ke->pfrke_flags |= PFRKE_FLAG_NOT;
1047999a6f61Ssashan 	return ((struct pfr_kentry *)ke);
1048999a6f61Ssashan }
1049999a6f61Ssashan 
1050999a6f61Ssashan void
pfr_kentry_kif_ref(struct pfr_kentry * ke_all)1051999a6f61Ssashan pfr_kentry_kif_ref(struct pfr_kentry *ke_all)
1052999a6f61Ssashan {
1053999a6f61Ssashan 	struct pfr_kentry_all	*ke = (struct pfr_kentry_all *)ke_all;
1054999a6f61Ssashan 
1055999a6f61Ssashan 	NET_ASSERT_LOCKED();
1056999a6f61Ssashan 	switch (ke->pfrke_type) {
1057999a6f61Ssashan 	case PFRKE_PLAIN:
1058999a6f61Ssashan 		break;
1059999a6f61Ssashan 	case PFRKE_COST:
1060999a6f61Ssashan 	case PFRKE_ROUTE:
1061999a6f61Ssashan 		if (ke->pfrke_rifname[0])
1062999a6f61Ssashan 			ke->pfrke_rkif = pfi_kif_get(ke->pfrke_rifname, NULL);
1063999a6f61Ssashan 		if (ke->pfrke_rkif)
1064999a6f61Ssashan 			pfi_kif_ref(ke->pfrke_rkif, PFI_KIF_REF_ROUTE);
1065999a6f61Ssashan 		break;
1066999a6f61Ssashan 	}
1067999a6f61Ssashan }
1068999a6f61Ssashan 
10696ee9b743Scedric void
pfr_destroy_kentries(struct pfr_kentryworkq * workq)10706ee9b743Scedric pfr_destroy_kentries(struct pfr_kentryworkq *workq)
10716ee9b743Scedric {
10727f9adf34Ssashan 	struct pfr_kentry	*p;
10732e3a002bShenning 
10747f9adf34Ssashan 	while ((p = SLIST_FIRST(workq)) != NULL) {
1075ac7813e4Ssashan 		YIELD(1);
10767f9adf34Ssashan 		SLIST_REMOVE_HEAD(workq, pfrke_workq);
10774e905526Scedric 		pfr_destroy_kentry(p);
10786ee9b743Scedric 	}
10796ee9b743Scedric }
10806ee9b743Scedric 
1081e82ca249Scedric void
pfr_destroy_ioq(struct pfr_kentryworkq * ioq,int flags)1082999a6f61Ssashan pfr_destroy_ioq(struct pfr_kentryworkq *ioq, int flags)
1083999a6f61Ssashan {
1084999a6f61Ssashan 	struct pfr_kentry	*p;
1085999a6f61Ssashan 
1086999a6f61Ssashan 	while ((p = SLIST_FIRST(ioq)) != NULL) {
1087999a6f61Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
1088999a6f61Ssashan 		SLIST_REMOVE_HEAD(ioq, pfrke_ioq);
1089999a6f61Ssashan 		/*
1090999a6f61Ssashan 		 * we destroy only those entries, which did not make it to
1091999a6f61Ssashan 		 * table
1092999a6f61Ssashan 		 */
1093999a6f61Ssashan 		if ((p->pfrke_fb != PFR_FB_ADDED) || (flags & PFR_FLAG_DUMMY))
1094999a6f61Ssashan 			pfr_destroy_kentry(p);
1095999a6f61Ssashan 	}
1096999a6f61Ssashan }
1097999a6f61Ssashan 
1098999a6f61Ssashan void
pfr_destroy_kentry(struct pfr_kentry * ke)10994e905526Scedric pfr_destroy_kentry(struct pfr_kentry *ke)
11004e905526Scedric {
1101c99a8a7bSmcbride 	if (ke->pfrke_counters)
1102c99a8a7bSmcbride 		pool_put(&pfr_kcounters_pl, ke->pfrke_counters);
11031faf2f78Smikeb 	if (ke->pfrke_type == PFRKE_COST || ke->pfrke_type == PFRKE_ROUTE)
11041faf2f78Smikeb 		pfi_kif_unref(((struct pfr_kentry_all *)ke)->pfrke_rkif,
11051faf2f78Smikeb 		    PFI_KIF_REF_ROUTE);
110636754172Smcbride 	pool_put(&pfr_kentry_pl[ke->pfrke_type], ke);
11074e905526Scedric }
11084e905526Scedric 
11094e905526Scedric void
pfr_insert_kentries(struct pfr_ktable * kt,struct pfr_kentryworkq * workq,time_t tzero)11106ee9b743Scedric pfr_insert_kentries(struct pfr_ktable *kt,
111126ca2c15Sguenther     struct pfr_kentryworkq *workq, time_t tzero)
11126ee9b743Scedric {
1113e82ca249Scedric 	struct pfr_kentry	*p;
1114e82ca249Scedric 	int			 rv, n = 0;
11156ee9b743Scedric 
11166ee9b743Scedric 	SLIST_FOREACH(p, workq, pfrke_workq) {
1117e82ca249Scedric 		rv = pfr_route_kentry(kt, p);
1118e82ca249Scedric 		if (rv) {
11192551ddbaSmcbride 			DPFPRINTF(LOG_ERR,
11202551ddbaSmcbride 			    "pfr_insert_kentries: cannot route entry "
11212551ddbaSmcbride 			    "(code=%d).", rv);
11226ee9b743Scedric 			break;
11236ee9b743Scedric 		}
1124c06aa877Scedric 		p->pfrke_tzero = tzero;
11251bdebab7Stedu 		++n;
1126cbdc262eSmcbride 		if (p->pfrke_type == PFRKE_COST)
1127cbdc262eSmcbride 			kt->pfrkt_refcntcost++;
1128cbdc262eSmcbride 		pfr_ktable_winfo_update(kt, p);
1129ac7813e4Ssashan 		YIELD(1);
11306ee9b743Scedric 	}
11316ee9b743Scedric 	kt->pfrkt_cnt += n;
11326ee9b743Scedric }
11336ee9b743Scedric 
11345142d35aSmcbride int
pfr_insert_kentry(struct pfr_ktable * kt,struct pfr_addr * ad,time_t tzero)113526ca2c15Sguenther pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, time_t tzero)
11365142d35aSmcbride {
11375142d35aSmcbride 	struct pfr_kentry	*p;
11385142d35aSmcbride 	int			 rv;
11395142d35aSmcbride 
11405142d35aSmcbride 	p = pfr_lookup_addr(kt, ad, 1);
11415142d35aSmcbride 	if (p != NULL)
11425142d35aSmcbride 		return (0);
1143f7f76181Smikeb 	p = pfr_create_kentry(ad);
11445142d35aSmcbride 	if (p == NULL)
11455142d35aSmcbride 		return (EINVAL);
11465142d35aSmcbride 
11475142d35aSmcbride 	rv = pfr_route_kentry(kt, p);
11485142d35aSmcbride 	if (rv)
11495142d35aSmcbride 		return (rv);
11505142d35aSmcbride 
11515142d35aSmcbride 	p->pfrke_tzero = tzero;
1152cbdc262eSmcbride 	if (p->pfrke_type == PFRKE_COST)
1153cbdc262eSmcbride 		kt->pfrkt_refcntcost++;
11545142d35aSmcbride 	kt->pfrkt_cnt++;
1155cbdc262eSmcbride 	pfr_ktable_winfo_update(kt, p);
11565142d35aSmcbride 
11575142d35aSmcbride 	return (0);
11585142d35aSmcbride }
11595142d35aSmcbride 
11606ee9b743Scedric void
pfr_remove_kentries(struct pfr_ktable * kt,struct pfr_kentryworkq * workq)11616ee9b743Scedric pfr_remove_kentries(struct pfr_ktable *kt,
11626ee9b743Scedric     struct pfr_kentryworkq *workq)
11636ee9b743Scedric {
11646ee9b743Scedric 	struct pfr_kentry	*p;
1165cbdc262eSmcbride 	struct pfr_kentryworkq   addrq;
11666ee9b743Scedric 	int			 n = 0;
11676ee9b743Scedric 
11686ee9b743Scedric 	SLIST_FOREACH(p, workq, pfrke_workq) {
11696ee9b743Scedric 		pfr_unroute_kentry(kt, p);
11701bdebab7Stedu 		++n;
1171ac7813e4Ssashan 		YIELD(1);
1172cbdc262eSmcbride 		if (p->pfrke_type == PFRKE_COST)
1173cbdc262eSmcbride 			kt->pfrkt_refcntcost--;
11746ee9b743Scedric 	}
11756ee9b743Scedric 	kt->pfrkt_cnt -= n;
11766ee9b743Scedric 	pfr_destroy_kentries(workq);
1177cbdc262eSmcbride 
1178cbdc262eSmcbride 	/* update maxweight and gcd for load balancing */
1179cbdc262eSmcbride 	if (kt->pfrkt_refcntcost > 0) {
1180cbdc262eSmcbride 		kt->pfrkt_gcdweight = 0;
1181cbdc262eSmcbride 		kt->pfrkt_maxweight = 1;
1182cbdc262eSmcbride 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
1183cbdc262eSmcbride 		SLIST_FOREACH(p, &addrq, pfrke_workq)
1184cbdc262eSmcbride 			pfr_ktable_winfo_update(kt, p);
1185cbdc262eSmcbride 	}
11866ee9b743Scedric }
11876ee9b743Scedric 
11886ee9b743Scedric void
pfr_clean_node_mask(struct pfr_ktable * kt,struct pfr_kentryworkq * workq)1189dd94896cScedric pfr_clean_node_mask(struct pfr_ktable *kt,
1190dd94896cScedric     struct pfr_kentryworkq *workq)
1191dd94896cScedric {
1192dd94896cScedric 	struct pfr_kentry	*p;
1193dd94896cScedric 
11941bdebab7Stedu 	SLIST_FOREACH(p, workq, pfrke_workq) {
1195dd94896cScedric 		pfr_unroute_kentry(kt, p);
1196dd94896cScedric 	}
11971bdebab7Stedu }
1198dd94896cScedric 
1199dd94896cScedric void
pfr_clstats_kentries(struct pfr_kentryworkq * workq,time_t tzero,int negchange)120026ca2c15Sguenther pfr_clstats_kentries(struct pfr_kentryworkq *workq, time_t tzero, int negchange)
12016ee9b743Scedric {
12026ee9b743Scedric 	struct pfr_kentry	*p;
12036ee9b743Scedric 
12046ee9b743Scedric 	SLIST_FOREACH(p, workq, pfrke_workq) {
1205c06aa877Scedric 		if (negchange)
12068009377eSmarkus 			p->pfrke_flags ^= PFRKE_FLAG_NOT;
12075f03a6e1Smcbride 		if (p->pfrke_counters) {
12085f03a6e1Smcbride 			pool_put(&pfr_kcounters_pl, p->pfrke_counters);
12095f03a6e1Smcbride 			p->pfrke_counters = NULL;
12105f03a6e1Smcbride 		}
12116ee9b743Scedric 		p->pfrke_tzero = tzero;
12126ee9b743Scedric 	}
12136ee9b743Scedric }
12146ee9b743Scedric 
12156ee9b743Scedric void
pfr_reset_feedback(struct pfr_addr * addr,int size,int flags)1216ec359bd5Scedric pfr_reset_feedback(struct pfr_addr *addr, int size, int flags)
12176ee9b743Scedric {
12186ee9b743Scedric 	struct pfr_addr	ad;
12196ee9b743Scedric 	int		i;
12206ee9b743Scedric 
12216ee9b743Scedric 	for (i = 0; i < size; i++) {
1222ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
122396d425afSmickey 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
12246ee9b743Scedric 			break;
12256ee9b743Scedric 		ad.pfra_fback = PFR_FB_NONE;
122696d425afSmickey 		if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
12276ee9b743Scedric 			break;
12286ee9b743Scedric 	}
12296ee9b743Scedric }
12306ee9b743Scedric 
12316ee9b743Scedric void
pfr_prepare_network(union sockaddr_union * sa,int af,int net)12326ee9b743Scedric pfr_prepare_network(union sockaddr_union *sa, int af, int net)
12336ee9b743Scedric {
12343f22add7Ssashan #ifdef	INET6
12356ee9b743Scedric 	int	i;
12363f22add7Ssashan #endif	/* INET6 */
12376ee9b743Scedric 
12386ee9b743Scedric 	bzero(sa, sizeof(*sa));
12399b00340fSsashan 	switch (af) {
12409b00340fSsashan 	case AF_INET:
12416ee9b743Scedric 		sa->sin.sin_len = sizeof(sa->sin);
12426ee9b743Scedric 		sa->sin.sin_family = AF_INET;
1243935bbdceSmcbride 		sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0;
12449b00340fSsashan 		break;
12459b00340fSsashan #ifdef	INET6
12469b00340fSsashan 	case AF_INET6:
12476ee9b743Scedric 		sa->sin6.sin6_len = sizeof(sa->sin6);
1248b20a6e9cScedric 		sa->sin6.sin6_family = AF_INET6;
12496ee9b743Scedric 		for (i = 0; i < 4; i++) {
12506ee9b743Scedric 			if (net <= 32) {
12516ee9b743Scedric 				sa->sin6.sin6_addr.s6_addr32[i] =
1252935bbdceSmcbride 				    net ? htonl(-1 << (32-net)) : 0;
12536ee9b743Scedric 				break;
12546ee9b743Scedric 			}
12556ee9b743Scedric 			sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF;
12566ee9b743Scedric 			net -= 32;
12576ee9b743Scedric 		}
12589b00340fSsashan 		break;
12599b00340fSsashan #endif	/* INET6 */
12609b00340fSsashan 	default:
12619b00340fSsashan 		unhandled_af(af);
12626ee9b743Scedric 	}
12636ee9b743Scedric }
12646ee9b743Scedric 
12656ee9b743Scedric int
pfr_route_kentry(struct pfr_ktable * kt,struct pfr_kentry * ke)12666ee9b743Scedric pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
12676ee9b743Scedric {
12686ee9b743Scedric 	union sockaddr_union	 mask;
12696ee9b743Scedric 	struct radix_node	*rn;
12706ee9b743Scedric 	struct radix_node_head	*head;
12716ee9b743Scedric 
1272a38119b2Scedric 	bzero(ke->pfrke_node, sizeof(ke->pfrke_node));
1273ba413839Sjsg 	switch (ke->pfrke_af) {
1274ba413839Sjsg 	case AF_INET:
12756ee9b743Scedric 		head = kt->pfrkt_ip4;
1276ba413839Sjsg 		break;
12779b00340fSsashan #ifdef	INET6
1278ba413839Sjsg 	case AF_INET6:
12796ee9b743Scedric 		head = kt->pfrkt_ip6;
1280ba413839Sjsg 		break;
12819b00340fSsashan #endif	/* INET6 */
1282ba413839Sjsg 	default:
1283ba413839Sjsg 		unhandled_af(ke->pfrke_af);
1284ba413839Sjsg 	}
12856ee9b743Scedric 
12866ee9b743Scedric 	if (KENTRY_NETWORK(ke)) {
12876ee9b743Scedric 		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
12880920b6e7Sclaudio 		rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node, 0);
12896ee9b743Scedric 	} else
12900920b6e7Sclaudio 		rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node, 0);
12916ee9b743Scedric 
12924e905526Scedric 	return (rn == NULL ? -1 : 0);
12936ee9b743Scedric }
12946ee9b743Scedric 
12956ee9b743Scedric int
pfr_unroute_kentry(struct pfr_ktable * kt,struct pfr_kentry * ke)12966ee9b743Scedric pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
12976ee9b743Scedric {
12986ee9b743Scedric 	union sockaddr_union	 mask;
12996ee9b743Scedric 	struct radix_node	*rn;
13006ee9b743Scedric 	struct radix_node_head	*head;
13016ee9b743Scedric 
1302ba413839Sjsg 	switch (ke->pfrke_af) {
1303ba413839Sjsg 	case AF_INET:
13046ee9b743Scedric 		head = kt->pfrkt_ip4;
1305ba413839Sjsg 		break;
13069b00340fSsashan #ifdef	INET6
1307ba413839Sjsg 	case AF_INET6:
13086ee9b743Scedric 		head = kt->pfrkt_ip6;
1309ba413839Sjsg 		break;
13109b00340fSsashan #endif	/* INET6 */
1311ba413839Sjsg 	default:
1312ba413839Sjsg 		unhandled_af(ke->pfrke_af);
1313ba413839Sjsg 	}
13146ee9b743Scedric 
13156ee9b743Scedric 	if (KENTRY_NETWORK(ke)) {
13166ee9b743Scedric 		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
1317f40e51e0Sitojun 		rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL);
13186ee9b743Scedric 	} else
1319f40e51e0Sitojun 		rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL);
13206ee9b743Scedric 
13216ee9b743Scedric 	if (rn == NULL) {
13222551ddbaSmcbride 		DPFPRINTF(LOG_ERR, "pfr_unroute_kentry: delete failed.\n");
13236ee9b743Scedric 		return (-1);
13246ee9b743Scedric 	}
13256ee9b743Scedric 	return (0);
13266ee9b743Scedric }
13276ee9b743Scedric 
13286ee9b743Scedric void
pfr_copyout_addr(struct pfr_addr * ad,struct pfr_kentry * ke)13296ee9b743Scedric pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke)
13306ee9b743Scedric {
13316ee9b743Scedric 	bzero(ad, sizeof(*ad));
1332e82ca249Scedric 	if (ke == NULL)
1333e82ca249Scedric 		return;
13346ee9b743Scedric 	ad->pfra_af = ke->pfrke_af;
13356ee9b743Scedric 	ad->pfra_net = ke->pfrke_net;
1336bcb11948Szinke 	ad->pfra_type = ke->pfrke_type;
133736754172Smcbride 	if (ke->pfrke_flags & PFRKE_FLAG_NOT)
133836754172Smcbride 		ad->pfra_not = 1;
13399b00340fSsashan 
13409b00340fSsashan 	switch (ad->pfra_af) {
13419b00340fSsashan 	case AF_INET:
13426ee9b743Scedric 		ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr;
13439b00340fSsashan 		break;
13449b00340fSsashan #ifdef	INET6
13459b00340fSsashan 	case AF_INET6:
13466ee9b743Scedric 		ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr;
13479b00340fSsashan 		break;
13489b00340fSsashan #endif	/* INET6 */
13499b00340fSsashan 	default:
13509b00340fSsashan 		unhandled_af(ad->pfra_af);
13519b00340fSsashan 	}
1352cbdc262eSmcbride 	if (ke->pfrke_counters != NULL)
1353cbdc262eSmcbride 		ad->pfra_states = ke->pfrke_counters->states;
1354bcb11948Szinke 	switch (ke->pfrke_type) {
1355bcb11948Szinke 	case PFRKE_COST:
1356cbdc262eSmcbride 		ad->pfra_weight = ((struct pfr_kentry_cost *)ke)->weight;
1357bcb11948Szinke 		/* FALLTHROUGH */
1358bcb11948Szinke 	case PFRKE_ROUTE:
1359bcb11948Szinke 		if (((struct pfr_kentry_route *)ke)->kif != NULL)
136036754172Smcbride 			strlcpy(ad->pfra_ifname,
136136754172Smcbride 			    ((struct pfr_kentry_route *)ke)->kif->pfik_name,
136236754172Smcbride 			    IFNAMSIZ);
1363bcb11948Szinke 		break;
1364bcb11948Szinke 	default:
1365bcb11948Szinke 		break;
1366bcb11948Szinke 	}
13676ee9b743Scedric }
13686ee9b743Scedric 
13696ee9b743Scedric int
pfr_walktree(struct radix_node * rn,void * arg,u_int id)1370dcabaadaSclaudio pfr_walktree(struct radix_node *rn, void *arg, u_int id)
13716ee9b743Scedric {
13726ee9b743Scedric 	struct pfr_kentry	*ke = (struct pfr_kentry *)rn;
13736ee9b743Scedric 	struct pfr_walktree	*w = arg;
137499a6f929Spatrick 	union sockaddr_union	 mask;
13750f94a2cfSmpi 	int			 flags = w->pfrw_flags;
13766ee9b743Scedric 
13776ee9b743Scedric 	switch (w->pfrw_op) {
13786ee9b743Scedric 	case PFRW_MARK:
137936754172Smcbride 		ke->pfrke_flags &= ~PFRKE_FLAG_MARK;
13806ee9b743Scedric 		break;
13816ee9b743Scedric 	case PFRW_SWEEP:
138236754172Smcbride 		if (ke->pfrke_flags & PFRKE_FLAG_MARK)
13836ee9b743Scedric 			break;
138460b10d66Smcbride 		/* FALLTHROUGH */
13856ee9b743Scedric 	case PFRW_ENQUEUE:
13866ee9b743Scedric 		SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq);
13876ee9b743Scedric 		w->pfrw_cnt++;
13886ee9b743Scedric 		break;
13896ee9b743Scedric 	case PFRW_GET_ADDRS:
13906ee9b743Scedric 		if (w->pfrw_free-- > 0) {
13916ee9b743Scedric 			struct pfr_addr ad;
13926ee9b743Scedric 
13936ee9b743Scedric 			pfr_copyout_addr(&ad, ke);
13946ee9b743Scedric 			if (copyout(&ad, w->pfrw_addr, sizeof(ad)))
13956ee9b743Scedric 				return (EFAULT);
13966ee9b743Scedric 			w->pfrw_addr++;
13976ee9b743Scedric 		}
13986ee9b743Scedric 		break;
13996ee9b743Scedric 	case PFRW_GET_ASTATS:
14006ee9b743Scedric 		if (w->pfrw_free-- > 0) {
14016ee9b743Scedric 			struct pfr_astats as;
14026ee9b743Scedric 
14036ee9b743Scedric 			pfr_copyout_addr(&as.pfras_a, ke);
14046ee9b743Scedric 
14055f03a6e1Smcbride 			if (ke->pfrke_counters) {
14065f03a6e1Smcbride 				bcopy(ke->pfrke_counters->pfrkc_packets,
14075f03a6e1Smcbride 				    as.pfras_packets, sizeof(as.pfras_packets));
14085f03a6e1Smcbride 				bcopy(ke->pfrke_counters->pfrkc_bytes,
14095f03a6e1Smcbride 				    as.pfras_bytes, sizeof(as.pfras_bytes));
14105f03a6e1Smcbride 			} else {
14111cc20b70Smcbride 				bzero(as.pfras_packets,
14121cc20b70Smcbride 				    sizeof(as.pfras_packets));
14135f03a6e1Smcbride 				bzero(as.pfras_bytes, sizeof(as.pfras_bytes));
14145f03a6e1Smcbride 				as.pfras_a.pfra_fback = PFR_FB_NOCOUNT;
14155f03a6e1Smcbride 			}
141641061370Shenning 			as.pfras_tzero = ke->pfrke_tzero;
14176ee9b743Scedric 
141896d425afSmickey 			if (COPYOUT(&as, w->pfrw_astats, sizeof(as), flags))
14196ee9b743Scedric 				return (EFAULT);
14206ee9b743Scedric 			w->pfrw_astats++;
14216ee9b743Scedric 		}
14226ee9b743Scedric 		break;
1423b47e54c9Scedric 	case PFRW_POOL_GET:
142436754172Smcbride 		if (ke->pfrke_flags & PFRKE_FLAG_NOT)
1425b47e54c9Scedric 			break; /* negative entries are ignored */
1426b47e54c9Scedric 		if (!w->pfrw_cnt--) {
1427b47e54c9Scedric 			w->pfrw_kentry = ke;
1428b47e54c9Scedric 			return (1); /* finish search */
1429b47e54c9Scedric 		}
1430b47e54c9Scedric 		break;
1431ec359bd5Scedric 	case PFRW_DYNADDR_UPDATE:
14329b00340fSsashan 		switch (ke->pfrke_af) {
14339b00340fSsashan 		case AF_INET:
1434ec359bd5Scedric 			if (w->pfrw_dyn->pfid_acnt4++ > 0)
1435ec359bd5Scedric 				break;
143699a6f929Spatrick 			pfr_prepare_network(&mask, AF_INET, ke->pfrke_net);
1437ec359bd5Scedric 			w->pfrw_dyn->pfid_addr4 = *SUNION2PF(
1438ec359bd5Scedric 			    &ke->pfrke_sa, AF_INET);
1439ec359bd5Scedric 			w->pfrw_dyn->pfid_mask4 = *SUNION2PF(
144099a6f929Spatrick 			    &mask, AF_INET);
14419b00340fSsashan 			break;
14429b00340fSsashan #ifdef	INET6
14439b00340fSsashan 		case AF_INET6:
1444ec359bd5Scedric 			if (w->pfrw_dyn->pfid_acnt6++ > 0)
1445ec359bd5Scedric 				break;
144699a6f929Spatrick 			pfr_prepare_network(&mask, AF_INET6, ke->pfrke_net);
1447ec359bd5Scedric 			w->pfrw_dyn->pfid_addr6 = *SUNION2PF(
1448ec359bd5Scedric 			    &ke->pfrke_sa, AF_INET6);
1449ec359bd5Scedric 			w->pfrw_dyn->pfid_mask6 = *SUNION2PF(
145099a6f929Spatrick 			    &mask, AF_INET6);
14519b00340fSsashan 			break;
14529b00340fSsashan #endif	/* INET6 */
14539b00340fSsashan 		default:
14549b00340fSsashan 			unhandled_af(ke->pfrke_af);
1455ec359bd5Scedric 		}
145660b10d66Smcbride 		break;
14576ee9b743Scedric 	}
14586ee9b743Scedric 	return (0);
14596ee9b743Scedric }
14606ee9b743Scedric 
14616ee9b743Scedric int
pfr_clr_tables(struct pfr_table * filter,int * ndel,int flags)1462a9b90787Scedric pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
14636ee9b743Scedric {
14646ee9b743Scedric 	struct pfr_ktableworkq	 workq;
14656ee9b743Scedric 	struct pfr_ktable	*p;
14661bdebab7Stedu 	int			 xdel = 0;
14676ee9b743Scedric 
14681bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ALLRSETS);
1469f560c95aSjaredy 	if (pfr_fix_anchor(filter->pfrt_anchor))
1470f560c95aSjaredy 		return (EINVAL);
1471a9b90787Scedric 	if (pfr_table_count(filter, flags) < 0)
1472a9b90787Scedric 		return (ENOENT);
1473a9b90787Scedric 
14746ee9b743Scedric 	SLIST_INIT(&workq);
1475342c264fSdlg 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1476a9b90787Scedric 		if (pfr_skip_table(filter, p, flags))
1477a9b90787Scedric 			continue;
1478ec359bd5Scedric 		if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR))
1479ec359bd5Scedric 			continue;
1480c06aa877Scedric 		if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE))
1481c06aa877Scedric 			continue;
14822c9e9fd6Scedric 		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
14836ee9b743Scedric 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
148422da039eScedric 		xdel++;
148522da039eScedric 	}
14866ee9b743Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
14872c9e9fd6Scedric 		pfr_setflags_ktables(&workq);
14886ee9b743Scedric 	}
14896ee9b743Scedric 	if (ndel != NULL)
14906ee9b743Scedric 		*ndel = xdel;
14916ee9b743Scedric 	return (0);
14926ee9b743Scedric }
14936ee9b743Scedric 
14946ee9b743Scedric int
pfr_add_tables(struct pfr_table * tbl,int size,int * nadd,int flags)14956ee9b743Scedric pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
14966ee9b743Scedric {
1497de97784bSsashan 	struct pfr_ktableworkq	 addq, changeq, auxq;
1498de97784bSsashan 	struct pfr_ktable	*p, *q, *r, *n, *w, key;
14991bdebab7Stedu 	int			 i, rv, xadd = 0;
15003209772dScheloha 	time_t			 tzero = gettime();
15016ee9b743Scedric 
15021bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
1503c06aa877Scedric 	SLIST_INIT(&addq);
1504bb75ae08Sdhartmei 	SLIST_INIT(&changeq);
1505de97784bSsashan 	SLIST_INIT(&auxq);
1506de97784bSsashan 	/* pre-allocate all memory outside of locks */
15076ee9b743Scedric 	for (i = 0; i < size; i++) {
1508ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
150996d425afSmickey 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
151071860fb0Scedric 			senderr(EFAULT);
1511ec359bd5Scedric 		if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK,
1512ec359bd5Scedric 		    flags & PFR_FLAG_USERIOCTL))
151371860fb0Scedric 			senderr(EINVAL);
1514c06aa877Scedric 		key.pfrkt_flags |= PFR_TFLAG_ACTIVE;
1515de97784bSsashan 		p = pfr_create_ktable(&key.pfrkt_t, tzero, 0,
151630d709c8Smbuhl 		    (flags & PFR_FLAG_USERIOCTL? PR_WAITOK : PR_NOWAIT));
151771860fb0Scedric 		if (p == NULL)
151871860fb0Scedric 			senderr(ENOMEM);
15193e963a2eScedric 
1520de97784bSsashan 		/*
1521de97784bSsashan 		 * Note: we also pre-allocate a root table here. We keep it
1522de97784bSsashan 		 * at ->pfrkt_root, which we must not forget about.
1523de97784bSsashan 		 */
15243e963a2eScedric 		key.pfrkt_flags = 0;
1525de97784bSsashan 		memset(key.pfrkt_anchor, 0, sizeof(key.pfrkt_anchor));
1526de97784bSsashan 		p->pfrkt_root = pfr_create_ktable(&key.pfrkt_t, 0, 0,
152730d709c8Smbuhl 		    (flags & PFR_FLAG_USERIOCTL? PR_WAITOK : PR_NOWAIT));
1528de97784bSsashan 		if (p->pfrkt_root == NULL) {
1529de97784bSsashan 			pfr_destroy_ktable(p, 0);
15303e963a2eScedric 			senderr(ENOMEM);
1531de97784bSsashan 		}
1532de97784bSsashan 
1533de97784bSsashan 		SLIST_FOREACH(q, &auxq, pfrkt_workq) {
1534de97784bSsashan 			if (!pfr_ktable_compare(p, q)) {
1535de97784bSsashan 				/*
1536de97784bSsashan 				 * We need no lock here, because `p` is empty,
1537de97784bSsashan 				 * there are no rules or shadow tables
1538de97784bSsashan 				 * attached.
1539de97784bSsashan 				 */
1540de97784bSsashan 				pfr_destroy_ktable(p->pfrkt_root, 0);
1541de97784bSsashan 				p->pfrkt_root = NULL;
1542de97784bSsashan 				pfr_destroy_ktable(p, 0);
1543de97784bSsashan 				p = NULL;
1544de97784bSsashan 				break;
1545de97784bSsashan 			}
1546de97784bSsashan 		}
1547de97784bSsashan 		if (q != NULL)
1548de97784bSsashan 			continue;
1549de97784bSsashan 
1550de97784bSsashan 		SLIST_INSERT_HEAD(&auxq, p, pfrkt_workq);
1551de97784bSsashan 	}
1552de97784bSsashan 
1553de97784bSsashan 	/*
1554de97784bSsashan 	 * auxq contains freshly allocated tables with no dups.
1555de97784bSsashan 	 * also note there are no rulesets attached, because
1556de97784bSsashan 	 * the attach operation requires PF_LOCK().
1557de97784bSsashan 	 */
1558de97784bSsashan 	NET_LOCK();
1559de97784bSsashan 	PF_LOCK();
1560de97784bSsashan 	SLIST_FOREACH_SAFE(n, &auxq, pfrkt_workq, w) {
1561de97784bSsashan 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, n);
1562de97784bSsashan 		if (p == NULL) {
1563de97784bSsashan 			SLIST_REMOVE(&auxq, n, pfr_ktable, pfrkt_workq);
1564de97784bSsashan 			SLIST_INSERT_HEAD(&addq, n, pfrkt_workq);
15659339d28aSsashan 			xadd++;
1566de97784bSsashan 		} else if (!(flags & PFR_FLAG_DUMMY) &&
1567de97784bSsashan 		    !(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1568*d40c6365Ssashan 			p->pfrkt_nflags =
1569*d40c6365Ssashan 			    (p->pfrkt_flags & ~PFR_TFLAG_USRMASK) |
1570*d40c6365Ssashan 			    (n->pfrkt_flags & PFR_TFLAG_USRMASK) |
1571*d40c6365Ssashan 			    PFR_TFLAG_ACTIVE;
1572bb75ae08Sdhartmei 			SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq);
1573de97784bSsashan 		}
15746ee9b743Scedric 	}
1575de97784bSsashan 
15766ee9b743Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
1577de97784bSsashan 		/*
1578de97784bSsashan 		 * addq contains tables we have to insert and attach rules to
1579de97784bSsashan 		 * them
1580de97784bSsashan 		 *
1581de97784bSsashan 		 * changeq contains tables we need to update
1582de97784bSsashan 		 *
1583de97784bSsashan 		 * auxq contains pre-allocated tables, we won't use and we must
1584de97784bSsashan 		 * free them
1585de97784bSsashan 		 */
1586de97784bSsashan 		SLIST_FOREACH_SAFE(p, &addq, pfrkt_workq, w) {
1587de97784bSsashan 			p->pfrkt_rs = pf_find_or_create_ruleset(
1588de97784bSsashan 			    p->pfrkt_anchor);
1589de97784bSsashan 			if (p->pfrkt_rs == NULL) {
1590de97784bSsashan 				xadd--;
1591de97784bSsashan 				SLIST_REMOVE(&addq, p, pfr_ktable, pfrkt_workq);
1592de97784bSsashan 				SLIST_INSERT_HEAD(&auxq, p, pfrkt_workq);
1593de97784bSsashan 				continue;
1594de97784bSsashan 			}
1595de97784bSsashan 			p->pfrkt_rs->tables++;
1596de97784bSsashan 
1597de97784bSsashan 			if (!p->pfrkt_anchor[0]) {
1598de97784bSsashan 				q = p->pfrkt_root;
1599de97784bSsashan 				p->pfrkt_root = NULL;
1600de97784bSsashan 				SLIST_INSERT_HEAD(&auxq, q, pfrkt_workq);
1601de97784bSsashan 				continue;
1602de97784bSsashan 			}
1603de97784bSsashan 
1604de97784bSsashan 			/* use pre-allocated root table as a key */
1605de97784bSsashan 			q = p->pfrkt_root;
1606de97784bSsashan 			p->pfrkt_root = NULL;
1607de97784bSsashan 			r = RB_FIND(pfr_ktablehead, &pfr_ktables, q);
1608de97784bSsashan 			if (r != NULL) {
1609de97784bSsashan 				p->pfrkt_root = r;
1610de97784bSsashan 				SLIST_INSERT_HEAD(&auxq, q, pfrkt_workq);
1611de97784bSsashan 				continue;
1612de97784bSsashan 			}
1613de97784bSsashan 			/*
1614de97784bSsashan 			 * there is a chance we could create root table in
1615de97784bSsashan 			 * earlier iteration. such table may exist in addq only
1616de97784bSsashan 			 * then.
1617de97784bSsashan 			 */
1618de97784bSsashan 			SLIST_FOREACH(r, &addq, pfrkt_workq) {
1619de97784bSsashan 				if (!pfr_ktable_compare(r, q)) {
1620de97784bSsashan 					/*
1621de97784bSsashan 					 * `r` is our root table we've found
1622de97784bSsashan 					 * earlier, `q` can get dropped.
1623de97784bSsashan 					 */
1624de97784bSsashan 					p->pfrkt_root = r;
1625de97784bSsashan 					SLIST_INSERT_HEAD(&auxq, q,
1626de97784bSsashan 					    pfrkt_workq);
1627de97784bSsashan 					break;
1628de97784bSsashan 				}
1629de97784bSsashan 			}
1630de97784bSsashan 			if (r != NULL)
1631de97784bSsashan 				continue;
1632de97784bSsashan 
1633e91a6840Ssashan 			q->pfrkt_rs = pf_find_or_create_ruleset(q->pfrkt_anchor);
1634de97784bSsashan 			/*
1635de97784bSsashan 			 * root tables are attached to main ruleset,
1636de97784bSsashan 			 * because ->pfrkt_anchor[0] == '\0'
1637de97784bSsashan 			 */
1638de97784bSsashan 			KASSERT(q->pfrkt_rs == &pf_main_ruleset);
1639de97784bSsashan 			q->pfrkt_rs->tables++;
1640de97784bSsashan 			p->pfrkt_root = q;
1641de97784bSsashan 			SLIST_INSERT_HEAD(&addq, q, pfrkt_workq);
1642de97784bSsashan 		}
1643de97784bSsashan 
1644c06aa877Scedric 		pfr_insert_ktables(&addq);
16452c9e9fd6Scedric 		pfr_setflags_ktables(&changeq);
1646de97784bSsashan 	}
1647de97784bSsashan 	PF_UNLOCK();
1648de97784bSsashan 	NET_UNLOCK();
1649de97784bSsashan 
1650de97784bSsashan 	pfr_destroy_ktables_aux(&auxq);
1651de97784bSsashan 	if (flags & PFR_FLAG_DUMMY)
1652de97784bSsashan 		pfr_destroy_ktables_aux(&addq);
1653de97784bSsashan 
16546ee9b743Scedric 	if (nadd != NULL)
16556ee9b743Scedric 		*nadd = xadd;
16566ee9b743Scedric 	return (0);
165771860fb0Scedric _bad:
1658de97784bSsashan 	pfr_destroy_ktables_aux(&auxq);
165971860fb0Scedric 	return (rv);
16606ee9b743Scedric }
16616ee9b743Scedric 
16626ee9b743Scedric int
pfr_del_tables(struct pfr_table * tbl,int size,int * ndel,int flags)16636ee9b743Scedric pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
16646ee9b743Scedric {
1665c06aa877Scedric 	struct pfr_ktableworkq	 workq;
166671860fb0Scedric 	struct pfr_ktable	*p, *q, key;
16671bdebab7Stedu 	int			 i, xdel = 0;
16686ee9b743Scedric 
16691bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
16706ee9b743Scedric 	SLIST_INIT(&workq);
16716ee9b743Scedric 	for (i = 0; i < size; i++) {
1672ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
167396d425afSmickey 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
16746ee9b743Scedric 			return (EFAULT);
1675ec359bd5Scedric 		if (pfr_validate_table(&key.pfrkt_t, 0,
1676ec359bd5Scedric 		    flags & PFR_FLAG_USERIOCTL))
16774e905526Scedric 			return (EINVAL);
1678342c264fSdlg 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1679c06aa877Scedric 		if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1680c06aa877Scedric 			SLIST_FOREACH(q, &workq, pfrkt_workq)
16813e963a2eScedric 				if (!pfr_ktable_compare(p, q))
168271860fb0Scedric 					goto _skip;
16832c9e9fd6Scedric 			p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
1684c06aa877Scedric 			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
16856ee9b743Scedric 			xdel++;
16866ee9b743Scedric 		}
168771860fb0Scedric _skip:
1688808d7db6Shenric 	;
16896ee9b743Scedric 	}
16906ee9b743Scedric 
16916ee9b743Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
16922c9e9fd6Scedric 		pfr_setflags_ktables(&workq);
16936ee9b743Scedric 	}
16946ee9b743Scedric 	if (ndel != NULL)
16956ee9b743Scedric 		*ndel = xdel;
16966ee9b743Scedric 	return (0);
16976ee9b743Scedric }
16986ee9b743Scedric 
16996ee9b743Scedric int
pfr_get_tables(struct pfr_table * filter,struct pfr_table * tbl,int * size,int flags)1700a9b90787Scedric pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
1701a9b90787Scedric 	int flags)
17026ee9b743Scedric {
17036ee9b743Scedric 	struct pfr_ktable	*p;
17049c80c900Scedric 	int			 n, nn;
17056ee9b743Scedric 
170696d425afSmickey 	ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS);
1707f560c95aSjaredy 	if (pfr_fix_anchor(filter->pfrt_anchor))
1708f560c95aSjaredy 		return (EINVAL);
17099c80c900Scedric 	n = nn = pfr_table_count(filter, flags);
1710a9b90787Scedric 	if (n < 0)
1711a9b90787Scedric 		return (ENOENT);
17126ee9b743Scedric 	if (n > *size) {
17136ee9b743Scedric 		*size = n;
17146ee9b743Scedric 		return (0);
17156ee9b743Scedric 	}
1716342c264fSdlg 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1717a9b90787Scedric 		if (pfr_skip_table(filter, p, flags))
1718a9b90787Scedric 			continue;
17196ee9b743Scedric 		if (n-- <= 0)
17206ee9b743Scedric 			continue;
172196d425afSmickey 		if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), flags))
17226ee9b743Scedric 			return (EFAULT);
17236ee9b743Scedric 	}
17246ee9b743Scedric 	if (n) {
17252551ddbaSmcbride 		DPFPRINTF(LOG_ERR,
17262551ddbaSmcbride 		    "pfr_get_tables: corruption detected (%d).", n);
17276ee9b743Scedric 		return (ENOTTY);
17286ee9b743Scedric 	}
17299c80c900Scedric 	*size = nn;
17306ee9b743Scedric 	return (0);
17316ee9b743Scedric }
17326ee9b743Scedric 
17336ee9b743Scedric int
pfr_get_tstats(struct pfr_table * filter,struct pfr_tstats * tbl,int * size,int flags)1734a9b90787Scedric pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
1735a9b90787Scedric 	int flags)
17366ee9b743Scedric {
17376ee9b743Scedric 	struct pfr_ktable	*p;
17386ee9b743Scedric 	struct pfr_ktableworkq	 workq;
17390f94a2cfSmpi 	int			 n, nn;
17403209772dScheloha 	time_t			 tzero = gettime();
17416ee9b743Scedric 
1742a9b90787Scedric 	/* XXX PFR_FLAG_CLSTATS disabled */
17431bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS);
1744f560c95aSjaredy 	if (pfr_fix_anchor(filter->pfrt_anchor))
1745f560c95aSjaredy 		return (EINVAL);
17469c80c900Scedric 	n = nn = pfr_table_count(filter, flags);
1747a9b90787Scedric 	if (n < 0)
1748a9b90787Scedric 		return (ENOENT);
17496ee9b743Scedric 	if (n > *size) {
17506ee9b743Scedric 		*size = n;
17516ee9b743Scedric 		return (0);
17526ee9b743Scedric 	}
17536ee9b743Scedric 	SLIST_INIT(&workq);
1754342c264fSdlg 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1755a9b90787Scedric 		if (pfr_skip_table(filter, p, flags))
1756a9b90787Scedric 			continue;
17576ee9b743Scedric 		if (n-- <= 0)
17586ee9b743Scedric 			continue;
17590f94a2cfSmpi 		if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), flags))
17606ee9b743Scedric 			return (EFAULT);
17616ee9b743Scedric 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
17626ee9b743Scedric 	}
17636ee9b743Scedric 	if (flags & PFR_FLAG_CLSTATS)
17646ee9b743Scedric 		pfr_clstats_ktables(&workq, tzero,
1765c06aa877Scedric 		    flags & PFR_FLAG_ADDRSTOO);
17666ee9b743Scedric 	if (n) {
17672551ddbaSmcbride 		DPFPRINTF(LOG_ERR,
17682551ddbaSmcbride 		    "pfr_get_tstats: corruption detected (%d).", n);
17696ee9b743Scedric 		return (ENOTTY);
17706ee9b743Scedric 	}
17719c80c900Scedric 	*size = nn;
17726ee9b743Scedric 	return (0);
17736ee9b743Scedric }
17746ee9b743Scedric 
17756ee9b743Scedric int
pfr_clr_tstats(struct pfr_table * tbl,int size,int * nzero,int flags)17766ee9b743Scedric pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
17776ee9b743Scedric {
17786ee9b743Scedric 	struct pfr_ktableworkq	 workq;
17796ee9b743Scedric 	struct pfr_ktable	*p, key;
17801bdebab7Stedu 	int			 i, xzero = 0;
17813209772dScheloha 	time_t			 tzero = gettime();
17826ee9b743Scedric 
17831bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO);
17846ee9b743Scedric 	SLIST_INIT(&workq);
17856ee9b743Scedric 	for (i = 0; i < size; i++) {
1786ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
178796d425afSmickey 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
17886ee9b743Scedric 			return (EFAULT);
1789ec359bd5Scedric 		if (pfr_validate_table(&key.pfrkt_t, 0, 0))
17904e905526Scedric 			return (EINVAL);
1791342c264fSdlg 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
17926ee9b743Scedric 		if (p != NULL) {
17936ee9b743Scedric 			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
17946ee9b743Scedric 			xzero++;
17956ee9b743Scedric 		}
17966ee9b743Scedric 	}
17976ee9b743Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
1798c06aa877Scedric 		pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO);
17996ee9b743Scedric 	}
18006ee9b743Scedric 	if (nzero != NULL)
18016ee9b743Scedric 		*nzero = xzero;
18026ee9b743Scedric 	return (0);
18036ee9b743Scedric }
18046ee9b743Scedric 
1805c06aa877Scedric int
pfr_set_tflags(struct pfr_table * tbl,int size,int setflag,int clrflag,int * nchange,int * ndel,int flags)1806c06aa877Scedric pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
1807c06aa877Scedric 	int *nchange, int *ndel, int flags)
1808c06aa877Scedric {
1809c06aa877Scedric 	struct pfr_ktableworkq	 workq;
1810c06aa877Scedric 	struct pfr_ktable	*p, *q, key;
18111bdebab7Stedu 	int			 i, xchange = 0, xdel = 0;
1812c06aa877Scedric 
18131bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
1814c06aa877Scedric 	if ((setflag & ~PFR_TFLAG_USRMASK) ||
1815c06aa877Scedric 	    (clrflag & ~PFR_TFLAG_USRMASK) ||
1816c06aa877Scedric 	    (setflag & clrflag))
1817c06aa877Scedric 		return (EINVAL);
1818c06aa877Scedric 	SLIST_INIT(&workq);
1819c06aa877Scedric 	for (i = 0; i < size; i++) {
1820ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
182196d425afSmickey 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
1822c06aa877Scedric 			return (EFAULT);
1823ec359bd5Scedric 		if (pfr_validate_table(&key.pfrkt_t, 0,
1824ec359bd5Scedric 		    flags & PFR_FLAG_USERIOCTL))
18254e905526Scedric 			return (EINVAL);
1826342c264fSdlg 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1827c06aa877Scedric 		if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
18282c9e9fd6Scedric 			p->pfrkt_nflags = (p->pfrkt_flags | setflag) &
18292c9e9fd6Scedric 			    ~clrflag;
18302c9e9fd6Scedric 			if (p->pfrkt_nflags == p->pfrkt_flags)
1831c06aa877Scedric 				goto _skip;
1832c06aa877Scedric 			SLIST_FOREACH(q, &workq, pfrkt_workq)
18333e963a2eScedric 				if (!pfr_ktable_compare(p, q))
1834c06aa877Scedric 					goto _skip;
1835c06aa877Scedric 			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1836c06aa877Scedric 			if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) &&
1837c06aa877Scedric 			    (clrflag & PFR_TFLAG_PERSIST) &&
1838c06aa877Scedric 			    !(p->pfrkt_flags & PFR_TFLAG_REFERENCED))
1839c06aa877Scedric 				xdel++;
1840c06aa877Scedric 			else
1841c06aa877Scedric 				xchange++;
1842c06aa877Scedric 		}
1843c06aa877Scedric _skip:
1844808d7db6Shenric 	;
1845c06aa877Scedric 	}
1846c06aa877Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
18472c9e9fd6Scedric 		pfr_setflags_ktables(&workq);
1848c06aa877Scedric 	}
1849c06aa877Scedric 	if (nchange != NULL)
1850c06aa877Scedric 		*nchange = xchange;
1851c06aa877Scedric 	if (ndel != NULL)
1852c06aa877Scedric 		*ndel = xdel;
1853c06aa877Scedric 	return (0);
1854c06aa877Scedric }
1855c06aa877Scedric 
1856c06aa877Scedric int
pfr_ina_begin(struct pfr_table * trs,u_int32_t * ticket,int * ndel,int flags)1857b2ba8e10Scedric pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags)
1858c06aa877Scedric {
1859c06aa877Scedric 	struct pfr_ktableworkq	 workq;
1860c06aa877Scedric 	struct pfr_ktable	*p;
1861b2ba8e10Scedric 	struct pf_ruleset	*rs;
1862c06aa877Scedric 	int			 xdel = 0;
1863c06aa877Scedric 
186496d425afSmickey 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
1865d9ad7941Sdhartmei 	rs = pf_find_or_create_ruleset(trs->pfrt_anchor);
1866b2ba8e10Scedric 	if (rs == NULL)
1867b2ba8e10Scedric 		return (ENOMEM);
1868c06aa877Scedric 	SLIST_INIT(&workq);
1869342c264fSdlg 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1870b2ba8e10Scedric 		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1871b2ba8e10Scedric 		    pfr_skip_table(trs, p, 0))
1872c06aa877Scedric 			continue;
18732c9e9fd6Scedric 		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
1874c06aa877Scedric 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1875c06aa877Scedric 		xdel++;
1876c06aa877Scedric 	}
1877b2ba8e10Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
18782c9e9fd6Scedric 		pfr_setflags_ktables(&workq);
1879b2ba8e10Scedric 		if (ticket != NULL)
1880b2ba8e10Scedric 			*ticket = ++rs->tticket;
1881b2ba8e10Scedric 		rs->topen = 1;
1882b2ba8e10Scedric 	} else
1883b2ba8e10Scedric 		pf_remove_if_empty_ruleset(rs);
1884c06aa877Scedric 	if (ndel != NULL)
1885c06aa877Scedric 		*ndel = xdel;
1886c06aa877Scedric 	return (0);
1887c06aa877Scedric }
1888c06aa877Scedric 
1889c06aa877Scedric int
pfr_ina_define(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int * naddr,u_int32_t ticket,int flags)1890c06aa877Scedric pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
1891b2ba8e10Scedric     int *nadd, int *naddr, u_int32_t ticket, int flags)
1892c06aa877Scedric {
1893c06aa877Scedric 	struct pfr_ktableworkq	 tableq;
1894c06aa877Scedric 	struct pfr_kentryworkq	 addrq;
18953e963a2eScedric 	struct pfr_ktable	*kt, *rt, *shadow, key;
1896c06aa877Scedric 	struct pfr_kentry	*p;
1897c06aa877Scedric 	struct pfr_addr		 ad;
1898b2ba8e10Scedric 	struct pf_ruleset	*rs;
1899c06aa877Scedric 	int			 i, rv, xadd = 0, xaddr = 0;
1900c06aa877Scedric 
190196d425afSmickey 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO);
1902c06aa877Scedric 	if (size && !(flags & PFR_FLAG_ADDRSTOO))
1903c06aa877Scedric 		return (EINVAL);
1904ec359bd5Scedric 	if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK,
1905ec359bd5Scedric 	    flags & PFR_FLAG_USERIOCTL))
1906c06aa877Scedric 		return (EINVAL);
1907d9ad7941Sdhartmei 	rs = pf_find_ruleset(tbl->pfrt_anchor);
1908b2ba8e10Scedric 	if (rs == NULL || !rs->topen || ticket != rs->tticket)
1909b2ba8e10Scedric 		return (EBUSY);
19104e905526Scedric 	tbl->pfrt_flags |= PFR_TFLAG_INACTIVE;
1911c06aa877Scedric 	SLIST_INIT(&tableq);
1912342c264fSdlg 	kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl);
1913c06aa877Scedric 	if (kt == NULL) {
19144b397724Smikeb 		kt = pfr_create_ktable(tbl, 0, 1,
191530d709c8Smbuhl 		    (flags & PFR_FLAG_USERIOCTL? PR_WAITOK : PR_NOWAIT));
1916c06aa877Scedric 		if (kt == NULL)
1917c06aa877Scedric 			return (ENOMEM);
1918c06aa877Scedric 		SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq);
1919c06aa877Scedric 		xadd++;
19203e963a2eScedric 		if (!tbl->pfrt_anchor[0])
19213e963a2eScedric 			goto _skip;
19223e963a2eScedric 
19233e963a2eScedric 		/* find or create root table */
19243e963a2eScedric 		bzero(&key, sizeof(key));
19253e963a2eScedric 		strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name));
1926342c264fSdlg 		rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
19273e963a2eScedric 		if (rt != NULL) {
19283e963a2eScedric 			kt->pfrkt_root = rt;
19293e963a2eScedric 			goto _skip;
19303e963a2eScedric 		}
19314b397724Smikeb 		rt = pfr_create_ktable(&key.pfrkt_t, 0, 1,
193230d709c8Smbuhl 		    (flags & PFR_FLAG_USERIOCTL? PR_WAITOK : PR_NOWAIT));
19333e963a2eScedric 		if (rt == NULL) {
19343e963a2eScedric 			pfr_destroy_ktables(&tableq, 0);
19353e963a2eScedric 			return (ENOMEM);
19363e963a2eScedric 		}
19373e963a2eScedric 		SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq);
19383e963a2eScedric 		kt->pfrkt_root = rt;
1939c06aa877Scedric 	} else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE))
1940c06aa877Scedric 		xadd++;
19413e963a2eScedric _skip:
194230d709c8Smbuhl 	shadow = pfr_create_ktable(tbl, 0, 0,
194330d709c8Smbuhl 	    (flags & PFR_FLAG_USERIOCTL? PR_WAITOK : PR_NOWAIT));
1944b20a6e9cScedric 	if (shadow == NULL) {
1945b20a6e9cScedric 		pfr_destroy_ktables(&tableq, 0);
1946c06aa877Scedric 		return (ENOMEM);
1947b20a6e9cScedric 	}
1948c06aa877Scedric 	SLIST_INIT(&addrq);
1949c06aa877Scedric 	for (i = 0; i < size; i++) {
1950ac7813e4Ssashan 		YIELD(flags & PFR_FLAG_USERIOCTL);
195196d425afSmickey 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
1952c06aa877Scedric 			senderr(EFAULT);
1953c06aa877Scedric 		if (pfr_validate_addr(&ad))
1954b20a6e9cScedric 			senderr(EINVAL);
1955c06aa877Scedric 		if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
1956c06aa877Scedric 			continue;
1957f7f76181Smikeb 		p = pfr_create_kentry(&ad);
1958c06aa877Scedric 		if (p == NULL)
1959c06aa877Scedric 			senderr(ENOMEM);
19608356f400Scedric 		if (pfr_route_kentry(shadow, p)) {
19618356f400Scedric 			pfr_destroy_kentry(p);
19628356f400Scedric 			continue;
19638356f400Scedric 		}
1964c06aa877Scedric 		SLIST_INSERT_HEAD(&addrq, p, pfrke_workq);
1965c06aa877Scedric 		xaddr++;
1966cbdc262eSmcbride 		if (p->pfrke_type == PFRKE_COST)
1967cbdc262eSmcbride 			kt->pfrkt_refcntcost++;
1968cbdc262eSmcbride 		pfr_ktable_winfo_update(kt, p);
1969c06aa877Scedric 	}
1970c06aa877Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
1971520c1c55Scedric 		if (kt->pfrkt_shadow != NULL)
1972c06aa877Scedric 			pfr_destroy_ktable(kt->pfrkt_shadow, 1);
1973c06aa877Scedric 		kt->pfrkt_flags |= PFR_TFLAG_INACTIVE;
1974c06aa877Scedric 		pfr_insert_ktables(&tableq);
19758356f400Scedric 		shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ?
19768356f400Scedric 		    xaddr : NO_ADDRESSES;
1977c06aa877Scedric 		kt->pfrkt_shadow = shadow;
1978c06aa877Scedric 	} else {
1979dd94896cScedric 		pfr_clean_node_mask(shadow, &addrq);
1980c06aa877Scedric 		pfr_destroy_ktable(shadow, 0);
1981c06aa877Scedric 		pfr_destroy_ktables(&tableq, 0);
1982c06aa877Scedric 		pfr_destroy_kentries(&addrq);
1983c06aa877Scedric 	}
1984c06aa877Scedric 	if (nadd != NULL)
1985c06aa877Scedric 		*nadd = xadd;
1986c06aa877Scedric 	if (naddr != NULL)
1987c06aa877Scedric 		*naddr = xaddr;
1988c06aa877Scedric 	return (0);
1989c06aa877Scedric _bad:
1990c06aa877Scedric 	pfr_destroy_ktable(shadow, 0);
1991c06aa877Scedric 	pfr_destroy_ktables(&tableq, 0);
1992c06aa877Scedric 	pfr_destroy_kentries(&addrq);
1993c06aa877Scedric 	return (rv);
1994c06aa877Scedric }
1995c06aa877Scedric 
1996c06aa877Scedric int
pfr_ina_rollback(struct pfr_table * trs,u_int32_t ticket,int * ndel,int flags)199779cc0068Scedric pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags)
199879cc0068Scedric {
199979cc0068Scedric 	struct pfr_ktableworkq	 workq;
200079cc0068Scedric 	struct pfr_ktable	*p;
200179cc0068Scedric 	struct pf_ruleset	*rs;
200279cc0068Scedric 	int			 xdel = 0;
200379cc0068Scedric 
200496d425afSmickey 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
2005d9ad7941Sdhartmei 	rs = pf_find_ruleset(trs->pfrt_anchor);
200679cc0068Scedric 	if (rs == NULL || !rs->topen || ticket != rs->tticket)
200779cc0068Scedric 		return (0);
200879cc0068Scedric 	SLIST_INIT(&workq);
2009342c264fSdlg 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
201079cc0068Scedric 		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
201179cc0068Scedric 		    pfr_skip_table(trs, p, 0))
201279cc0068Scedric 			continue;
201379cc0068Scedric 		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
201479cc0068Scedric 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
201579cc0068Scedric 		xdel++;
201679cc0068Scedric 	}
201779cc0068Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
201879cc0068Scedric 		pfr_setflags_ktables(&workq);
201979cc0068Scedric 		rs->topen = 0;
202079cc0068Scedric 		pf_remove_if_empty_ruleset(rs);
202179cc0068Scedric 	}
202279cc0068Scedric 	if (ndel != NULL)
202379cc0068Scedric 		*ndel = xdel;
202479cc0068Scedric 	return (0);
202579cc0068Scedric }
202679cc0068Scedric 
202779cc0068Scedric int
pfr_ina_commit(struct pfr_table * trs,u_int32_t ticket,int * nadd,int * nchange,int flags)2028b2ba8e10Scedric pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
2029b2ba8e10Scedric     int *nchange, int flags)
2030c06aa877Scedric {
2031ba9f08b3Smcbride 	struct pfr_ktable	*p, *q;
2032c06aa877Scedric 	struct pfr_ktableworkq	 workq;
2033b2ba8e10Scedric 	struct pf_ruleset	*rs;
20341bdebab7Stedu 	int			 xadd = 0, xchange = 0;
20353209772dScheloha 	time_t			 tzero = gettime();
2036c06aa877Scedric 
20371bdebab7Stedu 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
2038d9ad7941Sdhartmei 	rs = pf_find_ruleset(trs->pfrt_anchor);
2039b2ba8e10Scedric 	if (rs == NULL || !rs->topen || ticket != rs->tticket)
2040c06aa877Scedric 		return (EBUSY);
2041c06aa877Scedric 
2042c06aa877Scedric 	SLIST_INIT(&workq);
2043342c264fSdlg 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
2044b2ba8e10Scedric 		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
2045b2ba8e10Scedric 		    pfr_skip_table(trs, p, 0))
2046c06aa877Scedric 			continue;
2047c06aa877Scedric 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
2048c06aa877Scedric 		if (p->pfrkt_flags & PFR_TFLAG_ACTIVE)
2049c06aa877Scedric 			xchange++;
2050c06aa877Scedric 		else
2051c06aa877Scedric 			xadd++;
2052c06aa877Scedric 	}
2053c06aa877Scedric 
2054c06aa877Scedric 	if (!(flags & PFR_FLAG_DUMMY)) {
20557f9adf34Ssashan 		SLIST_FOREACH_SAFE(p, &workq, pfrkt_workq, q) {
2056c06aa877Scedric 			pfr_commit_ktable(p, tzero);
2057ba9f08b3Smcbride 		}
2058b2ba8e10Scedric 		rs->topen = 0;
2059b2ba8e10Scedric 		pf_remove_if_empty_ruleset(rs);
2060c06aa877Scedric 	}
2061c06aa877Scedric 	if (nadd != NULL)
2062c06aa877Scedric 		*nadd = xadd;
2063c06aa877Scedric 	if (nchange != NULL)
2064c06aa877Scedric 		*nchange = xchange;
2065c06aa877Scedric 
2066c06aa877Scedric 	return (0);
2067c06aa877Scedric }
2068c06aa877Scedric 
2069c06aa877Scedric void
pfr_commit_ktable(struct pfr_ktable * kt,time_t tzero)207026ca2c15Sguenther pfr_commit_ktable(struct pfr_ktable *kt, time_t tzero)
2071c06aa877Scedric {
2072c06aa877Scedric 	struct pfr_ktable	*shadow = kt->pfrkt_shadow;
20732c9e9fd6Scedric 	int			 nflags;
2074c06aa877Scedric 
2075c06aa877Scedric 	if (shadow->pfrkt_cnt == NO_ADDRESSES) {
2076c06aa877Scedric 		if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2077c06aa877Scedric 			pfr_clstats_ktable(kt, tzero, 1);
2078c06aa877Scedric 	} else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) {
2079c06aa877Scedric 		/* kt might contain addresses */
2080c06aa877Scedric 		struct pfr_kentryworkq	 addrq, addq, changeq, delq, garbageq;
20817f9adf34Ssashan 		struct pfr_kentry	*p, *q;
2082c06aa877Scedric 		struct pfr_addr		 ad;
2083c06aa877Scedric 
2084c06aa877Scedric 		pfr_enqueue_addrs(shadow, &addrq, NULL, 0);
2085c06aa877Scedric 		pfr_mark_addrs(kt);
2086c06aa877Scedric 		SLIST_INIT(&addq);
2087c06aa877Scedric 		SLIST_INIT(&changeq);
2088c06aa877Scedric 		SLIST_INIT(&delq);
2089c06aa877Scedric 		SLIST_INIT(&garbageq);
2090dd94896cScedric 		pfr_clean_node_mask(shadow, &addrq);
20917f9adf34Ssashan 		while ((p = SLIST_FIRST(&addrq)) != NULL) {
20927f9adf34Ssashan 			SLIST_REMOVE_HEAD(&addrq, pfrke_workq);
2093c06aa877Scedric 			pfr_copyout_addr(&ad, p);
2094c06aa877Scedric 			q = pfr_lookup_addr(kt, &ad, 1);
2095c06aa877Scedric 			if (q != NULL) {
209636754172Smcbride 				if ((q->pfrke_flags & PFRKE_FLAG_NOT) !=
209736754172Smcbride 				    (p->pfrke_flags & PFRKE_FLAG_NOT))
2098c06aa877Scedric 					SLIST_INSERT_HEAD(&changeq, q,
2099c06aa877Scedric 					    pfrke_workq);
210036754172Smcbride 				q->pfrke_flags |= PFRKE_FLAG_MARK;
2101c06aa877Scedric 				SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq);
2102c06aa877Scedric 			} else {
2103c06aa877Scedric 				p->pfrke_tzero = tzero;
2104c06aa877Scedric 				SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
2105c06aa877Scedric 			}
2106c06aa877Scedric 		}
210768bca9d0Scedric 		pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY);
2108c06aa877Scedric 		pfr_insert_kentries(kt, &addq, tzero);
2109c06aa877Scedric 		pfr_remove_kentries(kt, &delq);
211068bca9d0Scedric 		pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
2111c06aa877Scedric 		pfr_destroy_kentries(&garbageq);
2112c06aa877Scedric 	} else {
2113c06aa877Scedric 		/* kt cannot contain addresses */
2114c06aa877Scedric 		SWAP(struct radix_node_head *, kt->pfrkt_ip4,
2115c06aa877Scedric 		    shadow->pfrkt_ip4);
2116c06aa877Scedric 		SWAP(struct radix_node_head *, kt->pfrkt_ip6,
2117c06aa877Scedric 		    shadow->pfrkt_ip6);
2118c06aa877Scedric 		SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt);
2119c06aa877Scedric 		pfr_clstats_ktable(kt, tzero, 1);
2120c06aa877Scedric 	}
21212c9e9fd6Scedric 	nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) |
21222c9e9fd6Scedric 	    (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE)
21232c9e9fd6Scedric 		& ~PFR_TFLAG_INACTIVE;
2124520c1c55Scedric 	pfr_destroy_ktable(shadow, 0);
2125c06aa877Scedric 	kt->pfrkt_shadow = NULL;
21262c9e9fd6Scedric 	pfr_setflags_ktable(kt, nflags);
2127c06aa877Scedric }
2128c06aa877Scedric 
21294e905526Scedric int
pfr_validate_table(struct pfr_table * tbl,int allowedflags,int no_reserved)2130ec359bd5Scedric pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved)
21314e905526Scedric {
21324e905526Scedric 	int i;
21334e905526Scedric 
21344e905526Scedric 	if (!tbl->pfrt_name[0])
21354e905526Scedric 		return (-1);
2136ec359bd5Scedric 	if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR))
2137ec359bd5Scedric 		 return (-1);
21384e905526Scedric 	if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1])
21394e905526Scedric 		return (-1);
21404e905526Scedric 	for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++)
21414e905526Scedric 		if (tbl->pfrt_name[i])
21424e905526Scedric 			return (-1);
2143f560c95aSjaredy 	if (pfr_fix_anchor(tbl->pfrt_anchor))
2144f560c95aSjaredy 		return (-1);
21454e905526Scedric 	if (tbl->pfrt_flags & ~allowedflags)
21464e905526Scedric 		return (-1);
21474e905526Scedric 	return (0);
21484e905526Scedric }
21494e905526Scedric 
2150f560c95aSjaredy /*
2151f560c95aSjaredy  * Rewrite anchors referenced by tables to remove slashes
2152f560c95aSjaredy  * and check for validity.
2153f560c95aSjaredy  */
2154f560c95aSjaredy int
pfr_fix_anchor(char * anchor)2155f560c95aSjaredy pfr_fix_anchor(char *anchor)
2156f560c95aSjaredy {
2157f560c95aSjaredy 	size_t siz = MAXPATHLEN;
2158f560c95aSjaredy 	int i;
2159f560c95aSjaredy 
2160f560c95aSjaredy 	if (anchor[0] == '/') {
2161f560c95aSjaredy 		char *path;
2162f560c95aSjaredy 		int off;
2163f560c95aSjaredy 
2164f560c95aSjaredy 		path = anchor;
2165f560c95aSjaredy 		off = 1;
2166f560c95aSjaredy 		while (*++path == '/')
2167f560c95aSjaredy 			off++;
2168f560c95aSjaredy 		bcopy(path, anchor, siz - off);
2169f560c95aSjaredy 		memset(anchor + siz - off, 0, off);
2170f560c95aSjaredy 	}
2171f560c95aSjaredy 	if (anchor[siz - 1])
2172f560c95aSjaredy 		return (-1);
2173f560c95aSjaredy 	for (i = strlen(anchor); i < siz; i++)
2174f560c95aSjaredy 		if (anchor[i])
2175f560c95aSjaredy 			return (-1);
2176f560c95aSjaredy 	return (0);
2177f560c95aSjaredy }
2178f560c95aSjaredy 
2179a9b90787Scedric int
pfr_table_count(struct pfr_table * filter,int flags)2180a9b90787Scedric pfr_table_count(struct pfr_table *filter, int flags)
2181a9b90787Scedric {
2182a9b90787Scedric 	struct pf_ruleset *rs;
2183a9b90787Scedric 
2184a9b90787Scedric 	if (flags & PFR_FLAG_ALLRSETS)
2185a9b90787Scedric 		return (pfr_ktable_cnt);
2186a9b90787Scedric 	if (filter->pfrt_anchor[0]) {
2187d9ad7941Sdhartmei 		rs = pf_find_ruleset(filter->pfrt_anchor);
2188d9ad7941Sdhartmei 		return ((rs != NULL) ? rs->tables : -1);
2189a9b90787Scedric 	}
2190a9b90787Scedric 	return (pf_main_ruleset.tables);
2191a9b90787Scedric }
2192a9b90787Scedric 
2193a9b90787Scedric int
pfr_skip_table(struct pfr_table * filter,struct pfr_ktable * kt,int flags)2194a9b90787Scedric pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags)
2195a9b90787Scedric {
2196a9b90787Scedric 	if (flags & PFR_FLAG_ALLRSETS)
2197a9b90787Scedric 		return (0);
2198d9ad7941Sdhartmei 	if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor))
2199a9b90787Scedric 		return (1);
2200a9b90787Scedric 	return (0);
2201a9b90787Scedric }
2202a9b90787Scedric 
22036ee9b743Scedric void
pfr_insert_ktables(struct pfr_ktableworkq * workq)22046ee9b743Scedric pfr_insert_ktables(struct pfr_ktableworkq *workq)
22056ee9b743Scedric {
22066ee9b743Scedric 	struct pfr_ktable	*p;
22076ee9b743Scedric 
2208c06aa877Scedric 	SLIST_FOREACH(p, workq, pfrkt_workq)
2209c06aa877Scedric 		pfr_insert_ktable(p);
22106ee9b743Scedric }
22116ee9b743Scedric 
22126ee9b743Scedric void
pfr_insert_ktable(struct pfr_ktable * kt)2213c06aa877Scedric pfr_insert_ktable(struct pfr_ktable *kt)
2214c06aa877Scedric {
2215342c264fSdlg 	RB_INSERT(pfr_ktablehead, &pfr_ktables, kt);
2216c06aa877Scedric 	pfr_ktable_cnt++;
22173e963a2eScedric 	if (kt->pfrkt_root != NULL)
22183e963a2eScedric 		if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++)
22193e963a2eScedric 			pfr_setflags_ktable(kt->pfrkt_root,
22203e963a2eScedric 			    kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR);
2221c06aa877Scedric }
2222c06aa877Scedric 
2223c06aa877Scedric void
pfr_setflags_ktables(struct pfr_ktableworkq * workq)22242c9e9fd6Scedric pfr_setflags_ktables(struct pfr_ktableworkq *workq)
2225c06aa877Scedric {
2226c17558abSmcbride 	struct pfr_ktable	*p, *q;
2227c06aa877Scedric 
22287f9adf34Ssashan 	SLIST_FOREACH_SAFE(p, workq, pfrkt_workq, q) {
22292c9e9fd6Scedric 		pfr_setflags_ktable(p, p->pfrkt_nflags);
2230c06aa877Scedric 	}
2231c17558abSmcbride }
2232c06aa877Scedric 
2233c06aa877Scedric void
pfr_setflags_ktable(struct pfr_ktable * kt,int newf)22342c9e9fd6Scedric pfr_setflags_ktable(struct pfr_ktable *kt, int newf)
22356ee9b743Scedric {
22366ee9b743Scedric 	struct pfr_kentryworkq	addrq;
22376ee9b743Scedric 
2238c06aa877Scedric 	if (!(newf & PFR_TFLAG_REFERENCED) &&
223921c53b85Smikeb 	    !(newf & PFR_TFLAG_REFDANCHOR) &&
2240c06aa877Scedric 	    !(newf & PFR_TFLAG_PERSIST))
2241c06aa877Scedric 		newf &= ~PFR_TFLAG_ACTIVE;
2242c06aa877Scedric 	if (!(newf & PFR_TFLAG_ACTIVE))
2243c06aa877Scedric 		newf &= ~PFR_TFLAG_USRMASK;
2244c06aa877Scedric 	if (!(newf & PFR_TFLAG_SETMASK)) {
2245342c264fSdlg 		RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt);
22463e963a2eScedric 		if (kt->pfrkt_root != NULL)
22473e963a2eScedric 			if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR])
22483e963a2eScedric 				pfr_setflags_ktable(kt->pfrkt_root,
22493e963a2eScedric 				    kt->pfrkt_root->pfrkt_flags &
22503e963a2eScedric 					~PFR_TFLAG_REFDANCHOR);
2251c06aa877Scedric 		pfr_destroy_ktable(kt, 1);
2252c06aa877Scedric 		pfr_ktable_cnt--;
2253c06aa877Scedric 		return;
22546ee9b743Scedric 	}
2255c06aa877Scedric 	if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) {
2256c06aa877Scedric 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
2257c06aa877Scedric 		pfr_remove_kentries(kt, &addrq);
2258c06aa877Scedric 	}
2259c06aa877Scedric 	if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) {
2260c06aa877Scedric 		pfr_destroy_ktable(kt->pfrkt_shadow, 1);
2261c06aa877Scedric 		kt->pfrkt_shadow = NULL;
2262c06aa877Scedric 	}
2263c06aa877Scedric 	kt->pfrkt_flags = newf;
22646ee9b743Scedric }
22656ee9b743Scedric 
22666ee9b743Scedric void
pfr_clstats_ktables(struct pfr_ktableworkq * workq,time_t tzero,int recurse)226726ca2c15Sguenther pfr_clstats_ktables(struct pfr_ktableworkq *workq, time_t tzero, int recurse)
22686ee9b743Scedric {
22696ee9b743Scedric 	struct pfr_ktable	*p;
2270c06aa877Scedric 
2271c06aa877Scedric 	SLIST_FOREACH(p, workq, pfrkt_workq)
2272c06aa877Scedric 		pfr_clstats_ktable(p, tzero, recurse);
2273c06aa877Scedric }
2274c06aa877Scedric 
2275c06aa877Scedric void
pfr_clstats_ktable(struct pfr_ktable * kt,time_t tzero,int recurse)227626ca2c15Sguenther pfr_clstats_ktable(struct pfr_ktable *kt, time_t tzero, int recurse)
2277c06aa877Scedric {
2278c06aa877Scedric 	struct pfr_kentryworkq	 addrq;
22796ee9b743Scedric 
22806ee9b743Scedric 	if (recurse) {
2281c06aa877Scedric 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
2282c06aa877Scedric 		pfr_clstats_kentries(&addrq, tzero, 0);
22836ee9b743Scedric 	}
2284c06aa877Scedric 	bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets));
2285c06aa877Scedric 	bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes));
2286c06aa877Scedric 	kt->pfrkt_match = kt->pfrkt_nomatch = 0;
2287c06aa877Scedric 	kt->pfrkt_tzero = tzero;
22886ee9b743Scedric }
22896ee9b743Scedric 
22906ee9b743Scedric struct pfr_ktable *
pfr_create_ktable(struct pfr_table * tbl,time_t tzero,int attachruleset,int wait)229126ca2c15Sguenther pfr_create_ktable(struct pfr_table *tbl, time_t tzero, int attachruleset,
229230d709c8Smbuhl     int wait)
22936ee9b743Scedric {
22946ee9b743Scedric 	struct pfr_ktable	*kt;
2295a9b90787Scedric 	struct pf_ruleset	*rs;
22966ee9b743Scedric 
229730d709c8Smbuhl 	kt = pool_get(&pfr_ktable_pl, wait|PR_ZERO|PR_LIMITFAIL);
22986ee9b743Scedric 	if (kt == NULL)
22996ee9b743Scedric 		return (NULL);
23006ee9b743Scedric 	kt->pfrkt_t = *tbl;
23016ee9b743Scedric 
2302a9b90787Scedric 	if (attachruleset) {
2303de97784bSsashan 		PF_ASSERT_LOCKED();
2304d9ad7941Sdhartmei 		rs = pf_find_or_create_ruleset(tbl->pfrt_anchor);
2305a9b90787Scedric 		if (!rs) {
2306a9b90787Scedric 			pfr_destroy_ktable(kt, 0);
2307a9b90787Scedric 			return (NULL);
2308a9b90787Scedric 		}
2309a9b90787Scedric 		kt->pfrkt_rs = rs;
2310a9b90787Scedric 		rs->tables++;
2311a9b90787Scedric 	}
2312a9b90787Scedric 
23136ee9b743Scedric 	if (!rn_inithead((void **)&kt->pfrkt_ip4,
2314f214ddc3Smpi 	    offsetof(struct sockaddr_in, sin_addr)) ||
23156ee9b743Scedric 	    !rn_inithead((void **)&kt->pfrkt_ip6,
2316f214ddc3Smpi 	    offsetof(struct sockaddr_in6, sin6_addr))) {
2317c06aa877Scedric 		pfr_destroy_ktable(kt, 0);
23186ee9b743Scedric 		return (NULL);
23196ee9b743Scedric 	}
23206ee9b743Scedric 	kt->pfrkt_tzero = tzero;
2321cbdc262eSmcbride 	kt->pfrkt_refcntcost = 0;
2322cbdc262eSmcbride 	kt->pfrkt_gcdweight = 0;
2323cbdc262eSmcbride 	kt->pfrkt_maxweight = 1;
23246ee9b743Scedric 
23256ee9b743Scedric 	return (kt);
23266ee9b743Scedric }
23276ee9b743Scedric 
23286ee9b743Scedric void
pfr_destroy_ktables(struct pfr_ktableworkq * workq,int flushaddr)2329c06aa877Scedric pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr)
23306ee9b743Scedric {
23317f9adf34Ssashan 	struct pfr_ktable	*p;
23322e3a002bShenning 
23337f9adf34Ssashan 	while ((p = SLIST_FIRST(workq)) != NULL) {
23347f9adf34Ssashan 		SLIST_REMOVE_HEAD(workq, pfrkt_workq);
2335c06aa877Scedric 		pfr_destroy_ktable(p, flushaddr);
23366ee9b743Scedric 	}
23376ee9b743Scedric }
23386ee9b743Scedric 
2339c06aa877Scedric void
pfr_destroy_ktables_aux(struct pfr_ktableworkq * auxq)2340de97784bSsashan pfr_destroy_ktables_aux(struct pfr_ktableworkq *auxq)
2341de97784bSsashan {
2342de97784bSsashan 	struct pfr_ktable	*p;
2343de97784bSsashan 
2344de97784bSsashan 	while ((p = SLIST_FIRST(auxq)) != NULL) {
2345de97784bSsashan 		SLIST_REMOVE_HEAD(auxq, pfrkt_workq);
2346de97784bSsashan 		/*
2347de97784bSsashan 		 * There must be no extra data (rules, shadow tables, ...)
2348de97784bSsashan 		 * attached, because auxq holds just empty memory to be
2349de97784bSsashan 		 * initialized. Therefore we can also be called with no lock.
2350de97784bSsashan 		 */
2351de97784bSsashan 		if (p->pfrkt_root != NULL) {
2352de97784bSsashan 			KASSERT(p->pfrkt_root->pfrkt_rs == NULL);
2353de97784bSsashan 			KASSERT(p->pfrkt_root->pfrkt_shadow == NULL);
2354de97784bSsashan 			KASSERT(p->pfrkt_root->pfrkt_root == NULL);
2355de97784bSsashan 			pfr_destroy_ktable(p->pfrkt_root, 0);
2356de97784bSsashan 			p->pfrkt_root = NULL;
2357de97784bSsashan 		}
2358de97784bSsashan 		KASSERT(p->pfrkt_rs == NULL);
2359de97784bSsashan 		KASSERT(p->pfrkt_shadow == NULL);
2360de97784bSsashan 		pfr_destroy_ktable(p, 0);
2361de97784bSsashan 	}
2362de97784bSsashan }
2363de97784bSsashan 
2364de97784bSsashan void
pfr_destroy_ktable(struct pfr_ktable * kt,int flushaddr)2365c06aa877Scedric pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
2366c06aa877Scedric {
2367c06aa877Scedric 	struct pfr_kentryworkq	 addrq;
2368c06aa877Scedric 
2369c06aa877Scedric 	if (flushaddr) {
2370c06aa877Scedric 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
2371dd94896cScedric 		pfr_clean_node_mask(kt, &addrq);
2372c06aa877Scedric 		pfr_destroy_kentries(&addrq);
2373c06aa877Scedric 	}
2374c06aa877Scedric 	if (kt->pfrkt_ip4 != NULL)
237505aee34cSmpi 		free(kt->pfrkt_ip4, M_RTABLE, sizeof(*kt->pfrkt_ip4));
2376c06aa877Scedric 	if (kt->pfrkt_ip6 != NULL)
237705aee34cSmpi 		free(kt->pfrkt_ip6, M_RTABLE, sizeof(*kt->pfrkt_ip6));
2378520c1c55Scedric 	if (kt->pfrkt_shadow != NULL)
2379c06aa877Scedric 		pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
2380a9b90787Scedric 	if (kt->pfrkt_rs != NULL) {
2381a9b90787Scedric 		kt->pfrkt_rs->tables--;
2382a9b90787Scedric 		pf_remove_if_empty_ruleset(kt->pfrkt_rs);
2383a9b90787Scedric 	}
2384c06aa877Scedric 	pool_put(&pfr_ktable_pl, kt);
2385c06aa877Scedric }
2386c06aa877Scedric 
23876ee9b743Scedric int
pfr_ktable_compare(struct pfr_ktable * p,struct pfr_ktable * q)2388342c264fSdlg pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q)
23896ee9b743Scedric {
23903e963a2eScedric 	int d;
23913e963a2eScedric 
23923e963a2eScedric 	if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE)))
23933e963a2eScedric 		return (d);
2394d9ad7941Sdhartmei 	return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor));
23956ee9b743Scedric }
23966ee9b743Scedric 
23976ee9b743Scedric struct pfr_ktable *
pfr_lookup_table(struct pfr_table * tbl)23986ee9b743Scedric pfr_lookup_table(struct pfr_table *tbl)
23996ee9b743Scedric {
24006ee9b743Scedric 	/* struct pfr_ktable start like a struct pfr_table */
2401342c264fSdlg 	return (RB_FIND(pfr_ktablehead, &pfr_ktables,
240260b10d66Smcbride 	    (struct pfr_ktable *)tbl));
24036ee9b743Scedric }
24046ee9b743Scedric 
24056ee9b743Scedric int
pfr_match_addr(struct pfr_ktable * kt,struct pf_addr * a,sa_family_t af)2406bb75ae08Sdhartmei pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
24076ee9b743Scedric {
24086ee9b743Scedric 	struct pfr_kentry	*ke = NULL;
2409a7d8badaSyasuoka 	int			 match;
2410a7d8badaSyasuoka 
2411a7d8badaSyasuoka 	ke = pfr_kentry_byaddr(kt, a, af, 0);
2412a7d8badaSyasuoka 
2413a7d8badaSyasuoka 	match = (ke && !(ke->pfrke_flags & PFRKE_FLAG_NOT));
2414a7d8badaSyasuoka 	if (match)
2415a7d8badaSyasuoka 		kt->pfrkt_match++;
2416a7d8badaSyasuoka 	else
2417a7d8badaSyasuoka 		kt->pfrkt_nomatch++;
2418a7d8badaSyasuoka 
2419a7d8badaSyasuoka 	return (match);
2420a7d8badaSyasuoka }
2421a7d8badaSyasuoka 
2422a7d8badaSyasuoka struct pfr_kentry *
pfr_kentry_byaddr(struct pfr_ktable * kt,struct pf_addr * a,sa_family_t af,int exact)2423a7d8badaSyasuoka pfr_kentry_byaddr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
2424a7d8badaSyasuoka     int exact)
2425a7d8badaSyasuoka {
2426a7d8badaSyasuoka 	struct pfr_kentry	*ke = NULL;
242799a6f929Spatrick 	struct sockaddr_in	 tmp4;
242899a6f929Spatrick #ifdef INET6
242999a6f929Spatrick 	struct sockaddr_in6	 tmp6;
243099a6f929Spatrick #endif /* INET6 */
24316ee9b743Scedric 
243226b62979Syasuoka 	kt = pfr_ktable_select_active(kt);
243326b62979Syasuoka 	if (kt == NULL)
243460b10d66Smcbride 		return (0);
24353e963a2eScedric 
24366ee9b743Scedric 	switch (af) {
24376ee9b743Scedric 	case AF_INET:
243899a6f929Spatrick 		bzero(&tmp4, sizeof(tmp4));
243999a6f929Spatrick 		tmp4.sin_len = sizeof(tmp4);
244099a6f929Spatrick 		tmp4.sin_family = AF_INET;
244199a6f929Spatrick 		tmp4.sin_addr.s_addr = a->addr32[0];
244299a6f929Spatrick 		ke = (struct pfr_kentry *)rn_match(&tmp4, kt->pfrkt_ip4);
24436ee9b743Scedric 		break;
24447d37faf6Spb #ifdef INET6
24456ee9b743Scedric 	case AF_INET6:
244699a6f929Spatrick 		bzero(&tmp6, sizeof(tmp6));
244799a6f929Spatrick 		tmp6.sin6_len = sizeof(tmp6);
244899a6f929Spatrick 		tmp6.sin6_family = AF_INET6;
244999a6f929Spatrick 		bcopy(a, &tmp6.sin6_addr, sizeof(tmp6.sin6_addr));
245099a6f929Spatrick 		ke = (struct pfr_kentry *)rn_match(&tmp6, kt->pfrkt_ip6);
24516ee9b743Scedric 		break;
24527d37faf6Spb #endif /* INET6 */
24539b00340fSsashan 	default:
24549b00340fSsashan 		unhandled_af(af);
24556ee9b743Scedric 	}
2456a7d8badaSyasuoka 	if (exact && ke && KENTRY_NETWORK(ke))
2457a7d8badaSyasuoka 		ke = NULL;
2458a7d8badaSyasuoka 
2459a7d8badaSyasuoka 	return (ke);
24606ee9b743Scedric }
24616ee9b743Scedric 
24626ee9b743Scedric void
pfr_update_stats(struct pfr_ktable * kt,struct pf_addr * a,struct pf_pdesc * pd,int op,int notrule)2463401a01c8Sblambert pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, struct pf_pdesc *pd,
2464401a01c8Sblambert     int op, int notrule)
24656ee9b743Scedric {
24666ee9b743Scedric 	struct pfr_kentry	*ke = NULL;
246799a6f929Spatrick 	struct sockaddr_in	 tmp4;
246899a6f929Spatrick #ifdef INET6
246999a6f929Spatrick 	struct sockaddr_in6	 tmp6;
247099a6f929Spatrick #endif /* INET6 */
2471401a01c8Sblambert 	sa_family_t		 af = pd->af;
2472401a01c8Sblambert 	u_int64_t		 len = pd->tot_len;
2473401a01c8Sblambert 	int			 dir_idx = (pd->dir == PF_OUT);
2474401a01c8Sblambert 	int			 op_idx;
24756ee9b743Scedric 
247626b62979Syasuoka 	kt = pfr_ktable_select_active(kt);
247726b62979Syasuoka 	if (kt == NULL)
24783e963a2eScedric 		return;
24793e963a2eScedric 
24806ee9b743Scedric 	switch (af) {
24816ee9b743Scedric 	case AF_INET:
248299a6f929Spatrick 		bzero(&tmp4, sizeof(tmp4));
248399a6f929Spatrick 		tmp4.sin_len = sizeof(tmp4);
248499a6f929Spatrick 		tmp4.sin_family = AF_INET;
248599a6f929Spatrick 		tmp4.sin_addr.s_addr = a->addr32[0];
248699a6f929Spatrick 		ke = (struct pfr_kentry *)rn_match(&tmp4, kt->pfrkt_ip4);
24876ee9b743Scedric 		break;
24887d37faf6Spb #ifdef INET6
24896ee9b743Scedric 	case AF_INET6:
249099a6f929Spatrick 		bzero(&tmp6, sizeof(tmp6));
249199a6f929Spatrick 		tmp6.sin6_len = sizeof(tmp6);
249299a6f929Spatrick 		tmp6.sin6_family = AF_INET6;
249399a6f929Spatrick 		bcopy(a, &tmp6.sin6_addr, sizeof(tmp6.sin6_addr));
249499a6f929Spatrick 		ke = (struct pfr_kentry *)rn_match(&tmp6, kt->pfrkt_ip6);
24956ee9b743Scedric 		break;
24967d37faf6Spb #endif /* INET6 */
24977d37faf6Spb 	default:
24989b00340fSsashan 		unhandled_af(af);
24996ee9b743Scedric 	}
2500401a01c8Sblambert 
2501401a01c8Sblambert 	switch (op) {
2502401a01c8Sblambert 	case PF_PASS:
2503401a01c8Sblambert 		op_idx = PFR_OP_PASS;
2504401a01c8Sblambert 		break;
2505401a01c8Sblambert 	case PF_MATCH:
2506401a01c8Sblambert 		op_idx = PFR_OP_MATCH;
2507401a01c8Sblambert 		break;
2508401a01c8Sblambert 	case PF_DROP:
2509401a01c8Sblambert 		op_idx = PFR_OP_BLOCK;
2510401a01c8Sblambert 		break;
2511443353daSjsg 	default:
2512443353daSjsg 		panic("unhandled op");
2513401a01c8Sblambert 	}
2514401a01c8Sblambert 
251536754172Smcbride 	if ((ke == NULL || (ke->pfrke_flags & PFRKE_FLAG_NOT)) != notrule) {
2516401a01c8Sblambert 		if (op_idx != PFR_OP_PASS)
25172551ddbaSmcbride 			DPFPRINTF(LOG_DEBUG,
25182551ddbaSmcbride 			    "pfr_update_stats: assertion failed.");
2519401a01c8Sblambert 		op_idx = PFR_OP_XPASS;
25206ee9b743Scedric 	}
2521401a01c8Sblambert 	kt->pfrkt_packets[dir_idx][op_idx]++;
2522401a01c8Sblambert 	kt->pfrkt_bytes[dir_idx][op_idx] += len;
2523401a01c8Sblambert 	if (ke != NULL && op_idx != PFR_OP_XPASS &&
25245f03a6e1Smcbride 	    (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) {
25255f03a6e1Smcbride 		if (ke->pfrke_counters == NULL)
25265f03a6e1Smcbride 			ke->pfrke_counters = pool_get(&pfr_kcounters_pl,
25275f03a6e1Smcbride 			    PR_NOWAIT | PR_ZERO);
25285f03a6e1Smcbride 		if (ke->pfrke_counters != NULL) {
2529401a01c8Sblambert 			ke->pfrke_counters->pfrkc_packets[dir_idx][op_idx]++;
2530401a01c8Sblambert 			ke->pfrke_counters->pfrkc_bytes[dir_idx][op_idx] += len;
25315f03a6e1Smcbride 		}
25326ee9b743Scedric 	}
25336ee9b743Scedric }
2534bb75ae08Sdhartmei 
2535bb75ae08Sdhartmei struct pfr_ktable *
pfr_attach_table(struct pf_ruleset * rs,char * name,int wait)253630d709c8Smbuhl pfr_attach_table(struct pf_ruleset *rs, char *name, int wait)
2537bb75ae08Sdhartmei {
25383e963a2eScedric 	struct pfr_ktable	*kt, *rt;
2539c06aa877Scedric 	struct pfr_table	 tbl;
25403e963a2eScedric 	struct pf_anchor	*ac = rs->anchor;
2541bb75ae08Sdhartmei 
2542c06aa877Scedric 	bzero(&tbl, sizeof(tbl));
2543c06aa877Scedric 	strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
2544d9ad7941Sdhartmei 	if (ac != NULL)
25455a3f5e5bSdhartmei 		strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
2546c06aa877Scedric 	kt = pfr_lookup_table(&tbl);
2547c06aa877Scedric 	if (kt == NULL) {
254830d709c8Smbuhl 		kt = pfr_create_ktable(&tbl, gettime(), 1, wait);
2549c06aa877Scedric 		if (kt == NULL)
25503e963a2eScedric 			return (NULL);
25513e963a2eScedric 		if (ac != NULL) {
25523e963a2eScedric 			bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor));
25533e963a2eScedric 			rt = pfr_lookup_table(&tbl);
25543e963a2eScedric 			if (rt == NULL) {
255530d709c8Smbuhl 				rt = pfr_create_ktable(&tbl, 0, 1, wait);
25563e963a2eScedric 				if (rt == NULL) {
25573e963a2eScedric 					pfr_destroy_ktable(kt, 0);
25583e963a2eScedric 					return (NULL);
25593e963a2eScedric 				}
25603e963a2eScedric 				pfr_insert_ktable(rt);
25613e963a2eScedric 			}
25623e963a2eScedric 			kt->pfrkt_root = rt;
25633e963a2eScedric 		}
2564c06aa877Scedric 		pfr_insert_ktable(kt);
2565bb75ae08Sdhartmei 	}
25666a4ae675Scedric 	if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++)
25672c9e9fd6Scedric 		pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED);
256860b10d66Smcbride 	return (kt);
2569bb75ae08Sdhartmei }
2570bb75ae08Sdhartmei 
2571bb75ae08Sdhartmei void
pfr_detach_table(struct pfr_ktable * kt)2572bb75ae08Sdhartmei pfr_detach_table(struct pfr_ktable *kt)
2573bb75ae08Sdhartmei {
25746a4ae675Scedric 	if (kt->pfrkt_refcnt[PFR_REFCNT_RULE] <= 0)
25752551ddbaSmcbride 		DPFPRINTF(LOG_NOTICE, "pfr_detach_table: refcount = %d.",
25766a4ae675Scedric 		    kt->pfrkt_refcnt[PFR_REFCNT_RULE]);
25776a4ae675Scedric 	else if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE])
25782c9e9fd6Scedric 		pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED);
2579bb75ae08Sdhartmei }
2580b47e54c9Scedric 
2581b47e54c9Scedric int
pfr_islinklocal(sa_family_t af,struct pf_addr * addr)25822b27abb2Smarkus pfr_islinklocal(sa_family_t af, struct pf_addr *addr)
2583b47e54c9Scedric {
25849b00340fSsashan #ifdef	INET6
25852b27abb2Smarkus 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr->v6))
25862b27abb2Smarkus 		return (1);
25879b00340fSsashan #endif	/* INET6 */
25882b27abb2Smarkus 	return (0);
25892b27abb2Smarkus }
25902b27abb2Smarkus 
25912b27abb2Smarkus int
pfr_pool_get(struct pf_pool * rpool,struct pf_addr ** raddr,struct pf_addr ** rmask,sa_family_t af)25922b27abb2Smarkus pfr_pool_get(struct pf_pool *rpool, struct pf_addr **raddr,
25932b27abb2Smarkus     struct pf_addr **rmask, sa_family_t af)
25942b27abb2Smarkus {
25952b27abb2Smarkus 	struct pfr_ktable	*kt;
2596b47e54c9Scedric 	struct pfr_kentry	*ke, *ke2;
25972b27abb2Smarkus 	struct pf_addr		*addr, *counter;
2598b47e54c9Scedric 	union sockaddr_union	 mask;
259999a6f929Spatrick 	struct sockaddr_in	 tmp4;
260099a6f929Spatrick #ifdef INET6
260199a6f929Spatrick 	struct sockaddr_in6	 tmp6;
260299a6f929Spatrick #endif
2603e4fc4bddSmikeb 	int			 startidx, idx = -1, loop = 0, use_counter = 0;
2604b47e54c9Scedric 
26059b00340fSsashan 	switch (af) {
26069b00340fSsashan 	case AF_INET:
260799a6f929Spatrick 		bzero(&tmp4, sizeof(tmp4));
260899a6f929Spatrick 		tmp4.sin_len = sizeof(tmp4);
260999a6f929Spatrick 		tmp4.sin_family = AF_INET;
261099a6f929Spatrick 		addr = (struct pf_addr *)&tmp4.sin_addr;
26119b00340fSsashan 		break;
26129b00340fSsashan #ifdef	INET6
26139b00340fSsashan 	case AF_INET6:
261499a6f929Spatrick 		bzero(&tmp6, sizeof(tmp6));
261599a6f929Spatrick 		tmp6.sin6_len = sizeof(tmp6);
261699a6f929Spatrick 		tmp6.sin6_family = AF_INET6;
261799a6f929Spatrick 		addr = (struct pf_addr *)&tmp6.sin6_addr;
26189b00340fSsashan 		break;
26199b00340fSsashan #endif	/* INET6 */
26209b00340fSsashan 	default:
26219b00340fSsashan 		unhandled_af(af);
26229b00340fSsashan 	}
26239b00340fSsashan 
26242b27abb2Smarkus 	if (rpool->addr.type == PF_ADDR_TABLE)
26252b27abb2Smarkus 		kt = rpool->addr.p.tbl;
26262b27abb2Smarkus 	else if (rpool->addr.type == PF_ADDR_DYNIFTL)
26272b27abb2Smarkus 		kt = rpool->addr.p.dyn->pfid_kt;
26282b27abb2Smarkus 	else
26292b27abb2Smarkus 		return (-1);
263026b62979Syasuoka 	kt = pfr_ktable_select_active(kt);
263126b62979Syasuoka 	if (kt == NULL)
2632b47e54c9Scedric 		return (-1);
2633b47e54c9Scedric 
26342b27abb2Smarkus 	counter = &rpool->counter;
26352b27abb2Smarkus 	idx = rpool->tblidx;
2636dba347c9Smikeb 	if (idx < 0 || idx >= kt->pfrkt_cnt)
2637b47e54c9Scedric 		idx = 0;
26382b27abb2Smarkus 	else
2639dba347c9Smikeb 		use_counter = 1;
2640e4fc4bddSmikeb 	startidx = idx;
2641b47e54c9Scedric 
2642b47e54c9Scedric  _next_block:
2643e4fc4bddSmikeb 	if (loop && startidx == idx) {
264432fcaf6fSreyk 		kt->pfrkt_nomatch++;
2645b47e54c9Scedric 		return (1);
264632fcaf6fSreyk 	}
2647e4fc4bddSmikeb 
2648e4fc4bddSmikeb 	ke = pfr_kentry_byidx(kt, idx, af);
2649e4fc4bddSmikeb 	if (ke == NULL) {
2650e4fc4bddSmikeb 		/* we don't have this idx, try looping */
2651e4fc4bddSmikeb 		if (loop || (ke = pfr_kentry_byidx(kt, 0, af)) == NULL) {
2652e4fc4bddSmikeb 			kt->pfrkt_nomatch++;
2653e4fc4bddSmikeb 			return (1);
2654e4fc4bddSmikeb 		}
2655e4fc4bddSmikeb 		idx = 0;
2656e4fc4bddSmikeb 		loop++;
265736754172Smcbride 	}
2658cbdc262eSmcbride 
2659cbdc262eSmcbride 	/* Get current weight for weighted round-robin */
2660cbdc262eSmcbride 	if (idx == 0 && use_counter == 1 && kt->pfrkt_refcntcost > 0) {
26612b27abb2Smarkus 		rpool->curweight = rpool->curweight - kt->pfrkt_gcdweight;
2662cbdc262eSmcbride 
26632b27abb2Smarkus 		if (rpool->curweight < 1)
26642b27abb2Smarkus 			rpool->curweight = kt->pfrkt_maxweight;
2665cbdc262eSmcbride 	}
2666cbdc262eSmcbride 
2667b47e54c9Scedric 	pfr_prepare_network(&pfr_mask, af, ke->pfrke_net);
2668b47e54c9Scedric 	*raddr = SUNION2PF(&ke->pfrke_sa, af);
2669b47e54c9Scedric 	*rmask = SUNION2PF(&pfr_mask, af);
2670b47e54c9Scedric 
2671e4fc4bddSmikeb 	if (use_counter && !PF_AZERO(counter, af)) {
2672b47e54c9Scedric 		/* is supplied address within block? */
2673492cf661Skn 		if (!pf_match_addr(0, *raddr, *rmask, counter, af)) {
2674b47e54c9Scedric 			/* no, go to next block in table */
2675b47e54c9Scedric 			idx++;
2676b47e54c9Scedric 			use_counter = 0;
2677b47e54c9Scedric 			goto _next_block;
2678b47e54c9Scedric 		}
2679492cf661Skn 		pf_addrcpy(addr, counter, af);
2680b47e54c9Scedric 	} else {
2681b47e54c9Scedric 		/* use first address of block */
2682492cf661Skn 		pf_addrcpy(addr, *raddr, af);
2683b47e54c9Scedric 	}
2684b47e54c9Scedric 
2685b47e54c9Scedric 	if (!KENTRY_NETWORK(ke)) {
2686b47e54c9Scedric 		/* this is a single IP address - no possible nested block */
26872b27abb2Smarkus 		if (rpool->addr.type == PF_ADDR_DYNIFTL &&
26882b27abb2Smarkus 		    pfr_islinklocal(af, addr)) {
2689e4154893Smikeb 			idx++;
2690e4154893Smikeb 			goto _next_block;
2691e4154893Smikeb 		}
2692492cf661Skn 		pf_addrcpy(counter, addr, af);
26932b27abb2Smarkus 		rpool->tblidx = idx;
269432fcaf6fSreyk 		kt->pfrkt_match++;
26952b27abb2Smarkus 		rpool->states = 0;
2696cbdc262eSmcbride 		if (ke->pfrke_counters != NULL)
26972b27abb2Smarkus 			rpool->states = ke->pfrke_counters->states;
2698bcb11948Szinke 		switch (ke->pfrke_type) {
2699bcb11948Szinke 		case PFRKE_COST:
27002b27abb2Smarkus 			rpool->weight = ((struct pfr_kentry_cost *)ke)->weight;
2701bcb11948Szinke 			/* FALLTHROUGH */
2702bcb11948Szinke 		case PFRKE_ROUTE:
27032b27abb2Smarkus 			rpool->kif = ((struct pfr_kentry_route *)ke)->kif;
2704bcb11948Szinke 			break;
2705bcb11948Szinke 		default:
27062b27abb2Smarkus 			rpool->weight = 1;
2707bcb11948Szinke 			break;
2708bcb11948Szinke 		}
2709b47e54c9Scedric 		return (0);
2710b47e54c9Scedric 	}
2711b47e54c9Scedric 	for (;;) {
2712b47e54c9Scedric 		/* we don't want to use a nested block */
27139b00340fSsashan 		switch (af) {
27149b00340fSsashan 		case AF_INET:
271599a6f929Spatrick 			ke2 = (struct pfr_kentry *)rn_match(&tmp4,
27167d37faf6Spb 			    kt->pfrkt_ip4);
27179b00340fSsashan 			break;
27189b00340fSsashan #ifdef	INET6
27199b00340fSsashan 		case AF_INET6:
272099a6f929Spatrick 			ke2 = (struct pfr_kentry *)rn_match(&tmp6,
27217d37faf6Spb 			    kt->pfrkt_ip6);
27229b00340fSsashan 			break;
27239b00340fSsashan #endif	/* INET6 */
27249b00340fSsashan 		default:
27259b00340fSsashan 			unhandled_af(af);
27269b00340fSsashan 		}
2727b47e54c9Scedric 		if (ke2 == ke) {
2728b47e54c9Scedric 			/* lookup return the same block - perfect */
27292b27abb2Smarkus 			if (rpool->addr.type == PF_ADDR_DYNIFTL &&
27302b27abb2Smarkus 			    pfr_islinklocal(af, addr))
2731e4154893Smikeb 				goto _next_entry;
2732492cf661Skn 			pf_addrcpy(counter, addr, af);
27332b27abb2Smarkus 			rpool->tblidx = idx;
273432fcaf6fSreyk 			kt->pfrkt_match++;
27352b27abb2Smarkus 			rpool->states = 0;
2736cbdc262eSmcbride 			if (ke->pfrke_counters != NULL)
27372b27abb2Smarkus 				rpool->states = ke->pfrke_counters->states;
2738bcb11948Szinke 			switch (ke->pfrke_type) {
2739bcb11948Szinke 			case PFRKE_COST:
27402b27abb2Smarkus 				rpool->weight =
2741cbdc262eSmcbride 				    ((struct pfr_kentry_cost *)ke)->weight;
2742bcb11948Szinke 				/* FALLTHROUGH */
2743bcb11948Szinke 			case PFRKE_ROUTE:
27442b27abb2Smarkus 				rpool->kif = ((struct pfr_kentry_route *)ke)->kif;
2745bcb11948Szinke 				break;
2746bcb11948Szinke 			default:
27472b27abb2Smarkus 				rpool->weight = 1;
2748bcb11948Szinke 				break;
2749bcb11948Szinke 			}
2750b47e54c9Scedric 			return (0);
2751b47e54c9Scedric 		}
2752e4154893Smikeb _next_entry:
2753b47e54c9Scedric 		/* we need to increase the counter past the nested block */
2754b47e54c9Scedric 		pfr_prepare_network(&mask, AF_INET, ke2->pfrke_net);
2755492cf661Skn 		pf_poolmask(addr, addr, SUNION2PF(&mask, af), &pfr_ffaddr, af);
2756492cf661Skn 		pf_addr_inc(addr, af);
2757492cf661Skn 		if (!pf_match_addr(0, *raddr, *rmask, addr, af)) {
2758b47e54c9Scedric 			/* ok, we reached the end of our main block */
2759b47e54c9Scedric 			/* go to next block in table */
2760b47e54c9Scedric 			idx++;
2761b47e54c9Scedric 			use_counter = 0;
2762b47e54c9Scedric 			goto _next_block;
2763b47e54c9Scedric 		}
2764b47e54c9Scedric 	}
2765b47e54c9Scedric }
2766b47e54c9Scedric 
2767b47e54c9Scedric struct pfr_kentry *
pfr_kentry_byidx(struct pfr_ktable * kt,int idx,int af)2768b47e54c9Scedric pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af)
2769b47e54c9Scedric {
2770b47e54c9Scedric 	struct pfr_walktree	w;
2771b47e54c9Scedric 
2772b47e54c9Scedric 	bzero(&w, sizeof(w));
2773b47e54c9Scedric 	w.pfrw_op = PFRW_POOL_GET;
2774b47e54c9Scedric 	w.pfrw_cnt = idx;
2775b47e54c9Scedric 
2776b47e54c9Scedric 	switch (af) {
2777b47e54c9Scedric 	case AF_INET:
2778b47e54c9Scedric 		rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
277960b10d66Smcbride 		return (w.pfrw_kentry);
27807d37faf6Spb #ifdef INET6
2781b47e54c9Scedric 	case AF_INET6:
2782b47e54c9Scedric 		rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
278360b10d66Smcbride 		return (w.pfrw_kentry);
27847d37faf6Spb #endif /* INET6 */
2785b47e54c9Scedric 	default:
278660b10d66Smcbride 		return (NULL);
2787b47e54c9Scedric 	}
2788b47e54c9Scedric }
2789b47e54c9Scedric 
2790cbdc262eSmcbride /* Added for load balancing state counter use. */
2791bcb11948Szinke int
pfr_states_increase(struct pfr_ktable * kt,struct pf_addr * addr,int af)2792bcb11948Szinke pfr_states_increase(struct pfr_ktable *kt, struct pf_addr *addr, int af)
2793bcb11948Szinke {
2794bcb11948Szinke 	struct pfr_kentry *ke;
2795bcb11948Szinke 
2796bcb11948Szinke 	ke = pfr_kentry_byaddr(kt, addr, af, 1);
2797cbdc262eSmcbride 	if (ke == NULL)
2798bcb11948Szinke 		return (-1);
2799bcb11948Szinke 
2800cbdc262eSmcbride 	if (ke->pfrke_counters == NULL)
2801cbdc262eSmcbride 		ke->pfrke_counters = pool_get(&pfr_kcounters_pl,
2802cbdc262eSmcbride 		    PR_NOWAIT | PR_ZERO);
2803cbdc262eSmcbride 	if (ke->pfrke_counters == NULL)
2804cbdc262eSmcbride 		return (-1);
2805cbdc262eSmcbride 
2806cbdc262eSmcbride 	ke->pfrke_counters->states++;
2807cbdc262eSmcbride 	return ke->pfrke_counters->states;
2808bcb11948Szinke }
2809bcb11948Szinke 
2810cbdc262eSmcbride /* Added for load balancing state counter use. */
2811bcb11948Szinke int
pfr_states_decrease(struct pfr_ktable * kt,struct pf_addr * addr,int af)2812bcb11948Szinke pfr_states_decrease(struct pfr_ktable *kt, struct pf_addr *addr, int af)
2813bcb11948Szinke {
2814bcb11948Szinke 	struct pfr_kentry *ke;
2815bcb11948Szinke 
2816bcb11948Szinke 	ke = pfr_kentry_byaddr(kt, addr, af, 1);
2817cbdc262eSmcbride 	if (ke == NULL)
2818bcb11948Szinke 		return (-1);
2819bcb11948Szinke 
2820cbdc262eSmcbride 	if (ke->pfrke_counters == NULL)
2821cbdc262eSmcbride 		ke->pfrke_counters = pool_get(&pfr_kcounters_pl,
2822cbdc262eSmcbride 		    PR_NOWAIT | PR_ZERO);
2823cbdc262eSmcbride 	if (ke->pfrke_counters == NULL)
2824cbdc262eSmcbride 		return (-1);
2825cbdc262eSmcbride 
2826cbdc262eSmcbride 	if (ke->pfrke_counters->states > 0)
2827cbdc262eSmcbride 		ke->pfrke_counters->states--;
2828bcb11948Szinke 	else
2829bcb11948Szinke 		DPFPRINTF(LOG_DEBUG,
2830cbdc262eSmcbride 		    "pfr_states_decrease: states-- when states <= 0");
2831bcb11948Szinke 
2832cbdc262eSmcbride 	return ke->pfrke_counters->states;
2833bcb11948Szinke }
2834bcb11948Szinke 
2835ec359bd5Scedric void
pfr_dynaddr_update(struct pfr_ktable * kt,struct pfi_dynaddr * dyn)2836ec359bd5Scedric pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn)
2837ec359bd5Scedric {
2838ec359bd5Scedric 	struct pfr_walktree	w;
2839ec359bd5Scedric 
2840ec359bd5Scedric 	bzero(&w, sizeof(w));
2841ec359bd5Scedric 	w.pfrw_op = PFRW_DYNADDR_UPDATE;
2842ec359bd5Scedric 	w.pfrw_dyn = dyn;
2843ec359bd5Scedric 
2844ec359bd5Scedric 	dyn->pfid_acnt4 = 0;
2845ec359bd5Scedric 	dyn->pfid_acnt6 = 0;
28469b00340fSsashan 	switch (dyn->pfid_af) {
28473f22add7Ssashan 	case AF_UNSPEC:	/* look up all both addresses IPv4 + IPv6 */
2848ec359bd5Scedric 		rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
28493f22add7Ssashan 		rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
28503f22add7Ssashan 		break;
28513f22add7Ssashan 	case AF_INET:
28523f22add7Ssashan 		rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
28533f22add7Ssashan 		break;
28549b00340fSsashan #ifdef	INET6
28559b00340fSsashan 	case AF_INET6:
2856ec359bd5Scedric 		rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
28579b00340fSsashan 		break;
28589b00340fSsashan #endif	/* INET6 */
28599b00340fSsashan 	default:
28609b00340fSsashan 		unhandled_af(dyn->pfid_af);
28619b00340fSsashan 	}
2862ec359bd5Scedric }
2863cbdc262eSmcbride 
2864cbdc262eSmcbride void
pfr_ktable_winfo_update(struct pfr_ktable * kt,struct pfr_kentry * p)2865cbdc262eSmcbride pfr_ktable_winfo_update(struct pfr_ktable *kt, struct pfr_kentry *p) {
2866cbdc262eSmcbride 	/*
2867cbdc262eSmcbride 	 * If cost flag is set,
2868cbdc262eSmcbride 	 * gcdweight is needed for round-robin.
2869cbdc262eSmcbride 	 */
2870cbdc262eSmcbride 	if (kt->pfrkt_refcntcost > 0) {
2871cbdc262eSmcbride 		u_int16_t weight;
2872cbdc262eSmcbride 
2873cbdc262eSmcbride 		weight = (p->pfrke_type == PFRKE_COST) ?
2874cbdc262eSmcbride 		    ((struct pfr_kentry_cost *)p)->weight : 1;
2875cbdc262eSmcbride 
2876cbdc262eSmcbride 		if (kt->pfrkt_gcdweight == 0)
2877cbdc262eSmcbride 			kt->pfrkt_gcdweight = weight;
2878cbdc262eSmcbride 
2879cbdc262eSmcbride 		kt->pfrkt_gcdweight =
2880cbdc262eSmcbride 			pfr_gcd(weight, kt->pfrkt_gcdweight);
2881cbdc262eSmcbride 
2882cbdc262eSmcbride 		if (kt->pfrkt_maxweight < weight)
2883cbdc262eSmcbride 			kt->pfrkt_maxweight = weight;
2884cbdc262eSmcbride 	}
2885cbdc262eSmcbride }
288626b62979Syasuoka 
288726b62979Syasuoka struct pfr_ktable *
pfr_ktable_select_active(struct pfr_ktable * kt)288826b62979Syasuoka pfr_ktable_select_active(struct pfr_ktable *kt)
288926b62979Syasuoka {
289026b62979Syasuoka 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
289126b62979Syasuoka 		kt = kt->pfrkt_root;
289226b62979Syasuoka 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
289326b62979Syasuoka 		return (NULL);
289426b62979Syasuoka 
289526b62979Syasuoka 	return (kt);
289626b62979Syasuoka }
2897