xref: /dflybsd-src/sys/net/pf/pf_table.c (revision b272101acc636ac635f83d03265ef6a44a3ba51a)
1ed1f0be2SJan Lentfer /*	$OpenBSD: pf_table.c,v 1.78 2008/06/14 03:50:14 art Exp $	*/
202742ec6SJoerg Sonnenberger 
302742ec6SJoerg Sonnenberger /*
4ed1f0be2SJan Lentfer  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
502742ec6SJoerg Sonnenberger  *
602742ec6SJoerg Sonnenberger  * Copyright (c) 2002 Cedric Berger
702742ec6SJoerg Sonnenberger  * All rights reserved.
802742ec6SJoerg Sonnenberger  *
902742ec6SJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
1002742ec6SJoerg Sonnenberger  * modification, are permitted provided that the following conditions
1102742ec6SJoerg Sonnenberger  * are met:
1202742ec6SJoerg Sonnenberger  *
1302742ec6SJoerg Sonnenberger  *    - Redistributions of source code must retain the above copyright
1402742ec6SJoerg Sonnenberger  *      notice, this list of conditions and the following disclaimer.
1502742ec6SJoerg Sonnenberger  *    - Redistributions in binary form must reproduce the above
1602742ec6SJoerg Sonnenberger  *      copyright notice, this list of conditions and the following
1702742ec6SJoerg Sonnenberger  *      disclaimer in the documentation and/or other materials provided
1802742ec6SJoerg Sonnenberger  *      with the distribution.
1902742ec6SJoerg Sonnenberger  *
2002742ec6SJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2102742ec6SJoerg Sonnenberger  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2202742ec6SJoerg Sonnenberger  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2302742ec6SJoerg Sonnenberger  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2402742ec6SJoerg Sonnenberger  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2502742ec6SJoerg Sonnenberger  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2602742ec6SJoerg Sonnenberger  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2702742ec6SJoerg Sonnenberger  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2802742ec6SJoerg Sonnenberger  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2902742ec6SJoerg Sonnenberger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3002742ec6SJoerg Sonnenberger  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3102742ec6SJoerg Sonnenberger  * POSSIBILITY OF SUCH DAMAGE.
3202742ec6SJoerg Sonnenberger  *
3302742ec6SJoerg Sonnenberger  */
3402742ec6SJoerg Sonnenberger 
3502742ec6SJoerg Sonnenberger #include "opt_inet.h"
3602742ec6SJoerg Sonnenberger #include "opt_inet6.h"
3702742ec6SJoerg Sonnenberger 
3802742ec6SJoerg Sonnenberger #include <sys/param.h>
3902742ec6SJoerg Sonnenberger #include <sys/systm.h>
4002742ec6SJoerg Sonnenberger #include <sys/socket.h>
4102742ec6SJoerg Sonnenberger #include <sys/mbuf.h>
4202742ec6SJoerg Sonnenberger #include <sys/kernel.h>
4302742ec6SJoerg Sonnenberger #include <sys/malloc.h>
44cc6e5672SJoerg Sonnenberger #include <sys/thread2.h>
4502742ec6SJoerg Sonnenberger 
4602742ec6SJoerg Sonnenberger #include <net/if.h>
4702742ec6SJoerg Sonnenberger #include <net/route.h>
4802742ec6SJoerg Sonnenberger #include <netinet/in.h>
4902742ec6SJoerg Sonnenberger #include <net/pf/pfvar.h>
5002742ec6SJoerg Sonnenberger 
51315a7da3SJan Lentfer #define ACCEPT_FLAGS(flags, oklist)		\
5202742ec6SJoerg Sonnenberger 	do {					\
5302742ec6SJoerg Sonnenberger 		if ((flags & ~(oklist)) &	\
5402742ec6SJoerg Sonnenberger 		    PFR_FLAG_ALLMASK)		\
5502742ec6SJoerg Sonnenberger 			return (EINVAL);	\
5602742ec6SJoerg Sonnenberger 	} while (0)
5702742ec6SJoerg Sonnenberger 
58315a7da3SJan Lentfer #define COPYIN(from, to, size, flags)		\
5902742ec6SJoerg Sonnenberger 	((flags & PFR_FLAG_USERIOCTL) ?		\
6002742ec6SJoerg Sonnenberger 	copyin((from), (to), (size)) :		\
6102742ec6SJoerg Sonnenberger 	(bcopy((from), (to), (size)), 0))
6202742ec6SJoerg Sonnenberger 
63315a7da3SJan Lentfer #define COPYOUT(from, to, size, flags)		\
6402742ec6SJoerg Sonnenberger 	((flags & PFR_FLAG_USERIOCTL) ?		\
6502742ec6SJoerg Sonnenberger 	copyout((from), (to), (size)) :		\
6602742ec6SJoerg Sonnenberger 	(bcopy((from), (to), (size)), 0))
6702742ec6SJoerg Sonnenberger 
6802742ec6SJoerg Sonnenberger #define	FILLIN_SIN(sin, addr)			\
6902742ec6SJoerg Sonnenberger 	do {					\
7002742ec6SJoerg Sonnenberger 		(sin).sin_len = sizeof(sin);	\
7102742ec6SJoerg Sonnenberger 		(sin).sin_family = AF_INET;	\
7202742ec6SJoerg Sonnenberger 		(sin).sin_addr = (addr);	\
7302742ec6SJoerg Sonnenberger 	} while (0)
7402742ec6SJoerg Sonnenberger 
7502742ec6SJoerg Sonnenberger #define	FILLIN_SIN6(sin6, addr)			\
7602742ec6SJoerg Sonnenberger 	do {					\
7702742ec6SJoerg Sonnenberger 		(sin6).sin6_len = sizeof(sin6);	\
7802742ec6SJoerg Sonnenberger 		(sin6).sin6_family = AF_INET6;	\
7902742ec6SJoerg Sonnenberger 		(sin6).sin6_addr = (addr);	\
8002742ec6SJoerg Sonnenberger 	} while (0)
8102742ec6SJoerg Sonnenberger 
8202742ec6SJoerg Sonnenberger #define SWAP(type, a1, a2)			\
8302742ec6SJoerg Sonnenberger 	do {					\
8402742ec6SJoerg Sonnenberger 		type tmp = a1;			\
8502742ec6SJoerg Sonnenberger 		a1 = a2;			\
8602742ec6SJoerg Sonnenberger 		a2 = tmp;			\
8702742ec6SJoerg Sonnenberger 	} while (0)
8802742ec6SJoerg Sonnenberger 
8902742ec6SJoerg Sonnenberger #define SUNION2PF(su, af) (((af)==AF_INET) ?	\
9002742ec6SJoerg Sonnenberger     (struct pf_addr *)&(su)->sin.sin_addr :	\
9102742ec6SJoerg Sonnenberger     (struct pf_addr *)&(su)->sin6.sin6_addr)
9202742ec6SJoerg Sonnenberger 
9302742ec6SJoerg Sonnenberger #define	AF_BITS(af)		(((af)==AF_INET)?32:128)
9402742ec6SJoerg Sonnenberger #define	ADDR_NETWORK(ad)	((ad)->pfra_net < AF_BITS((ad)->pfra_af))
9502742ec6SJoerg Sonnenberger #define	KENTRY_NETWORK(ke)	((ke)->pfrke_net < AF_BITS((ke)->pfrke_af))
9602742ec6SJoerg Sonnenberger #define KENTRY_RNF_ROOT(ke) \
9702742ec6SJoerg Sonnenberger 		((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0)
9802742ec6SJoerg Sonnenberger 
9902742ec6SJoerg Sonnenberger #define NO_ADDRESSES		(-1)
10002742ec6SJoerg Sonnenberger #define ENQUEUE_UNMARKED_ONLY	(1)
10102742ec6SJoerg Sonnenberger #define INVERT_NEG_FLAG		(1)
10202742ec6SJoerg Sonnenberger 
1031186cbc0SJan Lentfer static MALLOC_DEFINE(M_PFRKTABLEPL, "pfrktable", "pf radix table pool list");
1041186cbc0SJan Lentfer static MALLOC_DEFINE(M_PFRKENTRYPL, "pfrkentry", "pf radix entry pool list");
1051186cbc0SJan Lentfer static MALLOC_DEFINE(M_PFRKENTRYPL2, "pfrkentry2", "pf radix entry 2 pool list");
1061186cbc0SJan Lentfer static MALLOC_DEFINE(M_PFRKCOUNTERSPL, "pfrkcounters", "pf radix counters");
1071186cbc0SJan Lentfer 
10802742ec6SJoerg Sonnenberger struct pfr_walktree {
10902742ec6SJoerg Sonnenberger 	enum pfrw_op {
11002742ec6SJoerg Sonnenberger 		PFRW_MARK,
11102742ec6SJoerg Sonnenberger 		PFRW_SWEEP,
11202742ec6SJoerg Sonnenberger 		PFRW_ENQUEUE,
11302742ec6SJoerg Sonnenberger 		PFRW_GET_ADDRS,
11402742ec6SJoerg Sonnenberger 		PFRW_GET_ASTATS,
11502742ec6SJoerg Sonnenberger 		PFRW_POOL_GET,
11602742ec6SJoerg Sonnenberger 		PFRW_DYNADDR_UPDATE
11702742ec6SJoerg Sonnenberger 	}	 pfrw_op;
11802742ec6SJoerg Sonnenberger 	union {
11902742ec6SJoerg Sonnenberger 		struct pfr_addr		*pfrw1_addr;
12002742ec6SJoerg Sonnenberger 		struct pfr_astats	*pfrw1_astats;
12102742ec6SJoerg Sonnenberger 		struct pfr_kentryworkq	*pfrw1_workq;
12202742ec6SJoerg Sonnenberger 		struct pfr_kentry	*pfrw1_kentry;
12302742ec6SJoerg Sonnenberger 		struct pfi_dynaddr	*pfrw1_dyn;
12402742ec6SJoerg Sonnenberger 	}	 pfrw_1;
12502742ec6SJoerg Sonnenberger 	int	 pfrw_free;
12602742ec6SJoerg Sonnenberger 	int	 pfrw_flags;
12702742ec6SJoerg Sonnenberger };
12802742ec6SJoerg Sonnenberger #define pfrw_addr	pfrw_1.pfrw1_addr
12902742ec6SJoerg Sonnenberger #define pfrw_astats	pfrw_1.pfrw1_astats
13002742ec6SJoerg Sonnenberger #define pfrw_workq	pfrw_1.pfrw1_workq
13102742ec6SJoerg Sonnenberger #define pfrw_kentry	pfrw_1.pfrw1_kentry
13202742ec6SJoerg Sonnenberger #define pfrw_dyn	pfrw_1.pfrw1_dyn
13302742ec6SJoerg Sonnenberger #define pfrw_cnt	pfrw_free
13402742ec6SJoerg Sonnenberger 
13502742ec6SJoerg Sonnenberger #define senderr(e)	do { rv = (e); goto _bad; } while (0)
1361186cbc0SJan Lentfer struct malloc_type	*pfr_ktable_pl;
1371186cbc0SJan Lentfer struct malloc_type	*pfr_kentry_pl;
1381186cbc0SJan Lentfer struct malloc_type	*pfr_kentry_pl2;
139d66d8bc0SMatthew Dillon static struct pf_addr	 pfr_ffaddr;		/* constant after setup */
14002742ec6SJoerg Sonnenberger 
14102742ec6SJoerg Sonnenberger void			 pfr_copyout_addr(struct pfr_addr *,
14202742ec6SJoerg Sonnenberger 			    struct pfr_kentry *ke);
14302742ec6SJoerg Sonnenberger int			 pfr_validate_addr(struct pfr_addr *);
14402742ec6SJoerg Sonnenberger void			 pfr_enqueue_addrs(struct pfr_ktable *,
14502742ec6SJoerg Sonnenberger 			    struct pfr_kentryworkq *, int *, int);
14602742ec6SJoerg Sonnenberger void			 pfr_mark_addrs(struct pfr_ktable *);
14702742ec6SJoerg Sonnenberger struct pfr_kentry	*pfr_lookup_addr(struct pfr_ktable *,
14802742ec6SJoerg Sonnenberger 			    struct pfr_addr *, int);
14970224baaSJan Lentfer struct pfr_kentry	*pfr_create_kentry(struct pfr_addr *, int);
15002742ec6SJoerg Sonnenberger void			 pfr_destroy_kentries(struct pfr_kentryworkq *);
15102742ec6SJoerg Sonnenberger void			 pfr_destroy_kentry(struct pfr_kentry *);
15202742ec6SJoerg Sonnenberger void			 pfr_insert_kentries(struct pfr_ktable *,
15302742ec6SJoerg Sonnenberger 			    struct pfr_kentryworkq *, long);
15402742ec6SJoerg Sonnenberger void			 pfr_remove_kentries(struct pfr_ktable *,
15502742ec6SJoerg Sonnenberger 			    struct pfr_kentryworkq *);
15602742ec6SJoerg Sonnenberger void			 pfr_clstats_kentries(struct pfr_kentryworkq *, long,
15702742ec6SJoerg Sonnenberger 			    int);
15802742ec6SJoerg Sonnenberger void			 pfr_reset_feedback(struct pfr_addr *, int, int);
15902742ec6SJoerg Sonnenberger void			 pfr_prepare_network(union sockaddr_union *, int, int);
16002742ec6SJoerg Sonnenberger int			 pfr_route_kentry(struct pfr_ktable *,
16102742ec6SJoerg Sonnenberger 			    struct pfr_kentry *);
16202742ec6SJoerg Sonnenberger int			 pfr_unroute_kentry(struct pfr_ktable *,
16302742ec6SJoerg Sonnenberger 			    struct pfr_kentry *);
16402742ec6SJoerg Sonnenberger int			 pfr_walktree(struct radix_node *, void *);
16502742ec6SJoerg Sonnenberger int			 pfr_validate_table(struct pfr_table *, int, int);
16670224baaSJan Lentfer int			 pfr_fix_anchor(char *);
16702742ec6SJoerg Sonnenberger void			 pfr_commit_ktable(struct pfr_ktable *, long);
16802742ec6SJoerg Sonnenberger void			 pfr_insert_ktables(struct pfr_ktableworkq *);
16902742ec6SJoerg Sonnenberger void			 pfr_insert_ktable(struct pfr_ktable *);
17002742ec6SJoerg Sonnenberger void			 pfr_setflags_ktables(struct pfr_ktableworkq *);
17102742ec6SJoerg Sonnenberger void			 pfr_setflags_ktable(struct pfr_ktable *, int);
17202742ec6SJoerg Sonnenberger void			 pfr_clstats_ktables(struct pfr_ktableworkq *, long,
17302742ec6SJoerg Sonnenberger 			    int);
17402742ec6SJoerg Sonnenberger void			 pfr_clstats_ktable(struct pfr_ktable *, long, int);
17502742ec6SJoerg Sonnenberger struct pfr_ktable	*pfr_create_ktable(struct pfr_table *, long, int);
17602742ec6SJoerg Sonnenberger void			 pfr_destroy_ktables(struct pfr_ktableworkq *, int);
17702742ec6SJoerg Sonnenberger void			 pfr_destroy_ktable(struct pfr_ktable *, int);
17802742ec6SJoerg Sonnenberger int			 pfr_ktable_compare(struct pfr_ktable *,
17902742ec6SJoerg Sonnenberger 			    struct pfr_ktable *);
18002742ec6SJoerg Sonnenberger struct pfr_ktable	*pfr_lookup_table(struct pfr_table *);
18102742ec6SJoerg Sonnenberger void			 pfr_clean_node_mask(struct pfr_ktable *,
18202742ec6SJoerg Sonnenberger 			    struct pfr_kentryworkq *);
18302742ec6SJoerg Sonnenberger int			 pfr_table_count(struct pfr_table *, int);
18402742ec6SJoerg Sonnenberger int			 pfr_skip_table(struct pfr_table *,
18502742ec6SJoerg Sonnenberger 			    struct pfr_ktable *, int);
18602742ec6SJoerg Sonnenberger struct pfr_kentry	*pfr_kentry_byidx(struct pfr_ktable *, int, int);
18702742ec6SJoerg Sonnenberger 
18802742ec6SJoerg Sonnenberger RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
18902742ec6SJoerg Sonnenberger RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
19002742ec6SJoerg Sonnenberger 
19102742ec6SJoerg Sonnenberger struct pfr_ktablehead	 pfr_ktables;
19202742ec6SJoerg Sonnenberger struct pfr_table	 pfr_nulltable;
19302742ec6SJoerg Sonnenberger int			 pfr_ktable_cnt;
19402742ec6SJoerg Sonnenberger 
19502742ec6SJoerg Sonnenberger void
pfr_initialize(void)19602742ec6SJoerg Sonnenberger pfr_initialize(void)
19702742ec6SJoerg Sonnenberger {
19802742ec6SJoerg Sonnenberger 	memset(&pfr_ffaddr, 0xff, sizeof(pfr_ffaddr));
19902742ec6SJoerg Sonnenberger }
20002742ec6SJoerg Sonnenberger 
20102742ec6SJoerg Sonnenberger int
pfr_clr_addrs(struct pfr_table * tbl,int * ndel,int flags)20202742ec6SJoerg Sonnenberger pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
20302742ec6SJoerg Sonnenberger {
20402742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt;
20502742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	 workq;
20602742ec6SJoerg Sonnenberger 
207315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
20802742ec6SJoerg Sonnenberger 	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
20902742ec6SJoerg Sonnenberger 		return (EINVAL);
21002742ec6SJoerg Sonnenberger 	kt = pfr_lookup_table(tbl);
21102742ec6SJoerg Sonnenberger 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
21202742ec6SJoerg Sonnenberger 		return (ESRCH);
21302742ec6SJoerg Sonnenberger 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
21402742ec6SJoerg Sonnenberger 		return (EPERM);
21502742ec6SJoerg Sonnenberger 	pfr_enqueue_addrs(kt, &workq, ndel, 0);
21602742ec6SJoerg Sonnenberger 
21702742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
21802742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
219cc6e5672SJoerg Sonnenberger 			crit_enter();
22002742ec6SJoerg Sonnenberger 		pfr_remove_kentries(kt, &workq);
22102742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
222cc6e5672SJoerg Sonnenberger 			crit_exit();
22302742ec6SJoerg Sonnenberger 		if (kt->pfrkt_cnt) {
2244b1cf444SSascha Wildner 			kprintf("pfr_clr_addrs: corruption detected (%d).\n",
22502742ec6SJoerg Sonnenberger 			    kt->pfrkt_cnt);
22602742ec6SJoerg Sonnenberger 			kt->pfrkt_cnt = 0;
22702742ec6SJoerg Sonnenberger 		}
22802742ec6SJoerg Sonnenberger 	}
22902742ec6SJoerg Sonnenberger 	return (0);
23002742ec6SJoerg Sonnenberger }
23102742ec6SJoerg Sonnenberger 
23202742ec6SJoerg Sonnenberger int
pfr_add_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int flags)23302742ec6SJoerg Sonnenberger pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
23402742ec6SJoerg Sonnenberger     int *nadd, int flags)
23502742ec6SJoerg Sonnenberger {
23602742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt, *tmpkt;
23702742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	 workq;
23802742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p, *q;
23902742ec6SJoerg Sonnenberger 	struct pfr_addr		 ad;
240cc6e5672SJoerg Sonnenberger 	int			 i, rv, xadd = 0;
24102742ec6SJoerg Sonnenberger 	long			 tzero = time_second;
24202742ec6SJoerg Sonnenberger 
243315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
244315a7da3SJan Lentfer 	    PFR_FLAG_FEEDBACK);
24502742ec6SJoerg Sonnenberger 	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
24602742ec6SJoerg Sonnenberger 		return (EINVAL);
24702742ec6SJoerg Sonnenberger 	kt = pfr_lookup_table(tbl);
24802742ec6SJoerg Sonnenberger 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
24902742ec6SJoerg Sonnenberger 		return (ESRCH);
25002742ec6SJoerg Sonnenberger 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
25102742ec6SJoerg Sonnenberger 		return (EPERM);
25202742ec6SJoerg Sonnenberger 	tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0);
25302742ec6SJoerg Sonnenberger 	if (tmpkt == NULL)
25402742ec6SJoerg Sonnenberger 		return (ENOMEM);
25502742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
25602742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
257315a7da3SJan Lentfer 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
25802742ec6SJoerg Sonnenberger 			senderr(EFAULT);
25902742ec6SJoerg Sonnenberger 		if (pfr_validate_addr(&ad))
26002742ec6SJoerg Sonnenberger 			senderr(EINVAL);
26102742ec6SJoerg Sonnenberger 		p = pfr_lookup_addr(kt, &ad, 1);
26202742ec6SJoerg Sonnenberger 		q = pfr_lookup_addr(tmpkt, &ad, 1);
26302742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_FEEDBACK) {
26402742ec6SJoerg Sonnenberger 			if (q != NULL)
26502742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_DUPLICATE;
26602742ec6SJoerg Sonnenberger 			else if (p == NULL)
26702742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_ADDED;
26802742ec6SJoerg Sonnenberger 			else if (p->pfrke_not != ad.pfra_not)
26902742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_CONFLICT;
27002742ec6SJoerg Sonnenberger 			else
27102742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_NONE;
27202742ec6SJoerg Sonnenberger 		}
27302742ec6SJoerg Sonnenberger 		if (p == NULL && q == NULL) {
274315a7da3SJan Lentfer 			p = pfr_create_kentry(&ad,
275315a7da3SJan Lentfer 			    !(flags & PFR_FLAG_USERIOCTL));
27602742ec6SJoerg Sonnenberger 			if (p == NULL)
27702742ec6SJoerg Sonnenberger 				senderr(ENOMEM);
27802742ec6SJoerg Sonnenberger 			if (pfr_route_kentry(tmpkt, p)) {
27902742ec6SJoerg Sonnenberger 				pfr_destroy_kentry(p);
28002742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_NONE;
28102742ec6SJoerg Sonnenberger 			} else {
28202742ec6SJoerg Sonnenberger 				SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
28302742ec6SJoerg Sonnenberger 				xadd++;
28402742ec6SJoerg Sonnenberger 			}
28502742ec6SJoerg Sonnenberger 		}
28602742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_FEEDBACK)
287315a7da3SJan Lentfer 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
28802742ec6SJoerg Sonnenberger 				senderr(EFAULT);
28902742ec6SJoerg Sonnenberger 	}
29002742ec6SJoerg Sonnenberger 	pfr_clean_node_mask(tmpkt, &workq);
29102742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
29202742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
293cc6e5672SJoerg Sonnenberger 			crit_enter();
29402742ec6SJoerg Sonnenberger 		pfr_insert_kentries(kt, &workq, tzero);
29502742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
296cc6e5672SJoerg Sonnenberger 			crit_exit();
29702742ec6SJoerg Sonnenberger 	} else
29802742ec6SJoerg Sonnenberger 		pfr_destroy_kentries(&workq);
29902742ec6SJoerg Sonnenberger 	if (nadd != NULL)
30002742ec6SJoerg Sonnenberger 		*nadd = xadd;
30102742ec6SJoerg Sonnenberger 	pfr_destroy_ktable(tmpkt, 0);
30202742ec6SJoerg Sonnenberger 	return (0);
30302742ec6SJoerg Sonnenberger _bad:
30402742ec6SJoerg Sonnenberger 	pfr_clean_node_mask(tmpkt, &workq);
30502742ec6SJoerg Sonnenberger 	pfr_destroy_kentries(&workq);
30602742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_FEEDBACK)
30702742ec6SJoerg Sonnenberger 		pfr_reset_feedback(addr, size, flags);
30802742ec6SJoerg Sonnenberger 	pfr_destroy_ktable(tmpkt, 0);
30902742ec6SJoerg Sonnenberger 	return (rv);
31002742ec6SJoerg Sonnenberger }
31102742ec6SJoerg Sonnenberger 
31202742ec6SJoerg Sonnenberger int
pfr_del_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * ndel,int flags)31302742ec6SJoerg Sonnenberger pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
31402742ec6SJoerg Sonnenberger     int *ndel, int flags)
31502742ec6SJoerg Sonnenberger {
31602742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt;
31702742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	 workq;
31802742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p;
31902742ec6SJoerg Sonnenberger 	struct pfr_addr		 ad;
32070224baaSJan Lentfer 	int			 i, rv, xdel = 0, log = 1;
32102742ec6SJoerg Sonnenberger 
322315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
323315a7da3SJan Lentfer 	    PFR_FLAG_FEEDBACK);
32402742ec6SJoerg Sonnenberger 	if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
32502742ec6SJoerg Sonnenberger 		return (EINVAL);
32602742ec6SJoerg Sonnenberger 	kt = pfr_lookup_table(tbl);
32702742ec6SJoerg Sonnenberger 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
32802742ec6SJoerg Sonnenberger 		return (ESRCH);
32902742ec6SJoerg Sonnenberger 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
33002742ec6SJoerg Sonnenberger 		return (EPERM);
33170224baaSJan Lentfer 	/*
33270224baaSJan Lentfer 	 * there are two algorithms to choose from here.
33370224baaSJan Lentfer 	 * with:
33470224baaSJan Lentfer 	 *   n: number of addresses to delete
33570224baaSJan Lentfer 	 *   N: number of addresses in the table
33670224baaSJan Lentfer 	 *
33770224baaSJan Lentfer 	 * one is O(N) and is better for large 'n'
33870224baaSJan Lentfer 	 * one is O(n*LOG(N)) and is better for small 'n'
33970224baaSJan Lentfer 	 *
34070224baaSJan Lentfer 	 * following code try to decide which one is best.
34170224baaSJan Lentfer 	 */
34270224baaSJan Lentfer 	for (i = kt->pfrkt_cnt; i > 0; i >>= 1)
34370224baaSJan Lentfer 		log++;
34470224baaSJan Lentfer 	if (size > kt->pfrkt_cnt/log) {
34570224baaSJan Lentfer 		/* full table scan */
34602742ec6SJoerg Sonnenberger 		pfr_mark_addrs(kt);
34770224baaSJan Lentfer 	} else {
34870224baaSJan Lentfer 		/* iterate over addresses to delete */
34970224baaSJan Lentfer 		for (i = 0; i < size; i++) {
350315a7da3SJan Lentfer 			if (COPYIN(addr+i, &ad, sizeof(ad), flags))
35170224baaSJan Lentfer 				return (EFAULT);
35270224baaSJan Lentfer 			if (pfr_validate_addr(&ad))
35370224baaSJan Lentfer 				return (EINVAL);
35470224baaSJan Lentfer 			p = pfr_lookup_addr(kt, &ad, 1);
35570224baaSJan Lentfer 			if (p != NULL)
35670224baaSJan Lentfer 				p->pfrke_mark = 0;
35770224baaSJan Lentfer 		}
35870224baaSJan Lentfer 	}
35902742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
36002742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
361315a7da3SJan Lentfer 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
36202742ec6SJoerg Sonnenberger 			senderr(EFAULT);
36302742ec6SJoerg Sonnenberger 		if (pfr_validate_addr(&ad))
36402742ec6SJoerg Sonnenberger 			senderr(EINVAL);
36502742ec6SJoerg Sonnenberger 		p = pfr_lookup_addr(kt, &ad, 1);
36602742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_FEEDBACK) {
36702742ec6SJoerg Sonnenberger 			if (p == NULL)
36802742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_NONE;
36902742ec6SJoerg Sonnenberger 			else if (p->pfrke_not != ad.pfra_not)
37002742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_CONFLICT;
37102742ec6SJoerg Sonnenberger 			else if (p->pfrke_mark)
37202742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_DUPLICATE;
37302742ec6SJoerg Sonnenberger 			else
37402742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_DELETED;
37502742ec6SJoerg Sonnenberger 		}
37602742ec6SJoerg Sonnenberger 		if (p != NULL && p->pfrke_not == ad.pfra_not &&
37702742ec6SJoerg Sonnenberger 		    !p->pfrke_mark) {
37802742ec6SJoerg Sonnenberger 			p->pfrke_mark = 1;
37902742ec6SJoerg Sonnenberger 			SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
38002742ec6SJoerg Sonnenberger 			xdel++;
38102742ec6SJoerg Sonnenberger 		}
38202742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_FEEDBACK)
383315a7da3SJan Lentfer 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
38402742ec6SJoerg Sonnenberger 				senderr(EFAULT);
38502742ec6SJoerg Sonnenberger 	}
38602742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
38702742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
388cc6e5672SJoerg Sonnenberger 			crit_enter();
38902742ec6SJoerg Sonnenberger 		pfr_remove_kentries(kt, &workq);
39002742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
391cc6e5672SJoerg Sonnenberger 			crit_exit();
39202742ec6SJoerg Sonnenberger 	}
39302742ec6SJoerg Sonnenberger 	if (ndel != NULL)
39402742ec6SJoerg Sonnenberger 		*ndel = xdel;
39502742ec6SJoerg Sonnenberger 	return (0);
39602742ec6SJoerg Sonnenberger _bad:
39702742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_FEEDBACK)
39802742ec6SJoerg Sonnenberger 		pfr_reset_feedback(addr, size, flags);
39902742ec6SJoerg Sonnenberger 	return (rv);
40002742ec6SJoerg Sonnenberger }
40102742ec6SJoerg Sonnenberger 
40202742ec6SJoerg Sonnenberger int
pfr_set_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * size2,int * nadd,int * ndel,int * nchange,int flags,u_int32_t ignore_pfrt_flags)40302742ec6SJoerg Sonnenberger pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
40470224baaSJan Lentfer     int *size2, int *nadd, int *ndel, int *nchange, int flags,
40570224baaSJan Lentfer     u_int32_t ignore_pfrt_flags)
40602742ec6SJoerg Sonnenberger {
40702742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt, *tmpkt;
40802742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	 addq, delq, changeq;
40902742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p, *q;
41002742ec6SJoerg Sonnenberger 	struct pfr_addr		 ad;
411cc6e5672SJoerg Sonnenberger 	int			 i, rv, xadd = 0, xdel = 0, xchange = 0;
41202742ec6SJoerg Sonnenberger 	long			 tzero = time_second;
41302742ec6SJoerg Sonnenberger 
414315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
415315a7da3SJan Lentfer 	    PFR_FLAG_FEEDBACK);
41670224baaSJan Lentfer 	if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
41770224baaSJan Lentfer 	    PFR_FLAG_USERIOCTL))
41802742ec6SJoerg Sonnenberger 		return (EINVAL);
41902742ec6SJoerg Sonnenberger 	kt = pfr_lookup_table(tbl);
42002742ec6SJoerg Sonnenberger 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
42102742ec6SJoerg Sonnenberger 		return (ESRCH);
42202742ec6SJoerg Sonnenberger 	if (kt->pfrkt_flags & PFR_TFLAG_CONST)
42302742ec6SJoerg Sonnenberger 		return (EPERM);
42402742ec6SJoerg Sonnenberger 	tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0);
42502742ec6SJoerg Sonnenberger 	if (tmpkt == NULL)
42602742ec6SJoerg Sonnenberger 		return (ENOMEM);
42702742ec6SJoerg Sonnenberger 	pfr_mark_addrs(kt);
42802742ec6SJoerg Sonnenberger 	SLIST_INIT(&addq);
42902742ec6SJoerg Sonnenberger 	SLIST_INIT(&delq);
43002742ec6SJoerg Sonnenberger 	SLIST_INIT(&changeq);
43102742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
432315a7da3SJan Lentfer 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
43302742ec6SJoerg Sonnenberger 			senderr(EFAULT);
43402742ec6SJoerg Sonnenberger 		if (pfr_validate_addr(&ad))
43502742ec6SJoerg Sonnenberger 			senderr(EINVAL);
43602742ec6SJoerg Sonnenberger 		ad.pfra_fback = PFR_FB_NONE;
43702742ec6SJoerg Sonnenberger 		p = pfr_lookup_addr(kt, &ad, 1);
43802742ec6SJoerg Sonnenberger 		if (p != NULL) {
43902742ec6SJoerg Sonnenberger 			if (p->pfrke_mark) {
44002742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_DUPLICATE;
44102742ec6SJoerg Sonnenberger 				goto _skip;
44202742ec6SJoerg Sonnenberger 			}
44302742ec6SJoerg Sonnenberger 			p->pfrke_mark = 1;
44402742ec6SJoerg Sonnenberger 			if (p->pfrke_not != ad.pfra_not) {
44502742ec6SJoerg Sonnenberger 				SLIST_INSERT_HEAD(&changeq, p, pfrke_workq);
44602742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_CHANGED;
44702742ec6SJoerg Sonnenberger 				xchange++;
44802742ec6SJoerg Sonnenberger 			}
44902742ec6SJoerg Sonnenberger 		} else {
45002742ec6SJoerg Sonnenberger 			q = pfr_lookup_addr(tmpkt, &ad, 1);
45102742ec6SJoerg Sonnenberger 			if (q != NULL) {
45202742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_DUPLICATE;
45302742ec6SJoerg Sonnenberger 				goto _skip;
45402742ec6SJoerg Sonnenberger 			}
455315a7da3SJan Lentfer 			p = pfr_create_kentry(&ad,
456315a7da3SJan Lentfer 			    !(flags & PFR_FLAG_USERIOCTL));
45702742ec6SJoerg Sonnenberger 			if (p == NULL)
45802742ec6SJoerg Sonnenberger 				senderr(ENOMEM);
45902742ec6SJoerg Sonnenberger 			if (pfr_route_kentry(tmpkt, p)) {
46002742ec6SJoerg Sonnenberger 				pfr_destroy_kentry(p);
46102742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_NONE;
46202742ec6SJoerg Sonnenberger 			} else {
46302742ec6SJoerg Sonnenberger 				SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
46402742ec6SJoerg Sonnenberger 				ad.pfra_fback = PFR_FB_ADDED;
46502742ec6SJoerg Sonnenberger 				xadd++;
46602742ec6SJoerg Sonnenberger 			}
46702742ec6SJoerg Sonnenberger 		}
46802742ec6SJoerg Sonnenberger _skip:
46902742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_FEEDBACK)
470315a7da3SJan Lentfer 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
47102742ec6SJoerg Sonnenberger 				senderr(EFAULT);
47202742ec6SJoerg Sonnenberger 	}
47302742ec6SJoerg Sonnenberger 	pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
47402742ec6SJoerg Sonnenberger 	if ((flags & PFR_FLAG_FEEDBACK) && *size2) {
47502742ec6SJoerg Sonnenberger 		if (*size2 < size+xdel) {
47602742ec6SJoerg Sonnenberger 			*size2 = size+xdel;
47702742ec6SJoerg Sonnenberger 			senderr(0);
47802742ec6SJoerg Sonnenberger 		}
47902742ec6SJoerg Sonnenberger 		i = 0;
48002742ec6SJoerg Sonnenberger 		SLIST_FOREACH(p, &delq, pfrke_workq) {
48102742ec6SJoerg Sonnenberger 			pfr_copyout_addr(&ad, p);
48202742ec6SJoerg Sonnenberger 			ad.pfra_fback = PFR_FB_DELETED;
483315a7da3SJan Lentfer 			if (COPYOUT(&ad, addr+size+i, sizeof(ad), flags))
48402742ec6SJoerg Sonnenberger 				senderr(EFAULT);
48502742ec6SJoerg Sonnenberger 			i++;
48602742ec6SJoerg Sonnenberger 		}
48702742ec6SJoerg Sonnenberger 	}
48802742ec6SJoerg Sonnenberger 	pfr_clean_node_mask(tmpkt, &addq);
48902742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
49002742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
491cc6e5672SJoerg Sonnenberger 			crit_enter();
49202742ec6SJoerg Sonnenberger 		pfr_insert_kentries(kt, &addq, tzero);
49302742ec6SJoerg Sonnenberger 		pfr_remove_kentries(kt, &delq);
49402742ec6SJoerg Sonnenberger 		pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
49502742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
496cc6e5672SJoerg Sonnenberger 			crit_exit();
49702742ec6SJoerg Sonnenberger 	} else
49802742ec6SJoerg Sonnenberger 		pfr_destroy_kentries(&addq);
49902742ec6SJoerg Sonnenberger 	if (nadd != NULL)
50002742ec6SJoerg Sonnenberger 		*nadd = xadd;
50102742ec6SJoerg Sonnenberger 	if (ndel != NULL)
50202742ec6SJoerg Sonnenberger 		*ndel = xdel;
50302742ec6SJoerg Sonnenberger 	if (nchange != NULL)
50402742ec6SJoerg Sonnenberger 		*nchange = xchange;
50502742ec6SJoerg Sonnenberger 	if ((flags & PFR_FLAG_FEEDBACK) && size2)
50602742ec6SJoerg Sonnenberger 		*size2 = size+xdel;
50702742ec6SJoerg Sonnenberger 	pfr_destroy_ktable(tmpkt, 0);
50802742ec6SJoerg Sonnenberger 	return (0);
50902742ec6SJoerg Sonnenberger _bad:
51002742ec6SJoerg Sonnenberger 	pfr_clean_node_mask(tmpkt, &addq);
51102742ec6SJoerg Sonnenberger 	pfr_destroy_kentries(&addq);
51202742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_FEEDBACK)
51302742ec6SJoerg Sonnenberger 		pfr_reset_feedback(addr, size, flags);
51402742ec6SJoerg Sonnenberger 	pfr_destroy_ktable(tmpkt, 0);
51502742ec6SJoerg Sonnenberger 	return (rv);
51602742ec6SJoerg Sonnenberger }
51702742ec6SJoerg Sonnenberger 
51802742ec6SJoerg Sonnenberger int
pfr_tst_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nmatch,int flags)51902742ec6SJoerg Sonnenberger pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
52002742ec6SJoerg Sonnenberger 	int *nmatch, int flags)
52102742ec6SJoerg Sonnenberger {
52202742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt;
52302742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p;
52402742ec6SJoerg Sonnenberger 	struct pfr_addr		 ad;
52502742ec6SJoerg Sonnenberger 	int			 i, xmatch = 0;
52602742ec6SJoerg Sonnenberger 
527315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE);
52802742ec6SJoerg Sonnenberger 	if (pfr_validate_table(tbl, 0, 0))
52902742ec6SJoerg Sonnenberger 		return (EINVAL);
53002742ec6SJoerg Sonnenberger 	kt = pfr_lookup_table(tbl);
53102742ec6SJoerg Sonnenberger 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
53202742ec6SJoerg Sonnenberger 		return (ESRCH);
53302742ec6SJoerg Sonnenberger 
53402742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
535315a7da3SJan Lentfer 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
53602742ec6SJoerg Sonnenberger 			return (EFAULT);
53702742ec6SJoerg Sonnenberger 		if (pfr_validate_addr(&ad))
53802742ec6SJoerg Sonnenberger 			return (EINVAL);
53902742ec6SJoerg Sonnenberger 		if (ADDR_NETWORK(&ad))
54002742ec6SJoerg Sonnenberger 			return (EINVAL);
54102742ec6SJoerg Sonnenberger 		p = pfr_lookup_addr(kt, &ad, 0);
54202742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_REPLACE)
54302742ec6SJoerg Sonnenberger 			pfr_copyout_addr(&ad, p);
54402742ec6SJoerg Sonnenberger 		ad.pfra_fback = (p == NULL) ? PFR_FB_NONE :
54502742ec6SJoerg Sonnenberger 		    (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH);
54602742ec6SJoerg Sonnenberger 		if (p != NULL && !p->pfrke_not)
54702742ec6SJoerg Sonnenberger 			xmatch++;
548315a7da3SJan Lentfer 		if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
54902742ec6SJoerg Sonnenberger 			return (EFAULT);
55002742ec6SJoerg Sonnenberger 	}
55102742ec6SJoerg Sonnenberger 	if (nmatch != NULL)
55202742ec6SJoerg Sonnenberger 		*nmatch = xmatch;
55302742ec6SJoerg Sonnenberger 	return (0);
55402742ec6SJoerg Sonnenberger }
55502742ec6SJoerg Sonnenberger 
55602742ec6SJoerg Sonnenberger int
pfr_get_addrs(struct pfr_table * tbl,struct pfr_addr * addr,int * size,int flags)55702742ec6SJoerg Sonnenberger pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
55802742ec6SJoerg Sonnenberger 	int flags)
55902742ec6SJoerg Sonnenberger {
56002742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt;
56102742ec6SJoerg Sonnenberger 	struct pfr_walktree	 w;
56202742ec6SJoerg Sonnenberger 	int			 rv;
56302742ec6SJoerg Sonnenberger 
564315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, 0);
56502742ec6SJoerg Sonnenberger 	if (pfr_validate_table(tbl, 0, 0))
56602742ec6SJoerg Sonnenberger 		return (EINVAL);
56702742ec6SJoerg Sonnenberger 	kt = pfr_lookup_table(tbl);
56802742ec6SJoerg Sonnenberger 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
56902742ec6SJoerg Sonnenberger 		return (ESRCH);
57002742ec6SJoerg Sonnenberger 	if (kt->pfrkt_cnt > *size) {
57102742ec6SJoerg Sonnenberger 		*size = kt->pfrkt_cnt;
57202742ec6SJoerg Sonnenberger 		return (0);
57302742ec6SJoerg Sonnenberger 	}
57402742ec6SJoerg Sonnenberger 
57502742ec6SJoerg Sonnenberger 	bzero(&w, sizeof(w));
57602742ec6SJoerg Sonnenberger 	w.pfrw_op = PFRW_GET_ADDRS;
57702742ec6SJoerg Sonnenberger 	w.pfrw_addr = addr;
57802742ec6SJoerg Sonnenberger 	w.pfrw_free = kt->pfrkt_cnt;
57902742ec6SJoerg Sonnenberger 	w.pfrw_flags = flags;
58002742ec6SJoerg Sonnenberger 	rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
58102742ec6SJoerg Sonnenberger 	if (!rv)
58202742ec6SJoerg Sonnenberger 		rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
58302742ec6SJoerg Sonnenberger 	if (rv)
58402742ec6SJoerg Sonnenberger 		return (rv);
58502742ec6SJoerg Sonnenberger 
58602742ec6SJoerg Sonnenberger 	if (w.pfrw_free) {
5874b1cf444SSascha Wildner 		kprintf("pfr_get_addrs: corruption detected (%d).\n",
58802742ec6SJoerg Sonnenberger 		    w.pfrw_free);
58902742ec6SJoerg Sonnenberger 		return (ENOTTY);
59002742ec6SJoerg Sonnenberger 	}
59102742ec6SJoerg Sonnenberger 	*size = kt->pfrkt_cnt;
59202742ec6SJoerg Sonnenberger 	return (0);
59302742ec6SJoerg Sonnenberger }
59402742ec6SJoerg Sonnenberger 
59502742ec6SJoerg Sonnenberger int
pfr_get_astats(struct pfr_table * tbl,struct pfr_astats * addr,int * size,int flags)59602742ec6SJoerg Sonnenberger pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
59702742ec6SJoerg Sonnenberger 	int flags)
59802742ec6SJoerg Sonnenberger {
59902742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt;
60002742ec6SJoerg Sonnenberger 	struct pfr_walktree	 w;
60102742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	 workq;
602cc6e5672SJoerg Sonnenberger 	int			 rv;
60302742ec6SJoerg Sonnenberger 	long			 tzero = time_second;
60402742ec6SJoerg Sonnenberger 
605315a7da3SJan Lentfer 	/* XXX PFR_FLAG_CLSTATS disabled */
606315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC);
60702742ec6SJoerg Sonnenberger 	if (pfr_validate_table(tbl, 0, 0))
60802742ec6SJoerg Sonnenberger 		return (EINVAL);
60902742ec6SJoerg Sonnenberger 	kt = pfr_lookup_table(tbl);
61002742ec6SJoerg Sonnenberger 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
61102742ec6SJoerg Sonnenberger 		return (ESRCH);
61202742ec6SJoerg Sonnenberger 	if (kt->pfrkt_cnt > *size) {
61302742ec6SJoerg Sonnenberger 		*size = kt->pfrkt_cnt;
61402742ec6SJoerg Sonnenberger 		return (0);
61502742ec6SJoerg Sonnenberger 	}
61602742ec6SJoerg Sonnenberger 
61702742ec6SJoerg Sonnenberger 	bzero(&w, sizeof(w));
61802742ec6SJoerg Sonnenberger 	w.pfrw_op = PFRW_GET_ASTATS;
61902742ec6SJoerg Sonnenberger 	w.pfrw_astats = addr;
62002742ec6SJoerg Sonnenberger 	w.pfrw_free = kt->pfrkt_cnt;
62102742ec6SJoerg Sonnenberger 	w.pfrw_flags = flags;
62202742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_ATOMIC)
623cc6e5672SJoerg Sonnenberger 		crit_enter();
62402742ec6SJoerg Sonnenberger 	rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
62502742ec6SJoerg Sonnenberger 	if (!rv)
62602742ec6SJoerg Sonnenberger 		rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
62702742ec6SJoerg Sonnenberger 	if (!rv && (flags & PFR_FLAG_CLSTATS)) {
62802742ec6SJoerg Sonnenberger 		pfr_enqueue_addrs(kt, &workq, NULL, 0);
62902742ec6SJoerg Sonnenberger 		pfr_clstats_kentries(&workq, tzero, 0);
63002742ec6SJoerg Sonnenberger 	}
63102742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_ATOMIC)
632cc6e5672SJoerg Sonnenberger 		crit_exit();
63302742ec6SJoerg Sonnenberger 	if (rv)
63402742ec6SJoerg Sonnenberger 		return (rv);
63502742ec6SJoerg Sonnenberger 
63602742ec6SJoerg Sonnenberger 	if (w.pfrw_free) {
6374b1cf444SSascha Wildner 		kprintf("pfr_get_astats: corruption detected (%d).\n",
63802742ec6SJoerg Sonnenberger 		    w.pfrw_free);
63902742ec6SJoerg Sonnenberger 		return (ENOTTY);
64002742ec6SJoerg Sonnenberger 	}
64102742ec6SJoerg Sonnenberger 	*size = kt->pfrkt_cnt;
64202742ec6SJoerg Sonnenberger 	return (0);
64302742ec6SJoerg Sonnenberger }
64402742ec6SJoerg Sonnenberger 
64502742ec6SJoerg Sonnenberger int
pfr_clr_astats(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nzero,int flags)64602742ec6SJoerg Sonnenberger pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
64702742ec6SJoerg Sonnenberger     int *nzero, int flags)
64802742ec6SJoerg Sonnenberger {
64902742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt;
65002742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	 workq;
65102742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p;
65202742ec6SJoerg Sonnenberger 	struct pfr_addr		 ad;
653cc6e5672SJoerg Sonnenberger 	int			 i, rv, xzero = 0;
65402742ec6SJoerg Sonnenberger 
655315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
656315a7da3SJan Lentfer 	    PFR_FLAG_FEEDBACK);
65702742ec6SJoerg Sonnenberger 	if (pfr_validate_table(tbl, 0, 0))
65802742ec6SJoerg Sonnenberger 		return (EINVAL);
65902742ec6SJoerg Sonnenberger 	kt = pfr_lookup_table(tbl);
66002742ec6SJoerg Sonnenberger 	if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
66102742ec6SJoerg Sonnenberger 		return (ESRCH);
66202742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
66302742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
664315a7da3SJan Lentfer 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
66502742ec6SJoerg Sonnenberger 			senderr(EFAULT);
66602742ec6SJoerg Sonnenberger 		if (pfr_validate_addr(&ad))
66702742ec6SJoerg Sonnenberger 			senderr(EINVAL);
66802742ec6SJoerg Sonnenberger 		p = pfr_lookup_addr(kt, &ad, 1);
66902742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_FEEDBACK) {
67002742ec6SJoerg Sonnenberger 			ad.pfra_fback = (p != NULL) ?
67102742ec6SJoerg Sonnenberger 			    PFR_FB_CLEARED : PFR_FB_NONE;
672315a7da3SJan Lentfer 			if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
67302742ec6SJoerg Sonnenberger 				senderr(EFAULT);
67402742ec6SJoerg Sonnenberger 		}
67502742ec6SJoerg Sonnenberger 		if (p != NULL) {
67602742ec6SJoerg Sonnenberger 			SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
67702742ec6SJoerg Sonnenberger 			xzero++;
67802742ec6SJoerg Sonnenberger 		}
67902742ec6SJoerg Sonnenberger 	}
68002742ec6SJoerg Sonnenberger 
68102742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
68202742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
683cc6e5672SJoerg Sonnenberger 			crit_enter();
68402742ec6SJoerg Sonnenberger 		pfr_clstats_kentries(&workq, 0, 0);
68502742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
686cc6e5672SJoerg Sonnenberger 			crit_exit();
68702742ec6SJoerg Sonnenberger 	}
68802742ec6SJoerg Sonnenberger 	if (nzero != NULL)
68902742ec6SJoerg Sonnenberger 		*nzero = xzero;
69002742ec6SJoerg Sonnenberger 	return (0);
69102742ec6SJoerg Sonnenberger _bad:
69202742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_FEEDBACK)
69302742ec6SJoerg Sonnenberger 		pfr_reset_feedback(addr, size, flags);
69402742ec6SJoerg Sonnenberger 	return (rv);
69502742ec6SJoerg Sonnenberger }
69602742ec6SJoerg Sonnenberger 
69702742ec6SJoerg Sonnenberger int
pfr_validate_addr(struct pfr_addr * ad)69802742ec6SJoerg Sonnenberger pfr_validate_addr(struct pfr_addr *ad)
69902742ec6SJoerg Sonnenberger {
70002742ec6SJoerg Sonnenberger 	int i;
70102742ec6SJoerg Sonnenberger 
70202742ec6SJoerg Sonnenberger 	switch (ad->pfra_af) {
70370224baaSJan Lentfer #ifdef INET
70402742ec6SJoerg Sonnenberger 	case AF_INET:
70502742ec6SJoerg Sonnenberger 		if (ad->pfra_net > 32)
70602742ec6SJoerg Sonnenberger 			return (-1);
70702742ec6SJoerg Sonnenberger 		break;
70870224baaSJan Lentfer #endif /* INET */
70970224baaSJan Lentfer #ifdef INET6
71002742ec6SJoerg Sonnenberger 	case AF_INET6:
71102742ec6SJoerg Sonnenberger 		if (ad->pfra_net > 128)
71202742ec6SJoerg Sonnenberger 			return (-1);
71302742ec6SJoerg Sonnenberger 		break;
71470224baaSJan Lentfer #endif /* INET6 */
71502742ec6SJoerg Sonnenberger 	default:
71602742ec6SJoerg Sonnenberger 		return (-1);
71702742ec6SJoerg Sonnenberger 	}
71802742ec6SJoerg Sonnenberger 	if (ad->pfra_net < 128 &&
71902742ec6SJoerg Sonnenberger 		(((caddr_t)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8))))
72002742ec6SJoerg Sonnenberger 			return (-1);
72102742ec6SJoerg Sonnenberger 	for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++)
72202742ec6SJoerg Sonnenberger 		if (((caddr_t)ad)[i])
72302742ec6SJoerg Sonnenberger 			return (-1);
72402742ec6SJoerg Sonnenberger 	if (ad->pfra_not && ad->pfra_not != 1)
72502742ec6SJoerg Sonnenberger 		return (-1);
72602742ec6SJoerg Sonnenberger 	if (ad->pfra_fback)
72702742ec6SJoerg Sonnenberger 		return (-1);
72802742ec6SJoerg Sonnenberger 	return (0);
72902742ec6SJoerg Sonnenberger }
73002742ec6SJoerg Sonnenberger 
73102742ec6SJoerg Sonnenberger void
pfr_enqueue_addrs(struct pfr_ktable * kt,struct pfr_kentryworkq * workq,int * naddr,int sweep)73202742ec6SJoerg Sonnenberger pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq,
73302742ec6SJoerg Sonnenberger 	int *naddr, int sweep)
73402742ec6SJoerg Sonnenberger {
73502742ec6SJoerg Sonnenberger 	struct pfr_walktree	w;
73602742ec6SJoerg Sonnenberger 
73702742ec6SJoerg Sonnenberger 	SLIST_INIT(workq);
73802742ec6SJoerg Sonnenberger 	bzero(&w, sizeof(w));
73902742ec6SJoerg Sonnenberger 	w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE;
74002742ec6SJoerg Sonnenberger 	w.pfrw_workq = workq;
74102742ec6SJoerg Sonnenberger 	if (kt->pfrkt_ip4 != NULL)
74202742ec6SJoerg Sonnenberger 		if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
7434b1cf444SSascha Wildner 			kprintf("pfr_enqueue_addrs: IPv4 walktree failed.\n");
74402742ec6SJoerg Sonnenberger 	if (kt->pfrkt_ip6 != NULL)
74502742ec6SJoerg Sonnenberger 		if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
7464b1cf444SSascha Wildner 			kprintf("pfr_enqueue_addrs: IPv6 walktree failed.\n");
74702742ec6SJoerg Sonnenberger 	if (naddr != NULL)
74802742ec6SJoerg Sonnenberger 		*naddr = w.pfrw_cnt;
74902742ec6SJoerg Sonnenberger }
75002742ec6SJoerg Sonnenberger 
75102742ec6SJoerg Sonnenberger void
pfr_mark_addrs(struct pfr_ktable * kt)75202742ec6SJoerg Sonnenberger pfr_mark_addrs(struct pfr_ktable *kt)
75302742ec6SJoerg Sonnenberger {
75402742ec6SJoerg Sonnenberger 	struct pfr_walktree	w;
75502742ec6SJoerg Sonnenberger 
75602742ec6SJoerg Sonnenberger 	bzero(&w, sizeof(w));
75702742ec6SJoerg Sonnenberger 	w.pfrw_op = PFRW_MARK;
75802742ec6SJoerg Sonnenberger 	if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
7594b1cf444SSascha Wildner 		kprintf("pfr_mark_addrs: IPv4 walktree failed.\n");
76002742ec6SJoerg Sonnenberger 	if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
7614b1cf444SSascha Wildner 		kprintf("pfr_mark_addrs: IPv6 walktree failed.\n");
76202742ec6SJoerg Sonnenberger }
76302742ec6SJoerg Sonnenberger 
76402742ec6SJoerg Sonnenberger 
76502742ec6SJoerg Sonnenberger struct pfr_kentry *
pfr_lookup_addr(struct pfr_ktable * kt,struct pfr_addr * ad,int exact)76602742ec6SJoerg Sonnenberger pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
76702742ec6SJoerg Sonnenberger {
76802742ec6SJoerg Sonnenberger 	union sockaddr_union	 sa, mask;
76970224baaSJan Lentfer 	struct radix_node_head	*head = NULL;
77002742ec6SJoerg Sonnenberger 	struct pfr_kentry	*ke;
77102742ec6SJoerg Sonnenberger 
77202742ec6SJoerg Sonnenberger 	bzero(&sa, sizeof(sa));
77302742ec6SJoerg Sonnenberger 	if (ad->pfra_af == AF_INET) {
77402742ec6SJoerg Sonnenberger 		FILLIN_SIN(sa.sin, ad->pfra_ip4addr);
77502742ec6SJoerg Sonnenberger 		head = kt->pfrkt_ip4;
77670224baaSJan Lentfer 	} else if ( ad->pfra_af == AF_INET6 ) {
77702742ec6SJoerg Sonnenberger 		FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr);
77802742ec6SJoerg Sonnenberger 		head = kt->pfrkt_ip6;
77902742ec6SJoerg Sonnenberger 	}
78002742ec6SJoerg Sonnenberger 	if (ADDR_NETWORK(ad)) {
78102742ec6SJoerg Sonnenberger 		pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net);
782*d8449084SAaron LI 		ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head);
78302742ec6SJoerg Sonnenberger 		if (ke && KENTRY_RNF_ROOT(ke))
78402742ec6SJoerg Sonnenberger 			ke = NULL;
78502742ec6SJoerg Sonnenberger 	} else {
786*d8449084SAaron LI 		ke = (struct pfr_kentry *)rn_match(&sa, head);
78702742ec6SJoerg Sonnenberger 		if (ke && KENTRY_RNF_ROOT(ke))
78802742ec6SJoerg Sonnenberger 			ke = NULL;
78902742ec6SJoerg Sonnenberger 		if (exact && ke && KENTRY_NETWORK(ke))
79002742ec6SJoerg Sonnenberger 			ke = NULL;
79102742ec6SJoerg Sonnenberger 	}
79202742ec6SJoerg Sonnenberger 	return (ke);
79302742ec6SJoerg Sonnenberger }
79402742ec6SJoerg Sonnenberger 
79502742ec6SJoerg Sonnenberger struct pfr_kentry *
pfr_create_kentry(struct pfr_addr * ad,int intr)79670224baaSJan Lentfer pfr_create_kentry(struct pfr_addr *ad, int intr)
79702742ec6SJoerg Sonnenberger {
79802742ec6SJoerg Sonnenberger 	struct pfr_kentry	*ke;
79902742ec6SJoerg Sonnenberger 
80070224baaSJan Lentfer 	if (intr)
8011186cbc0SJan Lentfer 		ke = kmalloc(sizeof(struct pfr_kentry), M_PFRKENTRYPL2, M_NOWAIT|M_ZERO);
80270224baaSJan Lentfer 	else
8031186cbc0SJan Lentfer 		ke = kmalloc(sizeof(struct pfr_kentry), M_PFRKENTRYPL, M_NOWAIT|M_ZERO|M_NULLOK);
80402742ec6SJoerg Sonnenberger 	if (ke == NULL)
80502742ec6SJoerg Sonnenberger 		return (NULL);
80602742ec6SJoerg Sonnenberger 
80702742ec6SJoerg Sonnenberger 	if (ad->pfra_af == AF_INET)
80802742ec6SJoerg Sonnenberger 		FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr);
80970224baaSJan Lentfer 	else if (ad->pfra_af == AF_INET6)
81002742ec6SJoerg Sonnenberger 		FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr);
81102742ec6SJoerg Sonnenberger 	ke->pfrke_af = ad->pfra_af;
81202742ec6SJoerg Sonnenberger 	ke->pfrke_net = ad->pfra_net;
81302742ec6SJoerg Sonnenberger 	ke->pfrke_not = ad->pfra_not;
81470224baaSJan Lentfer 	ke->pfrke_intrpool = intr;
81502742ec6SJoerg Sonnenberger 	return (ke);
81602742ec6SJoerg Sonnenberger }
81702742ec6SJoerg Sonnenberger 
81802742ec6SJoerg Sonnenberger void
pfr_destroy_kentries(struct pfr_kentryworkq * workq)81902742ec6SJoerg Sonnenberger pfr_destroy_kentries(struct pfr_kentryworkq *workq)
82002742ec6SJoerg Sonnenberger {
82102742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p, *q;
82202742ec6SJoerg Sonnenberger 
82302742ec6SJoerg Sonnenberger 	for (p = SLIST_FIRST(workq); p != NULL; p = q) {
82402742ec6SJoerg Sonnenberger 		q = SLIST_NEXT(p, pfrke_workq);
82502742ec6SJoerg Sonnenberger 		pfr_destroy_kentry(p);
82602742ec6SJoerg Sonnenberger 	}
82702742ec6SJoerg Sonnenberger }
82802742ec6SJoerg Sonnenberger 
82902742ec6SJoerg Sonnenberger void
pfr_destroy_kentry(struct pfr_kentry * ke)83002742ec6SJoerg Sonnenberger pfr_destroy_kentry(struct pfr_kentry *ke)
83102742ec6SJoerg Sonnenberger {
832ed1f0be2SJan Lentfer 	if (ke->pfrke_counters)
8331186cbc0SJan Lentfer 		kfree(ke->pfrke_counters, M_PFRKCOUNTERSPL);
83470224baaSJan Lentfer 	if (ke->pfrke_intrpool)
8351186cbc0SJan Lentfer 		kfree(ke, M_PFRKENTRYPL2);
83670224baaSJan Lentfer 	else
8371186cbc0SJan Lentfer 		kfree(ke, M_PFRKENTRYPL);
83802742ec6SJoerg Sonnenberger }
83902742ec6SJoerg Sonnenberger 
84002742ec6SJoerg Sonnenberger void
pfr_insert_kentries(struct pfr_ktable * kt,struct pfr_kentryworkq * workq,long tzero)84102742ec6SJoerg Sonnenberger pfr_insert_kentries(struct pfr_ktable *kt,
84202742ec6SJoerg Sonnenberger     struct pfr_kentryworkq *workq, long tzero)
84302742ec6SJoerg Sonnenberger {
84402742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p;
84502742ec6SJoerg Sonnenberger 	int			 rv, n = 0;
84602742ec6SJoerg Sonnenberger 
84702742ec6SJoerg Sonnenberger 	SLIST_FOREACH(p, workq, pfrke_workq) {
84802742ec6SJoerg Sonnenberger 		rv = pfr_route_kentry(kt, p);
84902742ec6SJoerg Sonnenberger 		if (rv) {
8504b1cf444SSascha Wildner 			kprintf("pfr_insert_kentries: cannot route entry "
85102742ec6SJoerg Sonnenberger 			    "(code=%d).\n", rv);
85202742ec6SJoerg Sonnenberger 			break;
85302742ec6SJoerg Sonnenberger 		}
85402742ec6SJoerg Sonnenberger 		p->pfrke_tzero = tzero;
85502742ec6SJoerg Sonnenberger 		n++;
85602742ec6SJoerg Sonnenberger 	}
85702742ec6SJoerg Sonnenberger 	kt->pfrkt_cnt += n;
85802742ec6SJoerg Sonnenberger }
85902742ec6SJoerg Sonnenberger 
86070224baaSJan Lentfer int
pfr_insert_kentry(struct pfr_ktable * kt,struct pfr_addr * ad,long tzero)86170224baaSJan Lentfer pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero)
86270224baaSJan Lentfer {
86370224baaSJan Lentfer 	struct pfr_kentry	*p;
86470224baaSJan Lentfer 	int			 rv;
86570224baaSJan Lentfer 
86670224baaSJan Lentfer 	p = pfr_lookup_addr(kt, ad, 1);
86770224baaSJan Lentfer 	if (p != NULL)
86870224baaSJan Lentfer 		return (0);
86970224baaSJan Lentfer 	p = pfr_create_kentry(ad, 1);
87070224baaSJan Lentfer 	if (p == NULL)
87170224baaSJan Lentfer 		return (EINVAL);
87270224baaSJan Lentfer 
87370224baaSJan Lentfer 	rv = pfr_route_kentry(kt, p);
87470224baaSJan Lentfer 	if (rv)
87570224baaSJan Lentfer 		return (rv);
87670224baaSJan Lentfer 
87770224baaSJan Lentfer 	p->pfrke_tzero = tzero;
87870224baaSJan Lentfer 	kt->pfrkt_cnt++;
87970224baaSJan Lentfer 
88070224baaSJan Lentfer 	return (0);
88170224baaSJan Lentfer }
88270224baaSJan Lentfer 
88302742ec6SJoerg Sonnenberger void
pfr_remove_kentries(struct pfr_ktable * kt,struct pfr_kentryworkq * workq)88402742ec6SJoerg Sonnenberger pfr_remove_kentries(struct pfr_ktable *kt,
88502742ec6SJoerg Sonnenberger     struct pfr_kentryworkq *workq)
88602742ec6SJoerg Sonnenberger {
88702742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p;
88802742ec6SJoerg Sonnenberger 	int			 n = 0;
88902742ec6SJoerg Sonnenberger 
89002742ec6SJoerg Sonnenberger 	SLIST_FOREACH(p, workq, pfrke_workq) {
89102742ec6SJoerg Sonnenberger 		pfr_unroute_kentry(kt, p);
89202742ec6SJoerg Sonnenberger 		n++;
89302742ec6SJoerg Sonnenberger 	}
89402742ec6SJoerg Sonnenberger 	kt->pfrkt_cnt -= n;
89502742ec6SJoerg Sonnenberger 	pfr_destroy_kentries(workq);
89602742ec6SJoerg Sonnenberger }
89702742ec6SJoerg Sonnenberger 
89802742ec6SJoerg Sonnenberger void
pfr_clean_node_mask(struct pfr_ktable * kt,struct pfr_kentryworkq * workq)89902742ec6SJoerg Sonnenberger pfr_clean_node_mask(struct pfr_ktable *kt,
90002742ec6SJoerg Sonnenberger     struct pfr_kentryworkq *workq)
90102742ec6SJoerg Sonnenberger {
90202742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p;
90302742ec6SJoerg Sonnenberger 
90402742ec6SJoerg Sonnenberger 	SLIST_FOREACH(p, workq, pfrke_workq)
90502742ec6SJoerg Sonnenberger 		pfr_unroute_kentry(kt, p);
90602742ec6SJoerg Sonnenberger }
90702742ec6SJoerg Sonnenberger 
90802742ec6SJoerg Sonnenberger void
pfr_clstats_kentries(struct pfr_kentryworkq * workq,long tzero,int negchange)90902742ec6SJoerg Sonnenberger pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange)
91002742ec6SJoerg Sonnenberger {
91102742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p;
91202742ec6SJoerg Sonnenberger 
91302742ec6SJoerg Sonnenberger 	SLIST_FOREACH(p, workq, pfrke_workq) {
914cc6e5672SJoerg Sonnenberger 		crit_enter();
91502742ec6SJoerg Sonnenberger 		if (negchange)
91602742ec6SJoerg Sonnenberger 			p->pfrke_not = !p->pfrke_not;
917ed1f0be2SJan Lentfer 		if (p->pfrke_counters) {
9181186cbc0SJan Lentfer 			kfree(p->pfrke_counters, M_PFRKCOUNTERSPL);
919ed1f0be2SJan Lentfer 			p->pfrke_counters = NULL;
920ed1f0be2SJan Lentfer 		}
921cc6e5672SJoerg Sonnenberger 		crit_exit();
92202742ec6SJoerg Sonnenberger 		p->pfrke_tzero = tzero;
92302742ec6SJoerg Sonnenberger 	}
92402742ec6SJoerg Sonnenberger }
92502742ec6SJoerg Sonnenberger 
92602742ec6SJoerg Sonnenberger void
pfr_reset_feedback(struct pfr_addr * addr,int size,int flags)92702742ec6SJoerg Sonnenberger pfr_reset_feedback(struct pfr_addr *addr, int size, int flags)
92802742ec6SJoerg Sonnenberger {
92902742ec6SJoerg Sonnenberger 	struct pfr_addr	ad;
93002742ec6SJoerg Sonnenberger 	int		i;
93102742ec6SJoerg Sonnenberger 
93202742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
933315a7da3SJan Lentfer 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
93402742ec6SJoerg Sonnenberger 			break;
93502742ec6SJoerg Sonnenberger 		ad.pfra_fback = PFR_FB_NONE;
936315a7da3SJan Lentfer 		if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
93702742ec6SJoerg Sonnenberger 			break;
93802742ec6SJoerg Sonnenberger 	}
93902742ec6SJoerg Sonnenberger }
94002742ec6SJoerg Sonnenberger 
94102742ec6SJoerg Sonnenberger void
pfr_prepare_network(union sockaddr_union * sa,int af,int net)94202742ec6SJoerg Sonnenberger pfr_prepare_network(union sockaddr_union *sa, int af, int net)
94302742ec6SJoerg Sonnenberger {
94402742ec6SJoerg Sonnenberger 	int	i;
94502742ec6SJoerg Sonnenberger 
94602742ec6SJoerg Sonnenberger 	bzero(sa, sizeof(*sa));
94702742ec6SJoerg Sonnenberger 	if (af == AF_INET) {
94802742ec6SJoerg Sonnenberger 		sa->sin.sin_len = sizeof(sa->sin);
94902742ec6SJoerg Sonnenberger 		sa->sin.sin_family = AF_INET;
95070224baaSJan Lentfer 		sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0;
95170224baaSJan Lentfer 	} else if (af == AF_INET6) {
95202742ec6SJoerg Sonnenberger 		sa->sin6.sin6_len = sizeof(sa->sin6);
95302742ec6SJoerg Sonnenberger 		sa->sin6.sin6_family = AF_INET6;
95402742ec6SJoerg Sonnenberger 		for (i = 0; i < 4; i++) {
95502742ec6SJoerg Sonnenberger 			if (net <= 32) {
95602742ec6SJoerg Sonnenberger 				sa->sin6.sin6_addr.s6_addr32[i] =
95770224baaSJan Lentfer 				    net ? htonl(-1 << (32-net)) : 0;
95802742ec6SJoerg Sonnenberger 				break;
95902742ec6SJoerg Sonnenberger 			}
96002742ec6SJoerg Sonnenberger 			sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF;
96102742ec6SJoerg Sonnenberger 			net -= 32;
96202742ec6SJoerg Sonnenberger 		}
96302742ec6SJoerg Sonnenberger 	}
96402742ec6SJoerg Sonnenberger }
96502742ec6SJoerg Sonnenberger 
96602742ec6SJoerg Sonnenberger int
pfr_route_kentry(struct pfr_ktable * kt,struct pfr_kentry * ke)96702742ec6SJoerg Sonnenberger pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
96802742ec6SJoerg Sonnenberger {
96902742ec6SJoerg Sonnenberger 	union sockaddr_union	 mask;
97002742ec6SJoerg Sonnenberger 	struct radix_node	*rn;
97170224baaSJan Lentfer 	struct radix_node_head	*head = NULL;
97202742ec6SJoerg Sonnenberger 
97302742ec6SJoerg Sonnenberger 	bzero(ke->pfrke_node, sizeof(ke->pfrke_node));
97402742ec6SJoerg Sonnenberger 	if (ke->pfrke_af == AF_INET)
97502742ec6SJoerg Sonnenberger 		head = kt->pfrkt_ip4;
97670224baaSJan Lentfer 	else if (ke->pfrke_af == AF_INET6)
97702742ec6SJoerg Sonnenberger 		head = kt->pfrkt_ip6;
97802742ec6SJoerg Sonnenberger 
97902742ec6SJoerg Sonnenberger 	if (KENTRY_NETWORK(ke)) {
98002742ec6SJoerg Sonnenberger 		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
981*d8449084SAaron LI 		rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node);
98202742ec6SJoerg Sonnenberger 	} else
983*d8449084SAaron LI 		rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node);
98402742ec6SJoerg Sonnenberger 
98502742ec6SJoerg Sonnenberger 	return (rn == NULL ? -1 : 0);
98602742ec6SJoerg Sonnenberger }
98702742ec6SJoerg Sonnenberger 
98802742ec6SJoerg Sonnenberger int
pfr_unroute_kentry(struct pfr_ktable * kt,struct pfr_kentry * ke)98902742ec6SJoerg Sonnenberger pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
99002742ec6SJoerg Sonnenberger {
99102742ec6SJoerg Sonnenberger 	union sockaddr_union	 mask;
99202742ec6SJoerg Sonnenberger 	struct radix_node	*rn;
99370224baaSJan Lentfer 	struct radix_node_head	*head = NULL;
99402742ec6SJoerg Sonnenberger 
99502742ec6SJoerg Sonnenberger 	if (ke->pfrke_af == AF_INET)
99602742ec6SJoerg Sonnenberger 		head = kt->pfrkt_ip4;
99770224baaSJan Lentfer 	else if (ke->pfrke_af == AF_INET6)
99802742ec6SJoerg Sonnenberger 		head = kt->pfrkt_ip6;
99902742ec6SJoerg Sonnenberger 
100002742ec6SJoerg Sonnenberger 	if (KENTRY_NETWORK(ke)) {
100102742ec6SJoerg Sonnenberger 		pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
1002*d8449084SAaron LI 		rn = rn_delete(&ke->pfrke_sa, &mask, head);
100302742ec6SJoerg Sonnenberger 	} else
1004*d8449084SAaron LI 		rn = rn_delete(&ke->pfrke_sa, NULL, head);
100502742ec6SJoerg Sonnenberger 
100602742ec6SJoerg Sonnenberger 	if (rn == NULL) {
10074b1cf444SSascha Wildner 		kprintf("pfr_unroute_kentry: delete failed.\n");
100802742ec6SJoerg Sonnenberger 		return (-1);
100902742ec6SJoerg Sonnenberger 	}
101002742ec6SJoerg Sonnenberger 	return (0);
101102742ec6SJoerg Sonnenberger }
101202742ec6SJoerg Sonnenberger 
101302742ec6SJoerg Sonnenberger void
pfr_copyout_addr(struct pfr_addr * ad,struct pfr_kentry * ke)101402742ec6SJoerg Sonnenberger pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke)
101502742ec6SJoerg Sonnenberger {
101602742ec6SJoerg Sonnenberger 	bzero(ad, sizeof(*ad));
101702742ec6SJoerg Sonnenberger 	if (ke == NULL)
101802742ec6SJoerg Sonnenberger 		return;
101902742ec6SJoerg Sonnenberger 	ad->pfra_af = ke->pfrke_af;
102002742ec6SJoerg Sonnenberger 	ad->pfra_net = ke->pfrke_net;
102102742ec6SJoerg Sonnenberger 	ad->pfra_not = ke->pfrke_not;
102202742ec6SJoerg Sonnenberger 	if (ad->pfra_af == AF_INET)
102302742ec6SJoerg Sonnenberger 		ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr;
102470224baaSJan Lentfer 	else if (ad->pfra_af == AF_INET6)
102502742ec6SJoerg Sonnenberger 		ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr;
102602742ec6SJoerg Sonnenberger }
102702742ec6SJoerg Sonnenberger 
102802742ec6SJoerg Sonnenberger int
pfr_walktree(struct radix_node * rn,void * arg)102902742ec6SJoerg Sonnenberger pfr_walktree(struct radix_node *rn, void *arg)
103002742ec6SJoerg Sonnenberger {
103102742ec6SJoerg Sonnenberger 	struct pfr_kentry	*ke = (struct pfr_kentry *)rn;
103202742ec6SJoerg Sonnenberger 	struct pfr_walktree	*w = arg;
1033d66d8bc0SMatthew Dillon 	union sockaddr_union	pfr_mask;
1034cc6e5672SJoerg Sonnenberger 	int			flags = w->pfrw_flags;
103502742ec6SJoerg Sonnenberger 
103602742ec6SJoerg Sonnenberger 	switch (w->pfrw_op) {
103702742ec6SJoerg Sonnenberger 	case PFRW_MARK:
103802742ec6SJoerg Sonnenberger 		ke->pfrke_mark = 0;
103902742ec6SJoerg Sonnenberger 		break;
104002742ec6SJoerg Sonnenberger 	case PFRW_SWEEP:
104102742ec6SJoerg Sonnenberger 		if (ke->pfrke_mark)
104202742ec6SJoerg Sonnenberger 			break;
104302742ec6SJoerg Sonnenberger 		/* FALLTHROUGH */
104402742ec6SJoerg Sonnenberger 	case PFRW_ENQUEUE:
104502742ec6SJoerg Sonnenberger 		SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq);
104602742ec6SJoerg Sonnenberger 		w->pfrw_cnt++;
104702742ec6SJoerg Sonnenberger 		break;
104802742ec6SJoerg Sonnenberger 	case PFRW_GET_ADDRS:
104902742ec6SJoerg Sonnenberger 		if (w->pfrw_free-- > 0) {
105002742ec6SJoerg Sonnenberger 			struct pfr_addr ad;
105102742ec6SJoerg Sonnenberger 
105202742ec6SJoerg Sonnenberger 			pfr_copyout_addr(&ad, ke);
105302742ec6SJoerg Sonnenberger 			if (copyout(&ad, w->pfrw_addr, sizeof(ad)))
105402742ec6SJoerg Sonnenberger 				return (EFAULT);
105502742ec6SJoerg Sonnenberger 			w->pfrw_addr++;
105602742ec6SJoerg Sonnenberger 		}
105702742ec6SJoerg Sonnenberger 		break;
105802742ec6SJoerg Sonnenberger 	case PFRW_GET_ASTATS:
105902742ec6SJoerg Sonnenberger 		if (w->pfrw_free-- > 0) {
106002742ec6SJoerg Sonnenberger 			struct pfr_astats as;
106102742ec6SJoerg Sonnenberger 
106202742ec6SJoerg Sonnenberger 			pfr_copyout_addr(&as.pfras_a, ke);
106302742ec6SJoerg Sonnenberger 
1064cc6e5672SJoerg Sonnenberger 			crit_enter();
1065ed1f0be2SJan Lentfer 			if (ke->pfrke_counters) {
1066ed1f0be2SJan Lentfer 				bcopy(ke->pfrke_counters->pfrkc_packets,
1067ed1f0be2SJan Lentfer 				    as.pfras_packets, sizeof(as.pfras_packets));
1068ed1f0be2SJan Lentfer 				bcopy(ke->pfrke_counters->pfrkc_bytes,
1069ed1f0be2SJan Lentfer 				    as.pfras_bytes, sizeof(as.pfras_bytes));
1070ed1f0be2SJan Lentfer 			} else {
1071ed1f0be2SJan Lentfer 				bzero(as.pfras_packets, sizeof(as.pfras_packets));
1072ed1f0be2SJan Lentfer 				bzero(as.pfras_bytes, sizeof(as.pfras_bytes));
1073ed1f0be2SJan Lentfer 				as.pfras_a.pfra_fback = PFR_FB_NOCOUNT;
1074ed1f0be2SJan Lentfer 			}
1075cc6e5672SJoerg Sonnenberger 			crit_exit();
107602742ec6SJoerg Sonnenberger 			as.pfras_tzero = ke->pfrke_tzero;
107702742ec6SJoerg Sonnenberger 
1078315a7da3SJan Lentfer 			if (COPYOUT(&as, w->pfrw_astats, sizeof(as), flags))
107902742ec6SJoerg Sonnenberger 				return (EFAULT);
108002742ec6SJoerg Sonnenberger 			w->pfrw_astats++;
108102742ec6SJoerg Sonnenberger 		}
108202742ec6SJoerg Sonnenberger 		break;
108302742ec6SJoerg Sonnenberger 	case PFRW_POOL_GET:
108402742ec6SJoerg Sonnenberger 		if (ke->pfrke_not)
108502742ec6SJoerg Sonnenberger 			break; /* negative entries are ignored */
108602742ec6SJoerg Sonnenberger 		if (!w->pfrw_cnt--) {
108702742ec6SJoerg Sonnenberger 			w->pfrw_kentry = ke;
108802742ec6SJoerg Sonnenberger 			return (1); /* finish search */
108902742ec6SJoerg Sonnenberger 		}
109002742ec6SJoerg Sonnenberger 		break;
109102742ec6SJoerg Sonnenberger 	case PFRW_DYNADDR_UPDATE:
109202742ec6SJoerg Sonnenberger 		if (ke->pfrke_af == AF_INET) {
109302742ec6SJoerg Sonnenberger 			if (w->pfrw_dyn->pfid_acnt4++ > 0)
109402742ec6SJoerg Sonnenberger 				break;
109502742ec6SJoerg Sonnenberger 			pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net);
109602742ec6SJoerg Sonnenberger 			w->pfrw_dyn->pfid_addr4 = *SUNION2PF(
109702742ec6SJoerg Sonnenberger 			    &ke->pfrke_sa, AF_INET);
109802742ec6SJoerg Sonnenberger 			w->pfrw_dyn->pfid_mask4 = *SUNION2PF(
109902742ec6SJoerg Sonnenberger 			    &pfr_mask, AF_INET);
110070224baaSJan Lentfer 		} else if (ke->pfrke_af == AF_INET6){
110102742ec6SJoerg Sonnenberger 			if (w->pfrw_dyn->pfid_acnt6++ > 0)
110202742ec6SJoerg Sonnenberger 				break;
110302742ec6SJoerg Sonnenberger 			pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net);
110402742ec6SJoerg Sonnenberger 			w->pfrw_dyn->pfid_addr6 = *SUNION2PF(
110502742ec6SJoerg Sonnenberger 			    &ke->pfrke_sa, AF_INET6);
110602742ec6SJoerg Sonnenberger 			w->pfrw_dyn->pfid_mask6 = *SUNION2PF(
110702742ec6SJoerg Sonnenberger 			    &pfr_mask, AF_INET6);
110802742ec6SJoerg Sonnenberger 		}
110902742ec6SJoerg Sonnenberger 		break;
111002742ec6SJoerg Sonnenberger 	}
111102742ec6SJoerg Sonnenberger 	return (0);
111202742ec6SJoerg Sonnenberger }
111302742ec6SJoerg Sonnenberger 
111402742ec6SJoerg Sonnenberger int
pfr_clr_tables(struct pfr_table * filter,int * ndel,int flags)111502742ec6SJoerg Sonnenberger pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
111602742ec6SJoerg Sonnenberger {
111702742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 workq;
111802742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p;
1119cc6e5672SJoerg Sonnenberger 	int			 xdel = 0;
112002742ec6SJoerg Sonnenberger 
1121315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
1122315a7da3SJan Lentfer 	    PFR_FLAG_ALLRSETS);
112370224baaSJan Lentfer 	if (pfr_fix_anchor(filter->pfrt_anchor))
112470224baaSJan Lentfer 		return (EINVAL);
112502742ec6SJoerg Sonnenberger 	if (pfr_table_count(filter, flags) < 0)
112602742ec6SJoerg Sonnenberger 		return (ENOENT);
112702742ec6SJoerg Sonnenberger 
112802742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
112902742ec6SJoerg Sonnenberger 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
113002742ec6SJoerg Sonnenberger 		if (pfr_skip_table(filter, p, flags))
113102742ec6SJoerg Sonnenberger 			continue;
113202742ec6SJoerg Sonnenberger 		if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR))
113302742ec6SJoerg Sonnenberger 			continue;
113402742ec6SJoerg Sonnenberger 		if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE))
113502742ec6SJoerg Sonnenberger 			continue;
113602742ec6SJoerg Sonnenberger 		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
113702742ec6SJoerg Sonnenberger 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
113802742ec6SJoerg Sonnenberger 		xdel++;
113902742ec6SJoerg Sonnenberger 	}
114002742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
114102742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1142cc6e5672SJoerg Sonnenberger 			crit_enter();
114302742ec6SJoerg Sonnenberger 		pfr_setflags_ktables(&workq);
114402742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1145cc6e5672SJoerg Sonnenberger 			crit_exit();
114602742ec6SJoerg Sonnenberger 	}
114702742ec6SJoerg Sonnenberger 	if (ndel != NULL)
114802742ec6SJoerg Sonnenberger 		*ndel = xdel;
114902742ec6SJoerg Sonnenberger 	return (0);
115002742ec6SJoerg Sonnenberger }
115102742ec6SJoerg Sonnenberger 
115202742ec6SJoerg Sonnenberger int
pfr_add_tables(struct pfr_table * tbl,int size,int * nadd,int flags)115302742ec6SJoerg Sonnenberger pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
115402742ec6SJoerg Sonnenberger {
115502742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 addq, changeq;
115602742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p, *q, *r, key;
1157cc6e5672SJoerg Sonnenberger 	int			 i, rv, xadd = 0;
115802742ec6SJoerg Sonnenberger 	long			 tzero = time_second;
115902742ec6SJoerg Sonnenberger 
1160315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
116102742ec6SJoerg Sonnenberger 	SLIST_INIT(&addq);
116202742ec6SJoerg Sonnenberger 	SLIST_INIT(&changeq);
116302742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
1164315a7da3SJan Lentfer 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
116502742ec6SJoerg Sonnenberger 			senderr(EFAULT);
116602742ec6SJoerg Sonnenberger 		if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK,
116702742ec6SJoerg Sonnenberger 		    flags & PFR_FLAG_USERIOCTL))
116802742ec6SJoerg Sonnenberger 			senderr(EINVAL);
116902742ec6SJoerg Sonnenberger 		key.pfrkt_flags |= PFR_TFLAG_ACTIVE;
117002742ec6SJoerg Sonnenberger 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
117102742ec6SJoerg Sonnenberger 		if (p == NULL) {
117202742ec6SJoerg Sonnenberger 			p = pfr_create_ktable(&key.pfrkt_t, tzero, 1);
117302742ec6SJoerg Sonnenberger 			if (p == NULL)
117402742ec6SJoerg Sonnenberger 				senderr(ENOMEM);
117502742ec6SJoerg Sonnenberger 			SLIST_FOREACH(q, &addq, pfrkt_workq) {
117602742ec6SJoerg Sonnenberger 				if (!pfr_ktable_compare(p, q))
117702742ec6SJoerg Sonnenberger 					goto _skip;
117802742ec6SJoerg Sonnenberger 			}
117902742ec6SJoerg Sonnenberger 			SLIST_INSERT_HEAD(&addq, p, pfrkt_workq);
118002742ec6SJoerg Sonnenberger 			xadd++;
118102742ec6SJoerg Sonnenberger 			if (!key.pfrkt_anchor[0])
118202742ec6SJoerg Sonnenberger 				goto _skip;
118302742ec6SJoerg Sonnenberger 
118402742ec6SJoerg Sonnenberger 			/* find or create root table */
118502742ec6SJoerg Sonnenberger 			bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor));
118602742ec6SJoerg Sonnenberger 			r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
118702742ec6SJoerg Sonnenberger 			if (r != NULL) {
118802742ec6SJoerg Sonnenberger 				p->pfrkt_root = r;
118902742ec6SJoerg Sonnenberger 				goto _skip;
119002742ec6SJoerg Sonnenberger 			}
119102742ec6SJoerg Sonnenberger 			SLIST_FOREACH(q, &addq, pfrkt_workq) {
119202742ec6SJoerg Sonnenberger 				if (!pfr_ktable_compare(&key, q)) {
119302742ec6SJoerg Sonnenberger 					p->pfrkt_root = q;
119402742ec6SJoerg Sonnenberger 					goto _skip;
119502742ec6SJoerg Sonnenberger 				}
119602742ec6SJoerg Sonnenberger 			}
119702742ec6SJoerg Sonnenberger 			key.pfrkt_flags = 0;
119802742ec6SJoerg Sonnenberger 			r = pfr_create_ktable(&key.pfrkt_t, 0, 1);
119902742ec6SJoerg Sonnenberger 			if (r == NULL)
120002742ec6SJoerg Sonnenberger 				senderr(ENOMEM);
120102742ec6SJoerg Sonnenberger 			SLIST_INSERT_HEAD(&addq, r, pfrkt_workq);
120202742ec6SJoerg Sonnenberger 			p->pfrkt_root = r;
120302742ec6SJoerg Sonnenberger 		} else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
120402742ec6SJoerg Sonnenberger 			SLIST_FOREACH(q, &changeq, pfrkt_workq)
120502742ec6SJoerg Sonnenberger 				if (!pfr_ktable_compare(&key, q))
120602742ec6SJoerg Sonnenberger 					goto _skip;
120702742ec6SJoerg Sonnenberger 			p->pfrkt_nflags = (p->pfrkt_flags &
120802742ec6SJoerg Sonnenberger 			    ~PFR_TFLAG_USRMASK) | key.pfrkt_flags;
120902742ec6SJoerg Sonnenberger 			SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq);
121002742ec6SJoerg Sonnenberger 			xadd++;
121102742ec6SJoerg Sonnenberger 		}
121202742ec6SJoerg Sonnenberger _skip:
121302742ec6SJoerg Sonnenberger 	;
121402742ec6SJoerg Sonnenberger 	}
121502742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
121602742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1217cc6e5672SJoerg Sonnenberger 			crit_enter();
121802742ec6SJoerg Sonnenberger 		pfr_insert_ktables(&addq);
121902742ec6SJoerg Sonnenberger 		pfr_setflags_ktables(&changeq);
122002742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1221cc6e5672SJoerg Sonnenberger 			crit_exit();
122202742ec6SJoerg Sonnenberger 	} else
122302742ec6SJoerg Sonnenberger 		 pfr_destroy_ktables(&addq, 0);
122402742ec6SJoerg Sonnenberger 	if (nadd != NULL)
122502742ec6SJoerg Sonnenberger 		*nadd = xadd;
122602742ec6SJoerg Sonnenberger 	return (0);
122702742ec6SJoerg Sonnenberger _bad:
122802742ec6SJoerg Sonnenberger 	pfr_destroy_ktables(&addq, 0);
122902742ec6SJoerg Sonnenberger 	return (rv);
123002742ec6SJoerg Sonnenberger }
123102742ec6SJoerg Sonnenberger 
123202742ec6SJoerg Sonnenberger int
pfr_del_tables(struct pfr_table * tbl,int size,int * ndel,int flags)123302742ec6SJoerg Sonnenberger pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
123402742ec6SJoerg Sonnenberger {
123502742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 workq;
123602742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p, *q, key;
1237cc6e5672SJoerg Sonnenberger 	int			 i, xdel = 0;
123802742ec6SJoerg Sonnenberger 
1239315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
124002742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
124102742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
1242315a7da3SJan Lentfer 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
124302742ec6SJoerg Sonnenberger 			return (EFAULT);
124402742ec6SJoerg Sonnenberger 		if (pfr_validate_table(&key.pfrkt_t, 0,
124502742ec6SJoerg Sonnenberger 		    flags & PFR_FLAG_USERIOCTL))
124602742ec6SJoerg Sonnenberger 			return (EINVAL);
124702742ec6SJoerg Sonnenberger 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
124802742ec6SJoerg Sonnenberger 		if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
124902742ec6SJoerg Sonnenberger 			SLIST_FOREACH(q, &workq, pfrkt_workq)
125002742ec6SJoerg Sonnenberger 				if (!pfr_ktable_compare(p, q))
125102742ec6SJoerg Sonnenberger 					goto _skip;
125202742ec6SJoerg Sonnenberger 			p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
125302742ec6SJoerg Sonnenberger 			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
125402742ec6SJoerg Sonnenberger 			xdel++;
125502742ec6SJoerg Sonnenberger 		}
125602742ec6SJoerg Sonnenberger _skip:
125702742ec6SJoerg Sonnenberger 	;
125802742ec6SJoerg Sonnenberger 	}
125902742ec6SJoerg Sonnenberger 
126002742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
126102742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1262cc6e5672SJoerg Sonnenberger 			crit_enter();
126302742ec6SJoerg Sonnenberger 		pfr_setflags_ktables(&workq);
126402742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1265cc6e5672SJoerg Sonnenberger 			crit_exit();
126602742ec6SJoerg Sonnenberger 	}
126702742ec6SJoerg Sonnenberger 	if (ndel != NULL)
126802742ec6SJoerg Sonnenberger 		*ndel = xdel;
126902742ec6SJoerg Sonnenberger 	return (0);
127002742ec6SJoerg Sonnenberger }
127102742ec6SJoerg Sonnenberger 
127202742ec6SJoerg Sonnenberger int
pfr_get_tables(struct pfr_table * filter,struct pfr_table * tbl,int * size,int flags)127302742ec6SJoerg Sonnenberger pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
127402742ec6SJoerg Sonnenberger 	int flags)
127502742ec6SJoerg Sonnenberger {
127602742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p;
127702742ec6SJoerg Sonnenberger 	int			 n, nn;
127802742ec6SJoerg Sonnenberger 
1279315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS);
128070224baaSJan Lentfer 	if (pfr_fix_anchor(filter->pfrt_anchor))
128170224baaSJan Lentfer 		return (EINVAL);
128202742ec6SJoerg Sonnenberger 	n = nn = pfr_table_count(filter, flags);
128302742ec6SJoerg Sonnenberger 	if (n < 0)
128402742ec6SJoerg Sonnenberger 		return (ENOENT);
128502742ec6SJoerg Sonnenberger 	if (n > *size) {
128602742ec6SJoerg Sonnenberger 		*size = n;
128702742ec6SJoerg Sonnenberger 		return (0);
128802742ec6SJoerg Sonnenberger 	}
128902742ec6SJoerg Sonnenberger 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
129002742ec6SJoerg Sonnenberger 		if (pfr_skip_table(filter, p, flags))
129102742ec6SJoerg Sonnenberger 			continue;
129202742ec6SJoerg Sonnenberger 		if (n-- <= 0)
129302742ec6SJoerg Sonnenberger 			continue;
1294315a7da3SJan Lentfer 		if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), flags))
129502742ec6SJoerg Sonnenberger 			return (EFAULT);
129602742ec6SJoerg Sonnenberger 	}
129702742ec6SJoerg Sonnenberger 	if (n) {
12984b1cf444SSascha Wildner 		kprintf("pfr_get_tables: corruption detected (%d).\n", n);
129902742ec6SJoerg Sonnenberger 		return (ENOTTY);
130002742ec6SJoerg Sonnenberger 	}
130102742ec6SJoerg Sonnenberger 	*size = nn;
130202742ec6SJoerg Sonnenberger 	return (0);
130302742ec6SJoerg Sonnenberger }
130402742ec6SJoerg Sonnenberger 
130502742ec6SJoerg Sonnenberger int
pfr_get_tstats(struct pfr_table * filter,struct pfr_tstats * tbl,int * size,int flags)130602742ec6SJoerg Sonnenberger pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
130702742ec6SJoerg Sonnenberger 	int flags)
130802742ec6SJoerg Sonnenberger {
130902742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p;
131002742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 workq;
1311cc6e5672SJoerg Sonnenberger 	int			 n, nn;
131202742ec6SJoerg Sonnenberger 	long			 tzero = time_second;
131302742ec6SJoerg Sonnenberger 
131402742ec6SJoerg Sonnenberger 	/* XXX PFR_FLAG_CLSTATS disabled */
1315315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_ALLRSETS);
131670224baaSJan Lentfer 	if (pfr_fix_anchor(filter->pfrt_anchor))
131770224baaSJan Lentfer 		return (EINVAL);
131802742ec6SJoerg Sonnenberger 	n = nn = pfr_table_count(filter, flags);
131902742ec6SJoerg Sonnenberger 	if (n < 0)
132002742ec6SJoerg Sonnenberger 		return (ENOENT);
132102742ec6SJoerg Sonnenberger 	if (n > *size) {
132202742ec6SJoerg Sonnenberger 		*size = n;
132302742ec6SJoerg Sonnenberger 		return (0);
132402742ec6SJoerg Sonnenberger 	}
132502742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
132602742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_ATOMIC)
1327cc6e5672SJoerg Sonnenberger 		crit_enter();
132802742ec6SJoerg Sonnenberger 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
132902742ec6SJoerg Sonnenberger 		if (pfr_skip_table(filter, p, flags))
133002742ec6SJoerg Sonnenberger 			continue;
133102742ec6SJoerg Sonnenberger 		if (n-- <= 0)
133202742ec6SJoerg Sonnenberger 			continue;
133302742ec6SJoerg Sonnenberger 		if (!(flags & PFR_FLAG_ATOMIC))
1334cc6e5672SJoerg Sonnenberger 			crit_enter();
1335315a7da3SJan Lentfer 		if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), flags)) {
1336cc6e5672SJoerg Sonnenberger 			crit_exit();
133702742ec6SJoerg Sonnenberger 			return (EFAULT);
133802742ec6SJoerg Sonnenberger 		}
133902742ec6SJoerg Sonnenberger 		if (!(flags & PFR_FLAG_ATOMIC))
1340cc6e5672SJoerg Sonnenberger 			crit_exit();
134102742ec6SJoerg Sonnenberger 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
134202742ec6SJoerg Sonnenberger 	}
134302742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_CLSTATS)
134402742ec6SJoerg Sonnenberger 		pfr_clstats_ktables(&workq, tzero,
134502742ec6SJoerg Sonnenberger 		    flags & PFR_FLAG_ADDRSTOO);
134602742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_ATOMIC)
1347cc6e5672SJoerg Sonnenberger 		crit_exit();
134802742ec6SJoerg Sonnenberger 	if (n) {
13494b1cf444SSascha Wildner 		kprintf("pfr_get_tstats: corruption detected (%d).\n", n);
135002742ec6SJoerg Sonnenberger 		return (ENOTTY);
135102742ec6SJoerg Sonnenberger 	}
135202742ec6SJoerg Sonnenberger 	*size = nn;
135302742ec6SJoerg Sonnenberger 	return (0);
135402742ec6SJoerg Sonnenberger }
135502742ec6SJoerg Sonnenberger 
135602742ec6SJoerg Sonnenberger int
pfr_clr_tstats(struct pfr_table * tbl,int size,int * nzero,int flags)135702742ec6SJoerg Sonnenberger pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
135802742ec6SJoerg Sonnenberger {
135902742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 workq;
136002742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p, key;
1361cc6e5672SJoerg Sonnenberger 	int			 i, xzero = 0;
136202742ec6SJoerg Sonnenberger 	long			 tzero = time_second;
136302742ec6SJoerg Sonnenberger 
1364315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
1365315a7da3SJan Lentfer 	    PFR_FLAG_ADDRSTOO);
136602742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
136702742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
1368315a7da3SJan Lentfer 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
136902742ec6SJoerg Sonnenberger 			return (EFAULT);
137002742ec6SJoerg Sonnenberger 		if (pfr_validate_table(&key.pfrkt_t, 0, 0))
137102742ec6SJoerg Sonnenberger 			return (EINVAL);
137202742ec6SJoerg Sonnenberger 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
137302742ec6SJoerg Sonnenberger 		if (p != NULL) {
137402742ec6SJoerg Sonnenberger 			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
137502742ec6SJoerg Sonnenberger 			xzero++;
137602742ec6SJoerg Sonnenberger 		}
137702742ec6SJoerg Sonnenberger 	}
137802742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
137902742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1380cc6e5672SJoerg Sonnenberger 			crit_enter();
138102742ec6SJoerg Sonnenberger 		pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO);
138202742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1383cc6e5672SJoerg Sonnenberger 			crit_exit();
138402742ec6SJoerg Sonnenberger 	}
138502742ec6SJoerg Sonnenberger 	if (nzero != NULL)
138602742ec6SJoerg Sonnenberger 		*nzero = xzero;
138702742ec6SJoerg Sonnenberger 	return (0);
138802742ec6SJoerg Sonnenberger }
138902742ec6SJoerg Sonnenberger 
139002742ec6SJoerg Sonnenberger int
pfr_set_tflags(struct pfr_table * tbl,int size,int setflag,int clrflag,int * nchange,int * ndel,int flags)139102742ec6SJoerg Sonnenberger pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
139202742ec6SJoerg Sonnenberger 	int *nchange, int *ndel, int flags)
139302742ec6SJoerg Sonnenberger {
139402742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 workq;
139502742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p, *q, key;
1396cc6e5672SJoerg Sonnenberger 	int			 i, xchange = 0, xdel = 0;
139702742ec6SJoerg Sonnenberger 
1398315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
139902742ec6SJoerg Sonnenberger 	if ((setflag & ~PFR_TFLAG_USRMASK) ||
140002742ec6SJoerg Sonnenberger 	    (clrflag & ~PFR_TFLAG_USRMASK) ||
140102742ec6SJoerg Sonnenberger 	    (setflag & clrflag))
140202742ec6SJoerg Sonnenberger 		return (EINVAL);
140302742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
140402742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
1405315a7da3SJan Lentfer 		if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
140602742ec6SJoerg Sonnenberger 			return (EFAULT);
140702742ec6SJoerg Sonnenberger 		if (pfr_validate_table(&key.pfrkt_t, 0,
140802742ec6SJoerg Sonnenberger 		    flags & PFR_FLAG_USERIOCTL))
140902742ec6SJoerg Sonnenberger 			return (EINVAL);
141002742ec6SJoerg Sonnenberger 		p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
141102742ec6SJoerg Sonnenberger 		if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
141202742ec6SJoerg Sonnenberger 			p->pfrkt_nflags = (p->pfrkt_flags | setflag) &
141302742ec6SJoerg Sonnenberger 			    ~clrflag;
141402742ec6SJoerg Sonnenberger 			if (p->pfrkt_nflags == p->pfrkt_flags)
141502742ec6SJoerg Sonnenberger 				goto _skip;
141602742ec6SJoerg Sonnenberger 			SLIST_FOREACH(q, &workq, pfrkt_workq)
141702742ec6SJoerg Sonnenberger 				if (!pfr_ktable_compare(p, q))
141802742ec6SJoerg Sonnenberger 					goto _skip;
141902742ec6SJoerg Sonnenberger 			SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
142002742ec6SJoerg Sonnenberger 			if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) &&
142102742ec6SJoerg Sonnenberger 			    (clrflag & PFR_TFLAG_PERSIST) &&
142202742ec6SJoerg Sonnenberger 			    !(p->pfrkt_flags & PFR_TFLAG_REFERENCED))
142302742ec6SJoerg Sonnenberger 				xdel++;
142402742ec6SJoerg Sonnenberger 			else
142502742ec6SJoerg Sonnenberger 				xchange++;
142602742ec6SJoerg Sonnenberger 		}
142702742ec6SJoerg Sonnenberger _skip:
142802742ec6SJoerg Sonnenberger 	;
142902742ec6SJoerg Sonnenberger 	}
143002742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
143102742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1432cc6e5672SJoerg Sonnenberger 			crit_enter();
143302742ec6SJoerg Sonnenberger 		pfr_setflags_ktables(&workq);
143402742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1435cc6e5672SJoerg Sonnenberger 			crit_exit();
143602742ec6SJoerg Sonnenberger 	}
143702742ec6SJoerg Sonnenberger 	if (nchange != NULL)
143802742ec6SJoerg Sonnenberger 		*nchange = xchange;
143902742ec6SJoerg Sonnenberger 	if (ndel != NULL)
144002742ec6SJoerg Sonnenberger 		*ndel = xdel;
144102742ec6SJoerg Sonnenberger 	return (0);
144202742ec6SJoerg Sonnenberger }
144302742ec6SJoerg Sonnenberger 
144402742ec6SJoerg Sonnenberger int
pfr_ina_begin(struct pfr_table * trs,u_int32_t * ticket,int * ndel,int flags)144502742ec6SJoerg Sonnenberger pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags)
144602742ec6SJoerg Sonnenberger {
144702742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 workq;
144802742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p;
144902742ec6SJoerg Sonnenberger 	struct pf_ruleset	*rs;
145002742ec6SJoerg Sonnenberger 	int			 xdel = 0;
145102742ec6SJoerg Sonnenberger 
1452315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
145370224baaSJan Lentfer 	rs = pf_find_or_create_ruleset(trs->pfrt_anchor);
145402742ec6SJoerg Sonnenberger 	if (rs == NULL)
145502742ec6SJoerg Sonnenberger 		return (ENOMEM);
145602742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
145702742ec6SJoerg Sonnenberger 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
145802742ec6SJoerg Sonnenberger 		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
145902742ec6SJoerg Sonnenberger 		    pfr_skip_table(trs, p, 0))
146002742ec6SJoerg Sonnenberger 			continue;
146102742ec6SJoerg Sonnenberger 		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
146202742ec6SJoerg Sonnenberger 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
146302742ec6SJoerg Sonnenberger 		xdel++;
146402742ec6SJoerg Sonnenberger 	}
146502742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
146602742ec6SJoerg Sonnenberger 		pfr_setflags_ktables(&workq);
146702742ec6SJoerg Sonnenberger 		if (ticket != NULL)
146802742ec6SJoerg Sonnenberger 			*ticket = ++rs->tticket;
146902742ec6SJoerg Sonnenberger 		rs->topen = 1;
147002742ec6SJoerg Sonnenberger 	} else
147102742ec6SJoerg Sonnenberger 		pf_remove_if_empty_ruleset(rs);
147202742ec6SJoerg Sonnenberger 	if (ndel != NULL)
147302742ec6SJoerg Sonnenberger 		*ndel = xdel;
147402742ec6SJoerg Sonnenberger 	return (0);
147502742ec6SJoerg Sonnenberger }
147602742ec6SJoerg Sonnenberger 
147702742ec6SJoerg Sonnenberger int
pfr_ina_define(struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int * naddr,u_int32_t ticket,int flags)147802742ec6SJoerg Sonnenberger pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
147902742ec6SJoerg Sonnenberger     int *nadd, int *naddr, u_int32_t ticket, int flags)
148002742ec6SJoerg Sonnenberger {
148102742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 tableq;
148202742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	 addrq;
148302742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt, *rt, *shadow, key;
148402742ec6SJoerg Sonnenberger 	struct pfr_kentry	*p;
148502742ec6SJoerg Sonnenberger 	struct pfr_addr		 ad;
148602742ec6SJoerg Sonnenberger 	struct pf_ruleset	*rs;
148702742ec6SJoerg Sonnenberger 	int			 i, rv, xadd = 0, xaddr = 0;
148802742ec6SJoerg Sonnenberger 
1489315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO);
149002742ec6SJoerg Sonnenberger 	if (size && !(flags & PFR_FLAG_ADDRSTOO))
149102742ec6SJoerg Sonnenberger 		return (EINVAL);
149202742ec6SJoerg Sonnenberger 	if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK,
149302742ec6SJoerg Sonnenberger 	    flags & PFR_FLAG_USERIOCTL))
149402742ec6SJoerg Sonnenberger 		return (EINVAL);
149570224baaSJan Lentfer 	rs = pf_find_ruleset(tbl->pfrt_anchor);
149602742ec6SJoerg Sonnenberger 	if (rs == NULL || !rs->topen || ticket != rs->tticket)
149702742ec6SJoerg Sonnenberger 		return (EBUSY);
149802742ec6SJoerg Sonnenberger 	tbl->pfrt_flags |= PFR_TFLAG_INACTIVE;
149902742ec6SJoerg Sonnenberger 	SLIST_INIT(&tableq);
150002742ec6SJoerg Sonnenberger 	kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl);
150102742ec6SJoerg Sonnenberger 	if (kt == NULL) {
150202742ec6SJoerg Sonnenberger 		kt = pfr_create_ktable(tbl, 0, 1);
150302742ec6SJoerg Sonnenberger 		if (kt == NULL)
150402742ec6SJoerg Sonnenberger 			return (ENOMEM);
150502742ec6SJoerg Sonnenberger 		SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq);
150602742ec6SJoerg Sonnenberger 		xadd++;
150702742ec6SJoerg Sonnenberger 		if (!tbl->pfrt_anchor[0])
150802742ec6SJoerg Sonnenberger 			goto _skip;
150902742ec6SJoerg Sonnenberger 
151002742ec6SJoerg Sonnenberger 		/* find or create root table */
151102742ec6SJoerg Sonnenberger 		bzero(&key, sizeof(key));
151202742ec6SJoerg Sonnenberger 		strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name));
151302742ec6SJoerg Sonnenberger 		rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
151402742ec6SJoerg Sonnenberger 		if (rt != NULL) {
151502742ec6SJoerg Sonnenberger 			kt->pfrkt_root = rt;
151602742ec6SJoerg Sonnenberger 			goto _skip;
151702742ec6SJoerg Sonnenberger 		}
151802742ec6SJoerg Sonnenberger 		rt = pfr_create_ktable(&key.pfrkt_t, 0, 1);
151902742ec6SJoerg Sonnenberger 		if (rt == NULL) {
152002742ec6SJoerg Sonnenberger 			pfr_destroy_ktables(&tableq, 0);
152102742ec6SJoerg Sonnenberger 			return (ENOMEM);
152202742ec6SJoerg Sonnenberger 		}
152302742ec6SJoerg Sonnenberger 		SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq);
152402742ec6SJoerg Sonnenberger 		kt->pfrkt_root = rt;
152502742ec6SJoerg Sonnenberger 	} else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE))
152602742ec6SJoerg Sonnenberger 		xadd++;
152702742ec6SJoerg Sonnenberger _skip:
152802742ec6SJoerg Sonnenberger 	shadow = pfr_create_ktable(tbl, 0, 0);
152902742ec6SJoerg Sonnenberger 	if (shadow == NULL) {
153002742ec6SJoerg Sonnenberger 		pfr_destroy_ktables(&tableq, 0);
153102742ec6SJoerg Sonnenberger 		return (ENOMEM);
153202742ec6SJoerg Sonnenberger 	}
153302742ec6SJoerg Sonnenberger 	SLIST_INIT(&addrq);
153402742ec6SJoerg Sonnenberger 	for (i = 0; i < size; i++) {
1535315a7da3SJan Lentfer 		if (COPYIN(addr+i, &ad, sizeof(ad), flags))
153602742ec6SJoerg Sonnenberger 			senderr(EFAULT);
153702742ec6SJoerg Sonnenberger 		if (pfr_validate_addr(&ad))
153802742ec6SJoerg Sonnenberger 			senderr(EINVAL);
153902742ec6SJoerg Sonnenberger 		if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
154002742ec6SJoerg Sonnenberger 			continue;
154170224baaSJan Lentfer 		p = pfr_create_kentry(&ad, 0);
154202742ec6SJoerg Sonnenberger 		if (p == NULL)
154302742ec6SJoerg Sonnenberger 			senderr(ENOMEM);
154402742ec6SJoerg Sonnenberger 		if (pfr_route_kentry(shadow, p)) {
154502742ec6SJoerg Sonnenberger 			pfr_destroy_kentry(p);
154602742ec6SJoerg Sonnenberger 			continue;
154702742ec6SJoerg Sonnenberger 		}
154802742ec6SJoerg Sonnenberger 		SLIST_INSERT_HEAD(&addrq, p, pfrke_workq);
154902742ec6SJoerg Sonnenberger 		xaddr++;
155002742ec6SJoerg Sonnenberger 	}
155102742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
155202742ec6SJoerg Sonnenberger 		if (kt->pfrkt_shadow != NULL)
155302742ec6SJoerg Sonnenberger 			pfr_destroy_ktable(kt->pfrkt_shadow, 1);
155402742ec6SJoerg Sonnenberger 		kt->pfrkt_flags |= PFR_TFLAG_INACTIVE;
155502742ec6SJoerg Sonnenberger 		pfr_insert_ktables(&tableq);
155602742ec6SJoerg Sonnenberger 		shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ?
155702742ec6SJoerg Sonnenberger 		    xaddr : NO_ADDRESSES;
155802742ec6SJoerg Sonnenberger 		kt->pfrkt_shadow = shadow;
155902742ec6SJoerg Sonnenberger 	} else {
156002742ec6SJoerg Sonnenberger 		pfr_clean_node_mask(shadow, &addrq);
156102742ec6SJoerg Sonnenberger 		pfr_destroy_ktable(shadow, 0);
156202742ec6SJoerg Sonnenberger 		pfr_destroy_ktables(&tableq, 0);
156302742ec6SJoerg Sonnenberger 		pfr_destroy_kentries(&addrq);
156402742ec6SJoerg Sonnenberger 	}
156502742ec6SJoerg Sonnenberger 	if (nadd != NULL)
156602742ec6SJoerg Sonnenberger 		*nadd = xadd;
156702742ec6SJoerg Sonnenberger 	if (naddr != NULL)
156802742ec6SJoerg Sonnenberger 		*naddr = xaddr;
156902742ec6SJoerg Sonnenberger 	return (0);
157002742ec6SJoerg Sonnenberger _bad:
157102742ec6SJoerg Sonnenberger 	pfr_destroy_ktable(shadow, 0);
157202742ec6SJoerg Sonnenberger 	pfr_destroy_ktables(&tableq, 0);
157302742ec6SJoerg Sonnenberger 	pfr_destroy_kentries(&addrq);
157402742ec6SJoerg Sonnenberger 	return (rv);
157502742ec6SJoerg Sonnenberger }
157602742ec6SJoerg Sonnenberger 
157702742ec6SJoerg Sonnenberger int
pfr_ina_rollback(struct pfr_table * trs,u_int32_t ticket,int * ndel,int flags)157802742ec6SJoerg Sonnenberger pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags)
157902742ec6SJoerg Sonnenberger {
158002742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 workq;
158102742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p;
158202742ec6SJoerg Sonnenberger 	struct pf_ruleset	*rs;
158302742ec6SJoerg Sonnenberger 	int			 xdel = 0;
158402742ec6SJoerg Sonnenberger 
1585315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
158670224baaSJan Lentfer 	rs = pf_find_ruleset(trs->pfrt_anchor);
158702742ec6SJoerg Sonnenberger 	if (rs == NULL || !rs->topen || ticket != rs->tticket)
158802742ec6SJoerg Sonnenberger 		return (0);
158902742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
159002742ec6SJoerg Sonnenberger 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
159102742ec6SJoerg Sonnenberger 		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
159202742ec6SJoerg Sonnenberger 		    pfr_skip_table(trs, p, 0))
159302742ec6SJoerg Sonnenberger 			continue;
159402742ec6SJoerg Sonnenberger 		p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
159502742ec6SJoerg Sonnenberger 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
159602742ec6SJoerg Sonnenberger 		xdel++;
159702742ec6SJoerg Sonnenberger 	}
159802742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
159902742ec6SJoerg Sonnenberger 		pfr_setflags_ktables(&workq);
160002742ec6SJoerg Sonnenberger 		rs->topen = 0;
160102742ec6SJoerg Sonnenberger 		pf_remove_if_empty_ruleset(rs);
160202742ec6SJoerg Sonnenberger 	}
160302742ec6SJoerg Sonnenberger 	if (ndel != NULL)
160402742ec6SJoerg Sonnenberger 		*ndel = xdel;
160502742ec6SJoerg Sonnenberger 	return (0);
160602742ec6SJoerg Sonnenberger }
160702742ec6SJoerg Sonnenberger 
160802742ec6SJoerg Sonnenberger int
pfr_ina_commit(struct pfr_table * trs,u_int32_t ticket,int * nadd,int * nchange,int flags)160902742ec6SJoerg Sonnenberger pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
161002742ec6SJoerg Sonnenberger     int *nchange, int flags)
161102742ec6SJoerg Sonnenberger {
161270224baaSJan Lentfer 	struct pfr_ktable	*p, *q;
161302742ec6SJoerg Sonnenberger 	struct pfr_ktableworkq	 workq;
161402742ec6SJoerg Sonnenberger 	struct pf_ruleset	*rs;
1615cc6e5672SJoerg Sonnenberger 	int			 xadd = 0, xchange = 0;
161602742ec6SJoerg Sonnenberger 	long			 tzero = time_second;
161702742ec6SJoerg Sonnenberger 
1618315a7da3SJan Lentfer 	ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
161970224baaSJan Lentfer 	rs = pf_find_ruleset(trs->pfrt_anchor);
162002742ec6SJoerg Sonnenberger 	if (rs == NULL || !rs->topen || ticket != rs->tticket)
162102742ec6SJoerg Sonnenberger 		return (EBUSY);
162202742ec6SJoerg Sonnenberger 
162302742ec6SJoerg Sonnenberger 	SLIST_INIT(&workq);
162402742ec6SJoerg Sonnenberger 	RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
162502742ec6SJoerg Sonnenberger 		if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
162602742ec6SJoerg Sonnenberger 		    pfr_skip_table(trs, p, 0))
162702742ec6SJoerg Sonnenberger 			continue;
162802742ec6SJoerg Sonnenberger 		SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
162902742ec6SJoerg Sonnenberger 		if (p->pfrkt_flags & PFR_TFLAG_ACTIVE)
163002742ec6SJoerg Sonnenberger 			xchange++;
163102742ec6SJoerg Sonnenberger 		else
163202742ec6SJoerg Sonnenberger 			xadd++;
163302742ec6SJoerg Sonnenberger 	}
163402742ec6SJoerg Sonnenberger 
163502742ec6SJoerg Sonnenberger 	if (!(flags & PFR_FLAG_DUMMY)) {
163602742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1637cc6e5672SJoerg Sonnenberger 			crit_enter();
163870224baaSJan Lentfer 		for (p = SLIST_FIRST(&workq); p != NULL; p = q) {
163970224baaSJan Lentfer 			q = SLIST_NEXT(p, pfrkt_workq);
164002742ec6SJoerg Sonnenberger 			pfr_commit_ktable(p, tzero);
164170224baaSJan Lentfer 		}
164202742ec6SJoerg Sonnenberger 		if (flags & PFR_FLAG_ATOMIC)
1643cc6e5672SJoerg Sonnenberger 			crit_exit();
164402742ec6SJoerg Sonnenberger 		rs->topen = 0;
164502742ec6SJoerg Sonnenberger 		pf_remove_if_empty_ruleset(rs);
164602742ec6SJoerg Sonnenberger 	}
164702742ec6SJoerg Sonnenberger 	if (nadd != NULL)
164802742ec6SJoerg Sonnenberger 		*nadd = xadd;
164902742ec6SJoerg Sonnenberger 	if (nchange != NULL)
165002742ec6SJoerg Sonnenberger 		*nchange = xchange;
165102742ec6SJoerg Sonnenberger 
165202742ec6SJoerg Sonnenberger 	return (0);
165302742ec6SJoerg Sonnenberger }
165402742ec6SJoerg Sonnenberger 
165502742ec6SJoerg Sonnenberger void
pfr_commit_ktable(struct pfr_ktable * kt,long tzero)165602742ec6SJoerg Sonnenberger pfr_commit_ktable(struct pfr_ktable *kt, long tzero)
165702742ec6SJoerg Sonnenberger {
165802742ec6SJoerg Sonnenberger 	struct pfr_ktable	*shadow = kt->pfrkt_shadow;
165902742ec6SJoerg Sonnenberger 	int			 nflags;
166002742ec6SJoerg Sonnenberger 
166102742ec6SJoerg Sonnenberger 	if (shadow->pfrkt_cnt == NO_ADDRESSES) {
166202742ec6SJoerg Sonnenberger 		if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
166302742ec6SJoerg Sonnenberger 			pfr_clstats_ktable(kt, tzero, 1);
166402742ec6SJoerg Sonnenberger 	} else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) {
166502742ec6SJoerg Sonnenberger 		/* kt might contain addresses */
166602742ec6SJoerg Sonnenberger 		struct pfr_kentryworkq	 addrq, addq, changeq, delq, garbageq;
166702742ec6SJoerg Sonnenberger 		struct pfr_kentry	*p, *q, *next;
166802742ec6SJoerg Sonnenberger 		struct pfr_addr		 ad;
166902742ec6SJoerg Sonnenberger 
167002742ec6SJoerg Sonnenberger 		pfr_enqueue_addrs(shadow, &addrq, NULL, 0);
167102742ec6SJoerg Sonnenberger 		pfr_mark_addrs(kt);
167202742ec6SJoerg Sonnenberger 		SLIST_INIT(&addq);
167302742ec6SJoerg Sonnenberger 		SLIST_INIT(&changeq);
167402742ec6SJoerg Sonnenberger 		SLIST_INIT(&delq);
167502742ec6SJoerg Sonnenberger 		SLIST_INIT(&garbageq);
167602742ec6SJoerg Sonnenberger 		pfr_clean_node_mask(shadow, &addrq);
167702742ec6SJoerg Sonnenberger 		for (p = SLIST_FIRST(&addrq); p != NULL; p = next) {
167802742ec6SJoerg Sonnenberger 			next = SLIST_NEXT(p, pfrke_workq);	/* XXX */
167902742ec6SJoerg Sonnenberger 			pfr_copyout_addr(&ad, p);
168002742ec6SJoerg Sonnenberger 			q = pfr_lookup_addr(kt, &ad, 1);
168102742ec6SJoerg Sonnenberger 			if (q != NULL) {
168202742ec6SJoerg Sonnenberger 				if (q->pfrke_not != p->pfrke_not)
168302742ec6SJoerg Sonnenberger 					SLIST_INSERT_HEAD(&changeq, q,
168402742ec6SJoerg Sonnenberger 					    pfrke_workq);
168502742ec6SJoerg Sonnenberger 				q->pfrke_mark = 1;
168602742ec6SJoerg Sonnenberger 				SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq);
168702742ec6SJoerg Sonnenberger 			} else {
168802742ec6SJoerg Sonnenberger 				p->pfrke_tzero = tzero;
168902742ec6SJoerg Sonnenberger 				SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
169002742ec6SJoerg Sonnenberger 			}
169102742ec6SJoerg Sonnenberger 		}
169202742ec6SJoerg Sonnenberger 		pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY);
169302742ec6SJoerg Sonnenberger 		pfr_insert_kentries(kt, &addq, tzero);
169402742ec6SJoerg Sonnenberger 		pfr_remove_kentries(kt, &delq);
169502742ec6SJoerg Sonnenberger 		pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
169602742ec6SJoerg Sonnenberger 		pfr_destroy_kentries(&garbageq);
169702742ec6SJoerg Sonnenberger 	} else {
169802742ec6SJoerg Sonnenberger 		/* kt cannot contain addresses */
169902742ec6SJoerg Sonnenberger 		SWAP(struct radix_node_head *, kt->pfrkt_ip4,
170002742ec6SJoerg Sonnenberger 		    shadow->pfrkt_ip4);
170102742ec6SJoerg Sonnenberger 		SWAP(struct radix_node_head *, kt->pfrkt_ip6,
170202742ec6SJoerg Sonnenberger 		    shadow->pfrkt_ip6);
170302742ec6SJoerg Sonnenberger 		SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt);
170402742ec6SJoerg Sonnenberger 		pfr_clstats_ktable(kt, tzero, 1);
170502742ec6SJoerg Sonnenberger 	}
170602742ec6SJoerg Sonnenberger 	nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) |
170702742ec6SJoerg Sonnenberger 	    (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE)
170802742ec6SJoerg Sonnenberger 		& ~PFR_TFLAG_INACTIVE;
170902742ec6SJoerg Sonnenberger 	pfr_destroy_ktable(shadow, 0);
171002742ec6SJoerg Sonnenberger 	kt->pfrkt_shadow = NULL;
171102742ec6SJoerg Sonnenberger 	pfr_setflags_ktable(kt, nflags);
171202742ec6SJoerg Sonnenberger }
171302742ec6SJoerg Sonnenberger 
171402742ec6SJoerg Sonnenberger int
pfr_validate_table(struct pfr_table * tbl,int allowedflags,int no_reserved)171502742ec6SJoerg Sonnenberger pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved)
171602742ec6SJoerg Sonnenberger {
171702742ec6SJoerg Sonnenberger 	int i;
171802742ec6SJoerg Sonnenberger 
171902742ec6SJoerg Sonnenberger 	if (!tbl->pfrt_name[0])
172002742ec6SJoerg Sonnenberger 		return (-1);
172102742ec6SJoerg Sonnenberger 	if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR))
172202742ec6SJoerg Sonnenberger 		 return (-1);
172302742ec6SJoerg Sonnenberger 	if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1])
172402742ec6SJoerg Sonnenberger 		return (-1);
172502742ec6SJoerg Sonnenberger 	for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++)
172602742ec6SJoerg Sonnenberger 		if (tbl->pfrt_name[i])
172702742ec6SJoerg Sonnenberger 			return (-1);
172870224baaSJan Lentfer 	if (pfr_fix_anchor(tbl->pfrt_anchor))
172970224baaSJan Lentfer 		return (-1);
173002742ec6SJoerg Sonnenberger 	if (tbl->pfrt_flags & ~allowedflags)
173102742ec6SJoerg Sonnenberger 		return (-1);
173202742ec6SJoerg Sonnenberger 	return (0);
173302742ec6SJoerg Sonnenberger }
173402742ec6SJoerg Sonnenberger 
173570224baaSJan Lentfer /*
173670224baaSJan Lentfer  * Rewrite anchors referenced by tables to remove slashes
173770224baaSJan Lentfer  * and check for validity.
173870224baaSJan Lentfer  */
173970224baaSJan Lentfer int
pfr_fix_anchor(char * anchor)174070224baaSJan Lentfer pfr_fix_anchor(char *anchor)
174170224baaSJan Lentfer {
174270224baaSJan Lentfer 	size_t siz = MAXPATHLEN;
174370224baaSJan Lentfer 	int i;
174470224baaSJan Lentfer 
174570224baaSJan Lentfer 	if (anchor[0] == '/') {
174670224baaSJan Lentfer 		char *path;
174770224baaSJan Lentfer 		int off;
174870224baaSJan Lentfer 
174970224baaSJan Lentfer 		path = anchor;
175070224baaSJan Lentfer 		off = 1;
175170224baaSJan Lentfer 		while (*++path == '/')
175270224baaSJan Lentfer 			off++;
175370224baaSJan Lentfer 		bcopy(path, anchor, siz - off);
175470224baaSJan Lentfer 		memset(anchor + siz - off, 0, off);
175570224baaSJan Lentfer 	}
175670224baaSJan Lentfer 	if (anchor[siz - 1])
175770224baaSJan Lentfer 		return (-1);
175870224baaSJan Lentfer 	for (i = strlen(anchor); i < siz; i++)
175970224baaSJan Lentfer 		if (anchor[i])
176070224baaSJan Lentfer 			return (-1);
176170224baaSJan Lentfer 	return (0);
176270224baaSJan Lentfer }
176370224baaSJan Lentfer 
176402742ec6SJoerg Sonnenberger int
pfr_table_count(struct pfr_table * filter,int flags)176502742ec6SJoerg Sonnenberger pfr_table_count(struct pfr_table *filter, int flags)
176602742ec6SJoerg Sonnenberger {
176702742ec6SJoerg Sonnenberger 	struct pf_ruleset *rs;
176802742ec6SJoerg Sonnenberger 
176902742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_ALLRSETS)
177002742ec6SJoerg Sonnenberger 		return (pfr_ktable_cnt);
177102742ec6SJoerg Sonnenberger 	if (filter->pfrt_anchor[0]) {
177270224baaSJan Lentfer 		rs = pf_find_ruleset(filter->pfrt_anchor);
177370224baaSJan Lentfer 		return ((rs != NULL) ? rs->tables : -1);
177402742ec6SJoerg Sonnenberger 	}
177502742ec6SJoerg Sonnenberger 	return (pf_main_ruleset.tables);
177602742ec6SJoerg Sonnenberger }
177702742ec6SJoerg Sonnenberger 
177802742ec6SJoerg Sonnenberger int
pfr_skip_table(struct pfr_table * filter,struct pfr_ktable * kt,int flags)177902742ec6SJoerg Sonnenberger pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags)
178002742ec6SJoerg Sonnenberger {
178102742ec6SJoerg Sonnenberger 	if (flags & PFR_FLAG_ALLRSETS)
178202742ec6SJoerg Sonnenberger 		return (0);
178370224baaSJan Lentfer 	if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor))
178402742ec6SJoerg Sonnenberger 		return (1);
178502742ec6SJoerg Sonnenberger 	return (0);
178602742ec6SJoerg Sonnenberger }
178702742ec6SJoerg Sonnenberger 
178802742ec6SJoerg Sonnenberger void
pfr_insert_ktables(struct pfr_ktableworkq * workq)178902742ec6SJoerg Sonnenberger pfr_insert_ktables(struct pfr_ktableworkq *workq)
179002742ec6SJoerg Sonnenberger {
179102742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p;
179202742ec6SJoerg Sonnenberger 
179302742ec6SJoerg Sonnenberger 	SLIST_FOREACH(p, workq, pfrkt_workq)
179402742ec6SJoerg Sonnenberger 		pfr_insert_ktable(p);
179502742ec6SJoerg Sonnenberger }
179602742ec6SJoerg Sonnenberger 
179702742ec6SJoerg Sonnenberger void
pfr_insert_ktable(struct pfr_ktable * kt)179802742ec6SJoerg Sonnenberger pfr_insert_ktable(struct pfr_ktable *kt)
179902742ec6SJoerg Sonnenberger {
180002742ec6SJoerg Sonnenberger 	RB_INSERT(pfr_ktablehead, &pfr_ktables, kt);
180102742ec6SJoerg Sonnenberger 	pfr_ktable_cnt++;
180202742ec6SJoerg Sonnenberger 	if (kt->pfrkt_root != NULL)
180302742ec6SJoerg Sonnenberger 		if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++)
180402742ec6SJoerg Sonnenberger 			pfr_setflags_ktable(kt->pfrkt_root,
180502742ec6SJoerg Sonnenberger 			    kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR);
180602742ec6SJoerg Sonnenberger }
180702742ec6SJoerg Sonnenberger 
180802742ec6SJoerg Sonnenberger void
pfr_setflags_ktables(struct pfr_ktableworkq * workq)180902742ec6SJoerg Sonnenberger pfr_setflags_ktables(struct pfr_ktableworkq *workq)
181002742ec6SJoerg Sonnenberger {
181170224baaSJan Lentfer 	struct pfr_ktable	*p, *q;
181202742ec6SJoerg Sonnenberger 
181370224baaSJan Lentfer 	for (p = SLIST_FIRST(workq); p; p = q) {
181470224baaSJan Lentfer 		q = SLIST_NEXT(p, pfrkt_workq);
181502742ec6SJoerg Sonnenberger 		pfr_setflags_ktable(p, p->pfrkt_nflags);
181602742ec6SJoerg Sonnenberger 	}
181770224baaSJan Lentfer }
181802742ec6SJoerg Sonnenberger 
181902742ec6SJoerg Sonnenberger void
pfr_setflags_ktable(struct pfr_ktable * kt,int newf)182002742ec6SJoerg Sonnenberger pfr_setflags_ktable(struct pfr_ktable *kt, int newf)
182102742ec6SJoerg Sonnenberger {
182202742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	addrq;
182302742ec6SJoerg Sonnenberger 
182402742ec6SJoerg Sonnenberger 	if (!(newf & PFR_TFLAG_REFERENCED) &&
182502742ec6SJoerg Sonnenberger 	    !(newf & PFR_TFLAG_PERSIST))
182602742ec6SJoerg Sonnenberger 		newf &= ~PFR_TFLAG_ACTIVE;
182702742ec6SJoerg Sonnenberger 	if (!(newf & PFR_TFLAG_ACTIVE))
182802742ec6SJoerg Sonnenberger 		newf &= ~PFR_TFLAG_USRMASK;
182902742ec6SJoerg Sonnenberger 	if (!(newf & PFR_TFLAG_SETMASK)) {
183002742ec6SJoerg Sonnenberger 		RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt);
183102742ec6SJoerg Sonnenberger 		if (kt->pfrkt_root != NULL)
183202742ec6SJoerg Sonnenberger 			if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR])
183302742ec6SJoerg Sonnenberger 				pfr_setflags_ktable(kt->pfrkt_root,
183402742ec6SJoerg Sonnenberger 				    kt->pfrkt_root->pfrkt_flags &
183502742ec6SJoerg Sonnenberger 					~PFR_TFLAG_REFDANCHOR);
183602742ec6SJoerg Sonnenberger 		pfr_destroy_ktable(kt, 1);
183702742ec6SJoerg Sonnenberger 		pfr_ktable_cnt--;
183802742ec6SJoerg Sonnenberger 		return;
183902742ec6SJoerg Sonnenberger 	}
184002742ec6SJoerg Sonnenberger 	if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) {
184102742ec6SJoerg Sonnenberger 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
184202742ec6SJoerg Sonnenberger 		pfr_remove_kentries(kt, &addrq);
184302742ec6SJoerg Sonnenberger 	}
184402742ec6SJoerg Sonnenberger 	if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) {
184502742ec6SJoerg Sonnenberger 		pfr_destroy_ktable(kt->pfrkt_shadow, 1);
184602742ec6SJoerg Sonnenberger 		kt->pfrkt_shadow = NULL;
184702742ec6SJoerg Sonnenberger 	}
184802742ec6SJoerg Sonnenberger 	kt->pfrkt_flags = newf;
184902742ec6SJoerg Sonnenberger }
185002742ec6SJoerg Sonnenberger 
185102742ec6SJoerg Sonnenberger void
pfr_clstats_ktables(struct pfr_ktableworkq * workq,long tzero,int recurse)185202742ec6SJoerg Sonnenberger pfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse)
185302742ec6SJoerg Sonnenberger {
185402742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p;
185502742ec6SJoerg Sonnenberger 
185602742ec6SJoerg Sonnenberger 	SLIST_FOREACH(p, workq, pfrkt_workq)
185702742ec6SJoerg Sonnenberger 		pfr_clstats_ktable(p, tzero, recurse);
185802742ec6SJoerg Sonnenberger }
185902742ec6SJoerg Sonnenberger 
186002742ec6SJoerg Sonnenberger void
pfr_clstats_ktable(struct pfr_ktable * kt,long tzero,int recurse)186102742ec6SJoerg Sonnenberger pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse)
186202742ec6SJoerg Sonnenberger {
186302742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	 addrq;
186402742ec6SJoerg Sonnenberger 
186502742ec6SJoerg Sonnenberger 	if (recurse) {
186602742ec6SJoerg Sonnenberger 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
186702742ec6SJoerg Sonnenberger 		pfr_clstats_kentries(&addrq, tzero, 0);
186802742ec6SJoerg Sonnenberger 	}
1869cc6e5672SJoerg Sonnenberger 	crit_enter();
187002742ec6SJoerg Sonnenberger 	bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets));
187102742ec6SJoerg Sonnenberger 	bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes));
187202742ec6SJoerg Sonnenberger 	kt->pfrkt_match = kt->pfrkt_nomatch = 0;
1873cc6e5672SJoerg Sonnenberger 	crit_exit();
187402742ec6SJoerg Sonnenberger 	kt->pfrkt_tzero = tzero;
187502742ec6SJoerg Sonnenberger }
187602742ec6SJoerg Sonnenberger 
187702742ec6SJoerg Sonnenberger struct pfr_ktable *
pfr_create_ktable(struct pfr_table * tbl,long tzero,int attachruleset)187802742ec6SJoerg Sonnenberger pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset)
187902742ec6SJoerg Sonnenberger {
188002742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt;
188102742ec6SJoerg Sonnenberger 	struct pf_ruleset	*rs;
188202742ec6SJoerg Sonnenberger 
18831186cbc0SJan Lentfer 	kt = kmalloc(sizeof(struct pfr_ktable), M_PFRKTABLEPL, M_NOWAIT|M_ZERO|M_NULLOK);
188402742ec6SJoerg Sonnenberger 	if (kt == NULL)
188502742ec6SJoerg Sonnenberger 		return (NULL);
188602742ec6SJoerg Sonnenberger 	kt->pfrkt_t = *tbl;
188702742ec6SJoerg Sonnenberger 
188802742ec6SJoerg Sonnenberger 	if (attachruleset) {
188970224baaSJan Lentfer 		rs = pf_find_or_create_ruleset(tbl->pfrt_anchor);
189002742ec6SJoerg Sonnenberger 		if (!rs) {
189102742ec6SJoerg Sonnenberger 			pfr_destroy_ktable(kt, 0);
189202742ec6SJoerg Sonnenberger 			return (NULL);
189302742ec6SJoerg Sonnenberger 		}
189402742ec6SJoerg Sonnenberger 		kt->pfrkt_rs = rs;
189502742ec6SJoerg Sonnenberger 		rs->tables++;
189602742ec6SJoerg Sonnenberger 	}
189702742ec6SJoerg Sonnenberger 
1898b4628cf9SSepherosa Ziehau 	KKASSERT(pf_maskhead != NULL);
18996823c302SAaron LI 	if (!rn_inithead(&kt->pfrkt_ip4, pf_maskhead,
1900a4f40cc8SAaron LI 			 offsetof(struct sockaddr_in, sin_addr)) ||
19016823c302SAaron LI 	    !rn_inithead(&kt->pfrkt_ip6, pf_maskhead,
1902a4f40cc8SAaron LI 			 offsetof(struct sockaddr_in6, sin6_addr))) {
190302742ec6SJoerg Sonnenberger 		pfr_destroy_ktable(kt, 0);
190402742ec6SJoerg Sonnenberger 		return (NULL);
190502742ec6SJoerg Sonnenberger 	}
190602742ec6SJoerg Sonnenberger 	kt->pfrkt_tzero = tzero;
190702742ec6SJoerg Sonnenberger 
190802742ec6SJoerg Sonnenberger 	return (kt);
190902742ec6SJoerg Sonnenberger }
191002742ec6SJoerg Sonnenberger 
191102742ec6SJoerg Sonnenberger void
pfr_destroy_ktables(struct pfr_ktableworkq * workq,int flushaddr)191202742ec6SJoerg Sonnenberger pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr)
191302742ec6SJoerg Sonnenberger {
191402742ec6SJoerg Sonnenberger 	struct pfr_ktable	*p, *q;
191502742ec6SJoerg Sonnenberger 
191602742ec6SJoerg Sonnenberger 	for (p = SLIST_FIRST(workq); p; p = q) {
191702742ec6SJoerg Sonnenberger 		q = SLIST_NEXT(p, pfrkt_workq);
191802742ec6SJoerg Sonnenberger 		pfr_destroy_ktable(p, flushaddr);
191902742ec6SJoerg Sonnenberger 	}
192002742ec6SJoerg Sonnenberger }
192102742ec6SJoerg Sonnenberger 
192202742ec6SJoerg Sonnenberger void
pfr_destroy_ktable(struct pfr_ktable * kt,int flushaddr)192302742ec6SJoerg Sonnenberger pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
192402742ec6SJoerg Sonnenberger {
192502742ec6SJoerg Sonnenberger 	struct pfr_kentryworkq	 addrq;
192602742ec6SJoerg Sonnenberger 
192702742ec6SJoerg Sonnenberger 	if (flushaddr) {
192802742ec6SJoerg Sonnenberger 		pfr_enqueue_addrs(kt, &addrq, NULL, 0);
192902742ec6SJoerg Sonnenberger 		pfr_clean_node_mask(kt, &addrq);
193002742ec6SJoerg Sonnenberger 		pfr_destroy_kentries(&addrq);
193102742ec6SJoerg Sonnenberger 	}
193202742ec6SJoerg Sonnenberger 	if (kt->pfrkt_ip4 != NULL)
1933efda3bd0SMatthew Dillon 		kfree((caddr_t)kt->pfrkt_ip4, M_RTABLE);
1934ed1f0be2SJan Lentfer 
193502742ec6SJoerg Sonnenberger 	if (kt->pfrkt_ip6 != NULL)
1936efda3bd0SMatthew Dillon 		kfree((caddr_t)kt->pfrkt_ip6, M_RTABLE);
193702742ec6SJoerg Sonnenberger 	if (kt->pfrkt_shadow != NULL)
193802742ec6SJoerg Sonnenberger 		pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
193902742ec6SJoerg Sonnenberger 	if (kt->pfrkt_rs != NULL) {
194002742ec6SJoerg Sonnenberger 		kt->pfrkt_rs->tables--;
194102742ec6SJoerg Sonnenberger 		pf_remove_if_empty_ruleset(kt->pfrkt_rs);
194202742ec6SJoerg Sonnenberger 	}
19431186cbc0SJan Lentfer 	kfree(kt, M_PFRKTABLEPL);
194402742ec6SJoerg Sonnenberger }
194502742ec6SJoerg Sonnenberger 
194602742ec6SJoerg Sonnenberger int
pfr_ktable_compare(struct pfr_ktable * p,struct pfr_ktable * q)194702742ec6SJoerg Sonnenberger pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q)
194802742ec6SJoerg Sonnenberger {
194902742ec6SJoerg Sonnenberger 	int d;
195002742ec6SJoerg Sonnenberger 
195102742ec6SJoerg Sonnenberger 	if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE)))
195202742ec6SJoerg Sonnenberger 		return (d);
195370224baaSJan Lentfer 	return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor));
195402742ec6SJoerg Sonnenberger }
195502742ec6SJoerg Sonnenberger 
195602742ec6SJoerg Sonnenberger struct pfr_ktable *
pfr_lookup_table(struct pfr_table * tbl)195702742ec6SJoerg Sonnenberger pfr_lookup_table(struct pfr_table *tbl)
195802742ec6SJoerg Sonnenberger {
195902742ec6SJoerg Sonnenberger 	/* struct pfr_ktable start like a struct pfr_table */
196002742ec6SJoerg Sonnenberger 	return (RB_FIND(pfr_ktablehead, &pfr_ktables,
196102742ec6SJoerg Sonnenberger 	    (struct pfr_ktable *)tbl));
196202742ec6SJoerg Sonnenberger }
196302742ec6SJoerg Sonnenberger 
196402742ec6SJoerg Sonnenberger int
pfr_match_addr(struct pfr_ktable * kt,struct pf_addr * a,sa_family_t af)196502742ec6SJoerg Sonnenberger pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
196602742ec6SJoerg Sonnenberger {
196702742ec6SJoerg Sonnenberger 	struct pfr_kentry	*ke = NULL;
196802742ec6SJoerg Sonnenberger 	int			 match;
1969d66d8bc0SMatthew Dillon 	struct sockaddr_in	 pfr_sin;
197006397f9cSFrançois Tigeot #ifdef INET6
1971d66d8bc0SMatthew Dillon 	struct sockaddr_in6	 pfr_sin6;
197206397f9cSFrançois Tigeot #endif
197302742ec6SJoerg Sonnenberger 
197402742ec6SJoerg Sonnenberger 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
197502742ec6SJoerg Sonnenberger 		kt = kt->pfrkt_root;
197602742ec6SJoerg Sonnenberger 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
197702742ec6SJoerg Sonnenberger 		return (0);
197802742ec6SJoerg Sonnenberger 
197902742ec6SJoerg Sonnenberger 	switch (af) {
198070224baaSJan Lentfer #ifdef INET
198102742ec6SJoerg Sonnenberger 	case AF_INET:
1982f059a200SMatthew Dillon 		bzero(&pfr_sin, sizeof(pfr_sin));
1983d66d8bc0SMatthew Dillon 		pfr_sin.sin_len = sizeof(pfr_sin);
1984d66d8bc0SMatthew Dillon 		pfr_sin.sin_family = AF_INET;
198502742ec6SJoerg Sonnenberger 		pfr_sin.sin_addr.s_addr = a->addr32[0];
1986*d8449084SAaron LI 		ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
198702742ec6SJoerg Sonnenberger 		if (ke && KENTRY_RNF_ROOT(ke))
198802742ec6SJoerg Sonnenberger 			ke = NULL;
198902742ec6SJoerg Sonnenberger 		break;
199070224baaSJan Lentfer #endif /* INET */
199170224baaSJan Lentfer #ifdef INET6
199202742ec6SJoerg Sonnenberger 	case AF_INET6:
1993f059a200SMatthew Dillon 		bzero(&pfr_sin6, sizeof(pfr_sin6));
1994d66d8bc0SMatthew Dillon 		pfr_sin6.sin6_len = sizeof(pfr_sin6);
1995d66d8bc0SMatthew Dillon 		pfr_sin6.sin6_family = AF_INET6;
199602742ec6SJoerg Sonnenberger 		bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
1997*d8449084SAaron LI 		ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
199802742ec6SJoerg Sonnenberger 		if (ke && KENTRY_RNF_ROOT(ke))
199902742ec6SJoerg Sonnenberger 			ke = NULL;
200002742ec6SJoerg Sonnenberger 		break;
200170224baaSJan Lentfer #endif /* INET6 */
200202742ec6SJoerg Sonnenberger 	}
200302742ec6SJoerg Sonnenberger 	match = (ke && !ke->pfrke_not);
200402742ec6SJoerg Sonnenberger 	if (match)
200502742ec6SJoerg Sonnenberger 		kt->pfrkt_match++;
200602742ec6SJoerg Sonnenberger 	else
200702742ec6SJoerg Sonnenberger 		kt->pfrkt_nomatch++;
200802742ec6SJoerg Sonnenberger 	return (match);
200902742ec6SJoerg Sonnenberger }
201002742ec6SJoerg Sonnenberger 
201102742ec6SJoerg Sonnenberger void
pfr_update_stats(struct pfr_ktable * kt,struct pf_addr * a,sa_family_t af,u_int64_t len,int dir_out,int op_pass,int notrule)201202742ec6SJoerg Sonnenberger pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
201302742ec6SJoerg Sonnenberger     u_int64_t len, int dir_out, int op_pass, int notrule)
201402742ec6SJoerg Sonnenberger {
201502742ec6SJoerg Sonnenberger 	struct pfr_kentry	*ke = NULL;
2016d66d8bc0SMatthew Dillon 	struct sockaddr_in	 pfr_sin;
201706397f9cSFrançois Tigeot #ifdef INET6
2018d66d8bc0SMatthew Dillon 	struct sockaddr_in6	 pfr_sin6;
201906397f9cSFrançois Tigeot #endif
202002742ec6SJoerg Sonnenberger 
202102742ec6SJoerg Sonnenberger 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
202202742ec6SJoerg Sonnenberger 		kt = kt->pfrkt_root;
202302742ec6SJoerg Sonnenberger 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
202402742ec6SJoerg Sonnenberger 		return;
202502742ec6SJoerg Sonnenberger 
202602742ec6SJoerg Sonnenberger 	switch (af) {
202770224baaSJan Lentfer #ifdef INET
202802742ec6SJoerg Sonnenberger 	case AF_INET:
2029f059a200SMatthew Dillon 		bzero(&pfr_sin, sizeof(pfr_sin));
2030d66d8bc0SMatthew Dillon 		pfr_sin.sin_len = sizeof(pfr_sin);
2031d66d8bc0SMatthew Dillon 		pfr_sin.sin_family = AF_INET;
203202742ec6SJoerg Sonnenberger 		pfr_sin.sin_addr.s_addr = a->addr32[0];
2033*d8449084SAaron LI 		ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
203402742ec6SJoerg Sonnenberger 		if (ke && KENTRY_RNF_ROOT(ke))
203502742ec6SJoerg Sonnenberger 			ke = NULL;
203602742ec6SJoerg Sonnenberger 		break;
203770224baaSJan Lentfer #endif /* INET */
203870224baaSJan Lentfer #ifdef INET6
203902742ec6SJoerg Sonnenberger 	case AF_INET6:
2040f059a200SMatthew Dillon 		bzero(&pfr_sin6, sizeof(pfr_sin6));
2041d66d8bc0SMatthew Dillon 		pfr_sin6.sin6_len = sizeof(pfr_sin6);
2042d66d8bc0SMatthew Dillon 		pfr_sin6.sin6_family = AF_INET6;
204302742ec6SJoerg Sonnenberger 		bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
2044*d8449084SAaron LI 		ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
204502742ec6SJoerg Sonnenberger 		if (ke && KENTRY_RNF_ROOT(ke))
204602742ec6SJoerg Sonnenberger 			ke = NULL;
204702742ec6SJoerg Sonnenberger 		break;
204870224baaSJan Lentfer #endif /* INET6 */
204970224baaSJan Lentfer 	default:
205070224baaSJan Lentfer 		;
205102742ec6SJoerg Sonnenberger 	}
205202742ec6SJoerg Sonnenberger 	if ((ke == NULL || ke->pfrke_not) != notrule) {
205302742ec6SJoerg Sonnenberger 		if (op_pass != PFR_OP_PASS)
20544b1cf444SSascha Wildner 			kprintf("pfr_update_stats: assertion failed.\n");
205502742ec6SJoerg Sonnenberger 		op_pass = PFR_OP_XPASS;
205602742ec6SJoerg Sonnenberger 	}
205702742ec6SJoerg Sonnenberger 	kt->pfrkt_packets[dir_out][op_pass]++;
205802742ec6SJoerg Sonnenberger 	kt->pfrkt_bytes[dir_out][op_pass] += len;
2059ed1f0be2SJan Lentfer 	if (ke != NULL && op_pass != PFR_OP_XPASS &&
2060ed1f0be2SJan Lentfer 	    (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) {
2061ed1f0be2SJan Lentfer 		if (ke->pfrke_counters == NULL)
20621186cbc0SJan Lentfer 			ke->pfrke_counters = kmalloc(sizeof(struct pfr_kcounters),
20631186cbc0SJan Lentfer 			    M_PFRKCOUNTERSPL, M_NOWAIT|M_ZERO);
2064ed1f0be2SJan Lentfer 		if (ke->pfrke_counters != NULL) {
2065ed1f0be2SJan Lentfer 			ke->pfrke_counters->pfrkc_packets[dir_out][op_pass]++;
2066ed1f0be2SJan Lentfer 			ke->pfrke_counters->pfrkc_bytes[dir_out][op_pass] += len;
2067ed1f0be2SJan Lentfer 		}
206802742ec6SJoerg Sonnenberger 	}
206902742ec6SJoerg Sonnenberger }
207002742ec6SJoerg Sonnenberger 
207102742ec6SJoerg Sonnenberger struct pfr_ktable *
pfr_attach_table(struct pf_ruleset * rs,char * name)207202742ec6SJoerg Sonnenberger pfr_attach_table(struct pf_ruleset *rs, char *name)
207302742ec6SJoerg Sonnenberger {
207402742ec6SJoerg Sonnenberger 	struct pfr_ktable	*kt, *rt;
207502742ec6SJoerg Sonnenberger 	struct pfr_table	 tbl;
207602742ec6SJoerg Sonnenberger 	struct pf_anchor	*ac = rs->anchor;
207702742ec6SJoerg Sonnenberger 
207802742ec6SJoerg Sonnenberger 	bzero(&tbl, sizeof(tbl));
207902742ec6SJoerg Sonnenberger 	strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
208070224baaSJan Lentfer 	if (ac != NULL)
208170224baaSJan Lentfer 		strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
208202742ec6SJoerg Sonnenberger 	kt = pfr_lookup_table(&tbl);
208302742ec6SJoerg Sonnenberger 	if (kt == NULL) {
208402742ec6SJoerg Sonnenberger 		kt = pfr_create_ktable(&tbl, time_second, 1);
208502742ec6SJoerg Sonnenberger 		if (kt == NULL)
208602742ec6SJoerg Sonnenberger 			return (NULL);
208702742ec6SJoerg Sonnenberger 		if (ac != NULL) {
208802742ec6SJoerg Sonnenberger 			bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor));
208902742ec6SJoerg Sonnenberger 			rt = pfr_lookup_table(&tbl);
209002742ec6SJoerg Sonnenberger 			if (rt == NULL) {
209102742ec6SJoerg Sonnenberger 				rt = pfr_create_ktable(&tbl, 0, 1);
209202742ec6SJoerg Sonnenberger 				if (rt == NULL) {
209302742ec6SJoerg Sonnenberger 					pfr_destroy_ktable(kt, 0);
209402742ec6SJoerg Sonnenberger 					return (NULL);
209502742ec6SJoerg Sonnenberger 				}
209602742ec6SJoerg Sonnenberger 				pfr_insert_ktable(rt);
209702742ec6SJoerg Sonnenberger 			}
209802742ec6SJoerg Sonnenberger 			kt->pfrkt_root = rt;
209902742ec6SJoerg Sonnenberger 		}
210002742ec6SJoerg Sonnenberger 		pfr_insert_ktable(kt);
210102742ec6SJoerg Sonnenberger 	}
210202742ec6SJoerg Sonnenberger 	if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++)
210302742ec6SJoerg Sonnenberger 		pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED);
210402742ec6SJoerg Sonnenberger 	return (kt);
210502742ec6SJoerg Sonnenberger }
210602742ec6SJoerg Sonnenberger 
210702742ec6SJoerg Sonnenberger void
pfr_detach_table(struct pfr_ktable * kt)210802742ec6SJoerg Sonnenberger pfr_detach_table(struct pfr_ktable *kt)
210902742ec6SJoerg Sonnenberger {
211002742ec6SJoerg Sonnenberger 	if (kt->pfrkt_refcnt[PFR_REFCNT_RULE] <= 0)
21114b1cf444SSascha Wildner 		kprintf("pfr_detach_table: refcount = %d.\n",
211202742ec6SJoerg Sonnenberger 		    kt->pfrkt_refcnt[PFR_REFCNT_RULE]);
211302742ec6SJoerg Sonnenberger 	else if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE])
211402742ec6SJoerg Sonnenberger 		pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED);
211502742ec6SJoerg Sonnenberger }
211602742ec6SJoerg Sonnenberger 
211702742ec6SJoerg Sonnenberger int
pfr_pool_get(struct pfr_ktable * kt,int * pidx,struct pf_addr * counter,struct pf_addr ** raddr,struct pf_addr ** rmask,sa_family_t af)211802742ec6SJoerg Sonnenberger pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
211902742ec6SJoerg Sonnenberger     struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af)
212002742ec6SJoerg Sonnenberger {
212170224baaSJan Lentfer 	struct pfr_kentry	*ke, *ke2 = NULL;
212270224baaSJan Lentfer 	struct pf_addr		*addr = NULL;
212302742ec6SJoerg Sonnenberger 	union sockaddr_union	 mask;
212402742ec6SJoerg Sonnenberger 	int			 idx = -1, use_counter = 0;
2125d66d8bc0SMatthew Dillon 	struct sockaddr_in	 pfr_sin;
2126d66d8bc0SMatthew Dillon 	struct sockaddr_in6	 pfr_sin6;
2127d66d8bc0SMatthew Dillon 	union sockaddr_union	 pfr_mask;
212802742ec6SJoerg Sonnenberger 
212970224baaSJan Lentfer 	if (af == AF_INET)
213070224baaSJan Lentfer 		addr = (struct pf_addr *)&pfr_sin.sin_addr;
213170224baaSJan Lentfer 	else if (af == AF_INET6)
213270224baaSJan Lentfer 		addr = (struct pf_addr *)&pfr_sin6.sin6_addr;
213302742ec6SJoerg Sonnenberger 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
213402742ec6SJoerg Sonnenberger 		kt = kt->pfrkt_root;
213502742ec6SJoerg Sonnenberger 	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
213602742ec6SJoerg Sonnenberger 		return (-1);
213702742ec6SJoerg Sonnenberger 
213802742ec6SJoerg Sonnenberger 	if (pidx != NULL)
213902742ec6SJoerg Sonnenberger 		idx = *pidx;
214002742ec6SJoerg Sonnenberger 	if (counter != NULL && idx >= 0)
214102742ec6SJoerg Sonnenberger 		use_counter = 1;
214202742ec6SJoerg Sonnenberger 	if (idx < 0)
214302742ec6SJoerg Sonnenberger 		idx = 0;
214402742ec6SJoerg Sonnenberger 
214502742ec6SJoerg Sonnenberger _next_block:
214602742ec6SJoerg Sonnenberger 	ke = pfr_kentry_byidx(kt, idx, af);
2147ed1f0be2SJan Lentfer 	if (ke == NULL) {
2148ed1f0be2SJan Lentfer 		kt->pfrkt_nomatch++;
214902742ec6SJoerg Sonnenberger 		return (1);
2150ed1f0be2SJan Lentfer 	}
215102742ec6SJoerg Sonnenberger 	pfr_prepare_network(&pfr_mask, af, ke->pfrke_net);
215202742ec6SJoerg Sonnenberger 	*raddr = SUNION2PF(&ke->pfrke_sa, af);
215302742ec6SJoerg Sonnenberger 	*rmask = SUNION2PF(&pfr_mask, af);
215402742ec6SJoerg Sonnenberger 
215502742ec6SJoerg Sonnenberger 	if (use_counter) {
215602742ec6SJoerg Sonnenberger 		/* is supplied address within block? */
215702742ec6SJoerg Sonnenberger 		if (!PF_MATCHA(0, *raddr, *rmask, counter, af)) {
215802742ec6SJoerg Sonnenberger 			/* no, go to next block in table */
215902742ec6SJoerg Sonnenberger 			idx++;
216002742ec6SJoerg Sonnenberger 			use_counter = 0;
216102742ec6SJoerg Sonnenberger 			goto _next_block;
216202742ec6SJoerg Sonnenberger 		}
216302742ec6SJoerg Sonnenberger 		PF_ACPY(addr, counter, af);
216402742ec6SJoerg Sonnenberger 	} else {
216502742ec6SJoerg Sonnenberger 		/* use first address of block */
216602742ec6SJoerg Sonnenberger 		PF_ACPY(addr, *raddr, af);
216702742ec6SJoerg Sonnenberger 	}
216802742ec6SJoerg Sonnenberger 
216902742ec6SJoerg Sonnenberger 	if (!KENTRY_NETWORK(ke)) {
217002742ec6SJoerg Sonnenberger 		/* this is a single IP address - no possible nested block */
217102742ec6SJoerg Sonnenberger 		PF_ACPY(counter, addr, af);
217202742ec6SJoerg Sonnenberger 		*pidx = idx;
2173ed1f0be2SJan Lentfer 		kt->pfrkt_match++;
217402742ec6SJoerg Sonnenberger 		return (0);
217502742ec6SJoerg Sonnenberger 	}
217602742ec6SJoerg Sonnenberger 	for (;;) {
217702742ec6SJoerg Sonnenberger 		/* we don't want to use a nested block */
217870224baaSJan Lentfer 		if (af == AF_INET)
2179*d8449084SAaron LI 			ke2 = (struct pfr_kentry *)rn_match(&pfr_sin,
218070224baaSJan Lentfer 			    kt->pfrkt_ip4);
218170224baaSJan Lentfer 		else if (af == AF_INET6)
2182*d8449084SAaron LI 			ke2 = (struct pfr_kentry *)rn_match(&pfr_sin6,
218370224baaSJan Lentfer 			    kt->pfrkt_ip6);
218402742ec6SJoerg Sonnenberger 		/* no need to check KENTRY_RNF_ROOT() here */
218502742ec6SJoerg Sonnenberger 		if (ke2 == ke) {
218602742ec6SJoerg Sonnenberger 			/* lookup return the same block - perfect */
218702742ec6SJoerg Sonnenberger 			PF_ACPY(counter, addr, af);
218802742ec6SJoerg Sonnenberger 			*pidx = idx;
2189ed1f0be2SJan Lentfer 			kt->pfrkt_match++;
219002742ec6SJoerg Sonnenberger 			return (0);
219102742ec6SJoerg Sonnenberger 		}
219202742ec6SJoerg Sonnenberger 
219302742ec6SJoerg Sonnenberger 		/* we need to increase the counter past the nested block */
219402742ec6SJoerg Sonnenberger 		pfr_prepare_network(&mask, AF_INET, ke2->pfrke_net);
219502742ec6SJoerg Sonnenberger 		PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &pfr_ffaddr, af);
219602742ec6SJoerg Sonnenberger 		PF_AINC(addr, af);
219702742ec6SJoerg Sonnenberger 		if (!PF_MATCHA(0, *raddr, *rmask, addr, af)) {
219802742ec6SJoerg Sonnenberger 			/* ok, we reached the end of our main block */
219902742ec6SJoerg Sonnenberger 			/* go to next block in table */
220002742ec6SJoerg Sonnenberger 			idx++;
220102742ec6SJoerg Sonnenberger 			use_counter = 0;
220202742ec6SJoerg Sonnenberger 			goto _next_block;
220302742ec6SJoerg Sonnenberger 		}
220402742ec6SJoerg Sonnenberger 	}
220502742ec6SJoerg Sonnenberger }
220602742ec6SJoerg Sonnenberger 
220702742ec6SJoerg Sonnenberger struct pfr_kentry *
pfr_kentry_byidx(struct pfr_ktable * kt,int idx,int af)220802742ec6SJoerg Sonnenberger pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af)
220902742ec6SJoerg Sonnenberger {
221002742ec6SJoerg Sonnenberger 	struct pfr_walktree	w;
221102742ec6SJoerg Sonnenberger 
221202742ec6SJoerg Sonnenberger 	bzero(&w, sizeof(w));
221302742ec6SJoerg Sonnenberger 	w.pfrw_op = PFRW_POOL_GET;
221402742ec6SJoerg Sonnenberger 	w.pfrw_cnt = idx;
221502742ec6SJoerg Sonnenberger 
221602742ec6SJoerg Sonnenberger 	switch (af) {
221770224baaSJan Lentfer #ifdef INET
221802742ec6SJoerg Sonnenberger 	case AF_INET:
221902742ec6SJoerg Sonnenberger 		kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
222002742ec6SJoerg Sonnenberger 		return (w.pfrw_kentry);
222170224baaSJan Lentfer #endif /* INET */
222270224baaSJan Lentfer #ifdef INET6
222302742ec6SJoerg Sonnenberger 	case AF_INET6:
222402742ec6SJoerg Sonnenberger 		kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
222502742ec6SJoerg Sonnenberger 		return (w.pfrw_kentry);
222670224baaSJan Lentfer #endif /* INET6 */
222702742ec6SJoerg Sonnenberger 	default:
222802742ec6SJoerg Sonnenberger 		return (NULL);
222902742ec6SJoerg Sonnenberger 	}
223002742ec6SJoerg Sonnenberger }
223102742ec6SJoerg Sonnenberger 
223202742ec6SJoerg Sonnenberger void
pfr_dynaddr_update(struct pfr_ktable * kt,struct pfi_dynaddr * dyn)223302742ec6SJoerg Sonnenberger pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn)
223402742ec6SJoerg Sonnenberger {
223502742ec6SJoerg Sonnenberger 	struct pfr_walktree	w;
223602742ec6SJoerg Sonnenberger 
223702742ec6SJoerg Sonnenberger 	bzero(&w, sizeof(w));
223802742ec6SJoerg Sonnenberger 	w.pfrw_op = PFRW_DYNADDR_UPDATE;
223902742ec6SJoerg Sonnenberger 	w.pfrw_dyn = dyn;
224002742ec6SJoerg Sonnenberger 
2241cc6e5672SJoerg Sonnenberger 	crit_enter();
224202742ec6SJoerg Sonnenberger 	dyn->pfid_acnt4 = 0;
224302742ec6SJoerg Sonnenberger 	dyn->pfid_acnt6 = 0;
224402742ec6SJoerg Sonnenberger 	if (!dyn->pfid_af || dyn->pfid_af == AF_INET)
224502742ec6SJoerg Sonnenberger 		kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
224602742ec6SJoerg Sonnenberger 	if (!dyn->pfid_af || dyn->pfid_af == AF_INET6)
224702742ec6SJoerg Sonnenberger 		kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
2248cc6e5672SJoerg Sonnenberger 	crit_exit();
224902742ec6SJoerg Sonnenberger }
2250