Annotation of sys/net/pf_table.c, Revision 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