[BACK]Return to pf_table.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/pf_table.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: pf_table.c,v 1.70 2007/05/23 11:53:45 markus Exp $    */
                      2:
                      3: /*
                      4:  * Copyright (c) 2002 Cedric Berger
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  *
                     11:  *    - Redistributions of source code must retain the above copyright
                     12:  *      notice, this list of conditions and the following disclaimer.
                     13:  *    - Redistributions in binary form must reproduce the above
                     14:  *      copyright notice, this list of conditions and the following
                     15:  *      disclaimer in the documentation and/or other materials provided
                     16:  *      with the distribution.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                     19:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     20:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
                     21:  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
                     22:  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
                     23:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     24:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     25:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
                     26:  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     28:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  *
                     31:  */
                     32:
                     33: #include <sys/param.h>
                     34: #include <sys/systm.h>
                     35: #include <sys/socket.h>
                     36: #include <sys/mbuf.h>
                     37: #include <sys/kernel.h>
                     38:
                     39: #include <net/if.h>
                     40: #include <net/route.h>
                     41: #include <netinet/in.h>
                     42: #include <netinet/ip_ipsp.h>
                     43: #include <net/pfvar.h>
                     44:
                     45: #define ACCEPT_FLAGS(flags, oklist)            \
                     46:        do {                                    \
                     47:                if ((flags & ~(oklist)) &       \
                     48:                    PFR_FLAG_ALLMASK)           \
                     49:                        return (EINVAL);        \
                     50:        } while (0)
                     51:
                     52: #define COPYIN(from, to, size, flags)          \
                     53:        ((flags & PFR_FLAG_USERIOCTL) ?         \
                     54:        copyin((from), (to), (size)) :          \
                     55:        (bcopy((from), (to), (size)), 0))
                     56:
                     57: #define COPYOUT(from, to, size, flags)         \
                     58:        ((flags & PFR_FLAG_USERIOCTL) ?         \
                     59:        copyout((from), (to), (size)) :         \
                     60:        (bcopy((from), (to), (size)), 0))
                     61:
                     62: #define        FILLIN_SIN(sin, addr)                   \
                     63:        do {                                    \
                     64:                (sin).sin_len = sizeof(sin);    \
                     65:                (sin).sin_family = AF_INET;     \
                     66:                (sin).sin_addr = (addr);        \
                     67:        } while (0)
                     68:
                     69: #define        FILLIN_SIN6(sin6, addr)                 \
                     70:        do {                                    \
                     71:                (sin6).sin6_len = sizeof(sin6); \
                     72:                (sin6).sin6_family = AF_INET6;  \
                     73:                (sin6).sin6_addr = (addr);      \
                     74:        } while (0)
                     75:
                     76: #define SWAP(type, a1, a2)                     \
                     77:        do {                                    \
                     78:                type tmp = a1;                  \
                     79:                a1 = a2;                        \
                     80:                a2 = tmp;                       \
                     81:        } while (0)
                     82:
                     83: #define SUNION2PF(su, af) (((af)==AF_INET) ?   \
                     84:     (struct pf_addr *)&(su)->sin.sin_addr :    \
                     85:     (struct pf_addr *)&(su)->sin6.sin6_addr)
                     86:
                     87: #define        AF_BITS(af)             (((af)==AF_INET)?32:128)
                     88: #define        ADDR_NETWORK(ad)        ((ad)->pfra_net < AF_BITS((ad)->pfra_af))
                     89: #define        KENTRY_NETWORK(ke)      ((ke)->pfrke_net < AF_BITS((ke)->pfrke_af))
                     90: #define KENTRY_RNF_ROOT(ke) \
                     91:                ((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0)
                     92:
                     93: #define NO_ADDRESSES           (-1)
                     94: #define ENQUEUE_UNMARKED_ONLY  (1)
                     95: #define INVERT_NEG_FLAG                (1)
                     96:
                     97: struct pfr_walktree {
                     98:        enum pfrw_op {
                     99:                PFRW_MARK,
                    100:                PFRW_SWEEP,
                    101:                PFRW_ENQUEUE,
                    102:                PFRW_GET_ADDRS,
                    103:                PFRW_GET_ASTATS,
                    104:                PFRW_POOL_GET,
                    105:                PFRW_DYNADDR_UPDATE
                    106:        }        pfrw_op;
                    107:        union {
                    108:                struct pfr_addr         *pfrw1_addr;
                    109:                struct pfr_astats       *pfrw1_astats;
                    110:                struct pfr_kentryworkq  *pfrw1_workq;
                    111:                struct pfr_kentry       *pfrw1_kentry;
                    112:                struct pfi_dynaddr      *pfrw1_dyn;
                    113:        }        pfrw_1;
                    114:        int      pfrw_free;
                    115:        int      pfrw_flags;
                    116: };
                    117: #define pfrw_addr      pfrw_1.pfrw1_addr
                    118: #define pfrw_astats    pfrw_1.pfrw1_astats
                    119: #define pfrw_workq     pfrw_1.pfrw1_workq
                    120: #define pfrw_kentry    pfrw_1.pfrw1_kentry
                    121: #define pfrw_dyn       pfrw_1.pfrw1_dyn
                    122: #define pfrw_cnt       pfrw_free
                    123:
                    124: #define senderr(e)     do { rv = (e); goto _bad; } while (0)
                    125:
                    126: struct pool             pfr_ktable_pl;
                    127: struct pool             pfr_kentry_pl;
                    128: struct pool             pfr_kentry_pl2;
                    129: struct sockaddr_in      pfr_sin;
                    130: struct sockaddr_in6     pfr_sin6;
                    131: union sockaddr_union    pfr_mask;
                    132: struct pf_addr          pfr_ffaddr;
                    133:
                    134: void                    pfr_copyout_addr(struct pfr_addr *,
                    135:                            struct pfr_kentry *ke);
                    136: int                     pfr_validate_addr(struct pfr_addr *);
                    137: void                    pfr_enqueue_addrs(struct pfr_ktable *,
                    138:                            struct pfr_kentryworkq *, int *, int);
                    139: void                    pfr_mark_addrs(struct pfr_ktable *);
                    140: struct pfr_kentry      *pfr_lookup_addr(struct pfr_ktable *,
                    141:                            struct pfr_addr *, int);
                    142: struct pfr_kentry      *pfr_create_kentry(struct pfr_addr *, int);
                    143: void                    pfr_destroy_kentries(struct pfr_kentryworkq *);
                    144: void                    pfr_destroy_kentry(struct pfr_kentry *);
                    145: void                    pfr_insert_kentries(struct pfr_ktable *,
                    146:                            struct pfr_kentryworkq *, long);
                    147: void                    pfr_remove_kentries(struct pfr_ktable *,
                    148:                            struct pfr_kentryworkq *);
                    149: void                    pfr_clstats_kentries(struct pfr_kentryworkq *, long,
                    150:                            int);
                    151: void                    pfr_reset_feedback(struct pfr_addr *, int, int);
                    152: void                    pfr_prepare_network(union sockaddr_union *, int, int);
                    153: int                     pfr_route_kentry(struct pfr_ktable *,
                    154:                            struct pfr_kentry *);
                    155: int                     pfr_unroute_kentry(struct pfr_ktable *,
                    156:                            struct pfr_kentry *);
                    157: int                     pfr_walktree(struct radix_node *, void *);
                    158: int                     pfr_validate_table(struct pfr_table *, int, int);
                    159: int                     pfr_fix_anchor(char *);
                    160: void                    pfr_commit_ktable(struct pfr_ktable *, long);
                    161: void                    pfr_insert_ktables(struct pfr_ktableworkq *);
                    162: void                    pfr_insert_ktable(struct pfr_ktable *);
                    163: void                    pfr_setflags_ktables(struct pfr_ktableworkq *);
                    164: void                    pfr_setflags_ktable(struct pfr_ktable *, int);
                    165: void                    pfr_clstats_ktables(struct pfr_ktableworkq *, long,
                    166:                            int);
                    167: void                    pfr_clstats_ktable(struct pfr_ktable *, long, int);
                    168: struct pfr_ktable      *pfr_create_ktable(struct pfr_table *, long, int);
                    169: void                    pfr_destroy_ktables(struct pfr_ktableworkq *, int);
                    170: void                    pfr_destroy_ktable(struct pfr_ktable *, int);
                    171: int                     pfr_ktable_compare(struct pfr_ktable *,
                    172:                            struct pfr_ktable *);
                    173: struct pfr_ktable      *pfr_lookup_table(struct pfr_table *);
                    174: void                    pfr_clean_node_mask(struct pfr_ktable *,
                    175:                            struct pfr_kentryworkq *);
                    176: int                     pfr_table_count(struct pfr_table *, int);
                    177: int                     pfr_skip_table(struct pfr_table *,
                    178:                            struct pfr_ktable *, int);
                    179: struct pfr_kentry      *pfr_kentry_byidx(struct pfr_ktable *, int, int);
                    180:
                    181: RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
                    182: RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
                    183:
                    184: struct pfr_ktablehead   pfr_ktables;
                    185: struct pfr_table        pfr_nulltable;
                    186: int                     pfr_ktable_cnt;
                    187:
                    188: void
                    189: pfr_initialize(void)
                    190: {
                    191:        pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0,
                    192:            "pfrktable", &pool_allocator_oldnointr);
                    193:        pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0,
                    194:            "pfrkentry", &pool_allocator_oldnointr);
                    195:        pool_init(&pfr_kentry_pl2, sizeof(struct pfr_kentry), 0, 0, 0,
                    196:            "pfrkentry2", NULL);
                    197:
                    198:        pfr_sin.sin_len = sizeof(pfr_sin);
                    199:        pfr_sin.sin_family = AF_INET;
                    200:        pfr_sin6.sin6_len = sizeof(pfr_sin6);
                    201:        pfr_sin6.sin6_family = AF_INET6;
                    202:
                    203:        memset(&pfr_ffaddr, 0xff, sizeof(pfr_ffaddr));
                    204: }
                    205:
                    206: int
                    207: pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
                    208: {
                    209:        struct pfr_ktable       *kt;
                    210:        struct pfr_kentryworkq   workq;
                    211:        int                      s;
                    212:
                    213:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
                    214:        if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
                    215:                return (EINVAL);
                    216:        kt = pfr_lookup_table(tbl);
                    217:        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                    218:                return (ESRCH);
                    219:        if (kt->pfrkt_flags & PFR_TFLAG_CONST)
                    220:                return (EPERM);
                    221:        pfr_enqueue_addrs(kt, &workq, ndel, 0);
                    222:
                    223:        if (!(flags & PFR_FLAG_DUMMY)) {
                    224:                if (flags & PFR_FLAG_ATOMIC)
                    225:                        s = splsoftnet();
                    226:                pfr_remove_kentries(kt, &workq);
                    227:                if (flags & PFR_FLAG_ATOMIC)
                    228:                        splx(s);
                    229:                if (kt->pfrkt_cnt) {
                    230:                        printf("pfr_clr_addrs: corruption detected (%d).\n",
                    231:                            kt->pfrkt_cnt);
                    232:                        kt->pfrkt_cnt = 0;
                    233:                }
                    234:        }
                    235:        return (0);
                    236: }
                    237:
                    238: int
                    239: pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                    240:     int *nadd, int flags)
                    241: {
                    242:        struct pfr_ktable       *kt, *tmpkt;
                    243:        struct pfr_kentryworkq   workq;
                    244:        struct pfr_kentry       *p, *q;
                    245:        struct pfr_addr          ad;
                    246:        int                      i, rv, s, xadd = 0;
                    247:        long                     tzero = time_second;
                    248:
                    249:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
                    250:            PFR_FLAG_FEEDBACK);
                    251:        if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
                    252:                return (EINVAL);
                    253:        kt = pfr_lookup_table(tbl);
                    254:        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                    255:                return (ESRCH);
                    256:        if (kt->pfrkt_flags & PFR_TFLAG_CONST)
                    257:                return (EPERM);
                    258:        tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0);
                    259:        if (tmpkt == NULL)
                    260:                return (ENOMEM);
                    261:        SLIST_INIT(&workq);
                    262:        for (i = 0; i < size; i++) {
                    263:                if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                    264:                        senderr(EFAULT);
                    265:                if (pfr_validate_addr(&ad))
                    266:                        senderr(EINVAL);
                    267:                p = pfr_lookup_addr(kt, &ad, 1);
                    268:                q = pfr_lookup_addr(tmpkt, &ad, 1);
                    269:                if (flags & PFR_FLAG_FEEDBACK) {
                    270:                        if (q != NULL)
                    271:                                ad.pfra_fback = PFR_FB_DUPLICATE;
                    272:                        else if (p == NULL)
                    273:                                ad.pfra_fback = PFR_FB_ADDED;
                    274:                        else if (p->pfrke_not != ad.pfra_not)
                    275:                                ad.pfra_fback = PFR_FB_CONFLICT;
                    276:                        else
                    277:                                ad.pfra_fback = PFR_FB_NONE;
                    278:                }
                    279:                if (p == NULL && q == NULL) {
                    280:                        p = pfr_create_kentry(&ad,
                    281:                            !(flags & PFR_FLAG_USERIOCTL));
                    282:                        if (p == NULL)
                    283:                                senderr(ENOMEM);
                    284:                        if (pfr_route_kentry(tmpkt, p)) {
                    285:                                pfr_destroy_kentry(p);
                    286:                                ad.pfra_fback = PFR_FB_NONE;
                    287:                        } else {
                    288:                                SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
                    289:                                xadd++;
                    290:                        }
                    291:                }
                    292:                if (flags & PFR_FLAG_FEEDBACK)
                    293:                        if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                    294:                                senderr(EFAULT);
                    295:        }
                    296:        pfr_clean_node_mask(tmpkt, &workq);
                    297:        if (!(flags & PFR_FLAG_DUMMY)) {
                    298:                if (flags & PFR_FLAG_ATOMIC)
                    299:                        s = splsoftnet();
                    300:                pfr_insert_kentries(kt, &workq, tzero);
                    301:                if (flags & PFR_FLAG_ATOMIC)
                    302:                        splx(s);
                    303:        } else
                    304:                pfr_destroy_kentries(&workq);
                    305:        if (nadd != NULL)
                    306:                *nadd = xadd;
                    307:        pfr_destroy_ktable(tmpkt, 0);
                    308:        return (0);
                    309: _bad:
                    310:        pfr_clean_node_mask(tmpkt, &workq);
                    311:        pfr_destroy_kentries(&workq);
                    312:        if (flags & PFR_FLAG_FEEDBACK)
                    313:                pfr_reset_feedback(addr, size, flags);
                    314:        pfr_destroy_ktable(tmpkt, 0);
                    315:        return (rv);
                    316: }
                    317:
                    318: int
                    319: pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                    320:     int *ndel, int flags)
                    321: {
                    322:        struct pfr_ktable       *kt;
                    323:        struct pfr_kentryworkq   workq;
                    324:        struct pfr_kentry       *p;
                    325:        struct pfr_addr          ad;
                    326:        int                      i, rv, s, xdel = 0, log = 1;
                    327:
                    328:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
                    329:            PFR_FLAG_FEEDBACK);
                    330:        if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL))
                    331:                return (EINVAL);
                    332:        kt = pfr_lookup_table(tbl);
                    333:        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                    334:                return (ESRCH);
                    335:        if (kt->pfrkt_flags & PFR_TFLAG_CONST)
                    336:                return (EPERM);
                    337:        /*
                    338:         * there are two algorithms to choose from here.
                    339:         * with:
                    340:         *   n: number of addresses to delete
                    341:         *   N: number of addresses in the table
                    342:         *
                    343:         * one is O(N) and is better for large 'n'
                    344:         * one is O(n*LOG(N)) and is better for small 'n'
                    345:         *
                    346:         * following code try to decide which one is best.
                    347:         */
                    348:        for (i = kt->pfrkt_cnt; i > 0; i >>= 1)
                    349:                log++;
                    350:        if (size > kt->pfrkt_cnt/log) {
                    351:                /* full table scan */
                    352:                pfr_mark_addrs(kt);
                    353:        } else {
                    354:                /* iterate over addresses to delete */
                    355:                for (i = 0; i < size; i++) {
                    356:                        if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                    357:                                return (EFAULT);
                    358:                        if (pfr_validate_addr(&ad))
                    359:                                return (EINVAL);
                    360:                        p = pfr_lookup_addr(kt, &ad, 1);
                    361:                        if (p != NULL)
                    362:                                p->pfrke_mark = 0;
                    363:                }
                    364:        }
                    365:        SLIST_INIT(&workq);
                    366:        for (i = 0; i < size; i++) {
                    367:                if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                    368:                        senderr(EFAULT);
                    369:                if (pfr_validate_addr(&ad))
                    370:                        senderr(EINVAL);
                    371:                p = pfr_lookup_addr(kt, &ad, 1);
                    372:                if (flags & PFR_FLAG_FEEDBACK) {
                    373:                        if (p == NULL)
                    374:                                ad.pfra_fback = PFR_FB_NONE;
                    375:                        else if (p->pfrke_not != ad.pfra_not)
                    376:                                ad.pfra_fback = PFR_FB_CONFLICT;
                    377:                        else if (p->pfrke_mark)
                    378:                                ad.pfra_fback = PFR_FB_DUPLICATE;
                    379:                        else
                    380:                                ad.pfra_fback = PFR_FB_DELETED;
                    381:                }
                    382:                if (p != NULL && p->pfrke_not == ad.pfra_not &&
                    383:                    !p->pfrke_mark) {
                    384:                        p->pfrke_mark = 1;
                    385:                        SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
                    386:                        xdel++;
                    387:                }
                    388:                if (flags & PFR_FLAG_FEEDBACK)
                    389:                        if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                    390:                                senderr(EFAULT);
                    391:        }
                    392:        if (!(flags & PFR_FLAG_DUMMY)) {
                    393:                if (flags & PFR_FLAG_ATOMIC)
                    394:                        s = splsoftnet();
                    395:                pfr_remove_kentries(kt, &workq);
                    396:                if (flags & PFR_FLAG_ATOMIC)
                    397:                        splx(s);
                    398:        }
                    399:        if (ndel != NULL)
                    400:                *ndel = xdel;
                    401:        return (0);
                    402: _bad:
                    403:        if (flags & PFR_FLAG_FEEDBACK)
                    404:                pfr_reset_feedback(addr, size, flags);
                    405:        return (rv);
                    406: }
                    407:
                    408: int
                    409: pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                    410:     int *size2, int *nadd, int *ndel, int *nchange, int flags,
                    411:     u_int32_t ignore_pfrt_flags)
                    412: {
                    413:        struct pfr_ktable       *kt, *tmpkt;
                    414:        struct pfr_kentryworkq   addq, delq, changeq;
                    415:        struct pfr_kentry       *p, *q;
                    416:        struct pfr_addr          ad;
                    417:        int                      i, rv, s, xadd = 0, xdel = 0, xchange = 0;
                    418:        long                     tzero = time_second;
                    419:
                    420:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
                    421:            PFR_FLAG_FEEDBACK);
                    422:        if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
                    423:            PFR_FLAG_USERIOCTL))
                    424:                return (EINVAL);
                    425:        kt = pfr_lookup_table(tbl);
                    426:        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                    427:                return (ESRCH);
                    428:        if (kt->pfrkt_flags & PFR_TFLAG_CONST)
                    429:                return (EPERM);
                    430:        tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0);
                    431:        if (tmpkt == NULL)
                    432:                return (ENOMEM);
                    433:        pfr_mark_addrs(kt);
                    434:        SLIST_INIT(&addq);
                    435:        SLIST_INIT(&delq);
                    436:        SLIST_INIT(&changeq);
                    437:        for (i = 0; i < size; i++) {
                    438:                if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                    439:                        senderr(EFAULT);
                    440:                if (pfr_validate_addr(&ad))
                    441:                        senderr(EINVAL);
                    442:                ad.pfra_fback = PFR_FB_NONE;
                    443:                p = pfr_lookup_addr(kt, &ad, 1);
                    444:                if (p != NULL) {
                    445:                        if (p->pfrke_mark) {
                    446:                                ad.pfra_fback = PFR_FB_DUPLICATE;
                    447:                                goto _skip;
                    448:                        }
                    449:                        p->pfrke_mark = 1;
                    450:                        if (p->pfrke_not != ad.pfra_not) {
                    451:                                SLIST_INSERT_HEAD(&changeq, p, pfrke_workq);
                    452:                                ad.pfra_fback = PFR_FB_CHANGED;
                    453:                                xchange++;
                    454:                        }
                    455:                } else {
                    456:                        q = pfr_lookup_addr(tmpkt, &ad, 1);
                    457:                        if (q != NULL) {
                    458:                                ad.pfra_fback = PFR_FB_DUPLICATE;
                    459:                                goto _skip;
                    460:                        }
                    461:                        p = pfr_create_kentry(&ad,
                    462:                            !(flags & PFR_FLAG_USERIOCTL));
                    463:                        if (p == NULL)
                    464:                                senderr(ENOMEM);
                    465:                        if (pfr_route_kentry(tmpkt, p)) {
                    466:                                pfr_destroy_kentry(p);
                    467:                                ad.pfra_fback = PFR_FB_NONE;
                    468:                        } else {
                    469:                                SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
                    470:                                ad.pfra_fback = PFR_FB_ADDED;
                    471:                                xadd++;
                    472:                        }
                    473:                }
                    474: _skip:
                    475:                if (flags & PFR_FLAG_FEEDBACK)
                    476:                        if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                    477:                                senderr(EFAULT);
                    478:        }
                    479:        pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
                    480:        if ((flags & PFR_FLAG_FEEDBACK) && *size2) {
                    481:                if (*size2 < size+xdel) {
                    482:                        *size2 = size+xdel;
                    483:                        senderr(0);
                    484:                }
                    485:                i = 0;
                    486:                SLIST_FOREACH(p, &delq, pfrke_workq) {
                    487:                        pfr_copyout_addr(&ad, p);
                    488:                        ad.pfra_fback = PFR_FB_DELETED;
                    489:                        if (COPYOUT(&ad, addr+size+i, sizeof(ad), flags))
                    490:                                senderr(EFAULT);
                    491:                        i++;
                    492:                }
                    493:        }
                    494:        pfr_clean_node_mask(tmpkt, &addq);
                    495:        if (!(flags & PFR_FLAG_DUMMY)) {
                    496:                if (flags & PFR_FLAG_ATOMIC)
                    497:                        s = splsoftnet();
                    498:                pfr_insert_kentries(kt, &addq, tzero);
                    499:                pfr_remove_kentries(kt, &delq);
                    500:                pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
                    501:                if (flags & PFR_FLAG_ATOMIC)
                    502:                        splx(s);
                    503:        } else
                    504:                pfr_destroy_kentries(&addq);
                    505:        if (nadd != NULL)
                    506:                *nadd = xadd;
                    507:        if (ndel != NULL)
                    508:                *ndel = xdel;
                    509:        if (nchange != NULL)
                    510:                *nchange = xchange;
                    511:        if ((flags & PFR_FLAG_FEEDBACK) && size2)
                    512:                *size2 = size+xdel;
                    513:        pfr_destroy_ktable(tmpkt, 0);
                    514:        return (0);
                    515: _bad:
                    516:        pfr_clean_node_mask(tmpkt, &addq);
                    517:        pfr_destroy_kentries(&addq);
                    518:        if (flags & PFR_FLAG_FEEDBACK)
                    519:                pfr_reset_feedback(addr, size, flags);
                    520:        pfr_destroy_ktable(tmpkt, 0);
                    521:        return (rv);
                    522: }
                    523:
                    524: int
                    525: pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                    526:        int *nmatch, int flags)
                    527: {
                    528:        struct pfr_ktable       *kt;
                    529:        struct pfr_kentry       *p;
                    530:        struct pfr_addr          ad;
                    531:        int                      i, xmatch = 0;
                    532:
                    533:        ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE);
                    534:        if (pfr_validate_table(tbl, 0, 0))
                    535:                return (EINVAL);
                    536:        kt = pfr_lookup_table(tbl);
                    537:        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                    538:                return (ESRCH);
                    539:
                    540:        for (i = 0; i < size; i++) {
                    541:                if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                    542:                        return (EFAULT);
                    543:                if (pfr_validate_addr(&ad))
                    544:                        return (EINVAL);
                    545:                if (ADDR_NETWORK(&ad))
                    546:                        return (EINVAL);
                    547:                p = pfr_lookup_addr(kt, &ad, 0);
                    548:                if (flags & PFR_FLAG_REPLACE)
                    549:                        pfr_copyout_addr(&ad, p);
                    550:                ad.pfra_fback = (p == NULL) ? PFR_FB_NONE :
                    551:                    (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH);
                    552:                if (p != NULL && !p->pfrke_not)
                    553:                        xmatch++;
                    554:                if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                    555:                        return (EFAULT);
                    556:        }
                    557:        if (nmatch != NULL)
                    558:                *nmatch = xmatch;
                    559:        return (0);
                    560: }
                    561:
                    562: int
                    563: pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
                    564:        int flags)
                    565: {
                    566:        struct pfr_ktable       *kt;
                    567:        struct pfr_walktree      w;
                    568:        int                      rv;
                    569:
                    570:        ACCEPT_FLAGS(flags, 0);
                    571:        if (pfr_validate_table(tbl, 0, 0))
                    572:                return (EINVAL);
                    573:        kt = pfr_lookup_table(tbl);
                    574:        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                    575:                return (ESRCH);
                    576:        if (kt->pfrkt_cnt > *size) {
                    577:                *size = kt->pfrkt_cnt;
                    578:                return (0);
                    579:        }
                    580:
                    581:        bzero(&w, sizeof(w));
                    582:        w.pfrw_op = PFRW_GET_ADDRS;
                    583:        w.pfrw_addr = addr;
                    584:        w.pfrw_free = kt->pfrkt_cnt;
                    585:        w.pfrw_flags = flags;
                    586:        rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
                    587:        if (!rv)
                    588:                rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
                    589:        if (rv)
                    590:                return (rv);
                    591:
                    592:        if (w.pfrw_free) {
                    593:                printf("pfr_get_addrs: corruption detected (%d).\n",
                    594:                    w.pfrw_free);
                    595:                return (ENOTTY);
                    596:        }
                    597:        *size = kt->pfrkt_cnt;
                    598:        return (0);
                    599: }
                    600:
                    601: int
                    602: pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
                    603:        int flags)
                    604: {
                    605:        struct pfr_ktable       *kt;
                    606:        struct pfr_walktree      w;
                    607:        struct pfr_kentryworkq   workq;
                    608:        int                      rv, s;
                    609:        long                     tzero = time_second;
                    610:
                    611:        /* XXX PFR_FLAG_CLSTATS disabled */
                    612:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC);
                    613:        if (pfr_validate_table(tbl, 0, 0))
                    614:                return (EINVAL);
                    615:        kt = pfr_lookup_table(tbl);
                    616:        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                    617:                return (ESRCH);
                    618:        if (kt->pfrkt_cnt > *size) {
                    619:                *size = kt->pfrkt_cnt;
                    620:                return (0);
                    621:        }
                    622:
                    623:        bzero(&w, sizeof(w));
                    624:        w.pfrw_op = PFRW_GET_ASTATS;
                    625:        w.pfrw_astats = addr;
                    626:        w.pfrw_free = kt->pfrkt_cnt;
                    627:        w.pfrw_flags = flags;
                    628:        if (flags & PFR_FLAG_ATOMIC)
                    629:                s = splsoftnet();
                    630:        rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
                    631:        if (!rv)
                    632:                rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
                    633:        if (!rv && (flags & PFR_FLAG_CLSTATS)) {
                    634:                pfr_enqueue_addrs(kt, &workq, NULL, 0);
                    635:                pfr_clstats_kentries(&workq, tzero, 0);
                    636:        }
                    637:        if (flags & PFR_FLAG_ATOMIC)
                    638:                splx(s);
                    639:        if (rv)
                    640:                return (rv);
                    641:
                    642:        if (w.pfrw_free) {
                    643:                printf("pfr_get_astats: corruption detected (%d).\n",
                    644:                    w.pfrw_free);
                    645:                return (ENOTTY);
                    646:        }
                    647:        *size = kt->pfrkt_cnt;
                    648:        return (0);
                    649: }
                    650:
                    651: int
                    652: pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                    653:     int *nzero, int flags)
                    654: {
                    655:        struct pfr_ktable       *kt;
                    656:        struct pfr_kentryworkq   workq;
                    657:        struct pfr_kentry       *p;
                    658:        struct pfr_addr          ad;
                    659:        int                      i, rv, s, xzero = 0;
                    660:
                    661:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
                    662:            PFR_FLAG_FEEDBACK);
                    663:        if (pfr_validate_table(tbl, 0, 0))
                    664:                return (EINVAL);
                    665:        kt = pfr_lookup_table(tbl);
                    666:        if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                    667:                return (ESRCH);
                    668:        SLIST_INIT(&workq);
                    669:        for (i = 0; i < size; i++) {
                    670:                if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                    671:                        senderr(EFAULT);
                    672:                if (pfr_validate_addr(&ad))
                    673:                        senderr(EINVAL);
                    674:                p = pfr_lookup_addr(kt, &ad, 1);
                    675:                if (flags & PFR_FLAG_FEEDBACK) {
                    676:                        ad.pfra_fback = (p != NULL) ?
                    677:                            PFR_FB_CLEARED : PFR_FB_NONE;
                    678:                        if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                    679:                                senderr(EFAULT);
                    680:                }
                    681:                if (p != NULL) {
                    682:                        SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
                    683:                        xzero++;
                    684:                }
                    685:        }
                    686:
                    687:        if (!(flags & PFR_FLAG_DUMMY)) {
                    688:                if (flags & PFR_FLAG_ATOMIC)
                    689:                        s = splsoftnet();
                    690:                pfr_clstats_kentries(&workq, 0, 0);
                    691:                if (flags & PFR_FLAG_ATOMIC)
                    692:                        splx(s);
                    693:        }
                    694:        if (nzero != NULL)
                    695:                *nzero = xzero;
                    696:        return (0);
                    697: _bad:
                    698:        if (flags & PFR_FLAG_FEEDBACK)
                    699:                pfr_reset_feedback(addr, size, flags);
                    700:        return (rv);
                    701: }
                    702:
                    703: int
                    704: pfr_validate_addr(struct pfr_addr *ad)
                    705: {
                    706:        int i;
                    707:
                    708:        switch (ad->pfra_af) {
                    709: #ifdef INET
                    710:        case AF_INET:
                    711:                if (ad->pfra_net > 32)
                    712:                        return (-1);
                    713:                break;
                    714: #endif /* INET */
                    715: #ifdef INET6
                    716:        case AF_INET6:
                    717:                if (ad->pfra_net > 128)
                    718:                        return (-1);
                    719:                break;
                    720: #endif /* INET6 */
                    721:        default:
                    722:                return (-1);
                    723:        }
                    724:        if (ad->pfra_net < 128 &&
                    725:                (((caddr_t)ad)[ad->pfra_net/8] & (0xFF >> (ad->pfra_net%8))))
                    726:                        return (-1);
                    727:        for (i = (ad->pfra_net+7)/8; i < sizeof(ad->pfra_u); i++)
                    728:                if (((caddr_t)ad)[i])
                    729:                        return (-1);
                    730:        if (ad->pfra_not && ad->pfra_not != 1)
                    731:                return (-1);
                    732:        if (ad->pfra_fback)
                    733:                return (-1);
                    734:        return (0);
                    735: }
                    736:
                    737: void
                    738: pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq,
                    739:        int *naddr, int sweep)
                    740: {
                    741:        struct pfr_walktree     w;
                    742:
                    743:        SLIST_INIT(workq);
                    744:        bzero(&w, sizeof(w));
                    745:        w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE;
                    746:        w.pfrw_workq = workq;
                    747:        if (kt->pfrkt_ip4 != NULL)
                    748:                if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
                    749:                        printf("pfr_enqueue_addrs: IPv4 walktree failed.\n");
                    750:        if (kt->pfrkt_ip6 != NULL)
                    751:                if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
                    752:                        printf("pfr_enqueue_addrs: IPv6 walktree failed.\n");
                    753:        if (naddr != NULL)
                    754:                *naddr = w.pfrw_cnt;
                    755: }
                    756:
                    757: void
                    758: pfr_mark_addrs(struct pfr_ktable *kt)
                    759: {
                    760:        struct pfr_walktree     w;
                    761:
                    762:        bzero(&w, sizeof(w));
                    763:        w.pfrw_op = PFRW_MARK;
                    764:        if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
                    765:                printf("pfr_mark_addrs: IPv4 walktree failed.\n");
                    766:        if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
                    767:                printf("pfr_mark_addrs: IPv6 walktree failed.\n");
                    768: }
                    769:
                    770:
                    771: struct pfr_kentry *
                    772: pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
                    773: {
                    774:        union sockaddr_union     sa, mask;
                    775:        struct radix_node_head  *head;
                    776:        struct pfr_kentry       *ke;
                    777:        int                      s;
                    778:
                    779:        bzero(&sa, sizeof(sa));
                    780:        if (ad->pfra_af == AF_INET) {
                    781:                FILLIN_SIN(sa.sin, ad->pfra_ip4addr);
                    782:                head = kt->pfrkt_ip4;
                    783:        } else if ( ad->pfra_af == AF_INET6 ) {
                    784:                FILLIN_SIN6(sa.sin6, ad->pfra_ip6addr);
                    785:                head = kt->pfrkt_ip6;
                    786:        }
                    787:        if (ADDR_NETWORK(ad)) {
                    788:                pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net);
                    789:                s = splsoftnet(); /* rn_lookup makes use of globals */
                    790:                ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head);
                    791:                splx(s);
                    792:                if (ke && KENTRY_RNF_ROOT(ke))
                    793:                        ke = NULL;
                    794:        } else {
                    795:                ke = (struct pfr_kentry *)rn_match(&sa, head);
                    796:                if (ke && KENTRY_RNF_ROOT(ke))
                    797:                        ke = NULL;
                    798:                if (exact && ke && KENTRY_NETWORK(ke))
                    799:                        ke = NULL;
                    800:        }
                    801:        return (ke);
                    802: }
                    803:
                    804: struct pfr_kentry *
                    805: pfr_create_kentry(struct pfr_addr *ad, int intr)
                    806: {
                    807:        struct pfr_kentry       *ke;
                    808:
                    809:        if (intr)
                    810:                ke = pool_get(&pfr_kentry_pl2, PR_NOWAIT);
                    811:        else
                    812:                ke = pool_get(&pfr_kentry_pl, PR_NOWAIT);
                    813:        if (ke == NULL)
                    814:                return (NULL);
                    815:        bzero(ke, sizeof(*ke));
                    816:
                    817:        if (ad->pfra_af == AF_INET)
                    818:                FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr);
                    819:        else if (ad->pfra_af == AF_INET6)
                    820:                FILLIN_SIN6(ke->pfrke_sa.sin6, ad->pfra_ip6addr);
                    821:        ke->pfrke_af = ad->pfra_af;
                    822:        ke->pfrke_net = ad->pfra_net;
                    823:        ke->pfrke_not = ad->pfra_not;
                    824:        ke->pfrke_intrpool = intr;
                    825:        return (ke);
                    826: }
                    827:
                    828: void
                    829: pfr_destroy_kentries(struct pfr_kentryworkq *workq)
                    830: {
                    831:        struct pfr_kentry       *p, *q;
                    832:
                    833:        for (p = SLIST_FIRST(workq); p != NULL; p = q) {
                    834:                q = SLIST_NEXT(p, pfrke_workq);
                    835:                pfr_destroy_kentry(p);
                    836:        }
                    837: }
                    838:
                    839: void
                    840: pfr_destroy_kentry(struct pfr_kentry *ke)
                    841: {
                    842:        if (ke->pfrke_intrpool)
                    843:                pool_put(&pfr_kentry_pl2, ke);
                    844:        else
                    845:                pool_put(&pfr_kentry_pl, ke);
                    846: }
                    847:
                    848: void
                    849: pfr_insert_kentries(struct pfr_ktable *kt,
                    850:     struct pfr_kentryworkq *workq, long tzero)
                    851: {
                    852:        struct pfr_kentry       *p;
                    853:        int                      rv, n = 0;
                    854:
                    855:        SLIST_FOREACH(p, workq, pfrke_workq) {
                    856:                rv = pfr_route_kentry(kt, p);
                    857:                if (rv) {
                    858:                        printf("pfr_insert_kentries: cannot route entry "
                    859:                            "(code=%d).\n", rv);
                    860:                        break;
                    861:                }
                    862:                p->pfrke_tzero = tzero;
                    863:                n++;
                    864:        }
                    865:        kt->pfrkt_cnt += n;
                    866: }
                    867:
                    868: int
                    869: pfr_insert_kentry(struct pfr_ktable *kt, struct pfr_addr *ad, long tzero)
                    870: {
                    871:        struct pfr_kentry       *p;
                    872:        int                      rv;
                    873:
                    874:        p = pfr_lookup_addr(kt, ad, 1);
                    875:        if (p != NULL)
                    876:                return (0);
                    877:        p = pfr_create_kentry(ad, 1);
                    878:        if (p == NULL)
                    879:                return (EINVAL);
                    880:
                    881:        rv = pfr_route_kentry(kt, p);
                    882:        if (rv)
                    883:                return (rv);
                    884:
                    885:        p->pfrke_tzero = tzero;
                    886:        kt->pfrkt_cnt++;
                    887:
                    888:        return (0);
                    889: }
                    890:
                    891: void
                    892: pfr_remove_kentries(struct pfr_ktable *kt,
                    893:     struct pfr_kentryworkq *workq)
                    894: {
                    895:        struct pfr_kentry       *p;
                    896:        int                      n = 0;
                    897:
                    898:        SLIST_FOREACH(p, workq, pfrke_workq) {
                    899:                pfr_unroute_kentry(kt, p);
                    900:                n++;
                    901:        }
                    902:        kt->pfrkt_cnt -= n;
                    903:        pfr_destroy_kentries(workq);
                    904: }
                    905:
                    906: void
                    907: pfr_clean_node_mask(struct pfr_ktable *kt,
                    908:     struct pfr_kentryworkq *workq)
                    909: {
                    910:        struct pfr_kentry       *p;
                    911:
                    912:        SLIST_FOREACH(p, workq, pfrke_workq)
                    913:                pfr_unroute_kentry(kt, p);
                    914: }
                    915:
                    916: void
                    917: pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange)
                    918: {
                    919:        struct pfr_kentry       *p;
                    920:        int                      s;
                    921:
                    922:        SLIST_FOREACH(p, workq, pfrke_workq) {
                    923:                s = splsoftnet();
                    924:                if (negchange)
                    925:                        p->pfrke_not = !p->pfrke_not;
                    926:                bzero(p->pfrke_packets, sizeof(p->pfrke_packets));
                    927:                bzero(p->pfrke_bytes, sizeof(p->pfrke_bytes));
                    928:                splx(s);
                    929:                p->pfrke_tzero = tzero;
                    930:        }
                    931: }
                    932:
                    933: void
                    934: pfr_reset_feedback(struct pfr_addr *addr, int size, int flags)
                    935: {
                    936:        struct pfr_addr ad;
                    937:        int             i;
                    938:
                    939:        for (i = 0; i < size; i++) {
                    940:                if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                    941:                        break;
                    942:                ad.pfra_fback = PFR_FB_NONE;
                    943:                if (COPYOUT(&ad, addr+i, sizeof(ad), flags))
                    944:                        break;
                    945:        }
                    946: }
                    947:
                    948: void
                    949: pfr_prepare_network(union sockaddr_union *sa, int af, int net)
                    950: {
                    951:        int     i;
                    952:
                    953:        bzero(sa, sizeof(*sa));
                    954:        if (af == AF_INET) {
                    955:                sa->sin.sin_len = sizeof(sa->sin);
                    956:                sa->sin.sin_family = AF_INET;
                    957:                sa->sin.sin_addr.s_addr = net ? htonl(-1 << (32-net)) : 0;
                    958:        } else if (af == AF_INET6) {
                    959:                sa->sin6.sin6_len = sizeof(sa->sin6);
                    960:                sa->sin6.sin6_family = AF_INET6;
                    961:                for (i = 0; i < 4; i++) {
                    962:                        if (net <= 32) {
                    963:                                sa->sin6.sin6_addr.s6_addr32[i] =
                    964:                                    net ? htonl(-1 << (32-net)) : 0;
                    965:                                break;
                    966:                        }
                    967:                        sa->sin6.sin6_addr.s6_addr32[i] = 0xFFFFFFFF;
                    968:                        net -= 32;
                    969:                }
                    970:        }
                    971: }
                    972:
                    973: int
                    974: pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
                    975: {
                    976:        union sockaddr_union     mask;
                    977:        struct radix_node       *rn;
                    978:        struct radix_node_head  *head;
                    979:        int                      s;
                    980:
                    981:        bzero(ke->pfrke_node, sizeof(ke->pfrke_node));
                    982:        if (ke->pfrke_af == AF_INET)
                    983:                head = kt->pfrkt_ip4;
                    984:        else if (ke->pfrke_af == AF_INET6)
                    985:                head = kt->pfrkt_ip6;
                    986:
                    987:        s = splsoftnet();
                    988:        if (KENTRY_NETWORK(ke)) {
                    989:                pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
                    990:                rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node);
                    991:        } else
                    992:                rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node);
                    993:        splx(s);
                    994:
                    995:        return (rn == NULL ? -1 : 0);
                    996: }
                    997:
                    998: int
                    999: pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
                   1000: {
                   1001:        union sockaddr_union     mask;
                   1002:        struct radix_node       *rn;
                   1003:        struct radix_node_head  *head;
                   1004:        int                      s;
                   1005:
                   1006:        if (ke->pfrke_af == AF_INET)
                   1007:                head = kt->pfrkt_ip4;
                   1008:        else if (ke->pfrke_af == AF_INET6)
                   1009:                head = kt->pfrkt_ip6;
                   1010:
                   1011:        s = splsoftnet();
                   1012:        if (KENTRY_NETWORK(ke)) {
                   1013:                pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
                   1014:                rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL);
                   1015:        } else
                   1016:                rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL);
                   1017:        splx(s);
                   1018:
                   1019:        if (rn == NULL) {
                   1020:                printf("pfr_unroute_kentry: delete failed.\n");
                   1021:                return (-1);
                   1022:        }
                   1023:        return (0);
                   1024: }
                   1025:
                   1026: void
                   1027: pfr_copyout_addr(struct pfr_addr *ad, struct pfr_kentry *ke)
                   1028: {
                   1029:        bzero(ad, sizeof(*ad));
                   1030:        if (ke == NULL)
                   1031:                return;
                   1032:        ad->pfra_af = ke->pfrke_af;
                   1033:        ad->pfra_net = ke->pfrke_net;
                   1034:        ad->pfra_not = ke->pfrke_not;
                   1035:        if (ad->pfra_af == AF_INET)
                   1036:                ad->pfra_ip4addr = ke->pfrke_sa.sin.sin_addr;
                   1037:        else if (ad->pfra_af == AF_INET6)
                   1038:                ad->pfra_ip6addr = ke->pfrke_sa.sin6.sin6_addr;
                   1039: }
                   1040:
                   1041: int
                   1042: pfr_walktree(struct radix_node *rn, void *arg)
                   1043: {
                   1044:        struct pfr_kentry       *ke = (struct pfr_kentry *)rn;
                   1045:        struct pfr_walktree     *w = arg;
                   1046:        int                      s, flags = w->pfrw_flags;
                   1047:
                   1048:        switch (w->pfrw_op) {
                   1049:        case PFRW_MARK:
                   1050:                ke->pfrke_mark = 0;
                   1051:                break;
                   1052:        case PFRW_SWEEP:
                   1053:                if (ke->pfrke_mark)
                   1054:                        break;
                   1055:                /* FALLTHROUGH */
                   1056:        case PFRW_ENQUEUE:
                   1057:                SLIST_INSERT_HEAD(w->pfrw_workq, ke, pfrke_workq);
                   1058:                w->pfrw_cnt++;
                   1059:                break;
                   1060:        case PFRW_GET_ADDRS:
                   1061:                if (w->pfrw_free-- > 0) {
                   1062:                        struct pfr_addr ad;
                   1063:
                   1064:                        pfr_copyout_addr(&ad, ke);
                   1065:                        if (copyout(&ad, w->pfrw_addr, sizeof(ad)))
                   1066:                                return (EFAULT);
                   1067:                        w->pfrw_addr++;
                   1068:                }
                   1069:                break;
                   1070:        case PFRW_GET_ASTATS:
                   1071:                if (w->pfrw_free-- > 0) {
                   1072:                        struct pfr_astats as;
                   1073:
                   1074:                        pfr_copyout_addr(&as.pfras_a, ke);
                   1075:
                   1076:                        s = splsoftnet();
                   1077:                        bcopy(ke->pfrke_packets, as.pfras_packets,
                   1078:                            sizeof(as.pfras_packets));
                   1079:                        bcopy(ke->pfrke_bytes, as.pfras_bytes,
                   1080:                            sizeof(as.pfras_bytes));
                   1081:                        splx(s);
                   1082:                        as.pfras_tzero = ke->pfrke_tzero;
                   1083:
                   1084:                        if (COPYOUT(&as, w->pfrw_astats, sizeof(as), flags))
                   1085:                                return (EFAULT);
                   1086:                        w->pfrw_astats++;
                   1087:                }
                   1088:                break;
                   1089:        case PFRW_POOL_GET:
                   1090:                if (ke->pfrke_not)
                   1091:                        break; /* negative entries are ignored */
                   1092:                if (!w->pfrw_cnt--) {
                   1093:                        w->pfrw_kentry = ke;
                   1094:                        return (1); /* finish search */
                   1095:                }
                   1096:                break;
                   1097:        case PFRW_DYNADDR_UPDATE:
                   1098:                if (ke->pfrke_af == AF_INET) {
                   1099:                        if (w->pfrw_dyn->pfid_acnt4++ > 0)
                   1100:                                break;
                   1101:                        pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net);
                   1102:                        w->pfrw_dyn->pfid_addr4 = *SUNION2PF(
                   1103:                            &ke->pfrke_sa, AF_INET);
                   1104:                        w->pfrw_dyn->pfid_mask4 = *SUNION2PF(
                   1105:                            &pfr_mask, AF_INET);
                   1106:                } else if (ke->pfrke_af == AF_INET6){
                   1107:                        if (w->pfrw_dyn->pfid_acnt6++ > 0)
                   1108:                                break;
                   1109:                        pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net);
                   1110:                        w->pfrw_dyn->pfid_addr6 = *SUNION2PF(
                   1111:                            &ke->pfrke_sa, AF_INET6);
                   1112:                        w->pfrw_dyn->pfid_mask6 = *SUNION2PF(
                   1113:                            &pfr_mask, AF_INET6);
                   1114:                }
                   1115:                break;
                   1116:        }
                   1117:        return (0);
                   1118: }
                   1119:
                   1120: int
                   1121: pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
                   1122: {
                   1123:        struct pfr_ktableworkq   workq;
                   1124:        struct pfr_ktable       *p;
                   1125:        int                      s, xdel = 0;
                   1126:
                   1127:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
                   1128:            PFR_FLAG_ALLRSETS);
                   1129:        if (pfr_fix_anchor(filter->pfrt_anchor))
                   1130:                return (EINVAL);
                   1131:        if (pfr_table_count(filter, flags) < 0)
                   1132:                return (ENOENT);
                   1133:
                   1134:        SLIST_INIT(&workq);
                   1135:        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
                   1136:                if (pfr_skip_table(filter, p, flags))
                   1137:                        continue;
                   1138:                if (!strcmp(p->pfrkt_anchor, PF_RESERVED_ANCHOR))
                   1139:                        continue;
                   1140:                if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE))
                   1141:                        continue;
                   1142:                p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
                   1143:                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
                   1144:                xdel++;
                   1145:        }
                   1146:        if (!(flags & PFR_FLAG_DUMMY)) {
                   1147:                if (flags & PFR_FLAG_ATOMIC)
                   1148:                        s = splsoftnet();
                   1149:                pfr_setflags_ktables(&workq);
                   1150:                if (flags & PFR_FLAG_ATOMIC)
                   1151:                        splx(s);
                   1152:        }
                   1153:        if (ndel != NULL)
                   1154:                *ndel = xdel;
                   1155:        return (0);
                   1156: }
                   1157:
                   1158: int
                   1159: pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
                   1160: {
                   1161:        struct pfr_ktableworkq   addq, changeq;
                   1162:        struct pfr_ktable       *p, *q, *r, key;
                   1163:        int                      i, rv, s, xadd = 0;
                   1164:        long                     tzero = time_second;
                   1165:
                   1166:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
                   1167:        SLIST_INIT(&addq);
                   1168:        SLIST_INIT(&changeq);
                   1169:        for (i = 0; i < size; i++) {
                   1170:                if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
                   1171:                        senderr(EFAULT);
                   1172:                if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK,
                   1173:                    flags & PFR_FLAG_USERIOCTL))
                   1174:                        senderr(EINVAL);
                   1175:                key.pfrkt_flags |= PFR_TFLAG_ACTIVE;
                   1176:                p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
                   1177:                if (p == NULL) {
                   1178:                        p = pfr_create_ktable(&key.pfrkt_t, tzero, 1);
                   1179:                        if (p == NULL)
                   1180:                                senderr(ENOMEM);
                   1181:                        SLIST_FOREACH(q, &addq, pfrkt_workq) {
                   1182:                                if (!pfr_ktable_compare(p, q))
                   1183:                                        goto _skip;
                   1184:                        }
                   1185:                        SLIST_INSERT_HEAD(&addq, p, pfrkt_workq);
                   1186:                        xadd++;
                   1187:                        if (!key.pfrkt_anchor[0])
                   1188:                                goto _skip;
                   1189:
                   1190:                        /* find or create root table */
                   1191:                        bzero(key.pfrkt_anchor, sizeof(key.pfrkt_anchor));
                   1192:                        r = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
                   1193:                        if (r != NULL) {
                   1194:                                p->pfrkt_root = r;
                   1195:                                goto _skip;
                   1196:                        }
                   1197:                        SLIST_FOREACH(q, &addq, pfrkt_workq) {
                   1198:                                if (!pfr_ktable_compare(&key, q)) {
                   1199:                                        p->pfrkt_root = q;
                   1200:                                        goto _skip;
                   1201:                                }
                   1202:                        }
                   1203:                        key.pfrkt_flags = 0;
                   1204:                        r = pfr_create_ktable(&key.pfrkt_t, 0, 1);
                   1205:                        if (r == NULL)
                   1206:                                senderr(ENOMEM);
                   1207:                        SLIST_INSERT_HEAD(&addq, r, pfrkt_workq);
                   1208:                        p->pfrkt_root = r;
                   1209:                } else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
                   1210:                        SLIST_FOREACH(q, &changeq, pfrkt_workq)
                   1211:                                if (!pfr_ktable_compare(&key, q))
                   1212:                                        goto _skip;
                   1213:                        p->pfrkt_nflags = (p->pfrkt_flags &
                   1214:                            ~PFR_TFLAG_USRMASK) | key.pfrkt_flags;
                   1215:                        SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq);
                   1216:                        xadd++;
                   1217:                }
                   1218: _skip:
                   1219:        ;
                   1220:        }
                   1221:        if (!(flags & PFR_FLAG_DUMMY)) {
                   1222:                if (flags & PFR_FLAG_ATOMIC)
                   1223:                        s = splsoftnet();
                   1224:                pfr_insert_ktables(&addq);
                   1225:                pfr_setflags_ktables(&changeq);
                   1226:                if (flags & PFR_FLAG_ATOMIC)
                   1227:                        splx(s);
                   1228:        } else
                   1229:                 pfr_destroy_ktables(&addq, 0);
                   1230:        if (nadd != NULL)
                   1231:                *nadd = xadd;
                   1232:        return (0);
                   1233: _bad:
                   1234:        pfr_destroy_ktables(&addq, 0);
                   1235:        return (rv);
                   1236: }
                   1237:
                   1238: int
                   1239: pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
                   1240: {
                   1241:        struct pfr_ktableworkq   workq;
                   1242:        struct pfr_ktable       *p, *q, key;
                   1243:        int                      i, s, xdel = 0;
                   1244:
                   1245:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
                   1246:        SLIST_INIT(&workq);
                   1247:        for (i = 0; i < size; i++) {
                   1248:                if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
                   1249:                        return (EFAULT);
                   1250:                if (pfr_validate_table(&key.pfrkt_t, 0,
                   1251:                    flags & PFR_FLAG_USERIOCTL))
                   1252:                        return (EINVAL);
                   1253:                p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
                   1254:                if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
                   1255:                        SLIST_FOREACH(q, &workq, pfrkt_workq)
                   1256:                                if (!pfr_ktable_compare(p, q))
                   1257:                                        goto _skip;
                   1258:                        p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_ACTIVE;
                   1259:                        SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
                   1260:                        xdel++;
                   1261:                }
                   1262: _skip:
                   1263:        ;
                   1264:        }
                   1265:
                   1266:        if (!(flags & PFR_FLAG_DUMMY)) {
                   1267:                if (flags & PFR_FLAG_ATOMIC)
                   1268:                        s = splsoftnet();
                   1269:                pfr_setflags_ktables(&workq);
                   1270:                if (flags & PFR_FLAG_ATOMIC)
                   1271:                        splx(s);
                   1272:        }
                   1273:        if (ndel != NULL)
                   1274:                *ndel = xdel;
                   1275:        return (0);
                   1276: }
                   1277:
                   1278: int
                   1279: pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
                   1280:        int flags)
                   1281: {
                   1282:        struct pfr_ktable       *p;
                   1283:        int                      n, nn;
                   1284:
                   1285:        ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS);
                   1286:        if (pfr_fix_anchor(filter->pfrt_anchor))
                   1287:                return (EINVAL);
                   1288:        n = nn = pfr_table_count(filter, flags);
                   1289:        if (n < 0)
                   1290:                return (ENOENT);
                   1291:        if (n > *size) {
                   1292:                *size = n;
                   1293:                return (0);
                   1294:        }
                   1295:        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
                   1296:                if (pfr_skip_table(filter, p, flags))
                   1297:                        continue;
                   1298:                if (n-- <= 0)
                   1299:                        continue;
                   1300:                if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), flags))
                   1301:                        return (EFAULT);
                   1302:        }
                   1303:        if (n) {
                   1304:                printf("pfr_get_tables: corruption detected (%d).\n", n);
                   1305:                return (ENOTTY);
                   1306:        }
                   1307:        *size = nn;
                   1308:        return (0);
                   1309: }
                   1310:
                   1311: int
                   1312: pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
                   1313:        int flags)
                   1314: {
                   1315:        struct pfr_ktable       *p;
                   1316:        struct pfr_ktableworkq   workq;
                   1317:        int                      s, n, nn;
                   1318:        long                     tzero = time_second;
                   1319:
                   1320:        /* XXX PFR_FLAG_CLSTATS disabled */
                   1321:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_ALLRSETS);
                   1322:        if (pfr_fix_anchor(filter->pfrt_anchor))
                   1323:                return (EINVAL);
                   1324:        n = nn = pfr_table_count(filter, flags);
                   1325:        if (n < 0)
                   1326:                return (ENOENT);
                   1327:        if (n > *size) {
                   1328:                *size = n;
                   1329:                return (0);
                   1330:        }
                   1331:        SLIST_INIT(&workq);
                   1332:        if (flags & PFR_FLAG_ATOMIC)
                   1333:                s = splsoftnet();
                   1334:        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
                   1335:                if (pfr_skip_table(filter, p, flags))
                   1336:                        continue;
                   1337:                if (n-- <= 0)
                   1338:                        continue;
                   1339:                if (!(flags & PFR_FLAG_ATOMIC))
                   1340:                        s = splsoftnet();
                   1341:                if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), flags)) {
                   1342:                        splx(s);
                   1343:                        return (EFAULT);
                   1344:                }
                   1345:                if (!(flags & PFR_FLAG_ATOMIC))
                   1346:                        splx(s);
                   1347:                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
                   1348:        }
                   1349:        if (flags & PFR_FLAG_CLSTATS)
                   1350:                pfr_clstats_ktables(&workq, tzero,
                   1351:                    flags & PFR_FLAG_ADDRSTOO);
                   1352:        if (flags & PFR_FLAG_ATOMIC)
                   1353:                splx(s);
                   1354:        if (n) {
                   1355:                printf("pfr_get_tstats: corruption detected (%d).\n", n);
                   1356:                return (ENOTTY);
                   1357:        }
                   1358:        *size = nn;
                   1359:        return (0);
                   1360: }
                   1361:
                   1362: int
                   1363: pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
                   1364: {
                   1365:        struct pfr_ktableworkq   workq;
                   1366:        struct pfr_ktable       *p, key;
                   1367:        int                      i, s, xzero = 0;
                   1368:        long                     tzero = time_second;
                   1369:
                   1370:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY |
                   1371:            PFR_FLAG_ADDRSTOO);
                   1372:        SLIST_INIT(&workq);
                   1373:        for (i = 0; i < size; i++) {
                   1374:                if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
                   1375:                        return (EFAULT);
                   1376:                if (pfr_validate_table(&key.pfrkt_t, 0, 0))
                   1377:                        return (EINVAL);
                   1378:                p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
                   1379:                if (p != NULL) {
                   1380:                        SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
                   1381:                        xzero++;
                   1382:                }
                   1383:        }
                   1384:        if (!(flags & PFR_FLAG_DUMMY)) {
                   1385:                if (flags & PFR_FLAG_ATOMIC)
                   1386:                        s = splsoftnet();
                   1387:                pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO);
                   1388:                if (flags & PFR_FLAG_ATOMIC)
                   1389:                        splx(s);
                   1390:        }
                   1391:        if (nzero != NULL)
                   1392:                *nzero = xzero;
                   1393:        return (0);
                   1394: }
                   1395:
                   1396: int
                   1397: pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
                   1398:        int *nchange, int *ndel, int flags)
                   1399: {
                   1400:        struct pfr_ktableworkq   workq;
                   1401:        struct pfr_ktable       *p, *q, key;
                   1402:        int                      i, s, xchange = 0, xdel = 0;
                   1403:
                   1404:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
                   1405:        if ((setflag & ~PFR_TFLAG_USRMASK) ||
                   1406:            (clrflag & ~PFR_TFLAG_USRMASK) ||
                   1407:            (setflag & clrflag))
                   1408:                return (EINVAL);
                   1409:        SLIST_INIT(&workq);
                   1410:        for (i = 0; i < size; i++) {
                   1411:                if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags))
                   1412:                        return (EFAULT);
                   1413:                if (pfr_validate_table(&key.pfrkt_t, 0,
                   1414:                    flags & PFR_FLAG_USERIOCTL))
                   1415:                        return (EINVAL);
                   1416:                p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
                   1417:                if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
                   1418:                        p->pfrkt_nflags = (p->pfrkt_flags | setflag) &
                   1419:                            ~clrflag;
                   1420:                        if (p->pfrkt_nflags == p->pfrkt_flags)
                   1421:                                goto _skip;
                   1422:                        SLIST_FOREACH(q, &workq, pfrkt_workq)
                   1423:                                if (!pfr_ktable_compare(p, q))
                   1424:                                        goto _skip;
                   1425:                        SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
                   1426:                        if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) &&
                   1427:                            (clrflag & PFR_TFLAG_PERSIST) &&
                   1428:                            !(p->pfrkt_flags & PFR_TFLAG_REFERENCED))
                   1429:                                xdel++;
                   1430:                        else
                   1431:                                xchange++;
                   1432:                }
                   1433: _skip:
                   1434:        ;
                   1435:        }
                   1436:        if (!(flags & PFR_FLAG_DUMMY)) {
                   1437:                if (flags & PFR_FLAG_ATOMIC)
                   1438:                        s = splsoftnet();
                   1439:                pfr_setflags_ktables(&workq);
                   1440:                if (flags & PFR_FLAG_ATOMIC)
                   1441:                        splx(s);
                   1442:        }
                   1443:        if (nchange != NULL)
                   1444:                *nchange = xchange;
                   1445:        if (ndel != NULL)
                   1446:                *ndel = xdel;
                   1447:        return (0);
                   1448: }
                   1449:
                   1450: int
                   1451: pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags)
                   1452: {
                   1453:        struct pfr_ktableworkq   workq;
                   1454:        struct pfr_ktable       *p;
                   1455:        struct pf_ruleset       *rs;
                   1456:        int                      xdel = 0;
                   1457:
                   1458:        ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
                   1459:        rs = pf_find_or_create_ruleset(trs->pfrt_anchor);
                   1460:        if (rs == NULL)
                   1461:                return (ENOMEM);
                   1462:        SLIST_INIT(&workq);
                   1463:        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
                   1464:                if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
                   1465:                    pfr_skip_table(trs, p, 0))
                   1466:                        continue;
                   1467:                p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
                   1468:                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
                   1469:                xdel++;
                   1470:        }
                   1471:        if (!(flags & PFR_FLAG_DUMMY)) {
                   1472:                pfr_setflags_ktables(&workq);
                   1473:                if (ticket != NULL)
                   1474:                        *ticket = ++rs->tticket;
                   1475:                rs->topen = 1;
                   1476:        } else
                   1477:                pf_remove_if_empty_ruleset(rs);
                   1478:        if (ndel != NULL)
                   1479:                *ndel = xdel;
                   1480:        return (0);
                   1481: }
                   1482:
                   1483: int
                   1484: pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
                   1485:     int *nadd, int *naddr, u_int32_t ticket, int flags)
                   1486: {
                   1487:        struct pfr_ktableworkq   tableq;
                   1488:        struct pfr_kentryworkq   addrq;
                   1489:        struct pfr_ktable       *kt, *rt, *shadow, key;
                   1490:        struct pfr_kentry       *p;
                   1491:        struct pfr_addr          ad;
                   1492:        struct pf_ruleset       *rs;
                   1493:        int                      i, rv, xadd = 0, xaddr = 0;
                   1494:
                   1495:        ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO);
                   1496:        if (size && !(flags & PFR_FLAG_ADDRSTOO))
                   1497:                return (EINVAL);
                   1498:        if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK,
                   1499:            flags & PFR_FLAG_USERIOCTL))
                   1500:                return (EINVAL);
                   1501:        rs = pf_find_ruleset(tbl->pfrt_anchor);
                   1502:        if (rs == NULL || !rs->topen || ticket != rs->tticket)
                   1503:                return (EBUSY);
                   1504:        tbl->pfrt_flags |= PFR_TFLAG_INACTIVE;
                   1505:        SLIST_INIT(&tableq);
                   1506:        kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl);
                   1507:        if (kt == NULL) {
                   1508:                kt = pfr_create_ktable(tbl, 0, 1);
                   1509:                if (kt == NULL)
                   1510:                        return (ENOMEM);
                   1511:                SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq);
                   1512:                xadd++;
                   1513:                if (!tbl->pfrt_anchor[0])
                   1514:                        goto _skip;
                   1515:
                   1516:                /* find or create root table */
                   1517:                bzero(&key, sizeof(key));
                   1518:                strlcpy(key.pfrkt_name, tbl->pfrt_name, sizeof(key.pfrkt_name));
                   1519:                rt = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
                   1520:                if (rt != NULL) {
                   1521:                        kt->pfrkt_root = rt;
                   1522:                        goto _skip;
                   1523:                }
                   1524:                rt = pfr_create_ktable(&key.pfrkt_t, 0, 1);
                   1525:                if (rt == NULL) {
                   1526:                        pfr_destroy_ktables(&tableq, 0);
                   1527:                        return (ENOMEM);
                   1528:                }
                   1529:                SLIST_INSERT_HEAD(&tableq, rt, pfrkt_workq);
                   1530:                kt->pfrkt_root = rt;
                   1531:        } else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE))
                   1532:                xadd++;
                   1533: _skip:
                   1534:        shadow = pfr_create_ktable(tbl, 0, 0);
                   1535:        if (shadow == NULL) {
                   1536:                pfr_destroy_ktables(&tableq, 0);
                   1537:                return (ENOMEM);
                   1538:        }
                   1539:        SLIST_INIT(&addrq);
                   1540:        for (i = 0; i < size; i++) {
                   1541:                if (COPYIN(addr+i, &ad, sizeof(ad), flags))
                   1542:                        senderr(EFAULT);
                   1543:                if (pfr_validate_addr(&ad))
                   1544:                        senderr(EINVAL);
                   1545:                if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
                   1546:                        continue;
                   1547:                p = pfr_create_kentry(&ad, 0);
                   1548:                if (p == NULL)
                   1549:                        senderr(ENOMEM);
                   1550:                if (pfr_route_kentry(shadow, p)) {
                   1551:                        pfr_destroy_kentry(p);
                   1552:                        continue;
                   1553:                }
                   1554:                SLIST_INSERT_HEAD(&addrq, p, pfrke_workq);
                   1555:                xaddr++;
                   1556:        }
                   1557:        if (!(flags & PFR_FLAG_DUMMY)) {
                   1558:                if (kt->pfrkt_shadow != NULL)
                   1559:                        pfr_destroy_ktable(kt->pfrkt_shadow, 1);
                   1560:                kt->pfrkt_flags |= PFR_TFLAG_INACTIVE;
                   1561:                pfr_insert_ktables(&tableq);
                   1562:                shadow->pfrkt_cnt = (flags & PFR_FLAG_ADDRSTOO) ?
                   1563:                    xaddr : NO_ADDRESSES;
                   1564:                kt->pfrkt_shadow = shadow;
                   1565:        } else {
                   1566:                pfr_clean_node_mask(shadow, &addrq);
                   1567:                pfr_destroy_ktable(shadow, 0);
                   1568:                pfr_destroy_ktables(&tableq, 0);
                   1569:                pfr_destroy_kentries(&addrq);
                   1570:        }
                   1571:        if (nadd != NULL)
                   1572:                *nadd = xadd;
                   1573:        if (naddr != NULL)
                   1574:                *naddr = xaddr;
                   1575:        return (0);
                   1576: _bad:
                   1577:        pfr_destroy_ktable(shadow, 0);
                   1578:        pfr_destroy_ktables(&tableq, 0);
                   1579:        pfr_destroy_kentries(&addrq);
                   1580:        return (rv);
                   1581: }
                   1582:
                   1583: int
                   1584: pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags)
                   1585: {
                   1586:        struct pfr_ktableworkq   workq;
                   1587:        struct pfr_ktable       *p;
                   1588:        struct pf_ruleset       *rs;
                   1589:        int                      xdel = 0;
                   1590:
                   1591:        ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY);
                   1592:        rs = pf_find_ruleset(trs->pfrt_anchor);
                   1593:        if (rs == NULL || !rs->topen || ticket != rs->tticket)
                   1594:                return (0);
                   1595:        SLIST_INIT(&workq);
                   1596:        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
                   1597:                if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
                   1598:                    pfr_skip_table(trs, p, 0))
                   1599:                        continue;
                   1600:                p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
                   1601:                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
                   1602:                xdel++;
                   1603:        }
                   1604:        if (!(flags & PFR_FLAG_DUMMY)) {
                   1605:                pfr_setflags_ktables(&workq);
                   1606:                rs->topen = 0;
                   1607:                pf_remove_if_empty_ruleset(rs);
                   1608:        }
                   1609:        if (ndel != NULL)
                   1610:                *ndel = xdel;
                   1611:        return (0);
                   1612: }
                   1613:
                   1614: int
                   1615: pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
                   1616:     int *nchange, int flags)
                   1617: {
                   1618:        struct pfr_ktable       *p, *q;
                   1619:        struct pfr_ktableworkq   workq;
                   1620:        struct pf_ruleset       *rs;
                   1621:        int                      s, xadd = 0, xchange = 0;
                   1622:        long                     tzero = time_second;
                   1623:
                   1624:        ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY);
                   1625:        rs = pf_find_ruleset(trs->pfrt_anchor);
                   1626:        if (rs == NULL || !rs->topen || ticket != rs->tticket)
                   1627:                return (EBUSY);
                   1628:
                   1629:        SLIST_INIT(&workq);
                   1630:        RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
                   1631:                if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
                   1632:                    pfr_skip_table(trs, p, 0))
                   1633:                        continue;
                   1634:                SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
                   1635:                if (p->pfrkt_flags & PFR_TFLAG_ACTIVE)
                   1636:                        xchange++;
                   1637:                else
                   1638:                        xadd++;
                   1639:        }
                   1640:
                   1641:        if (!(flags & PFR_FLAG_DUMMY)) {
                   1642:                if (flags & PFR_FLAG_ATOMIC)
                   1643:                        s = splsoftnet();
                   1644:                for (p = SLIST_FIRST(&workq); p != NULL; p = q) {
                   1645:                        q = SLIST_NEXT(p, pfrkt_workq);
                   1646:                        pfr_commit_ktable(p, tzero);
                   1647:                }
                   1648:                if (flags & PFR_FLAG_ATOMIC)
                   1649:                        splx(s);
                   1650:                rs->topen = 0;
                   1651:                pf_remove_if_empty_ruleset(rs);
                   1652:        }
                   1653:        if (nadd != NULL)
                   1654:                *nadd = xadd;
                   1655:        if (nchange != NULL)
                   1656:                *nchange = xchange;
                   1657:
                   1658:        return (0);
                   1659: }
                   1660:
                   1661: void
                   1662: pfr_commit_ktable(struct pfr_ktable *kt, long tzero)
                   1663: {
                   1664:        struct pfr_ktable       *shadow = kt->pfrkt_shadow;
                   1665:        int                      nflags;
                   1666:
                   1667:        if (shadow->pfrkt_cnt == NO_ADDRESSES) {
                   1668:                if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                   1669:                        pfr_clstats_ktable(kt, tzero, 1);
                   1670:        } else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) {
                   1671:                /* kt might contain addresses */
                   1672:                struct pfr_kentryworkq   addrq, addq, changeq, delq, garbageq;
                   1673:                struct pfr_kentry       *p, *q, *next;
                   1674:                struct pfr_addr          ad;
                   1675:
                   1676:                pfr_enqueue_addrs(shadow, &addrq, NULL, 0);
                   1677:                pfr_mark_addrs(kt);
                   1678:                SLIST_INIT(&addq);
                   1679:                SLIST_INIT(&changeq);
                   1680:                SLIST_INIT(&delq);
                   1681:                SLIST_INIT(&garbageq);
                   1682:                pfr_clean_node_mask(shadow, &addrq);
                   1683:                for (p = SLIST_FIRST(&addrq); p != NULL; p = next) {
                   1684:                        next = SLIST_NEXT(p, pfrke_workq);      /* XXX */
                   1685:                        pfr_copyout_addr(&ad, p);
                   1686:                        q = pfr_lookup_addr(kt, &ad, 1);
                   1687:                        if (q != NULL) {
                   1688:                                if (q->pfrke_not != p->pfrke_not)
                   1689:                                        SLIST_INSERT_HEAD(&changeq, q,
                   1690:                                            pfrke_workq);
                   1691:                                q->pfrke_mark = 1;
                   1692:                                SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq);
                   1693:                        } else {
                   1694:                                p->pfrke_tzero = tzero;
                   1695:                                SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
                   1696:                        }
                   1697:                }
                   1698:                pfr_enqueue_addrs(kt, &delq, NULL, ENQUEUE_UNMARKED_ONLY);
                   1699:                pfr_insert_kentries(kt, &addq, tzero);
                   1700:                pfr_remove_kentries(kt, &delq);
                   1701:                pfr_clstats_kentries(&changeq, tzero, INVERT_NEG_FLAG);
                   1702:                pfr_destroy_kentries(&garbageq);
                   1703:        } else {
                   1704:                /* kt cannot contain addresses */
                   1705:                SWAP(struct radix_node_head *, kt->pfrkt_ip4,
                   1706:                    shadow->pfrkt_ip4);
                   1707:                SWAP(struct radix_node_head *, kt->pfrkt_ip6,
                   1708:                    shadow->pfrkt_ip6);
                   1709:                SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt);
                   1710:                pfr_clstats_ktable(kt, tzero, 1);
                   1711:        }
                   1712:        nflags = ((shadow->pfrkt_flags & PFR_TFLAG_USRMASK) |
                   1713:            (kt->pfrkt_flags & PFR_TFLAG_SETMASK) | PFR_TFLAG_ACTIVE)
                   1714:                & ~PFR_TFLAG_INACTIVE;
                   1715:        pfr_destroy_ktable(shadow, 0);
                   1716:        kt->pfrkt_shadow = NULL;
                   1717:        pfr_setflags_ktable(kt, nflags);
                   1718: }
                   1719:
                   1720: int
                   1721: pfr_validate_table(struct pfr_table *tbl, int allowedflags, int no_reserved)
                   1722: {
                   1723:        int i;
                   1724:
                   1725:        if (!tbl->pfrt_name[0])
                   1726:                return (-1);
                   1727:        if (no_reserved && !strcmp(tbl->pfrt_anchor, PF_RESERVED_ANCHOR))
                   1728:                 return (-1);
                   1729:        if (tbl->pfrt_name[PF_TABLE_NAME_SIZE-1])
                   1730:                return (-1);
                   1731:        for (i = strlen(tbl->pfrt_name); i < PF_TABLE_NAME_SIZE; i++)
                   1732:                if (tbl->pfrt_name[i])
                   1733:                        return (-1);
                   1734:        if (pfr_fix_anchor(tbl->pfrt_anchor))
                   1735:                return (-1);
                   1736:        if (tbl->pfrt_flags & ~allowedflags)
                   1737:                return (-1);
                   1738:        return (0);
                   1739: }
                   1740:
                   1741: /*
                   1742:  * Rewrite anchors referenced by tables to remove slashes
                   1743:  * and check for validity.
                   1744:  */
                   1745: int
                   1746: pfr_fix_anchor(char *anchor)
                   1747: {
                   1748:        size_t siz = MAXPATHLEN;
                   1749:        int i;
                   1750:
                   1751:        if (anchor[0] == '/') {
                   1752:                char *path;
                   1753:                int off;
                   1754:
                   1755:                path = anchor;
                   1756:                off = 1;
                   1757:                while (*++path == '/')
                   1758:                        off++;
                   1759:                bcopy(path, anchor, siz - off);
                   1760:                memset(anchor + siz - off, 0, off);
                   1761:        }
                   1762:        if (anchor[siz - 1])
                   1763:                return (-1);
                   1764:        for (i = strlen(anchor); i < siz; i++)
                   1765:                if (anchor[i])
                   1766:                        return (-1);
                   1767:        return (0);
                   1768: }
                   1769:
                   1770: int
                   1771: pfr_table_count(struct pfr_table *filter, int flags)
                   1772: {
                   1773:        struct pf_ruleset *rs;
                   1774:
                   1775:        if (flags & PFR_FLAG_ALLRSETS)
                   1776:                return (pfr_ktable_cnt);
                   1777:        if (filter->pfrt_anchor[0]) {
                   1778:                rs = pf_find_ruleset(filter->pfrt_anchor);
                   1779:                return ((rs != NULL) ? rs->tables : -1);
                   1780:        }
                   1781:        return (pf_main_ruleset.tables);
                   1782: }
                   1783:
                   1784: int
                   1785: pfr_skip_table(struct pfr_table *filter, struct pfr_ktable *kt, int flags)
                   1786: {
                   1787:        if (flags & PFR_FLAG_ALLRSETS)
                   1788:                return (0);
                   1789:        if (strcmp(filter->pfrt_anchor, kt->pfrkt_anchor))
                   1790:                return (1);
                   1791:        return (0);
                   1792: }
                   1793:
                   1794: void
                   1795: pfr_insert_ktables(struct pfr_ktableworkq *workq)
                   1796: {
                   1797:        struct pfr_ktable       *p;
                   1798:
                   1799:        SLIST_FOREACH(p, workq, pfrkt_workq)
                   1800:                pfr_insert_ktable(p);
                   1801: }
                   1802:
                   1803: void
                   1804: pfr_insert_ktable(struct pfr_ktable *kt)
                   1805: {
                   1806:        RB_INSERT(pfr_ktablehead, &pfr_ktables, kt);
                   1807:        pfr_ktable_cnt++;
                   1808:        if (kt->pfrkt_root != NULL)
                   1809:                if (!kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR]++)
                   1810:                        pfr_setflags_ktable(kt->pfrkt_root,
                   1811:                            kt->pfrkt_root->pfrkt_flags|PFR_TFLAG_REFDANCHOR);
                   1812: }
                   1813:
                   1814: void
                   1815: pfr_setflags_ktables(struct pfr_ktableworkq *workq)
                   1816: {
                   1817:        struct pfr_ktable       *p, *q;
                   1818:
                   1819:        for (p = SLIST_FIRST(workq); p; p = q) {
                   1820:                q = SLIST_NEXT(p, pfrkt_workq);
                   1821:                pfr_setflags_ktable(p, p->pfrkt_nflags);
                   1822:        }
                   1823: }
                   1824:
                   1825: void
                   1826: pfr_setflags_ktable(struct pfr_ktable *kt, int newf)
                   1827: {
                   1828:        struct pfr_kentryworkq  addrq;
                   1829:
                   1830:        if (!(newf & PFR_TFLAG_REFERENCED) &&
                   1831:            !(newf & PFR_TFLAG_PERSIST))
                   1832:                newf &= ~PFR_TFLAG_ACTIVE;
                   1833:        if (!(newf & PFR_TFLAG_ACTIVE))
                   1834:                newf &= ~PFR_TFLAG_USRMASK;
                   1835:        if (!(newf & PFR_TFLAG_SETMASK)) {
                   1836:                RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt);
                   1837:                if (kt->pfrkt_root != NULL)
                   1838:                        if (!--kt->pfrkt_root->pfrkt_refcnt[PFR_REFCNT_ANCHOR])
                   1839:                                pfr_setflags_ktable(kt->pfrkt_root,
                   1840:                                    kt->pfrkt_root->pfrkt_flags &
                   1841:                                        ~PFR_TFLAG_REFDANCHOR);
                   1842:                pfr_destroy_ktable(kt, 1);
                   1843:                pfr_ktable_cnt--;
                   1844:                return;
                   1845:        }
                   1846:        if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) {
                   1847:                pfr_enqueue_addrs(kt, &addrq, NULL, 0);
                   1848:                pfr_remove_kentries(kt, &addrq);
                   1849:        }
                   1850:        if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) {
                   1851:                pfr_destroy_ktable(kt->pfrkt_shadow, 1);
                   1852:                kt->pfrkt_shadow = NULL;
                   1853:        }
                   1854:        kt->pfrkt_flags = newf;
                   1855: }
                   1856:
                   1857: void
                   1858: pfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse)
                   1859: {
                   1860:        struct pfr_ktable       *p;
                   1861:
                   1862:        SLIST_FOREACH(p, workq, pfrkt_workq)
                   1863:                pfr_clstats_ktable(p, tzero, recurse);
                   1864: }
                   1865:
                   1866: void
                   1867: pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse)
                   1868: {
                   1869:        struct pfr_kentryworkq   addrq;
                   1870:        int                      s;
                   1871:
                   1872:        if (recurse) {
                   1873:                pfr_enqueue_addrs(kt, &addrq, NULL, 0);
                   1874:                pfr_clstats_kentries(&addrq, tzero, 0);
                   1875:        }
                   1876:        s = splsoftnet();
                   1877:        bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets));
                   1878:        bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes));
                   1879:        kt->pfrkt_match = kt->pfrkt_nomatch = 0;
                   1880:        splx(s);
                   1881:        kt->pfrkt_tzero = tzero;
                   1882: }
                   1883:
                   1884: struct pfr_ktable *
                   1885: pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset)
                   1886: {
                   1887:        struct pfr_ktable       *kt;
                   1888:        struct pf_ruleset       *rs;
                   1889:
                   1890:        kt = pool_get(&pfr_ktable_pl, PR_NOWAIT);
                   1891:        if (kt == NULL)
                   1892:                return (NULL);
                   1893:        bzero(kt, sizeof(*kt));
                   1894:        kt->pfrkt_t = *tbl;
                   1895:
                   1896:        if (attachruleset) {
                   1897:                rs = pf_find_or_create_ruleset(tbl->pfrt_anchor);
                   1898:                if (!rs) {
                   1899:                        pfr_destroy_ktable(kt, 0);
                   1900:                        return (NULL);
                   1901:                }
                   1902:                kt->pfrkt_rs = rs;
                   1903:                rs->tables++;
                   1904:        }
                   1905:
                   1906:        if (!rn_inithead((void **)&kt->pfrkt_ip4,
                   1907:            offsetof(struct sockaddr_in, sin_addr) * 8) ||
                   1908:            !rn_inithead((void **)&kt->pfrkt_ip6,
                   1909:            offsetof(struct sockaddr_in6, sin6_addr) * 8)) {
                   1910:                pfr_destroy_ktable(kt, 0);
                   1911:                return (NULL);
                   1912:        }
                   1913:        kt->pfrkt_tzero = tzero;
                   1914:
                   1915:        return (kt);
                   1916: }
                   1917:
                   1918: void
                   1919: pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr)
                   1920: {
                   1921:        struct pfr_ktable       *p, *q;
                   1922:
                   1923:        for (p = SLIST_FIRST(workq); p; p = q) {
                   1924:                q = SLIST_NEXT(p, pfrkt_workq);
                   1925:                pfr_destroy_ktable(p, flushaddr);
                   1926:        }
                   1927: }
                   1928:
                   1929: void
                   1930: pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
                   1931: {
                   1932:        struct pfr_kentryworkq   addrq;
                   1933:
                   1934:        if (flushaddr) {
                   1935:                pfr_enqueue_addrs(kt, &addrq, NULL, 0);
                   1936:                pfr_clean_node_mask(kt, &addrq);
                   1937:                pfr_destroy_kentries(&addrq);
                   1938:        }
                   1939:        if (kt->pfrkt_ip4 != NULL)
                   1940:                free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
                   1941:        if (kt->pfrkt_ip6 != NULL)
                   1942:                free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
                   1943:        if (kt->pfrkt_shadow != NULL)
                   1944:                pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
                   1945:        if (kt->pfrkt_rs != NULL) {
                   1946:                kt->pfrkt_rs->tables--;
                   1947:                pf_remove_if_empty_ruleset(kt->pfrkt_rs);
                   1948:        }
                   1949:        pool_put(&pfr_ktable_pl, kt);
                   1950: }
                   1951:
                   1952: int
                   1953: pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q)
                   1954: {
                   1955:        int d;
                   1956:
                   1957:        if ((d = strncmp(p->pfrkt_name, q->pfrkt_name, PF_TABLE_NAME_SIZE)))
                   1958:                return (d);
                   1959:        return (strcmp(p->pfrkt_anchor, q->pfrkt_anchor));
                   1960: }
                   1961:
                   1962: struct pfr_ktable *
                   1963: pfr_lookup_table(struct pfr_table *tbl)
                   1964: {
                   1965:        /* struct pfr_ktable start like a struct pfr_table */
                   1966:        return (RB_FIND(pfr_ktablehead, &pfr_ktables,
                   1967:            (struct pfr_ktable *)tbl));
                   1968: }
                   1969:
                   1970: int
                   1971: pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
                   1972: {
                   1973:        struct pfr_kentry       *ke = NULL;
                   1974:        int                      match;
                   1975:
                   1976:        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
                   1977:                kt = kt->pfrkt_root;
                   1978:        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                   1979:                return (0);
                   1980:
                   1981:        switch (af) {
                   1982: #ifdef INET
                   1983:        case AF_INET:
                   1984:                pfr_sin.sin_addr.s_addr = a->addr32[0];
                   1985:                ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
                   1986:                if (ke && KENTRY_RNF_ROOT(ke))
                   1987:                        ke = NULL;
                   1988:                break;
                   1989: #endif /* INET */
                   1990: #ifdef INET6
                   1991:        case AF_INET6:
                   1992:                bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
                   1993:                ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
                   1994:                if (ke && KENTRY_RNF_ROOT(ke))
                   1995:                        ke = NULL;
                   1996:                break;
                   1997: #endif /* INET6 */
                   1998:        }
                   1999:        match = (ke && !ke->pfrke_not);
                   2000:        if (match)
                   2001:                kt->pfrkt_match++;
                   2002:        else
                   2003:                kt->pfrkt_nomatch++;
                   2004:        return (match);
                   2005: }
                   2006:
                   2007: void
                   2008: pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
                   2009:     u_int64_t len, int dir_out, int op_pass, int notrule)
                   2010: {
                   2011:        struct pfr_kentry       *ke = NULL;
                   2012:
                   2013:        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
                   2014:                kt = kt->pfrkt_root;
                   2015:        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                   2016:                return;
                   2017:
                   2018:        switch (af) {
                   2019: #ifdef INET
                   2020:        case AF_INET:
                   2021:                pfr_sin.sin_addr.s_addr = a->addr32[0];
                   2022:                ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
                   2023:                if (ke && KENTRY_RNF_ROOT(ke))
                   2024:                        ke = NULL;
                   2025:                break;
                   2026: #endif /* INET */
                   2027: #ifdef INET6
                   2028:        case AF_INET6:
                   2029:                bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
                   2030:                ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
                   2031:                if (ke && KENTRY_RNF_ROOT(ke))
                   2032:                        ke = NULL;
                   2033:                break;
                   2034: #endif /* INET6 */
                   2035:        default:
                   2036:                ;
                   2037:        }
                   2038:        if ((ke == NULL || ke->pfrke_not) != notrule) {
                   2039:                if (op_pass != PFR_OP_PASS)
                   2040:                        printf("pfr_update_stats: assertion failed.\n");
                   2041:                op_pass = PFR_OP_XPASS;
                   2042:        }
                   2043:        kt->pfrkt_packets[dir_out][op_pass]++;
                   2044:        kt->pfrkt_bytes[dir_out][op_pass] += len;
                   2045:        if (ke != NULL && op_pass != PFR_OP_XPASS) {
                   2046:                ke->pfrke_packets[dir_out][op_pass]++;
                   2047:                ke->pfrke_bytes[dir_out][op_pass] += len;
                   2048:        }
                   2049: }
                   2050:
                   2051: struct pfr_ktable *
                   2052: pfr_attach_table(struct pf_ruleset *rs, char *name)
                   2053: {
                   2054:        struct pfr_ktable       *kt, *rt;
                   2055:        struct pfr_table         tbl;
                   2056:        struct pf_anchor        *ac = rs->anchor;
                   2057:
                   2058:        bzero(&tbl, sizeof(tbl));
                   2059:        strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
                   2060:        if (ac != NULL)
                   2061:                strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
                   2062:        kt = pfr_lookup_table(&tbl);
                   2063:        if (kt == NULL) {
                   2064:                kt = pfr_create_ktable(&tbl, time_second, 1);
                   2065:                if (kt == NULL)
                   2066:                        return (NULL);
                   2067:                if (ac != NULL) {
                   2068:                        bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor));
                   2069:                        rt = pfr_lookup_table(&tbl);
                   2070:                        if (rt == NULL) {
                   2071:                                rt = pfr_create_ktable(&tbl, 0, 1);
                   2072:                                if (rt == NULL) {
                   2073:                                        pfr_destroy_ktable(kt, 0);
                   2074:                                        return (NULL);
                   2075:                                }
                   2076:                                pfr_insert_ktable(rt);
                   2077:                        }
                   2078:                        kt->pfrkt_root = rt;
                   2079:                }
                   2080:                pfr_insert_ktable(kt);
                   2081:        }
                   2082:        if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++)
                   2083:                pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED);
                   2084:        return (kt);
                   2085: }
                   2086:
                   2087: void
                   2088: pfr_detach_table(struct pfr_ktable *kt)
                   2089: {
                   2090:        if (kt->pfrkt_refcnt[PFR_REFCNT_RULE] <= 0)
                   2091:                printf("pfr_detach_table: refcount = %d.\n",
                   2092:                    kt->pfrkt_refcnt[PFR_REFCNT_RULE]);
                   2093:        else if (!--kt->pfrkt_refcnt[PFR_REFCNT_RULE])
                   2094:                pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED);
                   2095: }
                   2096:
                   2097: int
                   2098: pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
                   2099:     struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af)
                   2100: {
                   2101:        struct pfr_kentry       *ke, *ke2;
                   2102:        struct pf_addr          *addr;
                   2103:        union sockaddr_union     mask;
                   2104:        int                      idx = -1, use_counter = 0;
                   2105:
                   2106:        if (af == AF_INET)
                   2107:                addr = (struct pf_addr *)&pfr_sin.sin_addr;
                   2108:        else if (af == AF_INET6)
                   2109:                addr = (struct pf_addr *)&pfr_sin6.sin6_addr;
                   2110:        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
                   2111:                kt = kt->pfrkt_root;
                   2112:        if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
                   2113:                return (-1);
                   2114:
                   2115:        if (pidx != NULL)
                   2116:                idx = *pidx;
                   2117:        if (counter != NULL && idx >= 0)
                   2118:                use_counter = 1;
                   2119:        if (idx < 0)
                   2120:                idx = 0;
                   2121:
                   2122: _next_block:
                   2123:        ke = pfr_kentry_byidx(kt, idx, af);
                   2124:        if (ke == NULL)
                   2125:                return (1);
                   2126:        pfr_prepare_network(&pfr_mask, af, ke->pfrke_net);
                   2127:        *raddr = SUNION2PF(&ke->pfrke_sa, af);
                   2128:        *rmask = SUNION2PF(&pfr_mask, af);
                   2129:
                   2130:        if (use_counter) {
                   2131:                /* is supplied address within block? */
                   2132:                if (!PF_MATCHA(0, *raddr, *rmask, counter, af)) {
                   2133:                        /* no, go to next block in table */
                   2134:                        idx++;
                   2135:                        use_counter = 0;
                   2136:                        goto _next_block;
                   2137:                }
                   2138:                PF_ACPY(addr, counter, af);
                   2139:        } else {
                   2140:                /* use first address of block */
                   2141:                PF_ACPY(addr, *raddr, af);
                   2142:        }
                   2143:
                   2144:        if (!KENTRY_NETWORK(ke)) {
                   2145:                /* this is a single IP address - no possible nested block */
                   2146:                PF_ACPY(counter, addr, af);
                   2147:                *pidx = idx;
                   2148:                return (0);
                   2149:        }
                   2150:        for (;;) {
                   2151:                /* we don't want to use a nested block */
                   2152:                if (af == AF_INET)
                   2153:                        ke2 = (struct pfr_kentry *)rn_match(&pfr_sin,
                   2154:                            kt->pfrkt_ip4);
                   2155:                else if (af == AF_INET6)
                   2156:                        ke2 = (struct pfr_kentry *)rn_match(&pfr_sin6,
                   2157:                            kt->pfrkt_ip6);
                   2158:                /* no need to check KENTRY_RNF_ROOT() here */
                   2159:                if (ke2 == ke) {
                   2160:                        /* lookup return the same block - perfect */
                   2161:                        PF_ACPY(counter, addr, af);
                   2162:                        *pidx = idx;
                   2163:                        return (0);
                   2164:                }
                   2165:
                   2166:                /* we need to increase the counter past the nested block */
                   2167:                pfr_prepare_network(&mask, AF_INET, ke2->pfrke_net);
                   2168:                PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &pfr_ffaddr, af);
                   2169:                PF_AINC(addr, af);
                   2170:                if (!PF_MATCHA(0, *raddr, *rmask, addr, af)) {
                   2171:                        /* ok, we reached the end of our main block */
                   2172:                        /* go to next block in table */
                   2173:                        idx++;
                   2174:                        use_counter = 0;
                   2175:                        goto _next_block;
                   2176:                }
                   2177:        }
                   2178: }
                   2179:
                   2180: struct pfr_kentry *
                   2181: pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af)
                   2182: {
                   2183:        struct pfr_walktree     w;
                   2184:
                   2185:        bzero(&w, sizeof(w));
                   2186:        w.pfrw_op = PFRW_POOL_GET;
                   2187:        w.pfrw_cnt = idx;
                   2188:
                   2189:        switch (af) {
                   2190: #ifdef INET
                   2191:        case AF_INET:
                   2192:                rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
                   2193:                return (w.pfrw_kentry);
                   2194: #endif /* INET */
                   2195: #ifdef INET6
                   2196:        case AF_INET6:
                   2197:                rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
                   2198:                return (w.pfrw_kentry);
                   2199: #endif /* INET6 */
                   2200:        default:
                   2201:                return (NULL);
                   2202:        }
                   2203: }
                   2204:
                   2205: void
                   2206: pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn)
                   2207: {
                   2208:        struct pfr_walktree     w;
                   2209:        int                     s;
                   2210:
                   2211:        bzero(&w, sizeof(w));
                   2212:        w.pfrw_op = PFRW_DYNADDR_UPDATE;
                   2213:        w.pfrw_dyn = dyn;
                   2214:
                   2215:        s = splsoftnet();
                   2216:        dyn->pfid_acnt4 = 0;
                   2217:        dyn->pfid_acnt6 = 0;
                   2218:        if (!dyn->pfid_af || dyn->pfid_af == AF_INET)
                   2219:                rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
                   2220:        if (!dyn->pfid_af || dyn->pfid_af == AF_INET6)
                   2221:                rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
                   2222:        splx(s);
                   2223: }

CVSweb