1223637Sbz/*	$OpenBSD: pf_table.c,v 1.79 2008/10/08 06:24:50 mcbride Exp $	*/
2126258Smlaier
3126258Smlaier/*
4126258Smlaier * Copyright (c) 2002 Cedric Berger
5126258Smlaier * All rights reserved.
6126258Smlaier *
7126258Smlaier * Redistribution and use in source and binary forms, with or without
8126258Smlaier * modification, are permitted provided that the following conditions
9126258Smlaier * are met:
10126258Smlaier *
11126258Smlaier *    - Redistributions of source code must retain the above copyright
12126258Smlaier *      notice, this list of conditions and the following disclaimer.
13126258Smlaier *    - Redistributions in binary form must reproduce the above
14126258Smlaier *      copyright notice, this list of conditions and the following
15126258Smlaier *      disclaimer in the documentation and/or other materials provided
16126258Smlaier *      with the distribution.
17126258Smlaier *
18126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29126258Smlaier * POSSIBILITY OF SUCH DAMAGE.
30126258Smlaier *
31126258Smlaier */
32126258Smlaier
33127145Smlaier#ifdef __FreeBSD__
34126261Smlaier#include "opt_inet.h"
35126261Smlaier#include "opt_inet6.h"
36171168Smlaier
37171168Smlaier#include <sys/cdefs.h>
38171168Smlaier__FBSDID("$FreeBSD$");
39126261Smlaier#endif
40126261Smlaier
41126258Smlaier#include <sys/param.h>
42126258Smlaier#include <sys/systm.h>
43126258Smlaier#include <sys/socket.h>
44126258Smlaier#include <sys/mbuf.h>
45126258Smlaier#include <sys/kernel.h>
46127145Smlaier#ifdef __FreeBSD__
47126261Smlaier#include <sys/malloc.h>
48223637Sbz#else
49223637Sbz#include <sys/pool.h>
50126261Smlaier#endif
51126258Smlaier
52126258Smlaier#include <net/if.h>
53126258Smlaier#include <net/route.h>
54126258Smlaier#include <netinet/in.h>
55127145Smlaier#ifndef __FreeBSD__
56126258Smlaier#include <netinet/ip_ipsp.h>
57126261Smlaier#endif
58126258Smlaier#include <net/pfvar.h>
59126258Smlaier
60223637Sbz#define	ACCEPT_FLAGS(flags, oklist)		\
61126258Smlaier	do {					\
62126258Smlaier		if ((flags & ~(oklist)) &	\
63126258Smlaier		    PFR_FLAG_ALLMASK)		\
64126258Smlaier			return (EINVAL);	\
65126258Smlaier	} while (0)
66126258Smlaier
67130613Smlaier#ifdef __FreeBSD__
68130613Smlaierstatic inline int
69130613Smlaier_copyin(const void *uaddr, void *kaddr, size_t len)
70130613Smlaier{
71130613Smlaier	int r;
72130613Smlaier
73130613Smlaier	PF_UNLOCK();
74130613Smlaier	r = copyin(uaddr, kaddr, len);
75130613Smlaier	PF_LOCK();
76130613Smlaier
77130613Smlaier	return (r);
78130613Smlaier}
79130613Smlaier
80130613Smlaierstatic inline int
81130613Smlaier_copyout(const void *uaddr, void *kaddr, size_t len)
82130613Smlaier{
83130613Smlaier	int r;
84130613Smlaier
85130613Smlaier	PF_UNLOCK();
86130613Smlaier	r = copyout(uaddr, kaddr, len);
87130613Smlaier	PF_LOCK();
88130613Smlaier
89130613Smlaier	return (r);
90130613Smlaier}
91130613Smlaier
92223637Sbz#define	COPYIN(from, to, size, flags)		\
93130613Smlaier	((flags & PFR_FLAG_USERIOCTL) ?		\
94130613Smlaier	_copyin((from), (to), (size)) :		\
95130613Smlaier	(bcopy((from), (to), (size)), 0))
96130613Smlaier
97223637Sbz#define	COPYOUT(from, to, size, flags)		\
98130613Smlaier	((flags & PFR_FLAG_USERIOCTL) ?		\
99130613Smlaier	_copyout((from), (to), (size)) :	\
100130613Smlaier	(bcopy((from), (to), (size)), 0))
101130613Smlaier
102130613Smlaier#else
103223637Sbz#define	COPYIN(from, to, size, flags)		\
104130613Smlaier	((flags & PFR_FLAG_USERIOCTL) ?		\
105130613Smlaier	copyin((from), (to), (size)) :		\
106130613Smlaier	(bcopy((from), (to), (size)), 0))
107130613Smlaier
108223637Sbz#define	COPYOUT(from, to, size, flags)		\
109130613Smlaier	((flags & PFR_FLAG_USERIOCTL) ?		\
110130613Smlaier	copyout((from), (to), (size)) :		\
111130613Smlaier	(bcopy((from), (to), (size)), 0))
112130613Smlaier#endif
113130613Smlaier
114126258Smlaier#define	FILLIN_SIN(sin, addr)			\
115126258Smlaier	do {					\
116126258Smlaier		(sin).sin_len = sizeof(sin);	\
117126258Smlaier		(sin).sin_family = AF_INET;	\
118126258Smlaier		(sin).sin_addr = (addr);	\
119126258Smlaier	} while (0)
120126258Smlaier
121126258Smlaier#define	FILLIN_SIN6(sin6, addr)			\
122126258Smlaier	do {					\
123126258Smlaier		(sin6).sin6_len = sizeof(sin6);	\
124126258Smlaier		(sin6).sin6_family = AF_INET6;	\
125126258Smlaier		(sin6).sin6_addr = (addr);	\
126126258Smlaier	} while (0)
127126258Smlaier
128223637Sbz#define	SWAP(type, a1, a2)			\
129126258Smlaier	do {					\
130126258Smlaier		type tmp = a1;			\
131126258Smlaier		a1 = a2;			\
132126258Smlaier		a2 = tmp;			\
133126258Smlaier	} while (0)
134126258Smlaier
135223637Sbz#define	SUNION2PF(su, af) (((af)==AF_INET) ?	\
136130613Smlaier    (struct pf_addr *)&(su)->sin.sin_addr :	\
137130613Smlaier    (struct pf_addr *)&(su)->sin6.sin6_addr)
138126258Smlaier
139126258Smlaier#define	AF_BITS(af)		(((af)==AF_INET)?32:128)
140126258Smlaier#define	ADDR_NETWORK(ad)	((ad)->pfra_net < AF_BITS((ad)->pfra_af))
141126258Smlaier#define	KENTRY_NETWORK(ke)	((ke)->pfrke_net < AF_BITS((ke)->pfrke_af))
142223637Sbz#define	KENTRY_RNF_ROOT(ke) \
143126258Smlaier		((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0)
144126258Smlaier
145223637Sbz#define	NO_ADDRESSES		(-1)
146223637Sbz#define	ENQUEUE_UNMARKED_ONLY	(1)
147223637Sbz#define	INVERT_NEG_FLAG		(1)
148126258Smlaier
149126258Smlaierstruct pfr_walktree {
150126258Smlaier	enum pfrw_op {
151126258Smlaier		PFRW_MARK,
152126258Smlaier		PFRW_SWEEP,
153126258Smlaier		PFRW_ENQUEUE,
154126258Smlaier		PFRW_GET_ADDRS,
155126258Smlaier		PFRW_GET_ASTATS,
156130613Smlaier		PFRW_POOL_GET,
157130613Smlaier		PFRW_DYNADDR_UPDATE
158126258Smlaier	}	 pfrw_op;
159126258Smlaier	union {
160126258Smlaier		struct pfr_addr		*pfrw1_addr;
161126258Smlaier		struct pfr_astats	*pfrw1_astats;
162126258Smlaier		struct pfr_kentryworkq	*pfrw1_workq;
163126258Smlaier		struct pfr_kentry	*pfrw1_kentry;
164130613Smlaier		struct pfi_dynaddr	*pfrw1_dyn;
165126258Smlaier	}	 pfrw_1;
166126258Smlaier	int	 pfrw_free;
167130613Smlaier	int	 pfrw_flags;
168126258Smlaier};
169223637Sbz#define	pfrw_addr	pfrw_1.pfrw1_addr
170223637Sbz#define	pfrw_astats	pfrw_1.pfrw1_astats
171223637Sbz#define	pfrw_workq	pfrw_1.pfrw1_workq
172223637Sbz#define	pfrw_kentry	pfrw_1.pfrw1_kentry
173223637Sbz#define	pfrw_dyn	pfrw_1.pfrw1_dyn
174223637Sbz#define	pfrw_cnt	pfrw_free
175126258Smlaier
176223637Sbz#define	senderr(e)	do { rv = (e); goto _bad; } while (0)
177126258Smlaier
178127145Smlaier#ifdef __FreeBSD__
179223637SbzVNET_DEFINE(uma_zone_t,			pfr_ktable_pl);
180223637SbzVNET_DEFINE(uma_zone_t,			pfr_kentry_pl);
181223637SbzVNET_DEFINE(uma_zone_t,			pfr_kcounters_pl);
182223637SbzVNET_DEFINE(struct sockaddr_in,		pfr_sin);
183223637Sbz#define	V_pfr_sin			VNET(pfr_sin)
184223637SbzVNET_DEFINE(struct sockaddr_in6,	pfr_sin6);
185223637Sbz#define	V_pfr_sin6			VNET(pfr_sin6)
186223637SbzVNET_DEFINE(union sockaddr_union,	pfr_mask);
187223637Sbz#define	V_pfr_mask			VNET(pfr_mask)
188223637SbzVNET_DEFINE(struct pf_addr,		pfr_ffaddr);
189223637Sbz#define	V_pfr_ffaddr			VNET(pfr_ffaddr)
190126261Smlaier#else
191126258Smlaierstruct pool		 pfr_ktable_pl;
192126258Smlaierstruct pool		 pfr_kentry_pl;
193223637Sbzstruct pool		 pfr_kcounters_pl;
194126258Smlaierstruct sockaddr_in	 pfr_sin;
195126258Smlaierstruct sockaddr_in6	 pfr_sin6;
196130613Smlaierunion sockaddr_union	 pfr_mask;
197126258Smlaierstruct pf_addr		 pfr_ffaddr;
198223637Sbz#endif
199126258Smlaier
200126258Smlaiervoid			 pfr_copyout_addr(struct pfr_addr *,
201126258Smlaier			    struct pfr_kentry *ke);
202126258Smlaierint			 pfr_validate_addr(struct pfr_addr *);
203126258Smlaiervoid			 pfr_enqueue_addrs(struct pfr_ktable *,
204126258Smlaier			    struct pfr_kentryworkq *, int *, int);
205126258Smlaiervoid			 pfr_mark_addrs(struct pfr_ktable *);
206126258Smlaierstruct pfr_kentry	*pfr_lookup_addr(struct pfr_ktable *,
207126258Smlaier			    struct pfr_addr *, int);
208145836Smlaierstruct pfr_kentry	*pfr_create_kentry(struct pfr_addr *, int);
209126258Smlaiervoid			 pfr_destroy_kentries(struct pfr_kentryworkq *);
210126258Smlaiervoid			 pfr_destroy_kentry(struct pfr_kentry *);
211126258Smlaiervoid			 pfr_insert_kentries(struct pfr_ktable *,
212126258Smlaier			    struct pfr_kentryworkq *, long);
213126258Smlaiervoid			 pfr_remove_kentries(struct pfr_ktable *,
214126258Smlaier			    struct pfr_kentryworkq *);
215126258Smlaiervoid			 pfr_clstats_kentries(struct pfr_kentryworkq *, long,
216126258Smlaier			    int);
217130613Smlaiervoid			 pfr_reset_feedback(struct pfr_addr *, int, int);
218126258Smlaiervoid			 pfr_prepare_network(union sockaddr_union *, int, int);
219126258Smlaierint			 pfr_route_kentry(struct pfr_ktable *,
220126258Smlaier			    struct pfr_kentry *);
221126258Smlaierint			 pfr_unroute_kentry(struct pfr_ktable *,
222126258Smlaier			    struct pfr_kentry *);
223126258Smlaierint			 pfr_walktree(struct radix_node *, void *);
224130613Smlaierint			 pfr_validate_table(struct pfr_table *, int, int);
225145836Smlaierint			 pfr_fix_anchor(char *);
226126258Smlaiervoid			 pfr_commit_ktable(struct pfr_ktable *, long);
227126258Smlaiervoid			 pfr_insert_ktables(struct pfr_ktableworkq *);
228126258Smlaiervoid			 pfr_insert_ktable(struct pfr_ktable *);
229126258Smlaiervoid			 pfr_setflags_ktables(struct pfr_ktableworkq *);
230126258Smlaiervoid			 pfr_setflags_ktable(struct pfr_ktable *, int);
231126258Smlaiervoid			 pfr_clstats_ktables(struct pfr_ktableworkq *, long,
232126258Smlaier			    int);
233126258Smlaiervoid			 pfr_clstats_ktable(struct pfr_ktable *, long, int);
234223637Sbzstruct pfr_ktable	*pfr_create_ktable(struct pfr_table *, long, int, int);
235126258Smlaiervoid			 pfr_destroy_ktables(struct pfr_ktableworkq *, int);
236126258Smlaiervoid			 pfr_destroy_ktable(struct pfr_ktable *, int);
237126258Smlaierint			 pfr_ktable_compare(struct pfr_ktable *,
238126258Smlaier			    struct pfr_ktable *);
239126258Smlaierstruct pfr_ktable	*pfr_lookup_table(struct pfr_table *);
240130613Smlaiervoid			 pfr_clean_node_mask(struct pfr_ktable *,
241126258Smlaier			    struct pfr_kentryworkq *);
242126258Smlaierint			 pfr_table_count(struct pfr_table *, int);
243126258Smlaierint			 pfr_skip_table(struct pfr_table *,
244126258Smlaier			    struct pfr_ktable *, int);
245130613Smlaierstruct pfr_kentry	*pfr_kentry_byidx(struct pfr_ktable *, int, int);
246126258Smlaier
247126258SmlaierRB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
248126258SmlaierRB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
249126258Smlaier
250126258Smlaierstruct pfr_ktablehead	 pfr_ktables;
251126258Smlaierstruct pfr_table	 pfr_nulltable;
252126258Smlaierint			 pfr_ktable_cnt;
253126258Smlaier
254126258Smlaiervoid
255126258Smlaierpfr_initialize(void)
256126258Smlaier{
257127145Smlaier#ifndef __FreeBSD__
258126258Smlaier	pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0,
259223637Sbz	    "pfrktable", NULL);
260126258Smlaier	pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0,
261223637Sbz	    "pfrkentry", NULL);
262223637Sbz	pool_init(&pfr_kcounters_pl, sizeof(struct pfr_kcounters), 0, 0, 0,
263223637Sbz	    "pfrkcounters", NULL);
264126258Smlaier
265126258Smlaier	pfr_sin.sin_len = sizeof(pfr_sin);
266126258Smlaier	pfr_sin.sin_family = AF_INET;
267126258Smlaier	pfr_sin6.sin6_len = sizeof(pfr_sin6);
268126258Smlaier	pfr_sin6.sin6_family = AF_INET6;
269126258Smlaier
270126258Smlaier	memset(&pfr_ffaddr, 0xff, sizeof(pfr_ffaddr));
271223637Sbz#else
272223637Sbz	V_pfr_sin.sin_len = sizeof(V_pfr_sin);
273223637Sbz	V_pfr_sin.sin_family = AF_INET;
274223637Sbz	V_pfr_sin6.sin6_len = sizeof(V_pfr_sin6);
275223637Sbz	V_pfr_sin6.sin6_family = AF_INET6;
276223637Sbz
277223637Sbz	memset(&V_pfr_ffaddr, 0xff, sizeof(V_pfr_ffaddr));
278223637Sbz#endif
279126258Smlaier}
280126258Smlaier
281126258Smlaierint
282126258Smlaierpfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
283126258Smlaier{
284126258Smlaier	struct pfr_ktable	*kt;
285126258Smlaier	struct pfr_kentryworkq	 workq;
286126258Smlaier	int			 s;
287126258Smlaier
288223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
289130613Smlaier	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
290126258Smlaier		return (EINVAL);
291126258Smlaier	kt = pfr_lookup_table(tbl);
292126258Smlaier	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
293126258Smlaier		return (ESRCH);
294126258Smlaier	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
295126258Smlaier		return (EPERM);
296126258Smlaier	pfr_enqueue_addrs(kt, &workq, ndel, 0);
297126258Smlaier
298126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
299126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
300126258Smlaier			s = splsoftnet();
301126258Smlaier		pfr_remove_kentries(kt, &workq);
302126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
303126258Smlaier			splx(s);
304126258Smlaier		if (kt->pfrkt_cnt) {
305126258Smlaier			printf("pfr_clr_addrs: corruption detected (%d).\n",
306126258Smlaier			    kt->pfrkt_cnt);
307126258Smlaier			kt->pfrkt_cnt = 0;
308126258Smlaier		}
309126258Smlaier	}
310126258Smlaier	return (0);
311126258Smlaier}
312126258Smlaier
313126258Smlaierint
314126258Smlaierpfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
315126258Smlaier    int *nadd, int flags)
316126258Smlaier{
317126258Smlaier	struct pfr_ktable	*kt, *tmpkt;
318126258Smlaier	struct pfr_kentryworkq	 workq;
319126258Smlaier	struct pfr_kentry	*p, *q;
320126258Smlaier	struct pfr_addr		 ad;
321223637Sbz	int			 i, rv, s, xadd = 0;
322145836Smlaier	long			 tzero = time_second;
323126258Smlaier
324223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
325223637Sbz	    PFR_FLAG_FEEDBACK);
326130613Smlaier	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
327126258Smlaier		return (EINVAL);
328126258Smlaier	kt = pfr_lookup_table(tbl);
329126258Smlaier	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
330126258Smlaier		return (ESRCH);
331126258Smlaier	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
332126258Smlaier		return (EPERM);
333223637Sbz	tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0,
334223637Sbz	    !(flags & PFR_FLAG_USERIOCTL));
335126258Smlaier	if (tmpkt == NULL)
336126258Smlaier		return (ENOMEM);
337126258Smlaier	SLIST_INIT(&workq);
338126258Smlaier	for (i = 0; i < size; i++) {
339223637Sbz		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
340126261Smlaier			senderr(EFAULT);
341126258Smlaier		if (pfr_validate_addr(&ad))
342126258Smlaier			senderr(EINVAL);
343126258Smlaier		p = pfr_lookup_addr(kt, &ad, 1);
344126258Smlaier		q = pfr_lookup_addr(tmpkt, &ad, 1);
345126258Smlaier		if (flags & PFR_FLAG_FEEDBACK) {
346126258Smlaier			if (q != NULL)
347126258Smlaier				ad.pfra_fback = PFR_FB_DUPLICATE;
348126258Smlaier			else if (p == NULL)
349126258Smlaier				ad.pfra_fback = PFR_FB_ADDED;
350126258Smlaier			else if (p->pfrke_not != ad.pfra_not)
351126258Smlaier				ad.pfra_fback = PFR_FB_CONFLICT;
352126258Smlaier			else
353126258Smlaier				ad.pfra_fback = PFR_FB_NONE;
354126258Smlaier		}
355126258Smlaier		if (p == NULL && q == NULL) {
356223637Sbz			p = pfr_create_kentry(&ad,
357223637Sbz			    !(flags & PFR_FLAG_USERIOCTL));
358126258Smlaier			if (p == NULL)
359126258Smlaier				senderr(ENOMEM);
360126258Smlaier			if (pfr_route_kentry(tmpkt, p)) {
361126258Smlaier				pfr_destroy_kentry(p);
362126258Smlaier				ad.pfra_fback = PFR_FB_NONE;
363126258Smlaier			} else {
364126258Smlaier				SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
365126258Smlaier				xadd++;
366126258Smlaier			}
367126258Smlaier		}
368223637Sbz		if (flags & PFR_FLAG_FEEDBACK)
369223637Sbz			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
370126261Smlaier				senderr(EFAULT);
371126258Smlaier	}
372126258Smlaier	pfr_clean_node_mask(tmpkt, &workq);
373126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
374126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
375126258Smlaier			s = splsoftnet();
376126258Smlaier		pfr_insert_kentries(kt, &workq, tzero);
377126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
378126258Smlaier			splx(s);
379126258Smlaier	} else
380126258Smlaier		pfr_destroy_kentries(&workq);
381126258Smlaier	if (nadd != NULL)
382126258Smlaier		*nadd = xadd;
383126258Smlaier	pfr_destroy_ktable(tmpkt, 0);
384126258Smlaier	return (0);
385126258Smlaier_bad:
386126258Smlaier	pfr_clean_node_mask(tmpkt, &workq);
387126258Smlaier	pfr_destroy_kentries(&workq);
388126258Smlaier	if (flags & PFR_FLAG_FEEDBACK)
389130613Smlaier		pfr_reset_feedback(addr, size, flags);
390126258Smlaier	pfr_destroy_ktable(tmpkt, 0);
391126258Smlaier	return (rv);
392126258Smlaier}
393126258Smlaier
394126258Smlaierint
395126258Smlaierpfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
396126258Smlaier    int *ndel, int flags)
397126258Smlaier{
398126258Smlaier	struct pfr_ktable	*kt;
399126258Smlaier	struct pfr_kentryworkq	 workq;
400126258Smlaier	struct pfr_kentry	*p;
401126258Smlaier	struct pfr_addr		 ad;
402223637Sbz	int			 i, rv, s, xdel = 0, log = 1;
403126258Smlaier
404223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
405223637Sbz	    PFR_FLAG_FEEDBACK);
406130613Smlaier	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
407126258Smlaier		return (EINVAL);
408126258Smlaier	kt = pfr_lookup_table(tbl);
409126258Smlaier	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
410126258Smlaier		return (ESRCH);
411126258Smlaier	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
412126258Smlaier		return (EPERM);
413145836Smlaier	/*
414145836Smlaier	 * there are two algorithms to choose from here.
415145836Smlaier	 * with:
416145836Smlaier	 *   n: number of addresses to delete
417145836Smlaier	 *   N: number of addresses in the table
418145836Smlaier	 *
419145836Smlaier	 * one is O(N) and is better for large 'n'
420145836Smlaier	 * one is O(n*LOG(N)) and is better for small 'n'
421145836Smlaier	 *
422145836Smlaier	 * following code try to decide which one is best.
423145836Smlaier	 */
424145836Smlaier	for (i = kt->pfrkt_cnt; i > 0; i >>= 1)
425145836Smlaier		log++;
426145836Smlaier	if (size > kt->pfrkt_cnt/log) {
427145836Smlaier		/* full table scan */
428145836Smlaier		pfr_mark_addrs(kt);
429145836Smlaier	} else {
430145836Smlaier		/* iterate over addresses to delete */
431145836Smlaier		for (i = 0; i < size; i++) {
432223637Sbz			if (COPYIN(addr+i, &ad, sizeof(ad), flags))
433145836Smlaier				return (EFAULT);
434145836Smlaier			if (pfr_validate_addr(&ad))
435145836Smlaier				return (EINVAL);
436145836Smlaier			p = pfr_lookup_addr(kt, &ad, 1);
437145836Smlaier			if (p != NULL)
438145836Smlaier				p->pfrke_mark = 0;
439145836Smlaier		}
440145836Smlaier	}
441126258Smlaier	SLIST_INIT(&workq);
442126258Smlaier	for (i = 0; i < size; i++) {
443223637Sbz		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
444126261Smlaier			senderr(EFAULT);
445126258Smlaier		if (pfr_validate_addr(&ad))
446126258Smlaier			senderr(EINVAL);
447126258Smlaier		p = pfr_lookup_addr(kt, &ad, 1);
448126258Smlaier		if (flags & PFR_FLAG_FEEDBACK) {
449126258Smlaier			if (p == NULL)
450126258Smlaier				ad.pfra_fback = PFR_FB_NONE;
451126258Smlaier			else if (p->pfrke_not != ad.pfra_not)
452126258Smlaier				ad.pfra_fback = PFR_FB_CONFLICT;
453126258Smlaier			else if (p->pfrke_mark)
454126258Smlaier				ad.pfra_fback = PFR_FB_DUPLICATE;
455126258Smlaier			else
456126258Smlaier				ad.pfra_fback = PFR_FB_DELETED;
457126258Smlaier		}
458126258Smlaier		if (p != NULL && p->pfrke_not == ad.pfra_not &&
459126258Smlaier		    !p->pfrke_mark) {
460126258Smlaier			p->pfrke_mark = 1;
461126258Smlaier			SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
462126258Smlaier			xdel++;
463126258Smlaier		}
464126258Smlaier		if (flags & PFR_FLAG_FEEDBACK)
465223637Sbz			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
466126258Smlaier				senderr(EFAULT);
467126258Smlaier	}
468126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
469126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
470126258Smlaier			s = splsoftnet();
471126258Smlaier		pfr_remove_kentries(kt, &workq);
472126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
473126258Smlaier			splx(s);
474126258Smlaier	}
475126258Smlaier	if (ndel != NULL)
476126258Smlaier		*ndel = xdel;
477126258Smlaier	return (0);
478126258Smlaier_bad:
479126258Smlaier	if (flags & PFR_FLAG_FEEDBACK)
480130613Smlaier		pfr_reset_feedback(addr, size, flags);
481126258Smlaier	return (rv);
482126258Smlaier}
483126258Smlaier
484126258Smlaierint
485126258Smlaierpfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
486171168Smlaier    int *size2, int *nadd, int *ndel, int *nchange, int flags,
487171168Smlaier    u_int32_t ignore_pfrt_flags)
488126258Smlaier{
489126258Smlaier	struct pfr_ktable	*kt, *tmpkt;
490126258Smlaier	struct pfr_kentryworkq	 addq, delq, changeq;
491126258Smlaier	struct pfr_kentry	*p, *q;
492126258Smlaier	struct pfr_addr		 ad;
493223637Sbz	int			 i, rv, s, xadd = 0, xdel = 0, xchange = 0;
494145836Smlaier	long			 tzero = time_second;
495126258Smlaier
496223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
497223637Sbz	    PFR_FLAG_FEEDBACK);
498171168Smlaier	if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
499171168Smlaier	    PFR_FLAG_USERIOCTL))
500126258Smlaier		return (EINVAL);
501126258Smlaier	kt = pfr_lookup_table(tbl);
502126258Smlaier	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
503126258Smlaier		return (ESRCH);
504126258Smlaier	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
505126258Smlaier		return (EPERM);
506223637Sbz	tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0,
507223637Sbz	    !(flags & PFR_FLAG_USERIOCTL));
508126258Smlaier	if (tmpkt == NULL)
509126258Smlaier		return (ENOMEM);
510126258Smlaier	pfr_mark_addrs(kt);
511126258Smlaier	SLIST_INIT(&addq);
512126258Smlaier	SLIST_INIT(&delq);
513126258Smlaier	SLIST_INIT(&changeq);
514126258Smlaier	for (i = 0; i < size; i++) {
515223637Sbz		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
516126261Smlaier			senderr(EFAULT);
517126258Smlaier		if (pfr_validate_addr(&ad))
518126258Smlaier			senderr(EINVAL);
519126258Smlaier		ad.pfra_fback = PFR_FB_NONE;
520126258Smlaier		p = pfr_lookup_addr(kt, &ad, 1);
521126258Smlaier		if (p != NULL) {
522126258Smlaier			if (p->pfrke_mark) {
523126258Smlaier				ad.pfra_fback = PFR_FB_DUPLICATE;
524126258Smlaier				goto _skip;
525126258Smlaier			}
526126258Smlaier			p->pfrke_mark = 1;
527126258Smlaier			if (p->pfrke_not != ad.pfra_not) {
528126258Smlaier				SLIST_INSERT_HEAD(&changeq, p, pfrke_workq);
529126258Smlaier				ad.pfra_fback = PFR_FB_CHANGED;
530126258Smlaier				xchange++;
531126258Smlaier			}
532126258Smlaier		} else {
533126258Smlaier			q = pfr_lookup_addr(tmpkt, &ad, 1);
534126258Smlaier			if (q != NULL) {
535126258Smlaier				ad.pfra_fback = PFR_FB_DUPLICATE;
536126258Smlaier				goto _skip;
537126258Smlaier			}
538223637Sbz			p = pfr_create_kentry(&ad,
539223637Sbz			    !(flags & PFR_FLAG_USERIOCTL));
540126258Smlaier			if (p == NULL)
541126258Smlaier				senderr(ENOMEM);
542126258Smlaier			if (pfr_route_kentry(tmpkt, p)) {
543126258Smlaier				pfr_destroy_kentry(p);
544126258Smlaier				ad.pfra_fback = PFR_FB_NONE;
545126258Smlaier			} else {
546126258Smlaier				SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
547126258Smlaier				ad.pfra_fback = PFR_FB_ADDED;
548126258Smlaier				xadd++;
549126258Smlaier			}
550126258Smlaier		}
551126258Smlaier_skip:
552126258Smlaier		if (flags & PFR_FLAG_FEEDBACK)
553223637Sbz			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
554126258Smlaier				senderr(EFAULT);
555126258Smlaier	}
556126258Smlaier	pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
557126258Smlaier	if ((flags & PFR_FLAG_FEEDBACK) && *size2) {
558126258Smlaier		if (*size2 < size+xdel) {
559126258Smlaier			*size2 = size+xdel;
560126258Smlaier			senderr(0);
561126258Smlaier		}
562126258Smlaier		i = 0;
563126258Smlaier		SLIST_FOREACH(p, &delq, pfrke_workq) {
564126258Smlaier			pfr_copyout_addr(&ad, p);
565126258Smlaier			ad.pfra_fback = PFR_FB_DELETED;
566223637Sbz			if (COPYOUT(&ad, addr+size+i, sizeof(ad), flags))
567126261Smlaier				senderr(EFAULT);
568126258Smlaier			i++;
569126258Smlaier		}
570126258Smlaier	}
571126258Smlaier	pfr_clean_node_mask(tmpkt, &addq);
572126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
573126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
574126258Smlaier			s = splsoftnet();
575126258Smlaier		pfr_insert_kentries(kt, &addq, tzero);
576126258Smlaier		pfr_remove_kentries(kt, &delq);
577126258Smlaier		pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
578126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
579126258Smlaier			splx(s);
580126258Smlaier	} else
581126258Smlaier		pfr_destroy_kentries(&addq);
582126258Smlaier	if (nadd != NULL)
583126258Smlaier		*nadd = xadd;
584126258Smlaier	if (ndel != NULL)
585126258Smlaier		*ndel = xdel;
586126258Smlaier	if (nchange != NULL)
587126258Smlaier		*nchange = xchange;
588130613Smlaier	if ((flags & PFR_FLAG_FEEDBACK) && size2)
589126258Smlaier		*size2 = size+xdel;
590126258Smlaier	pfr_destroy_ktable(tmpkt, 0);
591126258Smlaier	return (0);
592126258Smlaier_bad:
593126258Smlaier	pfr_clean_node_mask(tmpkt, &addq);
594126258Smlaier	pfr_destroy_kentries(&addq);
595126258Smlaier	if (flags & PFR_FLAG_FEEDBACK)
596130613Smlaier		pfr_reset_feedback(addr, size, flags);
597126258Smlaier	pfr_destroy_ktable(tmpkt, 0);
598126258Smlaier	return (rv);
599126258Smlaier}
600126258Smlaier
601126258Smlaierint
602126258Smlaierpfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
603126258Smlaier	int *nmatch, int flags)
604126258Smlaier{
605126258Smlaier	struct pfr_ktable	*kt;
606126258Smlaier	struct pfr_kentry	*p;
607126258Smlaier	struct pfr_addr		 ad;
608126258Smlaier	int			 i, xmatch = 0;
609126258Smlaier
610223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE);
611130613Smlaier	if (pfr_validate_table(tbl, 0, 0))
612126258Smlaier		return (EINVAL);
613126258Smlaier	kt = pfr_lookup_table(tbl);
614126258Smlaier	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
615126258Smlaier		return (ESRCH);
616126258Smlaier
617126258Smlaier	for (i = 0; i < size; i++) {
618223637Sbz		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
619126261Smlaier			return (EFAULT);
620126258Smlaier		if (pfr_validate_addr(&ad))
621126258Smlaier			return (EINVAL);
622126258Smlaier		if (ADDR_NETWORK(&ad))
623126258Smlaier			return (EINVAL);
624126258Smlaier		p = pfr_lookup_addr(kt, &ad, 0);
625126258Smlaier		if (flags & PFR_FLAG_REPLACE)
626126258Smlaier			pfr_copyout_addr(&ad, p);
627126258Smlaier		ad.pfra_fback = (p == NULL) ? PFR_FB_NONE :
628126258Smlaier		    (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH);
629126258Smlaier		if (p != NULL && !p->pfrke_not)
630126258Smlaier			xmatch++;
631223637Sbz		if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
632126261Smlaier			return (EFAULT);
633126258Smlaier	}
634126258Smlaier	if (nmatch != NULL)
635126258Smlaier		*nmatch = xmatch;
636126258Smlaier	return (0);
637126258Smlaier}
638126258Smlaier
639126258Smlaierint
640126258Smlaierpfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
641126258Smlaier	int flags)
642126258Smlaier{
643126258Smlaier	struct pfr_ktable	*kt;
644126258Smlaier	struct pfr_walktree	 w;
645126258Smlaier	int			 rv;
646126258Smlaier
647223637Sbz	ACCEPT_FLAGS(flags, 0);
648130613Smlaier	if (pfr_validate_table(tbl, 0, 0))
649126258Smlaier		return (EINVAL);
650126258Smlaier	kt = pfr_lookup_table(tbl);
651126258Smlaier	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
652126258Smlaier		return (ESRCH);
653126258Smlaier	if (kt->pfrkt_cnt > *size) {
654126258Smlaier		*size = kt->pfrkt_cnt;
655126258Smlaier		return (0);
656126258Smlaier	}
657126258Smlaier
658126258Smlaier	bzero(&w, sizeof(w));
659126258Smlaier	w.pfrw_op = PFRW_GET_ADDRS;
660126258Smlaier	w.pfrw_addr = addr;
661126258Smlaier	w.pfrw_free = kt->pfrkt_cnt;
662130613Smlaier	w.pfrw_flags = flags;
663127145Smlaier#ifdef __FreeBSD__
664126261Smlaier	rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
665126261Smlaier#else
666126258Smlaier	rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
667126261Smlaier#endif
668126258Smlaier	if (!rv)
669127145Smlaier#ifdef __FreeBSD__
670223637Sbz		rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
671126261Smlaier		    &w);
672126261Smlaier#else
673126258Smlaier		rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
674126261Smlaier#endif
675126258Smlaier	if (rv)
676126258Smlaier		return (rv);
677126258Smlaier
678126258Smlaier	if (w.pfrw_free) {
679126258Smlaier		printf("pfr_get_addrs: corruption detected (%d).\n",
680126258Smlaier		    w.pfrw_free);
681126258Smlaier		return (ENOTTY);
682126258Smlaier	}
683126258Smlaier	*size = kt->pfrkt_cnt;
684126258Smlaier	return (0);
685126258Smlaier}
686126258Smlaier
687126258Smlaierint
688126258Smlaierpfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
689126258Smlaier	int flags)
690126258Smlaier{
691126258Smlaier	struct pfr_ktable	*kt;
692126258Smlaier	struct pfr_walktree	 w;
693126258Smlaier	struct pfr_kentryworkq	 workq;
694223637Sbz	int			 rv, s;
695145836Smlaier	long			 tzero = time_second;
696126258Smlaier
697223637Sbz	/* XXX PFR_FLAG_CLSTATS disabled */
698223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC);
699130613Smlaier	if (pfr_validate_table(tbl, 0, 0))
700126258Smlaier		return (EINVAL);
701126258Smlaier	kt = pfr_lookup_table(tbl);
702126258Smlaier	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
703126258Smlaier		return (ESRCH);
704126258Smlaier	if (kt->pfrkt_cnt > *size) {
705126258Smlaier		*size = kt->pfrkt_cnt;
706126258Smlaier		return (0);
707126258Smlaier	}
708126258Smlaier
709126258Smlaier	bzero(&w, sizeof(w));
710126258Smlaier	w.pfrw_op = PFRW_GET_ASTATS;
711126258Smlaier	w.pfrw_astats = addr;
712126258Smlaier	w.pfrw_free = kt->pfrkt_cnt;
713130613Smlaier	w.pfrw_flags = flags;
714126258Smlaier	if (flags & PFR_FLAG_ATOMIC)
715126258Smlaier		s = splsoftnet();
716127145Smlaier#ifdef __FreeBSD__
717126261Smlaier	rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
718126261Smlaier#else
719126258Smlaier	rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
720126261Smlaier#endif
721126258Smlaier	if (!rv)
722127145Smlaier#ifdef __FreeBSD__
723126261Smlaier		rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
724126261Smlaier		    &w);
725126261Smlaier#else
726126258Smlaier		rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
727126261Smlaier#endif
728126258Smlaier	if (!rv && (flags & PFR_FLAG_CLSTATS)) {
729126258Smlaier		pfr_enqueue_addrs(kt, &workq, NULL, 0);
730126258Smlaier		pfr_clstats_kentries(&workq, tzero, 0);
731126258Smlaier	}
732126258Smlaier	if (flags & PFR_FLAG_ATOMIC)
733126258Smlaier		splx(s);
734126258Smlaier	if (rv)
735126258Smlaier		return (rv);
736126258Smlaier
737126258Smlaier	if (w.pfrw_free) {
738126258Smlaier		printf("pfr_get_astats: corruption detected (%d).\n",
739126258Smlaier		    w.pfrw_free);
740126258Smlaier		return (ENOTTY);
741126258Smlaier	}
742126258Smlaier	*size = kt->pfrkt_cnt;
743126258Smlaier	return (0);
744126258Smlaier}
745126258Smlaier
746126258Smlaierint
747126258Smlaierpfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
748126258Smlaier    int *nzero, int flags)
749126258Smlaier{
750126258Smlaier	struct pfr_ktable	*kt;
751126258Smlaier	struct pfr_kentryworkq	 workq;
752126258Smlaier	struct pfr_kentry	*p;
753126258Smlaier	struct pfr_addr		 ad;
754223637Sbz	int			 i, rv, s, xzero = 0;
755126258Smlaier
756223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
757223637Sbz	    PFR_FLAG_FEEDBACK);
758130613Smlaier	if (pfr_validate_table(tbl, 0, 0))
759126258Smlaier		return (EINVAL);
760126258Smlaier	kt = pfr_lookup_table(tbl);
761126258Smlaier	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
762126258Smlaier		return (ESRCH);
763126258Smlaier	SLIST_INIT(&workq);
764126258Smlaier	for (i = 0; i < size; i++) {
765223637Sbz		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
766126261Smlaier			senderr(EFAULT);
767126258Smlaier		if (pfr_validate_addr(&ad))
768126258Smlaier			senderr(EINVAL);
769126258Smlaier		p = pfr_lookup_addr(kt, &ad, 1);
770126258Smlaier		if (flags & PFR_FLAG_FEEDBACK) {
771126258Smlaier			ad.pfra_fback = (p != NULL) ?
772126258Smlaier			    PFR_FB_CLEARED : PFR_FB_NONE;
773223637Sbz			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
774126261Smlaier				senderr(EFAULT);
775126258Smlaier		}
776126258Smlaier		if (p != NULL) {
777126258Smlaier			SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
778126258Smlaier			xzero++;
779126258Smlaier		}
780126258Smlaier	}
781126258Smlaier
782126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
783126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
784126258Smlaier			s = splsoftnet();
785126258Smlaier		pfr_clstats_kentries(&workq, 0, 0);
786126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
787126258Smlaier			splx(s);
788126258Smlaier	}
789126258Smlaier	if (nzero != NULL)
790126258Smlaier		*nzero = xzero;
791126258Smlaier	return (0);
792126258Smlaier_bad:
793126258Smlaier	if (flags & PFR_FLAG_FEEDBACK)
794130613Smlaier		pfr_reset_feedback(addr, size, flags);
795126258Smlaier	return (rv);
796126258Smlaier}
797126258Smlaier
798126258Smlaierint
799126258Smlaierpfr_validate_addr(struct pfr_addr *ad)
800126258Smlaier{
801126258Smlaier	int i;
802126258Smlaier
803126258Smlaier	switch (ad->pfra_af) {
804145836Smlaier#ifdef INET
805126258Smlaier	case AF_INET:
806126258Smlaier		if (ad->pfra_net > 32)
807126258Smlaier			return (-1);
808126258Smlaier		break;
809145836Smlaier#endif /* INET */
810145836Smlaier#ifdef INET6
811126258Smlaier	case AF_INET6:
812126258Smlaier		if (ad->pfra_net > 128)
813126258Smlaier			return (-1);
814126258Smlaier		break;
815145836Smlaier#endif /* INET6 */
816126258Smlaier	default:
817126258Smlaier		return (-1);
818126258Smlaier	}
819126258Smlaier	if (ad->pfra_net < 128 &&
820126258Smlaier		(((caddr_t)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8))))
821126258Smlaier			return (-1);
822126258Smlaier	for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++)
823126258Smlaier		if (((caddr_t)ad)[i])
824126258Smlaier			return (-1);
825126258Smlaier	if (ad->pfra_not && ad->pfra_not != 1)
826126258Smlaier		return (-1);
827126258Smlaier	if (ad->pfra_fback)
828126258Smlaier		return (-1);
829126258Smlaier	return (0);
830126258Smlaier}
831126258Smlaier
832126258Smlaiervoid
833126258Smlaierpfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq,
834126258Smlaier	int *naddr, int sweep)
835126258Smlaier{
836126258Smlaier	struct pfr_walktree	w;
837126258Smlaier
838126258Smlaier	SLIST_INIT(workq);
839126258Smlaier	bzero(&w, sizeof(w));
840126258Smlaier	w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE;
841126258Smlaier	w.pfrw_workq = workq;
842126258Smlaier	if (kt->pfrkt_ip4 != NULL)
843127145Smlaier#ifdef __FreeBSD__
844126261Smlaier		if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree,
845126261Smlaier		    &w))
846126261Smlaier#else
847126258Smlaier		if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
848126261Smlaier#endif
849126258Smlaier			printf("pfr_enqueue_addrs: IPv4 walktree failed.\n");
850126258Smlaier	if (kt->pfrkt_ip6 != NULL)
851127145Smlaier#ifdef __FreeBSD__
852126261Smlaier		if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
853126261Smlaier		    &w))
854126261Smlaier#else
855126258Smlaier		if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
856126261Smlaier#endif
857126258Smlaier			printf("pfr_enqueue_addrs: IPv6 walktree failed.\n");
858126258Smlaier	if (naddr != NULL)
859126258Smlaier		*naddr = w.pfrw_cnt;
860126258Smlaier}
861126258Smlaier
862126258Smlaiervoid
863126258Smlaierpfr_mark_addrs(struct pfr_ktable *kt)
864126258Smlaier{
865126258Smlaier	struct pfr_walktree	w;
866126258Smlaier
867126258Smlaier	bzero(&w, sizeof(w));
868126258Smlaier	w.pfrw_op = PFRW_MARK;
869127145Smlaier#ifdef __FreeBSD__
870126261Smlaier	if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
871126261Smlaier#else
872126258Smlaier	if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
873126261Smlaier#endif
874126258Smlaier		printf("pfr_mark_addrs: IPv4 walktree failed.\n");
875127145Smlaier#ifdef __FreeBSD__
876126261Smlaier	if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
877126261Smlaier#else
878126258Smlaier	if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
879126261Smlaier#endif
880126258Smlaier		printf("pfr_mark_addrs: IPv6 walktree failed.\n");
881126258Smlaier}
882126258Smlaier
883126258Smlaier
884126258Smlaierstruct pfr_kentry *
885126258Smlaierpfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
886126258Smlaier{
887126258Smlaier	union sockaddr_union	 sa, mask;
888223637Sbz#ifdef __FreeBSD__
889223637Sbz	struct radix_node_head	*head = NULL;
890223637Sbz#else
891223637Sbz	struct radix_node_head	*head;
892223637Sbz#endif
893126258Smlaier	struct pfr_kentry	*ke;
894126258Smlaier	int			 s;
895126258Smlaier
896126258Smlaier	bzero(&sa, sizeof(sa));
897126258Smlaier	if (ad->pfra_af == AF_INET) {
898126258Smlaier		FILLIN_SIN(sa.sin, ad->pfra_ip4addr);
899126258Smlaier		head = kt->pfrkt_ip4;
900145836Smlaier	} else if ( ad->pfra_af == AF_INET6 ) {
901126258Smlaier		FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr);
902126258Smlaier		head = kt->pfrkt_ip6;
903126258Smlaier	}
904126258Smlaier	if (ADDR_NETWORK(ad)) {
905126258Smlaier		pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net);
906126258Smlaier		s = splsoftnet(); /* rn_lookup makes use of globals */
907171168Smlaier#ifdef __FreeBSD__
908226801Sglebius		PF_LOCK_ASSERT();
909126261Smlaier#endif
910126258Smlaier		ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head);
911126258Smlaier		splx(s);
912126258Smlaier		if (ke && KENTRY_RNF_ROOT(ke))
913126258Smlaier			ke = NULL;
914126258Smlaier	} else {
915126258Smlaier		ke = (struct pfr_kentry *)rn_match(&sa, head);
916126258Smlaier		if (ke && KENTRY_RNF_ROOT(ke))
917126258Smlaier			ke = NULL;
918126258Smlaier		if (exact && ke && KENTRY_NETWORK(ke))
919126258Smlaier			ke = NULL;
920126258Smlaier	}
921126258Smlaier	return (ke);
922126258Smlaier}
923126258Smlaier
924126258Smlaierstruct pfr_kentry *
925145836Smlaierpfr_create_kentry(struct pfr_addr *ad, int intr)
926126258Smlaier{
927126258Smlaier	struct pfr_kentry	*ke;
928126258Smlaier
929223637Sbz#ifdef __FreeBSD__
930238600Sglebius	ke =  pool_get(&V_pfr_kentry_pl, PR_NOWAIT | PR_ZERO);
931223637Sbz#else
932238600Sglebius	if (intr)
933223637Sbz		ke = pool_get(&pfr_kentry_pl, PR_NOWAIT | PR_ZERO);
934145836Smlaier	else
935223637Sbz		ke = pool_get(&pfr_kentry_pl, PR_WAITOK|PR_ZERO|PR_LIMITFAIL);
936223637Sbz#endif
937126258Smlaier	if (ke == NULL)
938126258Smlaier		return (NULL);
939126258Smlaier
940126258Smlaier	if (ad->pfra_af == AF_INET)
941126258Smlaier		FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr);
942145836Smlaier	else if (ad->pfra_af == AF_INET6)
943126258Smlaier		FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr);
944126258Smlaier	ke->pfrke_af = ad->pfra_af;
945126258Smlaier	ke->pfrke_net = ad->pfra_net;
946126258Smlaier	ke->pfrke_not = ad->pfra_not;
947126258Smlaier	return (ke);
948126258Smlaier}
949126258Smlaier
950126258Smlaiervoid
951126258Smlaierpfr_destroy_kentries(struct pfr_kentryworkq *workq)
952126258Smlaier{
953126258Smlaier	struct pfr_kentry	*p, *q;
954126258Smlaier
955126258Smlaier	for (p = SLIST_FIRST(workq); p != NULL; p = q) {
956126258Smlaier		q = SLIST_NEXT(p, pfrke_workq);
957126258Smlaier		pfr_destroy_kentry(p);
958126258Smlaier	}
959126258Smlaier}
960126258Smlaier
961126258Smlaiervoid
962126258Smlaierpfr_destroy_kentry(struct pfr_kentry *ke)
963126258Smlaier{
964223637Sbz	if (ke->pfrke_counters)
965223637Sbz#ifdef __FreeBSD__
966223637Sbz		pool_put(&V_pfr_kcounters_pl, ke->pfrke_counters);
967223637Sbz	pool_put(&V_pfr_kentry_pl, ke);
968223637Sbz#else
969223637Sbz		pool_put(&pfr_kcounters_pl, ke->pfrke_counters);
970223637Sbz	pool_put(&pfr_kentry_pl, ke);
971223637Sbz#endif
972126258Smlaier}
973126258Smlaier
974126258Smlaiervoid
975126258Smlaierpfr_insert_kentries(struct pfr_ktable *kt,
976126258Smlaier    struct pfr_kentryworkq *workq, long tzero)
977126258Smlaier{
978126258Smlaier	struct pfr_kentry	*p;
979126258Smlaier	int			 rv, n = 0;
980126258Smlaier
981126258Smlaier	SLIST_FOREACH(p, workq, pfrke_workq) {
982126258Smlaier		rv = pfr_route_kentry(kt, p);
983126258Smlaier		if (rv) {
984126258Smlaier			printf("pfr_insert_kentries: cannot route entry "
985126258Smlaier			    "(code=%d).\n", rv);
986126258Smlaier			break;
987126258Smlaier		}
988126258Smlaier		p->pfrke_tzero = tzero;
989126258Smlaier		n++;
990126258Smlaier	}
991126258Smlaier	kt->pfrkt_cnt += n;
992126258Smlaier}
993126258Smlaier
994145836Smlaierint
995145836Smlaierpfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero)
996145836Smlaier{
997145836Smlaier	struct pfr_kentry	*p;
998145836Smlaier	int			 rv;
999145836Smlaier
1000145836Smlaier	p = pfr_lookup_addr(kt, ad, 1);
1001145836Smlaier	if (p != NULL)
1002145836Smlaier		return (0);
1003145836Smlaier	p = pfr_create_kentry(ad, 1);
1004145836Smlaier	if (p == NULL)
1005145836Smlaier		return (EINVAL);
1006145836Smlaier
1007145836Smlaier	rv = pfr_route_kentry(kt, p);
1008145836Smlaier	if (rv)
1009145836Smlaier		return (rv);
1010145836Smlaier
1011145836Smlaier	p->pfrke_tzero = tzero;
1012145836Smlaier	kt->pfrkt_cnt++;
1013145836Smlaier
1014145836Smlaier	return (0);
1015145836Smlaier}
1016145836Smlaier
1017126258Smlaiervoid
1018126258Smlaierpfr_remove_kentries(struct pfr_ktable *kt,
1019126258Smlaier    struct pfr_kentryworkq *workq)
1020126258Smlaier{
1021126258Smlaier	struct pfr_kentry	*p;
1022126258Smlaier	int			 n = 0;
1023126258Smlaier
1024126258Smlaier	SLIST_FOREACH(p, workq, pfrke_workq) {
1025126258Smlaier		pfr_unroute_kentry(kt, p);
1026126258Smlaier		n++;
1027126258Smlaier	}
1028126258Smlaier	kt->pfrkt_cnt -= n;
1029126258Smlaier	pfr_destroy_kentries(workq);
1030126258Smlaier}
1031126258Smlaier
1032126258Smlaiervoid
1033126258Smlaierpfr_clean_node_mask(struct pfr_ktable *kt,
1034126258Smlaier    struct pfr_kentryworkq *workq)
1035126258Smlaier{
1036130613Smlaier	struct pfr_kentry	*p;
1037126258Smlaier
1038130613Smlaier	SLIST_FOREACH(p, workq, pfrke_workq)
1039130613Smlaier		pfr_unroute_kentry(kt, p);
1040126258Smlaier}
1041126258Smlaier
1042126258Smlaiervoid
1043126258Smlaierpfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange)
1044126258Smlaier{
1045126258Smlaier	struct pfr_kentry	*p;
1046126258Smlaier	int			 s;
1047126258Smlaier
1048126258Smlaier	SLIST_FOREACH(p, workq, pfrke_workq) {
1049126258Smlaier		s = splsoftnet();
1050126258Smlaier		if (negchange)
1051126258Smlaier			p->pfrke_not = !p->pfrke_not;
1052223637Sbz		if (p->pfrke_counters) {
1053223637Sbz#ifdef __FreeBSD__
1054223637Sbz			pool_put(&V_pfr_kcounters_pl, p->pfrke_counters);
1055223637Sbz#else
1056223637Sbz			pool_put(&pfr_kcounters_pl, p->pfrke_counters);
1057223637Sbz#endif
1058223637Sbz			p->pfrke_counters = NULL;
1059223637Sbz		}
1060126258Smlaier		splx(s);
1061126258Smlaier		p->pfrke_tzero = tzero;
1062126258Smlaier	}
1063126258Smlaier}
1064126258Smlaier
1065126258Smlaiervoid
1066130613Smlaierpfr_reset_feedback(struct pfr_addr *addr, int size, int flags)
1067126258Smlaier{
1068126258Smlaier	struct pfr_addr	ad;
1069126258Smlaier	int		i;
1070126258Smlaier
1071126258Smlaier	for (i = 0; i < size; i++) {
1072223637Sbz		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
1073126261Smlaier			break;
1074126258Smlaier		ad.pfra_fback = PFR_FB_NONE;
1075223637Sbz		if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
1076126261Smlaier			break;
1077126258Smlaier	}
1078126258Smlaier}
1079126258Smlaier
1080126258Smlaiervoid
1081126258Smlaierpfr_prepare_network(union sockaddr_union *sa, int af, int net)
1082126258Smlaier{
1083126258Smlaier	int	i;
1084126258Smlaier
1085126258Smlaier	bzero(sa, sizeof(*sa));
1086126258Smlaier	if (af == AF_INET) {
1087126258Smlaier		sa->sin.sin_len = sizeof(sa->sin);
1088126258Smlaier		sa->sin.sin_family = AF_INET;
1089145836Smlaier		sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0;
1090145836Smlaier	} else if (af == AF_INET6) {
1091126258Smlaier		sa->sin6.sin6_len = sizeof(sa->sin6);
1092126258Smlaier		sa->sin6.sin6_family = AF_INET6;
1093126258Smlaier		for (i = 0; i < 4; i++) {
1094126258Smlaier			if (net <= 32) {
1095126258Smlaier				sa->sin6.sin6_addr.s6_addr32[i] =
1096145836Smlaier				    net ? htonl(-1 << (32-net)) : 0;
1097126258Smlaier				break;
1098126258Smlaier			}
1099126258Smlaier			sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF;
1100126258Smlaier			net -= 32;
1101126258Smlaier		}
1102126258Smlaier	}
1103126258Smlaier}
1104126258Smlaier
1105126258Smlaierint
1106126258Smlaierpfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
1107126258Smlaier{
1108126258Smlaier	union sockaddr_union	 mask;
1109126258Smlaier	struct radix_node	*rn;
1110223637Sbz#ifdef __FreeBSD__
1111223637Sbz	struct radix_node_head	*head = NULL;
1112223637Sbz#else
1113223637Sbz	struct radix_node_head	*head;
1114223637Sbz#endif
1115126258Smlaier	int			 s;
1116126258Smlaier
1117126258Smlaier	bzero(ke->pfrke_node, sizeof(ke->pfrke_node));
1118126258Smlaier	if (ke->pfrke_af == AF_INET)
1119126258Smlaier		head = kt->pfrkt_ip4;
1120145836Smlaier	else if (ke->pfrke_af == AF_INET6)
1121126258Smlaier		head = kt->pfrkt_ip6;
1122126258Smlaier
1123126258Smlaier	s = splsoftnet();
1124171168Smlaier#ifdef __FreeBSD__
1125226801Sglebius	PF_LOCK_ASSERT();
1126126261Smlaier#endif
1127126258Smlaier	if (KENTRY_NETWORK(ke)) {
1128126258Smlaier		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
1129223637Sbz#ifdef __FreeBSD__
1130126258Smlaier		rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node);
1131223637Sbz#else
1132223637Sbz		rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node, 0);
1133223637Sbz#endif
1134126258Smlaier	} else
1135223637Sbz#ifdef __FreeBSD__
1136126258Smlaier		rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node);
1137223637Sbz#else
1138223637Sbz		rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node, 0);
1139223637Sbz#endif
1140126258Smlaier	splx(s);
1141126258Smlaier
1142126258Smlaier	return (rn == NULL ? -1 : 0);
1143126258Smlaier}
1144126258Smlaier
1145126258Smlaierint
1146126258Smlaierpfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
1147126258Smlaier{
1148126258Smlaier	union sockaddr_union	 mask;
1149126258Smlaier	struct radix_node	*rn;
1150223637Sbz#ifdef __FreeBSD__
1151223637Sbz	struct radix_node_head	*head = NULL;
1152223637Sbz#else
1153223637Sbz	struct radix_node_head	*head;
1154223637Sbz#endif
1155126258Smlaier	int			 s;
1156126258Smlaier
1157126258Smlaier	if (ke->pfrke_af == AF_INET)
1158126258Smlaier		head = kt->pfrkt_ip4;
1159145836Smlaier	else if (ke->pfrke_af == AF_INET6)
1160126258Smlaier		head = kt->pfrkt_ip6;
1161126258Smlaier
1162126258Smlaier	s = splsoftnet();
1163171168Smlaier#ifdef __FreeBSD__
1164226801Sglebius	PF_LOCK_ASSERT();
1165126261Smlaier#endif
1166126258Smlaier	if (KENTRY_NETWORK(ke)) {
1167126258Smlaier		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
1168145836Smlaier#ifdef __FreeBSD__
1169126258Smlaier		rn = rn_delete(&ke->pfrke_sa, &mask, head);
1170145836Smlaier#else
1171145836Smlaier		rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL);
1172145836Smlaier#endif
1173126258Smlaier	} else
1174145836Smlaier#ifdef __FreeBSD__
1175126258Smlaier		rn = rn_delete(&ke->pfrke_sa, NULL, head);
1176145836Smlaier#else
1177145836Smlaier		rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL);
1178145836Smlaier#endif
1179126258Smlaier	splx(s);
1180126258Smlaier
1181126258Smlaier	if (rn == NULL) {
1182126258Smlaier		printf("pfr_unroute_kentry: delete failed.\n");
1183126258Smlaier		return (-1);
1184126258Smlaier	}
1185126258Smlaier	return (0);
1186126258Smlaier}
1187126258Smlaier
1188126258Smlaiervoid
1189126258Smlaierpfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke)
1190126258Smlaier{
1191126258Smlaier	bzero(ad, sizeof(*ad));
1192126258Smlaier	if (ke == NULL)
1193126258Smlaier		return;
1194126258Smlaier	ad->pfra_af = ke->pfrke_af;
1195126258Smlaier	ad->pfra_net = ke->pfrke_net;
1196126258Smlaier	ad->pfra_not = ke->pfrke_not;
1197126258Smlaier	if (ad->pfra_af == AF_INET)
1198126258Smlaier		ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr;
1199145836Smlaier	else if (ad->pfra_af == AF_INET6)
1200126258Smlaier		ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr;
1201126258Smlaier}
1202126258Smlaier
1203126258Smlaierint
1204126258Smlaierpfr_walktree(struct radix_node *rn, void *arg)
1205126258Smlaier{
1206126258Smlaier	struct pfr_kentry	*ke = (struct pfr_kentry *)rn;
1207126258Smlaier	struct pfr_walktree	*w = arg;
1208130613Smlaier	int			 s, flags = w->pfrw_flags;
1209126258Smlaier
1210126258Smlaier	switch (w->pfrw_op) {
1211126258Smlaier	case PFRW_MARK:
1212126258Smlaier		ke->pfrke_mark = 0;
1213126258Smlaier		break;
1214126258Smlaier	case PFRW_SWEEP:
1215126258Smlaier		if (ke->pfrke_mark)
1216126258Smlaier			break;
1217130613Smlaier		/* FALLTHROUGH */
1218126258Smlaier	case PFRW_ENQUEUE:
1219126258Smlaier		SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq);
1220126258Smlaier		w->pfrw_cnt++;
1221126258Smlaier		break;
1222126258Smlaier	case PFRW_GET_ADDRS:
1223126258Smlaier		if (w->pfrw_free-- > 0) {
1224126258Smlaier			struct pfr_addr ad;
1225126258Smlaier
1226126258Smlaier			pfr_copyout_addr(&ad, ke);
1227223637Sbz			if (copyout(&ad, w->pfrw_addr, sizeof(ad)))
1228126258Smlaier				return (EFAULT);
1229126258Smlaier			w->pfrw_addr++;
1230126258Smlaier		}
1231126258Smlaier		break;
1232126258Smlaier	case PFRW_GET_ASTATS:
1233126258Smlaier		if (w->pfrw_free-- > 0) {
1234126258Smlaier			struct pfr_astats as;
1235126258Smlaier
1236126258Smlaier			pfr_copyout_addr(&as.pfras_a, ke);
1237126258Smlaier
1238126258Smlaier			s = splsoftnet();
1239223637Sbz			if (ke->pfrke_counters) {
1240223637Sbz				bcopy(ke->pfrke_counters->pfrkc_packets,
1241223637Sbz				    as.pfras_packets, sizeof(as.pfras_packets));
1242223637Sbz				bcopy(ke->pfrke_counters->pfrkc_bytes,
1243223637Sbz				    as.pfras_bytes, sizeof(as.pfras_bytes));
1244223637Sbz			} else {
1245223637Sbz				bzero(as.pfras_packets, sizeof(as.pfras_packets));
1246223637Sbz				bzero(as.pfras_bytes, sizeof(as.pfras_bytes));
1247223637Sbz				as.pfras_a.pfra_fback = PFR_FB_NOCOUNT;
1248223637Sbz			}
1249126258Smlaier			splx(s);
1250126258Smlaier			as.pfras_tzero = ke->pfrke_tzero;
1251126258Smlaier
1252223637Sbz			if (COPYOUT(&as, w->pfrw_astats, sizeof(as), flags))
1253126261Smlaier				return (EFAULT);
1254126258Smlaier			w->pfrw_astats++;
1255126258Smlaier		}
1256126258Smlaier		break;
1257126258Smlaier	case PFRW_POOL_GET:
1258126258Smlaier		if (ke->pfrke_not)
1259126258Smlaier			break; /* negative entries are ignored */
1260126258Smlaier		if (!w->pfrw_cnt--) {
1261126258Smlaier			w->pfrw_kentry = ke;
1262126258Smlaier			return (1); /* finish search */
1263126258Smlaier		}
1264126258Smlaier		break;
1265130613Smlaier	case PFRW_DYNADDR_UPDATE:
1266130613Smlaier		if (ke->pfrke_af == AF_INET) {
1267130613Smlaier			if (w->pfrw_dyn->pfid_acnt4++ > 0)
1268130613Smlaier				break;
1269223637Sbz#ifdef __FreeBSD__
1270223637Sbz			pfr_prepare_network(&V_pfr_mask, AF_INET, ke->pfrke_net);
1271223637Sbz#else
1272130613Smlaier			pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net);
1273223637Sbz#endif
1274130613Smlaier			w->pfrw_dyn->pfid_addr4 = *SUNION2PF(
1275130613Smlaier			    &ke->pfrke_sa, AF_INET);
1276130613Smlaier			w->pfrw_dyn->pfid_mask4 = *SUNION2PF(
1277223637Sbz#ifdef __FreeBSD__
1278223637Sbz			    &V_pfr_mask, AF_INET);
1279223637Sbz#else
1280130613Smlaier			    &pfr_mask, AF_INET);
1281223637Sbz#endif
1282145836Smlaier		} else if (ke->pfrke_af == AF_INET6){
1283130613Smlaier			if (w->pfrw_dyn->pfid_acnt6++ > 0)
1284130613Smlaier				break;
1285223637Sbz#ifdef __FreeBSD__
1286223637Sbz			pfr_prepare_network(&V_pfr_mask, AF_INET6, ke->pfrke_net);
1287223637Sbz#else
1288130613Smlaier			pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net);
1289223637Sbz#endif
1290130613Smlaier			w->pfrw_dyn->pfid_addr6 = *SUNION2PF(
1291130613Smlaier			    &ke->pfrke_sa, AF_INET6);
1292130613Smlaier			w->pfrw_dyn->pfid_mask6 = *SUNION2PF(
1293223637Sbz#ifdef __FreeBSD__
1294223637Sbz			    &V_pfr_mask, AF_INET6);
1295223637Sbz#else
1296130613Smlaier			    &pfr_mask, AF_INET6);
1297223637Sbz#endif
1298130613Smlaier		}
1299130613Smlaier		break;
1300126258Smlaier	}
1301126258Smlaier	return (0);
1302126258Smlaier}
1303126258Smlaier
1304126258Smlaierint
1305126258Smlaierpfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
1306126258Smlaier{
1307126258Smlaier	struct pfr_ktableworkq	 workq;
1308126258Smlaier	struct pfr_ktable	*p;
1309223637Sbz	int			 s, xdel = 0;
1310126258Smlaier
1311223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
1312223637Sbz	    PFR_FLAG_ALLRSETS);
1313145836Smlaier	if (pfr_fix_anchor(filter->pfrt_anchor))
1314145836Smlaier		return (EINVAL);
1315126258Smlaier	if (pfr_table_count(filter, flags) < 0)
1316126258Smlaier		return (ENOENT);
1317126258Smlaier
1318126258Smlaier	SLIST_INIT(&workq);
1319126258Smlaier	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1320126258Smlaier		if (pfr_skip_table(filter, p, flags))
1321126258Smlaier			continue;
1322130613Smlaier		if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR))
1323130613Smlaier			continue;
1324126258Smlaier		if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE))
1325126258Smlaier			continue;
1326126258Smlaier		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
1327126258Smlaier		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1328126258Smlaier		xdel++;
1329126258Smlaier	}
1330126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
1331126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1332126258Smlaier			s = splsoftnet();
1333126258Smlaier		pfr_setflags_ktables(&workq);
1334126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1335126258Smlaier			splx(s);
1336126258Smlaier	}
1337126258Smlaier	if (ndel != NULL)
1338126258Smlaier		*ndel = xdel;
1339126258Smlaier	return (0);
1340126258Smlaier}
1341126258Smlaier
1342126258Smlaierint
1343126258Smlaierpfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
1344126258Smlaier{
1345126258Smlaier	struct pfr_ktableworkq	 addq, changeq;
1346126258Smlaier	struct pfr_ktable	*p, *q, *r, key;
1347223637Sbz	int			 i, rv, s, xadd = 0;
1348145836Smlaier	long			 tzero = time_second;
1349126258Smlaier
1350223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
1351126258Smlaier	SLIST_INIT(&addq);
1352126258Smlaier	SLIST_INIT(&changeq);
1353126258Smlaier	for (i = 0; i < size; i++) {
1354223637Sbz		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
1355126261Smlaier			senderr(EFAULT);
1356130613Smlaier		if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK,
1357130613Smlaier		    flags & PFR_FLAG_USERIOCTL))
1358126258Smlaier			senderr(EINVAL);
1359126258Smlaier		key.pfrkt_flags |= PFR_TFLAG_ACTIVE;
1360126258Smlaier		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1361126258Smlaier		if (p == NULL) {
1362223637Sbz			p = pfr_create_ktable(&key.pfrkt_t, tzero, 1,
1363223637Sbz			    !(flags & PFR_FLAG_USERIOCTL));
1364126258Smlaier			if (p == NULL)
1365126258Smlaier				senderr(ENOMEM);
1366126258Smlaier			SLIST_FOREACH(q, &addq, pfrkt_workq) {
1367126258Smlaier				if (!pfr_ktable_compare(p, q))
1368126258Smlaier					goto _skip;
1369126258Smlaier			}
1370126258Smlaier			SLIST_INSERT_HEAD(&addq, p, pfrkt_workq);
1371126258Smlaier			xadd++;
1372126258Smlaier			if (!key.pfrkt_anchor[0])
1373126258Smlaier				goto _skip;
1374126258Smlaier
1375126258Smlaier			/* find or create root table */
1376126258Smlaier			bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor));
1377126258Smlaier			r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1378126258Smlaier			if (r != NULL) {
1379126258Smlaier				p->pfrkt_root = r;
1380126258Smlaier				goto _skip;
1381126258Smlaier			}
1382126258Smlaier			SLIST_FOREACH(q, &addq, pfrkt_workq) {
1383126258Smlaier				if (!pfr_ktable_compare(&key, q)) {
1384126258Smlaier					p->pfrkt_root = q;
1385126258Smlaier					goto _skip;
1386126258Smlaier				}
1387126258Smlaier			}
1388126258Smlaier			key.pfrkt_flags = 0;
1389223637Sbz			r = pfr_create_ktable(&key.pfrkt_t, 0, 1,
1390223637Sbz			    !(flags & PFR_FLAG_USERIOCTL));
1391126258Smlaier			if (r == NULL)
1392126258Smlaier				senderr(ENOMEM);
1393126258Smlaier			SLIST_INSERT_HEAD(&addq, r, pfrkt_workq);
1394126258Smlaier			p->pfrkt_root = r;
1395126258Smlaier		} else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1396126258Smlaier			SLIST_FOREACH(q, &changeq, pfrkt_workq)
1397126258Smlaier				if (!pfr_ktable_compare(&key, q))
1398126258Smlaier					goto _skip;
1399126258Smlaier			p->pfrkt_nflags = (p->pfrkt_flags &
1400126258Smlaier			    ~PFR_TFLAG_USRMASK) | key.pfrkt_flags;
1401126258Smlaier			SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq);
1402126258Smlaier			xadd++;
1403126258Smlaier		}
1404126258Smlaier_skip:
1405126258Smlaier	;
1406126258Smlaier	}
1407126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
1408126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1409126258Smlaier			s = splsoftnet();
1410126258Smlaier		pfr_insert_ktables(&addq);
1411126258Smlaier		pfr_setflags_ktables(&changeq);
1412126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1413126258Smlaier			splx(s);
1414126258Smlaier	} else
1415126258Smlaier		 pfr_destroy_ktables(&addq, 0);
1416126258Smlaier	if (nadd != NULL)
1417126258Smlaier		*nadd = xadd;
1418126258Smlaier	return (0);
1419126258Smlaier_bad:
1420126258Smlaier	pfr_destroy_ktables(&addq, 0);
1421126258Smlaier	return (rv);
1422126258Smlaier}
1423126258Smlaier
1424126258Smlaierint
1425126258Smlaierpfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
1426126258Smlaier{
1427126258Smlaier	struct pfr_ktableworkq	 workq;
1428126258Smlaier	struct pfr_ktable	*p, *q, key;
1429223637Sbz	int			 i, s, xdel = 0;
1430126258Smlaier
1431223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
1432126258Smlaier	SLIST_INIT(&workq);
1433126258Smlaier	for (i = 0; i < size; i++) {
1434223637Sbz		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
1435126261Smlaier			return (EFAULT);
1436130613Smlaier		if (pfr_validate_table(&key.pfrkt_t, 0,
1437130613Smlaier		    flags & PFR_FLAG_USERIOCTL))
1438126258Smlaier			return (EINVAL);
1439126258Smlaier		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1440126258Smlaier		if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1441126258Smlaier			SLIST_FOREACH(q, &workq, pfrkt_workq)
1442126258Smlaier				if (!pfr_ktable_compare(p, q))
1443126258Smlaier					goto _skip;
1444126258Smlaier			p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
1445126258Smlaier			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1446126258Smlaier			xdel++;
1447126258Smlaier		}
1448126258Smlaier_skip:
1449126258Smlaier	;
1450126258Smlaier	}
1451126258Smlaier
1452126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
1453126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1454126258Smlaier			s = splsoftnet();
1455126258Smlaier		pfr_setflags_ktables(&workq);
1456126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1457126258Smlaier			splx(s);
1458126258Smlaier	}
1459126258Smlaier	if (ndel != NULL)
1460126258Smlaier		*ndel = xdel;
1461126258Smlaier	return (0);
1462126258Smlaier}
1463126258Smlaier
1464126258Smlaierint
1465126258Smlaierpfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
1466126258Smlaier	int flags)
1467126258Smlaier{
1468126258Smlaier	struct pfr_ktable	*p;
1469126258Smlaier	int			 n, nn;
1470126258Smlaier
1471223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS);
1472145836Smlaier	if (pfr_fix_anchor(filter->pfrt_anchor))
1473145836Smlaier		return (EINVAL);
1474126258Smlaier	n = nn = pfr_table_count(filter, flags);
1475126258Smlaier	if (n < 0)
1476126258Smlaier		return (ENOENT);
1477126258Smlaier	if (n > *size) {
1478126258Smlaier		*size = n;
1479126258Smlaier		return (0);
1480126258Smlaier	}
1481126258Smlaier	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1482126258Smlaier		if (pfr_skip_table(filter, p, flags))
1483126258Smlaier			continue;
1484126258Smlaier		if (n-- <= 0)
1485126258Smlaier			continue;
1486223637Sbz		if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), flags))
1487126261Smlaier			return (EFAULT);
1488126258Smlaier	}
1489126258Smlaier	if (n) {
1490126258Smlaier		printf("pfr_get_tables: corruption detected (%d).\n", n);
1491126258Smlaier		return (ENOTTY);
1492126258Smlaier	}
1493126258Smlaier	*size = nn;
1494126258Smlaier	return (0);
1495126258Smlaier}
1496126258Smlaier
1497126258Smlaierint
1498126258Smlaierpfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
1499126258Smlaier	int flags)
1500126258Smlaier{
1501126258Smlaier	struct pfr_ktable	*p;
1502126258Smlaier	struct pfr_ktableworkq	 workq;
1503223637Sbz	int			 s, n, nn;
1504145836Smlaier	long			 tzero = time_second;
1505126258Smlaier
1506223637Sbz	/* XXX PFR_FLAG_CLSTATS disabled */
1507223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_ALLRSETS);
1508145836Smlaier	if (pfr_fix_anchor(filter->pfrt_anchor))
1509145836Smlaier		return (EINVAL);
1510126258Smlaier	n = nn = pfr_table_count(filter, flags);
1511126258Smlaier	if (n < 0)
1512126258Smlaier		return (ENOENT);
1513126258Smlaier	if (n > *size) {
1514126258Smlaier		*size = n;
1515126258Smlaier		return (0);
1516126258Smlaier	}
1517126258Smlaier	SLIST_INIT(&workq);
1518126258Smlaier	if (flags & PFR_FLAG_ATOMIC)
1519126258Smlaier		s = splsoftnet();
1520126258Smlaier	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1521126258Smlaier		if (pfr_skip_table(filter, p, flags))
1522126258Smlaier			continue;
1523126258Smlaier		if (n-- <= 0)
1524126258Smlaier			continue;
1525126258Smlaier		if (!(flags & PFR_FLAG_ATOMIC))
1526126258Smlaier			s = splsoftnet();
1527223637Sbz		if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), flags)) {
1528223637Sbz			splx(s);
1529126261Smlaier			return (EFAULT);
1530126261Smlaier		}
1531126258Smlaier		if (!(flags & PFR_FLAG_ATOMIC))
1532126258Smlaier			splx(s);
1533126258Smlaier		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1534126258Smlaier	}
1535126258Smlaier	if (flags & PFR_FLAG_CLSTATS)
1536126258Smlaier		pfr_clstats_ktables(&workq, tzero,
1537126258Smlaier		    flags & PFR_FLAG_ADDRSTOO);
1538126258Smlaier	if (flags & PFR_FLAG_ATOMIC)
1539126258Smlaier		splx(s);
1540126258Smlaier	if (n) {
1541126258Smlaier		printf("pfr_get_tstats: corruption detected (%d).\n", n);
1542126258Smlaier		return (ENOTTY);
1543126258Smlaier	}
1544126258Smlaier	*size = nn;
1545126258Smlaier	return (0);
1546126258Smlaier}
1547126258Smlaier
1548126258Smlaierint
1549126258Smlaierpfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
1550126258Smlaier{
1551126258Smlaier	struct pfr_ktableworkq	 workq;
1552126258Smlaier	struct pfr_ktable	*p, key;
1553223637Sbz	int			 i, s, xzero = 0;
1554145836Smlaier	long			 tzero = time_second;
1555126258Smlaier
1556223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
1557223637Sbz	    PFR_FLAG_ADDRSTOO);
1558126258Smlaier	SLIST_INIT(&workq);
1559126258Smlaier	for (i = 0; i < size; i++) {
1560223637Sbz		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
1561126261Smlaier			return (EFAULT);
1562130613Smlaier		if (pfr_validate_table(&key.pfrkt_t, 0, 0))
1563126258Smlaier			return (EINVAL);
1564126258Smlaier		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1565126258Smlaier		if (p != NULL) {
1566126258Smlaier			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1567126258Smlaier			xzero++;
1568126258Smlaier		}
1569126258Smlaier	}
1570126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
1571126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1572126258Smlaier			s = splsoftnet();
1573126258Smlaier		pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO);
1574126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1575126258Smlaier			splx(s);
1576126258Smlaier	}
1577126258Smlaier	if (nzero != NULL)
1578126258Smlaier		*nzero = xzero;
1579126258Smlaier	return (0);
1580126258Smlaier}
1581126258Smlaier
1582126258Smlaierint
1583126258Smlaierpfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
1584126258Smlaier	int *nchange, int *ndel, int flags)
1585126258Smlaier{
1586126258Smlaier	struct pfr_ktableworkq	 workq;
1587126258Smlaier	struct pfr_ktable	*p, *q, key;
1588223637Sbz	int			 i, s, xchange = 0, xdel = 0;
1589126258Smlaier
1590223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
1591126258Smlaier	if ((setflag & ~PFR_TFLAG_USRMASK) ||
1592126258Smlaier	    (clrflag & ~PFR_TFLAG_USRMASK) ||
1593126258Smlaier	    (setflag & clrflag))
1594126258Smlaier		return (EINVAL);
1595126258Smlaier	SLIST_INIT(&workq);
1596126258Smlaier	for (i = 0; i < size; i++) {
1597223637Sbz		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
1598126261Smlaier			return (EFAULT);
1599130613Smlaier		if (pfr_validate_table(&key.pfrkt_t, 0,
1600130613Smlaier		    flags & PFR_FLAG_USERIOCTL))
1601126258Smlaier			return (EINVAL);
1602126258Smlaier		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1603126258Smlaier		if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
1604126258Smlaier			p->pfrkt_nflags = (p->pfrkt_flags | setflag) &
1605126258Smlaier			    ~clrflag;
1606126258Smlaier			if (p->pfrkt_nflags == p->pfrkt_flags)
1607126258Smlaier				goto _skip;
1608126258Smlaier			SLIST_FOREACH(q, &workq, pfrkt_workq)
1609126258Smlaier				if (!pfr_ktable_compare(p, q))
1610126258Smlaier					goto _skip;
1611126258Smlaier			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1612126258Smlaier			if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) &&
1613126258Smlaier			    (clrflag & PFR_TFLAG_PERSIST) &&
1614126258Smlaier			    !(p->pfrkt_flags & PFR_TFLAG_REFERENCED))
1615126258Smlaier				xdel++;
1616126258Smlaier			else
1617126258Smlaier				xchange++;
1618126258Smlaier		}
1619126258Smlaier_skip:
1620126258Smlaier	;
1621126258Smlaier	}
1622126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
1623126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1624126258Smlaier			s = splsoftnet();
1625126258Smlaier		pfr_setflags_ktables(&workq);
1626126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1627126258Smlaier			splx(s);
1628126258Smlaier	}
1629126258Smlaier	if (nchange != NULL)
1630126258Smlaier		*nchange = xchange;
1631126258Smlaier	if (ndel != NULL)
1632126258Smlaier		*ndel = xdel;
1633126258Smlaier	return (0);
1634126258Smlaier}
1635126258Smlaier
1636126258Smlaierint
1637126258Smlaierpfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags)
1638126258Smlaier{
1639126258Smlaier	struct pfr_ktableworkq	 workq;
1640126258Smlaier	struct pfr_ktable	*p;
1641126258Smlaier	struct pf_ruleset	*rs;
1642126258Smlaier	int			 xdel = 0;
1643126258Smlaier
1644223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
1645145836Smlaier	rs = pf_find_or_create_ruleset(trs->pfrt_anchor);
1646126258Smlaier	if (rs == NULL)
1647126258Smlaier		return (ENOMEM);
1648126258Smlaier	SLIST_INIT(&workq);
1649126258Smlaier	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1650126258Smlaier		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1651126258Smlaier		    pfr_skip_table(trs, p, 0))
1652126258Smlaier			continue;
1653126258Smlaier		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
1654126258Smlaier		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1655126258Smlaier		xdel++;
1656126258Smlaier	}
1657126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
1658126258Smlaier		pfr_setflags_ktables(&workq);
1659126258Smlaier		if (ticket != NULL)
1660126258Smlaier			*ticket = ++rs->tticket;
1661126258Smlaier		rs->topen = 1;
1662126258Smlaier	} else
1663126258Smlaier		pf_remove_if_empty_ruleset(rs);
1664126258Smlaier	if (ndel != NULL)
1665126258Smlaier		*ndel = xdel;
1666126258Smlaier	return (0);
1667126258Smlaier}
1668126258Smlaier
1669126258Smlaierint
1670126258Smlaierpfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
1671126258Smlaier    int *nadd, int *naddr, u_int32_t ticket, int flags)
1672126258Smlaier{
1673126258Smlaier	struct pfr_ktableworkq	 tableq;
1674126258Smlaier	struct pfr_kentryworkq	 addrq;
1675126258Smlaier	struct pfr_ktable	*kt, *rt, *shadow, key;
1676126258Smlaier	struct pfr_kentry	*p;
1677126258Smlaier	struct pfr_addr		 ad;
1678126258Smlaier	struct pf_ruleset	*rs;
1679126258Smlaier	int			 i, rv, xadd = 0, xaddr = 0;
1680126258Smlaier
1681223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO);
1682126258Smlaier	if (size && !(flags & PFR_FLAG_ADDRSTOO))
1683126258Smlaier		return (EINVAL);
1684130613Smlaier	if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK,
1685130613Smlaier	    flags & PFR_FLAG_USERIOCTL))
1686126258Smlaier		return (EINVAL);
1687145836Smlaier	rs = pf_find_ruleset(tbl->pfrt_anchor);
1688126258Smlaier	if (rs == NULL || !rs->topen || ticket != rs->tticket)
1689126258Smlaier		return (EBUSY);
1690126258Smlaier	tbl->pfrt_flags |= PFR_TFLAG_INACTIVE;
1691126258Smlaier	SLIST_INIT(&tableq);
1692126258Smlaier	kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl);
1693126258Smlaier	if (kt == NULL) {
1694223637Sbz		kt = pfr_create_ktable(tbl, 0, 1,
1695223637Sbz		    !(flags & PFR_FLAG_USERIOCTL));
1696126258Smlaier		if (kt == NULL)
1697126258Smlaier			return (ENOMEM);
1698126258Smlaier		SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq);
1699126258Smlaier		xadd++;
1700126258Smlaier		if (!tbl->pfrt_anchor[0])
1701126258Smlaier			goto _skip;
1702126258Smlaier
1703126258Smlaier		/* find or create root table */
1704126258Smlaier		bzero(&key, sizeof(key));
1705126258Smlaier		strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name));
1706126258Smlaier		rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
1707126258Smlaier		if (rt != NULL) {
1708126258Smlaier			kt->pfrkt_root = rt;
1709126258Smlaier			goto _skip;
1710126258Smlaier		}
1711223637Sbz		rt = pfr_create_ktable(&key.pfrkt_t, 0, 1,
1712223637Sbz		    !(flags & PFR_FLAG_USERIOCTL));
1713126258Smlaier		if (rt == NULL) {
1714126258Smlaier			pfr_destroy_ktables(&tableq, 0);
1715126258Smlaier			return (ENOMEM);
1716126258Smlaier		}
1717126258Smlaier		SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq);
1718126258Smlaier		kt->pfrkt_root = rt;
1719126258Smlaier	} else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE))
1720126258Smlaier		xadd++;
1721126258Smlaier_skip:
1722223637Sbz	shadow = pfr_create_ktable(tbl, 0, 0, !(flags & PFR_FLAG_USERIOCTL));
1723126258Smlaier	if (shadow == NULL) {
1724126258Smlaier		pfr_destroy_ktables(&tableq, 0);
1725126258Smlaier		return (ENOMEM);
1726126258Smlaier	}
1727126258Smlaier	SLIST_INIT(&addrq);
1728126258Smlaier	for (i = 0; i < size; i++) {
1729223637Sbz		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
1730126261Smlaier			senderr(EFAULT);
1731126258Smlaier		if (pfr_validate_addr(&ad))
1732126258Smlaier			senderr(EINVAL);
1733126258Smlaier		if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
1734126258Smlaier			continue;
1735145836Smlaier		p = pfr_create_kentry(&ad, 0);
1736126258Smlaier		if (p == NULL)
1737126258Smlaier			senderr(ENOMEM);
1738126258Smlaier		if (pfr_route_kentry(shadow, p)) {
1739126258Smlaier			pfr_destroy_kentry(p);
1740126258Smlaier			continue;
1741126258Smlaier		}
1742126258Smlaier		SLIST_INSERT_HEAD(&addrq, p, pfrke_workq);
1743126258Smlaier		xaddr++;
1744126258Smlaier	}
1745126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
1746126258Smlaier		if (kt->pfrkt_shadow != NULL)
1747126258Smlaier			pfr_destroy_ktable(kt->pfrkt_shadow, 1);
1748126258Smlaier		kt->pfrkt_flags |= PFR_TFLAG_INACTIVE;
1749126258Smlaier		pfr_insert_ktables(&tableq);
1750126258Smlaier		shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ?
1751126258Smlaier		    xaddr : NO_ADDRESSES;
1752126258Smlaier		kt->pfrkt_shadow = shadow;
1753126258Smlaier	} else {
1754126258Smlaier		pfr_clean_node_mask(shadow, &addrq);
1755126258Smlaier		pfr_destroy_ktable(shadow, 0);
1756126258Smlaier		pfr_destroy_ktables(&tableq, 0);
1757126258Smlaier		pfr_destroy_kentries(&addrq);
1758126258Smlaier	}
1759126258Smlaier	if (nadd != NULL)
1760126258Smlaier		*nadd = xadd;
1761126258Smlaier	if (naddr != NULL)
1762126258Smlaier		*naddr = xaddr;
1763126258Smlaier	return (0);
1764126258Smlaier_bad:
1765126258Smlaier	pfr_destroy_ktable(shadow, 0);
1766126258Smlaier	pfr_destroy_ktables(&tableq, 0);
1767126258Smlaier	pfr_destroy_kentries(&addrq);
1768126258Smlaier	return (rv);
1769126258Smlaier}
1770126258Smlaier
1771126258Smlaierint
1772130613Smlaierpfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags)
1773130613Smlaier{
1774130613Smlaier	struct pfr_ktableworkq	 workq;
1775130613Smlaier	struct pfr_ktable	*p;
1776130613Smlaier	struct pf_ruleset	*rs;
1777130613Smlaier	int			 xdel = 0;
1778130613Smlaier
1779223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
1780145836Smlaier	rs = pf_find_ruleset(trs->pfrt_anchor);
1781130613Smlaier	if (rs == NULL || !rs->topen || ticket != rs->tticket)
1782130613Smlaier		return (0);
1783130613Smlaier	SLIST_INIT(&workq);
1784130613Smlaier	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1785130613Smlaier		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1786130613Smlaier		    pfr_skip_table(trs, p, 0))
1787130613Smlaier			continue;
1788130613Smlaier		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
1789130613Smlaier		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1790130613Smlaier		xdel++;
1791130613Smlaier	}
1792130613Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
1793130613Smlaier		pfr_setflags_ktables(&workq);
1794130613Smlaier		rs->topen = 0;
1795130613Smlaier		pf_remove_if_empty_ruleset(rs);
1796130613Smlaier	}
1797130613Smlaier	if (ndel != NULL)
1798130613Smlaier		*ndel = xdel;
1799130613Smlaier	return (0);
1800130613Smlaier}
1801130613Smlaier
1802130613Smlaierint
1803126258Smlaierpfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
1804126258Smlaier    int *nchange, int flags)
1805126258Smlaier{
1806145836Smlaier	struct pfr_ktable	*p, *q;
1807126258Smlaier	struct pfr_ktableworkq	 workq;
1808126258Smlaier	struct pf_ruleset	*rs;
1809223637Sbz	int			 s, xadd = 0, xchange = 0;
1810145836Smlaier	long			 tzero = time_second;
1811126258Smlaier
1812223637Sbz	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
1813145836Smlaier	rs = pf_find_ruleset(trs->pfrt_anchor);
1814126258Smlaier	if (rs == NULL || !rs->topen || ticket != rs->tticket)
1815126258Smlaier		return (EBUSY);
1816126258Smlaier
1817126258Smlaier	SLIST_INIT(&workq);
1818126258Smlaier	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
1819126258Smlaier		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
1820126258Smlaier		    pfr_skip_table(trs, p, 0))
1821126258Smlaier			continue;
1822126258Smlaier		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
1823126258Smlaier		if (p->pfrkt_flags & PFR_TFLAG_ACTIVE)
1824126258Smlaier			xchange++;
1825126258Smlaier		else
1826126258Smlaier			xadd++;
1827126258Smlaier	}
1828126258Smlaier
1829126258Smlaier	if (!(flags & PFR_FLAG_DUMMY)) {
1830126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1831126258Smlaier			s = splsoftnet();
1832145836Smlaier		for (p = SLIST_FIRST(&workq); p != NULL; p = q) {
1833145836Smlaier			q = SLIST_NEXT(p, pfrkt_workq);
1834126258Smlaier			pfr_commit_ktable(p, tzero);
1835145836Smlaier		}
1836126258Smlaier		if (flags & PFR_FLAG_ATOMIC)
1837126258Smlaier			splx(s);
1838126258Smlaier		rs->topen = 0;
1839126258Smlaier		pf_remove_if_empty_ruleset(rs);
1840126258Smlaier	}
1841126258Smlaier	if (nadd != NULL)
1842126258Smlaier		*nadd = xadd;
1843126258Smlaier	if (nchange != NULL)
1844126258Smlaier		*nchange = xchange;
1845126258Smlaier
1846126258Smlaier	return (0);
1847126258Smlaier}
1848126258Smlaier
1849126258Smlaiervoid
1850126258Smlaierpfr_commit_ktable(struct pfr_ktable *kt, long tzero)
1851126258Smlaier{
1852126258Smlaier	struct pfr_ktable	*shadow = kt->pfrkt_shadow;
1853126258Smlaier	int			 nflags;
1854126258Smlaier
1855126258Smlaier	if (shadow->pfrkt_cnt == NO_ADDRESSES) {
1856126258Smlaier		if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
1857126258Smlaier			pfr_clstats_ktable(kt, tzero, 1);
1858126258Smlaier	} else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) {
1859126258Smlaier		/* kt might contain addresses */
1860126258Smlaier		struct pfr_kentryworkq	 addrq, addq, changeq, delq, garbageq;
1861126258Smlaier		struct pfr_kentry	*p, *q, *next;
1862126258Smlaier		struct pfr_addr		 ad;
1863126258Smlaier
1864126258Smlaier		pfr_enqueue_addrs(shadow, &addrq, NULL, 0);
1865126258Smlaier		pfr_mark_addrs(kt);
1866126258Smlaier		SLIST_INIT(&addq);
1867126258Smlaier		SLIST_INIT(&changeq);
1868126258Smlaier		SLIST_INIT(&delq);
1869126258Smlaier		SLIST_INIT(&garbageq);
1870126258Smlaier		pfr_clean_node_mask(shadow, &addrq);
1871126258Smlaier		for (p = SLIST_FIRST(&addrq); p != NULL; p = next) {
1872126258Smlaier			next = SLIST_NEXT(p, pfrke_workq);	/* XXX */
1873126258Smlaier			pfr_copyout_addr(&ad, p);
1874126258Smlaier			q = pfr_lookup_addr(kt, &ad, 1);
1875126258Smlaier			if (q != NULL) {
1876126258Smlaier				if (q->pfrke_not != p->pfrke_not)
1877126258Smlaier					SLIST_INSERT_HEAD(&changeq, q,
1878126258Smlaier					    pfrke_workq);
1879126258Smlaier				q->pfrke_mark = 1;
1880126258Smlaier				SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq);
1881126258Smlaier			} else {
1882126258Smlaier				p->pfrke_tzero = tzero;
1883126258Smlaier				SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
1884126258Smlaier			}
1885126258Smlaier		}
1886126258Smlaier		pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY);
1887126258Smlaier		pfr_insert_kentries(kt, &addq, tzero);
1888126258Smlaier		pfr_remove_kentries(kt, &delq);
1889126258Smlaier		pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
1890126258Smlaier		pfr_destroy_kentries(&garbageq);
1891126258Smlaier	} else {
1892126258Smlaier		/* kt cannot contain addresses */
1893126258Smlaier		SWAP(struct radix_node_head *, kt->pfrkt_ip4,
1894126258Smlaier		    shadow->pfrkt_ip4);
1895126258Smlaier		SWAP(struct radix_node_head *, kt->pfrkt_ip6,
1896126258Smlaier		    shadow->pfrkt_ip6);
1897126258Smlaier		SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt);
1898126258Smlaier		pfr_clstats_ktable(kt, tzero, 1);
1899126258Smlaier	}
1900126258Smlaier	nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) |
1901126258Smlaier	    (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE)
1902126258Smlaier		& ~PFR_TFLAG_INACTIVE;
1903126258Smlaier	pfr_destroy_ktable(shadow, 0);
1904126258Smlaier	kt->pfrkt_shadow = NULL;
1905126258Smlaier	pfr_setflags_ktable(kt, nflags);
1906126258Smlaier}
1907126258Smlaier
1908126258Smlaierint
1909130613Smlaierpfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved)
1910126258Smlaier{
1911126258Smlaier	int i;
1912126258Smlaier
1913126258Smlaier	if (!tbl->pfrt_name[0])
1914126258Smlaier		return (-1);
1915130613Smlaier	if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR))
1916130613Smlaier		 return (-1);
1917126258Smlaier	if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1])
1918126258Smlaier		return (-1);
1919126258Smlaier	for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++)
1920126258Smlaier		if (tbl->pfrt_name[i])
1921126258Smlaier			return (-1);
1922145836Smlaier	if (pfr_fix_anchor(tbl->pfrt_anchor))
1923145836Smlaier		return (-1);
1924126258Smlaier	if (tbl->pfrt_flags & ~allowedflags)
1925126258Smlaier		return (-1);
1926126258Smlaier	return (0);
1927126258Smlaier}
1928126258Smlaier
1929145836Smlaier/*
1930145836Smlaier * Rewrite anchors referenced by tables to remove slashes
1931145836Smlaier * and check for validity.
1932145836Smlaier */
1933126258Smlaierint
1934145836Smlaierpfr_fix_anchor(char *anchor)
1935145836Smlaier{
1936145836Smlaier	size_t siz = MAXPATHLEN;
1937145836Smlaier	int i;
1938145836Smlaier
1939145836Smlaier	if (anchor[0] == '/') {
1940145836Smlaier		char *path;
1941145836Smlaier		int off;
1942145836Smlaier
1943145836Smlaier		path = anchor;
1944145836Smlaier		off = 1;
1945145836Smlaier		while (*++path == '/')
1946145836Smlaier			off++;
1947145836Smlaier		bcopy(path, anchor, siz - off);
1948145836Smlaier		memset(anchor + siz - off, 0, off);
1949145836Smlaier	}
1950145836Smlaier	if (anchor[siz - 1])
1951145836Smlaier		return (-1);
1952145836Smlaier	for (i = strlen(anchor); i < siz; i++)
1953145836Smlaier		if (anchor[i])
1954145836Smlaier			return (-1);
1955145836Smlaier	return (0);
1956145836Smlaier}
1957145836Smlaier
1958145836Smlaierint
1959126258Smlaierpfr_table_count(struct pfr_table *filter, int flags)
1960126258Smlaier{
1961126258Smlaier	struct pf_ruleset *rs;
1962126258Smlaier
1963126258Smlaier	if (flags & PFR_FLAG_ALLRSETS)
1964126258Smlaier		return (pfr_ktable_cnt);
1965145836Smlaier	if (filter->pfrt_anchor[0]) {
1966145836Smlaier		rs = pf_find_ruleset(filter->pfrt_anchor);
1967126258Smlaier		return ((rs != NULL) ? rs->tables : -1);
1968126258Smlaier	}
1969126258Smlaier	return (pf_main_ruleset.tables);
1970126258Smlaier}
1971126258Smlaier
1972126258Smlaierint
1973126258Smlaierpfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags)
1974126258Smlaier{
1975126258Smlaier	if (flags & PFR_FLAG_ALLRSETS)
1976126258Smlaier		return (0);
1977145836Smlaier	if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor))
1978126258Smlaier		return (1);
1979126258Smlaier	return (0);
1980126258Smlaier}
1981126258Smlaier
1982126258Smlaiervoid
1983126258Smlaierpfr_insert_ktables(struct pfr_ktableworkq *workq)
1984126258Smlaier{
1985126258Smlaier	struct pfr_ktable	*p;
1986126258Smlaier
1987126258Smlaier	SLIST_FOREACH(p, workq, pfrkt_workq)
1988126258Smlaier		pfr_insert_ktable(p);
1989126258Smlaier}
1990126258Smlaier
1991126258Smlaiervoid
1992126258Smlaierpfr_insert_ktable(struct pfr_ktable *kt)
1993126258Smlaier{
1994126258Smlaier	RB_INSERT(pfr_ktablehead, &pfr_ktables, kt);
1995126258Smlaier	pfr_ktable_cnt++;
1996126258Smlaier	if (kt->pfrkt_root != NULL)
1997126258Smlaier		if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++)
1998126258Smlaier			pfr_setflags_ktable(kt->pfrkt_root,
1999126258Smlaier			    kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR);
2000126258Smlaier}
2001126258Smlaier
2002126258Smlaiervoid
2003126258Smlaierpfr_setflags_ktables(struct pfr_ktableworkq *workq)
2004126258Smlaier{
2005145836Smlaier	struct pfr_ktable	*p, *q;
2006126258Smlaier
2007145836Smlaier	for (p = SLIST_FIRST(workq); p; p = q) {
2008145836Smlaier		q = SLIST_NEXT(p, pfrkt_workq);
2009126258Smlaier		pfr_setflags_ktable(p, p->pfrkt_nflags);
2010145836Smlaier	}
2011126258Smlaier}
2012126258Smlaier
2013126258Smlaiervoid
2014126258Smlaierpfr_setflags_ktable(struct pfr_ktable *kt, int newf)
2015126258Smlaier{
2016126258Smlaier	struct pfr_kentryworkq	addrq;
2017126258Smlaier
2018126258Smlaier	if (!(newf & PFR_TFLAG_REFERENCED) &&
2019126258Smlaier	    !(newf & PFR_TFLAG_PERSIST))
2020126258Smlaier		newf &= ~PFR_TFLAG_ACTIVE;
2021126258Smlaier	if (!(newf & PFR_TFLAG_ACTIVE))
2022126258Smlaier		newf &= ~PFR_TFLAG_USRMASK;
2023126258Smlaier	if (!(newf & PFR_TFLAG_SETMASK)) {
2024126258Smlaier		RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt);
2025126258Smlaier		if (kt->pfrkt_root != NULL)
2026126258Smlaier			if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR])
2027126258Smlaier				pfr_setflags_ktable(kt->pfrkt_root,
2028126258Smlaier				    kt->pfrkt_root->pfrkt_flags &
2029126258Smlaier					~PFR_TFLAG_REFDANCHOR);
2030126258Smlaier		pfr_destroy_ktable(kt, 1);
2031126258Smlaier		pfr_ktable_cnt--;
2032126258Smlaier		return;
2033126258Smlaier	}
2034126258Smlaier	if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) {
2035126258Smlaier		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
2036126258Smlaier		pfr_remove_kentries(kt, &addrq);
2037126258Smlaier	}
2038126258Smlaier	if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) {
2039126258Smlaier		pfr_destroy_ktable(kt->pfrkt_shadow, 1);
2040126258Smlaier		kt->pfrkt_shadow = NULL;
2041126258Smlaier	}
2042126258Smlaier	kt->pfrkt_flags = newf;
2043126258Smlaier}
2044126258Smlaier
2045126258Smlaiervoid
2046126258Smlaierpfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse)
2047126258Smlaier{
2048126258Smlaier	struct pfr_ktable	*p;
2049126258Smlaier
2050126258Smlaier	SLIST_FOREACH(p, workq, pfrkt_workq)
2051126258Smlaier		pfr_clstats_ktable(p, tzero, recurse);
2052126258Smlaier}
2053126258Smlaier
2054126258Smlaiervoid
2055126258Smlaierpfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse)
2056126258Smlaier{
2057126258Smlaier	struct pfr_kentryworkq	 addrq;
2058126258Smlaier	int			 s;
2059126258Smlaier
2060126258Smlaier	if (recurse) {
2061126258Smlaier		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
2062126258Smlaier		pfr_clstats_kentries(&addrq, tzero, 0);
2063126258Smlaier	}
2064126258Smlaier	s = splsoftnet();
2065126258Smlaier	bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets));
2066126258Smlaier	bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes));
2067126258Smlaier	kt->pfrkt_match = kt->pfrkt_nomatch = 0;
2068126258Smlaier	splx(s);
2069126258Smlaier	kt->pfrkt_tzero = tzero;
2070126258Smlaier}
2071126258Smlaier
2072126258Smlaierstruct pfr_ktable *
2073223637Sbzpfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset,
2074223637Sbz    int intr)
2075126258Smlaier{
2076126258Smlaier	struct pfr_ktable	*kt;
2077126258Smlaier	struct pf_ruleset	*rs;
2078126258Smlaier
2079223637Sbz#ifdef __FreeBSD__
2080238600Sglebius	kt = pool_get(&V_pfr_ktable_pl, PR_NOWAIT|PR_ZERO);
2081223637Sbz#else
2082238600Sglebius	if (intr)
2083223637Sbz		kt = pool_get(&pfr_ktable_pl, PR_NOWAIT|PR_ZERO|PR_LIMITFAIL);
2084223637Sbz	else
2085223637Sbz		kt = pool_get(&pfr_ktable_pl, PR_WAITOK|PR_ZERO|PR_LIMITFAIL);
2086223637Sbz#endif
2087126258Smlaier	if (kt == NULL)
2088126258Smlaier		return (NULL);
2089126258Smlaier	kt->pfrkt_t = *tbl;
2090126258Smlaier
2091126258Smlaier	if (attachruleset) {
2092145836Smlaier		rs = pf_find_or_create_ruleset(tbl->pfrt_anchor);
2093126258Smlaier		if (!rs) {
2094126258Smlaier			pfr_destroy_ktable(kt, 0);
2095126258Smlaier			return (NULL);
2096126258Smlaier		}
2097126258Smlaier		kt->pfrkt_rs = rs;
2098126258Smlaier		rs->tables++;
2099126258Smlaier	}
2100126258Smlaier
2101126258Smlaier	if (!rn_inithead((void **)&kt->pfrkt_ip4,
2102126258Smlaier	    offsetof(struct sockaddr_in, sin_addr) * 8) ||
2103126258Smlaier	    !rn_inithead((void **)&kt->pfrkt_ip6,
2104126258Smlaier	    offsetof(struct sockaddr_in6, sin6_addr) * 8)) {
2105126258Smlaier		pfr_destroy_ktable(kt, 0);
2106126258Smlaier		return (NULL);
2107126258Smlaier	}
2108126258Smlaier	kt->pfrkt_tzero = tzero;
2109126258Smlaier
2110126258Smlaier	return (kt);
2111126258Smlaier}
2112126258Smlaier
2113126258Smlaiervoid
2114126258Smlaierpfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr)
2115126258Smlaier{
2116126258Smlaier	struct pfr_ktable	*p, *q;
2117126258Smlaier
2118126258Smlaier	for (p = SLIST_FIRST(workq); p; p = q) {
2119126258Smlaier		q = SLIST_NEXT(p, pfrkt_workq);
2120126258Smlaier		pfr_destroy_ktable(p, flushaddr);
2121126258Smlaier	}
2122126258Smlaier}
2123126258Smlaier
2124126258Smlaiervoid
2125126258Smlaierpfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
2126126258Smlaier{
2127126258Smlaier	struct pfr_kentryworkq	 addrq;
2128126258Smlaier
2129126258Smlaier	if (flushaddr) {
2130126258Smlaier		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
2131126258Smlaier		pfr_clean_node_mask(kt, &addrq);
2132126258Smlaier		pfr_destroy_kentries(&addrq);
2133126258Smlaier	}
2134126261Smlaier#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
2135126261Smlaier	if (kt->pfrkt_ip4 != NULL) {
2136126261Smlaier		RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip4);
2137126261Smlaier		free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
2138126261Smlaier	}
2139126261Smlaier	if (kt->pfrkt_ip6 != NULL) {
2140126261Smlaier		RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip6);
2141126261Smlaier		free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
2142126261Smlaier	}
2143126261Smlaier#else
2144126258Smlaier	if (kt->pfrkt_ip4 != NULL)
2145126258Smlaier		free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
2146126258Smlaier	if (kt->pfrkt_ip6 != NULL)
2147126258Smlaier		free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
2148126261Smlaier#endif
2149126258Smlaier	if (kt->pfrkt_shadow != NULL)
2150126258Smlaier		pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
2151126258Smlaier	if (kt->pfrkt_rs != NULL) {
2152126258Smlaier		kt->pfrkt_rs->tables--;
2153126258Smlaier		pf_remove_if_empty_ruleset(kt->pfrkt_rs);
2154126258Smlaier	}
2155223637Sbz#ifdef __FreeBSD__
2156223637Sbz	pool_put(&V_pfr_ktable_pl, kt);
2157223637Sbz#else
2158126258Smlaier	pool_put(&pfr_ktable_pl, kt);
2159223637Sbz#endif
2160126258Smlaier}
2161126258Smlaier
2162126258Smlaierint
2163126258Smlaierpfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q)
2164126258Smlaier{
2165126258Smlaier	int d;
2166126258Smlaier
2167126258Smlaier	if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE)))
2168126258Smlaier		return (d);
2169145836Smlaier	return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor));
2170126258Smlaier}
2171126258Smlaier
2172126258Smlaierstruct pfr_ktable *
2173126258Smlaierpfr_lookup_table(struct pfr_table *tbl)
2174126258Smlaier{
2175126258Smlaier	/* struct pfr_ktable start like a struct pfr_table */
2176130613Smlaier	return (RB_FIND(pfr_ktablehead, &pfr_ktables,
2177130613Smlaier	    (struct pfr_ktable *)tbl));
2178126258Smlaier}
2179126258Smlaier
2180126258Smlaierint
2181126258Smlaierpfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
2182126258Smlaier{
2183126258Smlaier	struct pfr_kentry	*ke = NULL;
2184126258Smlaier	int			 match;
2185126258Smlaier
2186126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
2187126258Smlaier		kt = kt->pfrkt_root;
2188126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2189130613Smlaier		return (0);
2190126258Smlaier
2191126258Smlaier	switch (af) {
2192145836Smlaier#ifdef INET
2193126258Smlaier	case AF_INET:
2194223637Sbz#ifdef __FreeBSD__
2195223637Sbz		V_pfr_sin.sin_addr.s_addr = a->addr32[0];
2196223637Sbz		ke = (struct pfr_kentry *)rn_match(&V_pfr_sin, kt->pfrkt_ip4);
2197223637Sbz#else
2198126258Smlaier		pfr_sin.sin_addr.s_addr = a->addr32[0];
2199126258Smlaier		ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
2200223637Sbz#endif
2201126258Smlaier		if (ke && KENTRY_RNF_ROOT(ke))
2202126258Smlaier			ke = NULL;
2203126258Smlaier		break;
2204145836Smlaier#endif /* INET */
2205145836Smlaier#ifdef INET6
2206126258Smlaier	case AF_INET6:
2207223637Sbz#ifdef __FreeBSD__
2208223637Sbz		bcopy(a, &V_pfr_sin6.sin6_addr, sizeof(V_pfr_sin6.sin6_addr));
2209223637Sbz		ke = (struct pfr_kentry *)rn_match(&V_pfr_sin6, kt->pfrkt_ip6);
2210223637Sbz#else
2211126258Smlaier		bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
2212126258Smlaier		ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
2213223637Sbz#endif
2214126258Smlaier		if (ke && KENTRY_RNF_ROOT(ke))
2215126258Smlaier			ke = NULL;
2216126258Smlaier		break;
2217145836Smlaier#endif /* INET6 */
2218126258Smlaier	}
2219126258Smlaier	match = (ke && !ke->pfrke_not);
2220126258Smlaier	if (match)
2221126258Smlaier		kt->pfrkt_match++;
2222126258Smlaier	else
2223126258Smlaier		kt->pfrkt_nomatch++;
2224126258Smlaier	return (match);
2225126258Smlaier}
2226126258Smlaier
2227126258Smlaiervoid
2228126258Smlaierpfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
2229126258Smlaier    u_int64_t len, int dir_out, int op_pass, int notrule)
2230126258Smlaier{
2231126258Smlaier	struct pfr_kentry	*ke = NULL;
2232126258Smlaier
2233126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
2234126258Smlaier		kt = kt->pfrkt_root;
2235126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2236126258Smlaier		return;
2237126258Smlaier
2238126258Smlaier	switch (af) {
2239145836Smlaier#ifdef INET
2240126258Smlaier	case AF_INET:
2241223637Sbz#ifdef __FreeBSD__
2242223637Sbz		V_pfr_sin.sin_addr.s_addr = a->addr32[0];
2243223637Sbz		ke = (struct pfr_kentry *)rn_match(&V_pfr_sin, kt->pfrkt_ip4);
2244223637Sbz#else
2245126258Smlaier		pfr_sin.sin_addr.s_addr = a->addr32[0];
2246126258Smlaier		ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
2247223637Sbz#endif
2248126258Smlaier		if (ke && KENTRY_RNF_ROOT(ke))
2249126258Smlaier			ke = NULL;
2250126258Smlaier		break;
2251145836Smlaier#endif /* INET */
2252145836Smlaier#ifdef INET6
2253126258Smlaier	case AF_INET6:
2254223637Sbz#ifdef __FreeBSD__
2255223637Sbz		bcopy(a, &V_pfr_sin6.sin6_addr, sizeof(V_pfr_sin6.sin6_addr));
2256223637Sbz		ke = (struct pfr_kentry *)rn_match(&V_pfr_sin6, kt->pfrkt_ip6);
2257223637Sbz#else
2258126258Smlaier		bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
2259126258Smlaier		ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
2260223637Sbz#endif
2261126258Smlaier		if (ke && KENTRY_RNF_ROOT(ke))
2262126258Smlaier			ke = NULL;
2263126258Smlaier		break;
2264145836Smlaier#endif /* INET6 */
2265145836Smlaier	default:
2266145836Smlaier		;
2267126258Smlaier	}
2268126258Smlaier	if ((ke == NULL || ke->pfrke_not) != notrule) {
2269126258Smlaier		if (op_pass != PFR_OP_PASS)
2270126258Smlaier			printf("pfr_update_stats: assertion failed.\n");
2271126258Smlaier		op_pass = PFR_OP_XPASS;
2272126258Smlaier	}
2273126258Smlaier	kt->pfrkt_packets[dir_out][op_pass]++;
2274126258Smlaier	kt->pfrkt_bytes[dir_out][op_pass] += len;
2275223637Sbz	if (ke != NULL && op_pass != PFR_OP_XPASS &&
2276223637Sbz	    (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) {
2277223637Sbz		if (ke->pfrke_counters == NULL)
2278223637Sbz#ifdef __FreeBSD__
2279223637Sbz			ke->pfrke_counters = pool_get(&V_pfr_kcounters_pl,
2280223637Sbz#else
2281223637Sbz			ke->pfrke_counters = pool_get(&pfr_kcounters_pl,
2282223637Sbz#endif
2283223637Sbz			    PR_NOWAIT | PR_ZERO);
2284223637Sbz		if (ke->pfrke_counters != NULL) {
2285223637Sbz			ke->pfrke_counters->pfrkc_packets[dir_out][op_pass]++;
2286223637Sbz			ke->pfrke_counters->pfrkc_bytes[dir_out][op_pass] += len;
2287223637Sbz		}
2288126258Smlaier	}
2289126258Smlaier}
2290126258Smlaier
2291126258Smlaierstruct pfr_ktable *
2292223637Sbzpfr_attach_table(struct pf_ruleset *rs, char *name, int intr)
2293126258Smlaier{
2294126258Smlaier	struct pfr_ktable	*kt, *rt;
2295126258Smlaier	struct pfr_table	 tbl;
2296126258Smlaier	struct pf_anchor	*ac = rs->anchor;
2297126258Smlaier
2298126258Smlaier	bzero(&tbl, sizeof(tbl));
2299126258Smlaier	strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
2300145836Smlaier	if (ac != NULL)
2301171168Smlaier		strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
2302126258Smlaier	kt = pfr_lookup_table(&tbl);
2303126258Smlaier	if (kt == NULL) {
2304223637Sbz		kt = pfr_create_ktable(&tbl, time_second, 1, intr);
2305126258Smlaier		if (kt == NULL)
2306126258Smlaier			return (NULL);
2307126258Smlaier		if (ac != NULL) {
2308126258Smlaier			bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor));
2309126258Smlaier			rt = pfr_lookup_table(&tbl);
2310126258Smlaier			if (rt == NULL) {
2311223637Sbz				rt = pfr_create_ktable(&tbl, 0, 1, intr);
2312126258Smlaier				if (rt == NULL) {
2313126258Smlaier					pfr_destroy_ktable(kt, 0);
2314126258Smlaier					return (NULL);
2315126258Smlaier				}
2316126258Smlaier				pfr_insert_ktable(rt);
2317126258Smlaier			}
2318126258Smlaier			kt->pfrkt_root = rt;
2319126258Smlaier		}
2320126258Smlaier		pfr_insert_ktable(kt);
2321126258Smlaier	}
2322126258Smlaier	if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++)
2323126258Smlaier		pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED);
2324130613Smlaier	return (kt);
2325126258Smlaier}
2326126258Smlaier
2327126258Smlaiervoid
2328126258Smlaierpfr_detach_table(struct pfr_ktable *kt)
2329126258Smlaier{
2330126258Smlaier	if (kt->pfrkt_refcnt[PFR_REFCNT_RULE] <= 0)
2331126258Smlaier		printf("pfr_detach_table: refcount = %d.\n",
2332126258Smlaier		    kt->pfrkt_refcnt[PFR_REFCNT_RULE]);
2333126258Smlaier	else if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE])
2334126258Smlaier		pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED);
2335126258Smlaier}
2336126258Smlaier
2337126258Smlaierint
2338126258Smlaierpfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
2339126258Smlaier    struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af)
2340126258Smlaier{
2341223637Sbz#ifdef __FreeBSD__
2342145836Smlaier	struct pfr_kentry	*ke, *ke2 = NULL;
2343145836Smlaier	struct pf_addr		*addr = NULL;
2344223637Sbz#else
2345223637Sbz	struct pfr_kentry	*ke, *ke2;
2346223637Sbz	struct pf_addr		*addr;
2347223637Sbz#endif
2348126258Smlaier	union sockaddr_union	 mask;
2349126258Smlaier	int			 idx = -1, use_counter = 0;
2350126258Smlaier
2351223637Sbz#ifdef __FreeBSD__
2352145836Smlaier	if (af == AF_INET)
2353223637Sbz		addr = (struct pf_addr *)&V_pfr_sin.sin_addr;
2354223637Sbz	else if (af == AF_INET6)
2355223637Sbz		addr = (struct pf_addr *)&V_pfr_sin6.sin6_addr;
2356223637Sbz#else
2357223637Sbz	if (af == AF_INET)
2358145836Smlaier		addr = (struct pf_addr *)&pfr_sin.sin_addr;
2359145836Smlaier	else if (af == AF_INET6)
2360145836Smlaier		addr = (struct pf_addr *)&pfr_sin6.sin6_addr;
2361223637Sbz#endif
2362126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
2363126258Smlaier		kt = kt->pfrkt_root;
2364126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
2365126258Smlaier		return (-1);
2366126258Smlaier
2367126258Smlaier	if (pidx != NULL)
2368126258Smlaier		idx = *pidx;
2369126258Smlaier	if (counter != NULL && idx >= 0)
2370126258Smlaier		use_counter = 1;
2371126258Smlaier	if (idx < 0)
2372126258Smlaier		idx = 0;
2373126258Smlaier
2374126258Smlaier_next_block:
2375126258Smlaier	ke = pfr_kentry_byidx(kt, idx, af);
2376223637Sbz	if (ke == NULL) {
2377223637Sbz		kt->pfrkt_nomatch++;
2378126258Smlaier		return (1);
2379223637Sbz	}
2380223637Sbz#ifdef __FreeBSD__
2381223637Sbz	pfr_prepare_network(&V_pfr_mask, af, ke->pfrke_net);
2382223637Sbz#else
2383126258Smlaier	pfr_prepare_network(&pfr_mask, af, ke->pfrke_net);
2384223637Sbz#endif
2385126258Smlaier	*raddr = SUNION2PF(&ke->pfrke_sa, af);
2386223637Sbz#ifdef __FreeBSD__
2387223637Sbz	*rmask = SUNION2PF(&V_pfr_mask, af);
2388223637Sbz#else
2389126258Smlaier	*rmask = SUNION2PF(&pfr_mask, af);
2390223637Sbz#endif
2391126258Smlaier
2392126258Smlaier	if (use_counter) {
2393126258Smlaier		/* is supplied address within block? */
2394126258Smlaier		if (!PF_MATCHA(0, *raddr, *rmask, counter, af)) {
2395126258Smlaier			/* no, go to next block in table */
2396126258Smlaier			idx++;
2397126258Smlaier			use_counter = 0;
2398126258Smlaier			goto _next_block;
2399126258Smlaier		}
2400126258Smlaier		PF_ACPY(addr, counter, af);
2401126258Smlaier	} else {
2402126258Smlaier		/* use first address of block */
2403126258Smlaier		PF_ACPY(addr, *raddr, af);
2404126258Smlaier	}
2405126258Smlaier
2406126258Smlaier	if (!KENTRY_NETWORK(ke)) {
2407126258Smlaier		/* this is a single IP address - no possible nested block */
2408126258Smlaier		PF_ACPY(counter, addr, af);
2409126258Smlaier		*pidx = idx;
2410223637Sbz		kt->pfrkt_match++;
2411126258Smlaier		return (0);
2412126258Smlaier	}
2413126258Smlaier	for (;;) {
2414126258Smlaier		/* we don't want to use a nested block */
2415223637Sbz#ifdef __FreeBSD__
2416145836Smlaier		if (af == AF_INET)
2417223637Sbz			ke2 = (struct pfr_kentry *)rn_match(&V_pfr_sin,
2418223637Sbz			    kt->pfrkt_ip4);
2419223637Sbz		else if (af == AF_INET6)
2420223637Sbz			ke2 = (struct pfr_kentry *)rn_match(&V_pfr_sin6,
2421223637Sbz			    kt->pfrkt_ip6);
2422223637Sbz#else
2423223637Sbz		if (af == AF_INET)
2424145836Smlaier			ke2 = (struct pfr_kentry *)rn_match(&pfr_sin,
2425145836Smlaier			    kt->pfrkt_ip4);
2426145836Smlaier		else if (af == AF_INET6)
2427145836Smlaier			ke2 = (struct pfr_kentry *)rn_match(&pfr_sin6,
2428145836Smlaier			    kt->pfrkt_ip6);
2429223637Sbz#endif
2430126258Smlaier		/* no need to check KENTRY_RNF_ROOT() here */
2431126258Smlaier		if (ke2 == ke) {
2432126258Smlaier			/* lookup return the same block - perfect */
2433126258Smlaier			PF_ACPY(counter, addr, af);
2434126258Smlaier			*pidx = idx;
2435223637Sbz			kt->pfrkt_match++;
2436126258Smlaier			return (0);
2437126258Smlaier		}
2438126258Smlaier
2439126258Smlaier		/* we need to increase the counter past the nested block */
2440126258Smlaier		pfr_prepare_network(&mask, AF_INET, ke2->pfrke_net);
2441223637Sbz#ifdef __FreeBSD__
2442223637Sbz		PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &V_pfr_ffaddr, af);
2443223637Sbz#else
2444126258Smlaier		PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &pfr_ffaddr, af);
2445223637Sbz#endif
2446126258Smlaier		PF_AINC(addr, af);
2447126258Smlaier		if (!PF_MATCHA(0, *raddr, *rmask, addr, af)) {
2448126258Smlaier			/* ok, we reached the end of our main block */
2449126258Smlaier			/* go to next block in table */
2450126258Smlaier			idx++;
2451126258Smlaier			use_counter = 0;
2452126258Smlaier			goto _next_block;
2453126258Smlaier		}
2454126258Smlaier	}
2455126258Smlaier}
2456126258Smlaier
2457126258Smlaierstruct pfr_kentry *
2458126258Smlaierpfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af)
2459126258Smlaier{
2460126258Smlaier	struct pfr_walktree	w;
2461126258Smlaier
2462130613Smlaier	bzero(&w, sizeof(w));
2463130613Smlaier	w.pfrw_op = PFRW_POOL_GET;
2464130613Smlaier	w.pfrw_cnt = idx;
2465126258Smlaier
2466130613Smlaier	switch (af) {
2467145836Smlaier#ifdef INET
2468126258Smlaier	case AF_INET:
2469127145Smlaier#ifdef __FreeBSD__
2470126261Smlaier		kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2471126261Smlaier#else
2472126258Smlaier		rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2473126261Smlaier#endif
2474130613Smlaier		return (w.pfrw_kentry);
2475145836Smlaier#endif /* INET */
2476145836Smlaier#ifdef INET6
2477126258Smlaier	case AF_INET6:
2478127145Smlaier#ifdef __FreeBSD__
2479126261Smlaier		kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2480126261Smlaier#else
2481126258Smlaier		rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2482126261Smlaier#endif
2483130613Smlaier		return (w.pfrw_kentry);
2484145836Smlaier#endif /* INET6 */
2485126258Smlaier	default:
2486130613Smlaier		return (NULL);
2487126258Smlaier	}
2488126258Smlaier}
2489130613Smlaier
2490130613Smlaiervoid
2491130613Smlaierpfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn)
2492130613Smlaier{
2493130613Smlaier	struct pfr_walktree	w;
2494130613Smlaier	int			s;
2495130613Smlaier
2496130613Smlaier	bzero(&w, sizeof(w));
2497130613Smlaier	w.pfrw_op = PFRW_DYNADDR_UPDATE;
2498130613Smlaier	w.pfrw_dyn = dyn;
2499130613Smlaier
2500130613Smlaier	s = splsoftnet();
2501130613Smlaier	dyn->pfid_acnt4 = 0;
2502130613Smlaier	dyn->pfid_acnt6 = 0;
2503130613Smlaier	if (!dyn->pfid_af || dyn->pfid_af == AF_INET)
2504130613Smlaier#ifdef __FreeBSD__
2505130613Smlaier		kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2506130613Smlaier#else
2507130613Smlaier		rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
2508130613Smlaier#endif
2509130613Smlaier	if (!dyn->pfid_af || dyn->pfid_af == AF_INET6)
2510130613Smlaier#ifdef __FreeBSD__
2511130613Smlaier		kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2512130613Smlaier#else
2513130613Smlaier		rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2514130613Smlaier#endif
2515130613Smlaier	splx(s);
2516130613Smlaier}
2517