root/net/pf_table.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pfr_initialize
  2. pfr_clr_addrs
  3. pfr_add_addrs
  4. pfr_del_addrs
  5. pfr_set_addrs
  6. pfr_tst_addrs
  7. pfr_get_addrs
  8. pfr_get_astats
  9. pfr_clr_astats
  10. pfr_validate_addr
  11. pfr_enqueue_addrs
  12. pfr_mark_addrs
  13. pfr_lookup_addr
  14. pfr_create_kentry
  15. pfr_destroy_kentries
  16. pfr_destroy_kentry
  17. pfr_insert_kentries
  18. pfr_insert_kentry
  19. pfr_remove_kentries
  20. pfr_clean_node_mask
  21. pfr_clstats_kentries
  22. pfr_reset_feedback
  23. pfr_prepare_network
  24. pfr_route_kentry
  25. pfr_unroute_kentry
  26. pfr_copyout_addr
  27. pfr_walktree
  28. pfr_clr_tables
  29. pfr_add_tables
  30. pfr_del_tables
  31. pfr_get_tables
  32. pfr_get_tstats
  33. pfr_clr_tstats
  34. pfr_set_tflags
  35. pfr_ina_begin
  36. pfr_ina_define
  37. pfr_ina_rollback
  38. pfr_ina_commit
  39. pfr_commit_ktable
  40. pfr_validate_table
  41. pfr_fix_anchor
  42. pfr_table_count
  43. pfr_skip_table
  44. pfr_insert_ktables
  45. pfr_insert_ktable
  46. pfr_setflags_ktables
  47. pfr_setflags_ktable
  48. pfr_clstats_ktables
  49. pfr_clstats_ktable
  50. pfr_create_ktable
  51. pfr_destroy_ktables
  52. pfr_destroy_ktable
  53. pfr_ktable_compare
  54. pfr_lookup_table
  55. pfr_match_addr
  56. pfr_update_stats
  57. pfr_attach_table
  58. pfr_detach_table
  59. pfr_pool_get
  60. pfr_kentry_byidx
  61. pfr_dynaddr_update

    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 }

/* [<][>][^][v][top][bottom][index][help] */