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