The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netpfil/ipfilter/netinet/ip_pool.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (C) 2012 by Darren Reed.
    3  *
    4  * See the IPFILTER.LICENCE file for details on licencing.
    5  */
    6 #if defined(KERNEL) || defined(_KERNEL)
    7 # undef KERNEL
    8 # undef _KERNEL
    9 # define        KERNEL  1
   10 # define        _KERNEL 1
   11 #endif
   12 #include <sys/errno.h>
   13 #include <sys/types.h>
   14 #include <sys/param.h>
   15 #include <sys/file.h>
   16 #if !defined(_KERNEL) && !defined(__KERNEL__)
   17 # include <stdio.h>
   18 # include <stdlib.h>
   19 # include <string.h>
   20 # define _KERNEL
   21 # include <sys/uio.h>
   22 # undef _KERNEL
   23 #else
   24 # include <sys/systm.h>
   25 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
   26 #  include <sys/proc.h>
   27 # endif
   28 #endif
   29 #include <sys/time.h>
   30 #if defined(_KERNEL) && !defined(SOLARIS2)
   31 # include <sys/mbuf.h>
   32 #endif
   33 #if defined(__SVR4)
   34 # include <sys/byteorder.h>
   35 # ifdef _KERNEL
   36 #  include <sys/dditypes.h>
   37 # endif
   38 # include <sys/stream.h>
   39 # include <sys/kmem.h>
   40 #endif
   41 #if defined(__FreeBSD__)
   42 # include <sys/malloc.h>
   43 #endif
   44 
   45 #include <sys/socket.h>
   46 #include <net/if.h>
   47 #include <netinet/in.h>
   48 #if !defined(_KERNEL)
   49 # include "ipf.h"
   50 #endif
   51 
   52 #include "netinet/ip_compat.h"
   53 #include "netinet/ip_fil.h"
   54 #include "netinet/ip_pool.h"
   55 #include "netinet/radix_ipf.h"
   56 
   57 /* END OF INCLUDES */
   58 
   59 #if !defined(lint)
   60 static const char sccsid[] = "@(#)ip_fil.c      2.41 6/5/96 (C) 1993-2000 Darren Reed";
   61 static const char rcsid[] = "@(#)$Id$";
   62 #endif
   63 
   64 typedef struct ipf_pool_softc_s {
   65         void            *ipf_radix;
   66         ip_pool_t       *ipf_pool_list[LOOKUP_POOL_SZ];
   67         ipf_pool_stat_t ipf_pool_stats;
   68         ip_pool_node_t  *ipf_node_explist;
   69 } ipf_pool_softc_t;
   70 
   71 
   72 static void ipf_pool_clearnodes(ipf_main_softc_t *, ipf_pool_softc_t *,
   73                                      ip_pool_t *);
   74 static int ipf_pool_create(ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *);
   75 static int ipf_pool_deref(ipf_main_softc_t *, void *, void *);
   76 static int ipf_pool_destroy(ipf_main_softc_t *, ipf_pool_softc_t *, int, char *);
   77 static void *ipf_pool_exists(ipf_pool_softc_t *, int, char *);
   78 static void *ipf_pool_find(void *, int, char *);
   79 static ip_pool_node_t *ipf_pool_findeq(ipf_pool_softc_t *, ip_pool_t *,
   80                                             addrfamily_t *, addrfamily_t *);
   81 static void ipf_pool_free(ipf_main_softc_t *, ipf_pool_softc_t *,
   82                                ip_pool_t *);
   83 static int ipf_pool_insert_node(ipf_main_softc_t *, ipf_pool_softc_t *,
   84                                      ip_pool_t *, struct ip_pool_node *);
   85 static int ipf_pool_iter_deref(ipf_main_softc_t *, void *, int, int, void *);
   86 static int ipf_pool_iter_next(ipf_main_softc_t *,  void *, ipftoken_t *,
   87                                    ipflookupiter_t *);
   88 static size_t ipf_pool_flush(ipf_main_softc_t *, void *, iplookupflush_t *);
   89 static int ipf_pool_node_add(ipf_main_softc_t *, void *, iplookupop_t *,
   90                                   int);
   91 static int ipf_pool_node_del(ipf_main_softc_t *, void *, iplookupop_t *,
   92                                   int);
   93 static void ipf_pool_node_deref(ipf_pool_softc_t *, ip_pool_node_t *);
   94 static int ipf_pool_remove_node(ipf_main_softc_t *, ipf_pool_softc_t *,
   95                                      ip_pool_t *, ip_pool_node_t *);
   96 static int ipf_pool_search(ipf_main_softc_t *, void *, int,
   97                                 void *, u_int);
   98 static void *ipf_pool_soft_create(ipf_main_softc_t *);
   99 static void ipf_pool_soft_destroy(ipf_main_softc_t *, void *);
  100 static void ipf_pool_soft_fini(ipf_main_softc_t *, void *);
  101 static int ipf_pool_soft_init(ipf_main_softc_t *, void *);
  102 static int ipf_pool_stats_get(ipf_main_softc_t *, void *, iplookupop_t *);
  103 static int ipf_pool_table_add(ipf_main_softc_t *, void *, iplookupop_t *);
  104 static int ipf_pool_table_del(ipf_main_softc_t *, void *, iplookupop_t *);
  105 static void *ipf_pool_select_add_ref(void *, int, char *);
  106 static void ipf_pool_expire(ipf_main_softc_t *, void *);
  107 
  108 ipf_lookup_t ipf_pool_backend = {
  109         IPLT_POOL,
  110         ipf_pool_soft_create,
  111         ipf_pool_soft_destroy,
  112         ipf_pool_soft_init,
  113         ipf_pool_soft_fini,
  114         ipf_pool_search,
  115         ipf_pool_flush,
  116         ipf_pool_iter_deref,
  117         ipf_pool_iter_next,
  118         ipf_pool_node_add,
  119         ipf_pool_node_del,
  120         ipf_pool_stats_get,
  121         ipf_pool_table_add,
  122         ipf_pool_table_del,
  123         ipf_pool_deref,
  124         ipf_pool_find,
  125         ipf_pool_select_add_ref,
  126         NULL,
  127         ipf_pool_expire,
  128         NULL
  129 };
  130 
  131 
  132 #ifdef TEST_POOL
  133 void treeprint(ip_pool_t *);
  134 
  135 int
  136 main(int argc, char *argv[])
  137 {
  138         ip_pool_node_t node;
  139         addrfamily_t a, b;
  140         iplookupop_t op;
  141         ip_pool_t *ipo;
  142         i6addr_t ip;
  143 
  144         RWLOCK_INIT(softc->ipf_poolrw, "poolrw");
  145         ipf_pool_init();
  146 
  147         bzero((char *)&ip, sizeof(ip));
  148         bzero((char *)&op, sizeof(op));
  149         bzero((char *)&node, sizeof(node));
  150         strcpy(op.iplo_name, "");
  151 
  152         if (ipf_pool_create(&op) == 0)
  153                 ipo = ipf_pool_exists(0, "");
  154 
  155         node.ipn_addr.adf_family = AF_INET;
  156 
  157         node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203;
  158         node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
  159         node.ipn_info = 1;
  160         ipf_pool_insert_node(ipo, &node);
  161 
  162         node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000;
  163         node.ipn_mask.adf_addr.in4.s_addr = 0xff000000;
  164         node.ipn_info = 0;
  165         ipf_pool_insert_node(ipo, &node);
  166 
  167         node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100;
  168         node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
  169         node.ipn_info = 1;
  170         ipf_pool_insert_node(ipo, &node);
  171 
  172         node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200;
  173         node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
  174         node.ipn_info = 0;
  175         ipf_pool_insert_node(ipo, &node);
  176 
  177         node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000;
  178         node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000;
  179         node.ipn_info = 1;
  180         ipf_pool_insert_node(ipo, &node);
  181 
  182         node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f;
  183         node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
  184         node.ipn_info = 1;
  185         ipf_pool_insert_node(ipo, &node);
  186 #ifdef  DEBUG_POOL
  187         treeprint(ipo);
  188 #endif
  189         ip.in4.s_addr = 0x0a00aabb;
  190         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
  191                 ipf_pool_search(ipo, 4, &ip, 1));
  192 
  193         ip.in4.s_addr = 0x0a000001;
  194         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
  195                 ipf_pool_search(ipo, 4, &ip, 1));
  196 
  197         ip.in4.s_addr = 0x0a000101;
  198         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
  199                 ipf_pool_search(ipo, 4, &ip, 1));
  200 
  201         ip.in4.s_addr = 0x0a010001;
  202         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
  203                 ipf_pool_search(ipo, 4, &ip, 1));
  204 
  205         ip.in4.s_addr = 0x0a010101;
  206         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
  207                 ipf_pool_search(ipo, 4, &ip, 1));
  208 
  209         ip.in4.s_addr = 0x0a010201;
  210         printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
  211                 ipf_pool_search(ipo, 4, &ip, 1));
  212 
  213         ip.in4.s_addr = 0x0a010203;
  214         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
  215                 ipf_pool_search(ipo, 4, &ip, 1));
  216 
  217         ip.in4.s_addr = 0x0a01020f;
  218         printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
  219                 ipf_pool_search(ipo, 4, &ip, 1));
  220 
  221         ip.in4.s_addr = 0x0b00aabb;
  222         printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
  223                 ipf_pool_search(ipo, 4, &ip, 1));
  224 
  225 #ifdef  DEBUG_POOL
  226         treeprint(ipo);
  227 #endif
  228 
  229         ipf_pool_fini();
  230 
  231         return (0);
  232 }
  233 
  234 
  235 void
  236 treeprint(ip_pool_t *ipo)
  237 {
  238         ip_pool_node_t *c;
  239 
  240         for (c = ipo->ipo_list; c != NULL; c = c->ipn_next)
  241                 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n",
  242                         c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr,
  243                         c->ipn_mask.adf_addr.in4.s_addr,
  244                         c->ipn_info, c->ipn_hits);
  245 }
  246 #endif /* TEST_POOL */
  247 
  248 
  249 /* ------------------------------------------------------------------------ */
  250 /* Function:    ipf_pool_soft_create                                        */
  251 /* Returns:     void *   - NULL = failure, else pointer to local context    */
  252 /* Parameters:  softc(I) - pointer to soft context main structure           */
  253 /*                                                                          */
  254 /* Initialise the routing table data structures where required.             */
  255 /* ------------------------------------------------------------------------ */
  256 static void *
  257 ipf_pool_soft_create(ipf_main_softc_t *softc)
  258 {
  259         ipf_pool_softc_t *softp;
  260 
  261         KMALLOC(softp, ipf_pool_softc_t *);
  262         if (softp == NULL) {
  263                 IPFERROR(70032);
  264                 return (NULL);
  265         }
  266 
  267         bzero((char *)softp, sizeof(*softp));
  268 
  269         softp->ipf_radix = ipf_rx_create();
  270         if (softp->ipf_radix == NULL) {
  271                 IPFERROR(70033);
  272                 KFREE(softp);
  273                 return (NULL);
  274         }
  275 
  276         return (softp);
  277 }
  278 
  279 
  280 /* ------------------------------------------------------------------------ */
  281 /* Function:    ipf_pool_soft_init                                          */
  282 /* Returns:     int     - 0 = success, else error                           */
  283 /* Parameters:  softc(I) - pointer to soft context main structure           */
  284 /*              arg(I)   - pointer to local context to use                  */
  285 /*                                                                          */
  286 /* Initialise the routing table data structures where required.             */
  287 /* ------------------------------------------------------------------------ */
  288 static int
  289 ipf_pool_soft_init(ipf_main_softc_t *softc, void *arg)
  290 {
  291         ipf_pool_softc_t *softp = arg;
  292 
  293         ipf_rx_init(softp->ipf_radix);
  294 
  295         return (0);
  296 }
  297 
  298 
  299 /* ------------------------------------------------------------------------ */
  300 /* Function:    ipf_pool_soft_fini                                          */
  301 /* Returns:     Nil                                                         */
  302 /* Parameters:  softc(I) - pointer to soft context main structure           */
  303 /*              arg(I)   - pointer to local context to use                  */
  304 /* Locks:       WRITE(ipf_global)                                           */
  305 /*                                                                          */
  306 /* Clean up all the pool data structures allocated and call the cleanup     */
  307 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
  308 /* used to delete the pools one by one to ensure they're properly freed up. */
  309 /* ------------------------------------------------------------------------ */
  310 static void
  311 ipf_pool_soft_fini(ipf_main_softc_t *softc, void *arg)
  312 {
  313         ipf_pool_softc_t *softp = arg;
  314         ip_pool_t *p, *q;
  315         int i;
  316 
  317         softc = arg;
  318 
  319         for (i = -1; i <= IPL_LOGMAX; i++) {
  320                 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
  321                         q = p->ipo_next;
  322                         (void) ipf_pool_destroy(softc, arg, i, p->ipo_name);
  323                 }
  324         }
  325 }
  326 
  327 
  328 /* ------------------------------------------------------------------------ */
  329 /* Function:    ipf_pool_soft_destroy                                       */
  330 /* Returns:     Nil                                                         */
  331 /* Parameters:  softc(I) - pointer to soft context main structure           */
  332 /*              arg(I)   - pointer to local context to use                  */
  333 /*                                                                          */
  334 /* Clean up the pool by free'ing the radix tree associated with it and free */
  335 /* up the pool context too.                                                 */
  336 /* ------------------------------------------------------------------------ */
  337 static void
  338 ipf_pool_soft_destroy(ipf_main_softc_t *softc, void *arg)
  339 {
  340         ipf_pool_softc_t *softp = arg;
  341 
  342         ipf_rx_destroy(softp->ipf_radix);
  343 
  344         KFREE(softp);
  345 }
  346 
  347 
  348 /* ------------------------------------------------------------------------ */
  349 /* Function:   ipf_pool_node_add                                            */
  350 /* Returns:    int - 0 = success, else error                                */
  351 /* Parameters: softc(I) - pointer to soft context main structure            */
  352 /*             arg(I)   - pointer to local context to use                   */
  353 /*             op(I) - pointer to lookup operatin data                      */
  354 /*                                                                          */
  355 /* When adding a new node, a check is made to ensure that the address/mask  */
  356 /* pair supplied has been appropriately prepared by applying the mask to    */
  357 /* the address prior to calling for the pair to be added.                   */
  358 /* ------------------------------------------------------------------------ */
  359 static int
  360 ipf_pool_node_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
  361         int uid)
  362 {
  363         ip_pool_node_t node, *m;
  364         ip_pool_t *p;
  365         int err;
  366 
  367         if (op->iplo_size != sizeof(node)) {
  368                 IPFERROR(70014);
  369                 return (EINVAL);
  370         }
  371 
  372         err = COPYIN(op->iplo_struct, &node, sizeof(node));
  373         if (err != 0) {
  374                 IPFERROR(70015);
  375                 return (EFAULT);
  376         }
  377 
  378         p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
  379         if (p == NULL) {
  380                 IPFERROR(70017);
  381                 return (ESRCH);
  382         }
  383 
  384         if (node.ipn_addr.adf_family == AF_INET) {
  385                 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
  386                                              sizeof(struct in_addr)) {
  387                         IPFERROR(70028);
  388                         return (EINVAL);
  389                 }
  390         }
  391 #ifdef USE_INET6
  392         else if (node.ipn_addr.adf_family == AF_INET6) {
  393                 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
  394                                              sizeof(struct in6_addr)) {
  395                         IPFERROR(70034);
  396                         return (EINVAL);
  397                 }
  398         }
  399 #endif
  400         if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
  401                 IPFERROR(70029);
  402                 return (EINVAL);
  403         }
  404 
  405         /*
  406          * Check that the address/mask pair works.
  407          */
  408         if (node.ipn_addr.adf_family == AF_INET) {
  409                 if ((node.ipn_addr.adf_addr.in4.s_addr &
  410                      node.ipn_mask.adf_addr.in4.s_addr) !=
  411                     node.ipn_addr.adf_addr.in4.s_addr) {
  412                         IPFERROR(70035);
  413                         return (EINVAL);
  414                 }
  415         }
  416 #ifdef USE_INET6
  417         else if (node.ipn_addr.adf_family == AF_INET6) {
  418                 if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6,
  419                                 &node.ipn_mask.adf_addr.in6,
  420                                 &node.ipn_addr.adf_addr.in6)) {
  421                         IPFERROR(70036);
  422                         return (EINVAL);
  423                 }
  424         }
  425 #endif
  426 
  427         /*
  428         * add an entry to a pool - return an error if it already
  429          * exists remove an entry from a pool - if it exists
  430          * - in both cases, the pool *must* exist!
  431          */
  432         m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
  433         if (m != NULL) {
  434                 IPFERROR(70018);
  435                 return (EEXIST);
  436         }
  437         err = ipf_pool_insert_node(softc, arg, p, &node);
  438 
  439         return (err);
  440 }
  441 
  442 
  443 /* ------------------------------------------------------------------------ */
  444 /* Function:   ipf_pool_node_del                                            */
  445 /* Returns:    int - 0 = success, else error                                */
  446 /* Parameters: softc(I) - pointer to soft context main structure            */
  447 /*             arg(I)   - pointer to local context to use                   */
  448 /*             op(I)    - pointer to lookup operatin data                   */
  449 /*                                                                          */
  450 /* ------------------------------------------------------------------------ */
  451 static int
  452 ipf_pool_node_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
  453         int uid)
  454 {
  455         ip_pool_node_t node, *m;
  456         ip_pool_t *p;
  457         int err;
  458 
  459 
  460         if (op->iplo_size != sizeof(node)) {
  461                 IPFERROR(70019);
  462                 return (EINVAL);
  463         }
  464         node.ipn_uid = uid;
  465 
  466         err = COPYIN(op->iplo_struct, &node, sizeof(node));
  467         if (err != 0) {
  468                 IPFERROR(70020);
  469                 return (EFAULT);
  470         }
  471 
  472         if (node.ipn_addr.adf_family == AF_INET) {
  473                 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
  474                                              sizeof(struct in_addr)) {
  475                         IPFERROR(70030);
  476                         return (EINVAL);
  477                 }
  478         }
  479 #ifdef USE_INET6
  480         else if (node.ipn_addr.adf_family == AF_INET6) {
  481                 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
  482                                              sizeof(struct in6_addr)) {
  483                         IPFERROR(70037);
  484                         return (EINVAL);
  485                 }
  486         }
  487 #endif
  488         if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
  489                 IPFERROR(70031);
  490                 return (EINVAL);
  491         }
  492 
  493         p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
  494         if (p == NULL) {
  495                 IPFERROR(70021);
  496                 return (ESRCH);
  497         }
  498 
  499         m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
  500         if (m == NULL) {
  501                 IPFERROR(70022);
  502                 return (ENOENT);
  503         }
  504 
  505         if ((uid != 0) && (uid != m->ipn_uid)) {
  506                 IPFERROR(70024);
  507                 return (EACCES);
  508         }
  509 
  510         err = ipf_pool_remove_node(softc, arg, p, m);
  511 
  512         return (err);
  513 }
  514 
  515 
  516 /* ------------------------------------------------------------------------ */
  517 /* Function:   ipf_pool_table_add                                           */
  518 /* Returns:    int - 0 = success, else error                                */
  519 /* Parameters: softc(I) - pointer to soft context main structure            */
  520 /*             arg(I)   - pointer to local context to use                   */
  521 /*             op(I)    - pointer to lookup operatin data                   */
  522 /*                                                                          */
  523 /* ------------------------------------------------------------------------ */
  524 static int
  525 ipf_pool_table_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
  526 {
  527         int err;
  528 
  529         if (((op->iplo_arg & LOOKUP_ANON) == 0) &&
  530             (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) {
  531                 IPFERROR(70023);
  532                 err = EEXIST;
  533         } else {
  534                 err = ipf_pool_create(softc, arg, op);
  535         }
  536 
  537         return (err);
  538 }
  539 
  540 
  541 /* ------------------------------------------------------------------------ */
  542 /* Function:   ipf_pool_table_del                                           */
  543 /* Returns:    int - 0 = success, else error                                */
  544 /* Parameters: softc(I) - pointer to soft context main structure            */
  545 /*             arg(I)   - pointer to local context to use                   */
  546 /*             op(I)    - pointer to lookup operatin data                   */
  547 /*                                                                          */
  548 /* ------------------------------------------------------------------------ */
  549 static int
  550 ipf_pool_table_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
  551 {
  552         return (ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name));
  553 }
  554 
  555 
  556 /* ------------------------------------------------------------------------ */
  557 /* Function:    ipf_pool_statistics                                         */
  558 /* Returns:     int      - 0 = success, else error                          */
  559 /* Parameters:  softc(I) - pointer to soft context main structure           */
  560 /*              arg(I)   - pointer to local context to use                  */
  561 /*              op(I)    - pointer to lookup operatin data                  */
  562 /*                                                                          */
  563 /* Copy the current statistics out into user space, collecting pool list    */
  564 /* pointers as appropriate for later use.                                   */
  565 /* ------------------------------------------------------------------------ */
  566 static int
  567 ipf_pool_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
  568 {
  569         ipf_pool_softc_t *softp = arg;
  570         ipf_pool_stat_t stats;
  571         int unit, i, err = 0;
  572 
  573         if (op->iplo_size != sizeof(ipf_pool_stat_t)) {
  574                 IPFERROR(70001);
  575                 return (EINVAL);
  576         }
  577 
  578         bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats));
  579         unit = op->iplo_unit;
  580         if (unit == IPL_LOGALL) {
  581                 for (i = 0; i <= LOOKUP_POOL_MAX; i++)
  582                         stats.ipls_list[i] = softp->ipf_pool_list[i];
  583         } else if (unit >= 0 && unit <= IPL_LOGMAX) {
  584                 unit++;                                         /* -1 => 0 */
  585                 if (op->iplo_name[0] != '\0')
  586                         stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1,
  587                                                                 op->iplo_name);
  588                 else
  589                         stats.ipls_list[unit] = softp->ipf_pool_list[unit];
  590         } else {
  591                 IPFERROR(70025);
  592                 err = EINVAL;
  593         }
  594         if (err == 0) {
  595                 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
  596                 if (err != 0) {
  597                         IPFERROR(70026);
  598                         return (EFAULT);
  599                 }
  600         }
  601         return (0);
  602 }
  603 
  604 
  605 /* ------------------------------------------------------------------------ */
  606 /* Function:    ipf_pool_exists                                             */
  607 /* Returns:     int      - 0 = success, else error                          */
  608 /* Parameters:  softp(I) - pointer to soft context pool information         */
  609 /*              unit(I)  - ipfilter device to which we are working on       */
  610 /*              name(I)  - name of the pool                                 */
  611 /*                                                                          */
  612 /* Find a matching pool inside the collection of pools for a particular     */
  613 /* device, indicated by the unit number.                                    */
  614 /* ------------------------------------------------------------------------ */
  615 static void *
  616 ipf_pool_exists(ipf_pool_softc_t *softp, int unit, char *name)
  617 {
  618         ip_pool_t *p;
  619         int i;
  620 
  621         if (unit == IPL_LOGALL) {
  622                 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
  623                         for (p = softp->ipf_pool_list[i]; p != NULL;
  624                              p = p->ipo_next) {
  625                                 if (strncmp(p->ipo_name, name,
  626                                             sizeof(p->ipo_name)) == 0)
  627                                         break;
  628                         }
  629                         if (p != NULL)
  630                                 break;
  631                 }
  632         } else {
  633                 for (p = softp->ipf_pool_list[unit + 1]; p != NULL;
  634                      p = p->ipo_next)
  635                         if (strncmp(p->ipo_name, name,
  636                                     sizeof(p->ipo_name)) == 0)
  637                                 break;
  638         }
  639         return (p);
  640 }
  641 
  642 
  643 /* ------------------------------------------------------------------------ */
  644 /* Function:    ipf_pool_find                                               */
  645 /* Returns:     int    - 0 = success, else error                            */
  646 /* Parameters:  arg(I)  - pointer to local context to use                   */
  647 /*              unit(I) - ipfilter device to which we are working on        */
  648 /*              name(I)  - name of the pool                                 */
  649 /*                                                                          */
  650 /* Find a matching pool inside the collection of pools for a particular     */
  651 /* device, indicated by the unit number.  If it is marked for deletion then */
  652 /* pretend it does not exist.                                               */
  653 /* ------------------------------------------------------------------------ */
  654 static void *
  655 ipf_pool_find(void *arg, int unit, char *name)
  656 {
  657         ipf_pool_softc_t *softp = arg;
  658         ip_pool_t *p;
  659 
  660         p = ipf_pool_exists(softp, unit, name);
  661         if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
  662                 return (NULL);
  663 
  664         return (p);
  665 }
  666 
  667 
  668 /* ------------------------------------------------------------------------ */
  669 /* Function:    ipf_pool_select_add_ref                                     */
  670 /* Returns:     int - 0 = success, else error                               */
  671 /* Parameters:  arg(I)  - pointer to local context to use                   */
  672 /*              unit(I) - ipfilter device to which we are working on        */
  673 /*              name(I)  - name of the pool                                 */
  674 /*                                                                          */
  675 /* ------------------------------------------------------------------------ */
  676 static void *
  677 ipf_pool_select_add_ref(void *arg, int unit, char *name)
  678 {
  679         ip_pool_t *p;
  680 
  681         p = ipf_pool_find(arg, -1, name);
  682         if (p == NULL)
  683                 p = ipf_pool_find(arg, unit, name);
  684         if (p != NULL) {
  685                 ATOMIC_INC32(p->ipo_ref);
  686         }
  687         return (p);
  688 }
  689 
  690 
  691 /* ------------------------------------------------------------------------ */
  692 /* Function:    ipf_pool_findeq                                             */
  693 /* Returns:     int     - 0 = success, else error                           */
  694 /* Parameters:  softp(I) - pointer to soft context pool information         */
  695 /*              ipo(I)  - pointer to the pool getting the new node.         */
  696 /*              addr(I) - pointer to address information to match on        */
  697 /*              mask(I) - pointer to the address mask to match              */
  698 /*                                                                          */
  699 /* Searches for an exact match of an entry in the pool.                     */
  700 /* ------------------------------------------------------------------------ */
  701 extern void printhostmask(int, u_32_t *, u_32_t *);
  702 static ip_pool_node_t *
  703 ipf_pool_findeq(ipf_pool_softc_t *softp, ip_pool_t *ipo, addrfamily_t *addr,
  704         addrfamily_t *mask)
  705 {
  706         ipf_rdx_node_t *n;
  707 
  708         n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask);
  709         return (ip_pool_node_t *)n;
  710 }
  711 
  712 
  713 /* ------------------------------------------------------------------------ */
  714 /* Function:    ipf_pool_search                                             */
  715 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
  716 /* Parameters:  softc(I) - pointer to soft context main structure           */
  717 /*              tptr(I)    - pointer to the pool to search                  */
  718 /*              version(I) - IP protocol version (4 or 6)                   */
  719 /*              dptr(I)    - pointer to address information                 */
  720 /*              bytes(I)   - length of packet                               */
  721 /*                                                                          */
  722 /* Search the pool for a given address and return a search result.          */
  723 /* ------------------------------------------------------------------------ */
  724 static int
  725 ipf_pool_search(ipf_main_softc_t *softc, void *tptr, int ipversion, void *dptr,
  726         u_int bytes)
  727 {
  728         ipf_rdx_node_t *rn;
  729         ip_pool_node_t *m;
  730         i6addr_t *addr;
  731         addrfamily_t v;
  732         ip_pool_t *ipo;
  733         int rv;
  734 
  735         ipo = tptr;
  736         if (ipo == NULL)
  737                 return (-1);
  738 
  739         rv = 1;
  740         m = NULL;
  741         addr = (i6addr_t *)dptr;
  742         bzero(&v, sizeof(v));
  743 
  744         if (ipversion == 4) {
  745                 v.adf_family = AF_INET;
  746                 v.adf_len = offsetof(addrfamily_t, adf_addr) +
  747                             sizeof(struct in_addr);
  748                 v.adf_addr.in4 = addr->in4;
  749 #ifdef USE_INET6
  750         } else if (ipversion == 6) {
  751                 v.adf_family = AF_INET6;
  752                 v.adf_len = offsetof(addrfamily_t, adf_addr) +
  753                             sizeof(struct in6_addr);
  754                 v.adf_addr.in6 = addr->in6;
  755 #endif
  756         } else
  757                 return (-1);
  758 
  759         READ_ENTER(&softc->ipf_poolrw);
  760 
  761         rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v);
  762 
  763         if ((rn != NULL) && (rn->root == 0)) {
  764                 m = (ip_pool_node_t *)rn;
  765                 ipo->ipo_hits++;
  766                 m->ipn_bytes += bytes;
  767                 m->ipn_hits++;
  768                 rv = m->ipn_info;
  769         }
  770         RWLOCK_EXIT(&softc->ipf_poolrw);
  771         return (rv);
  772 }
  773 
  774 
  775 /* ------------------------------------------------------------------------ */
  776 /* Function:    ipf_pool_insert_node                                        */
  777 /* Returns:     int      - 0 = success, else error                          */
  778 /* Parameters:  softc(I) - pointer to soft context main structure           */
  779 /*              softp(I) - pointer to soft context pool information         */
  780 /*              ipo(I)   - pointer to the pool getting the new node.        */
  781 /*              node(I)  - structure with address/mask to add               */
  782 /* Locks:       WRITE(ipf_poolrw)                                           */
  783 /*                                                                          */
  784 /* Add another node to the pool given by ipo.  The three parameters passed  */
  785 /* in (addr, mask, info) shold all be stored in the node.                   */
  786 /* ------------------------------------------------------------------------ */
  787 static int
  788 ipf_pool_insert_node(ipf_main_softc_t *softc, ipf_pool_softc_t *softp,
  789         ip_pool_t *ipo, struct ip_pool_node *node)
  790 {
  791         ipf_rdx_node_t *rn;
  792         ip_pool_node_t *x;
  793 
  794         if ((node->ipn_addr.adf_len > sizeof(*rn)) ||
  795             (node->ipn_addr.adf_len < 4)) {
  796                 IPFERROR(70003);
  797                 return (EINVAL);
  798         }
  799 
  800         if ((node->ipn_mask.adf_len > sizeof(*rn)) ||
  801             (node->ipn_mask.adf_len < 4)) {
  802                 IPFERROR(70004);
  803                 return (EINVAL);
  804         }
  805 
  806         KMALLOC(x, ip_pool_node_t *);
  807         if (x == NULL) {
  808                 IPFERROR(70002);
  809                 return (ENOMEM);
  810         }
  811 
  812         *x = *node;
  813         bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes));
  814         x->ipn_owner = ipo;
  815         x->ipn_hits = 0;
  816         x->ipn_next = NULL;
  817         x->ipn_pnext = NULL;
  818         x->ipn_dnext = NULL;
  819         x->ipn_pdnext = NULL;
  820 
  821         if (x->ipn_die != 0) {
  822                 /*
  823                  * If the new node has a given expiration time, insert it
  824                  * into the list of expiring nodes with the ones to be
  825                  * removed first added to the front of the list. The
  826                  * insertion is O(n) but it is kept sorted for quick scans
  827                  * at expiration interval checks.
  828                  */
  829                 ip_pool_node_t *n;
  830 
  831                 x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die);
  832                 for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) {
  833                         if (x->ipn_die < n->ipn_die)
  834                                 break;
  835                         if (n->ipn_dnext == NULL) {
  836                                 /*
  837                                  * We've got to the last node and everything
  838                                  * wanted to be expired before this new node,
  839                                  * so we have to tack it on the end...
  840                                  */
  841                                 n->ipn_dnext = x;
  842                                 x->ipn_pdnext = &n->ipn_dnext;
  843                                 n = NULL;
  844                                 break;
  845                         }
  846                 }
  847 
  848                 if (softp->ipf_node_explist == NULL) {
  849                         softp->ipf_node_explist = x;
  850                         x->ipn_pdnext = &softp->ipf_node_explist;
  851                 } else if (n != NULL) {
  852                         x->ipn_dnext = n;
  853                         x->ipn_pdnext = n->ipn_pdnext;
  854                         n->ipn_pdnext = &x->ipn_dnext;
  855                 }
  856         }
  857 
  858         rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask,
  859                                     x->ipn_nodes);
  860 #ifdef  DEBUG_POOL
  861         printf("Added %p at %p\n", x, rn);
  862 #endif
  863 
  864         if (rn == NULL) {
  865                 KFREE(x);
  866                 IPFERROR(70005);
  867                 return (ENOMEM);
  868         }
  869 
  870         x->ipn_ref = 1;
  871         x->ipn_pnext = ipo->ipo_tail;
  872         *ipo->ipo_tail = x;
  873         ipo->ipo_tail = &x->ipn_next;
  874 
  875         softp->ipf_pool_stats.ipls_nodes++;
  876 
  877         return (0);
  878 }
  879 
  880 
  881 /* ------------------------------------------------------------------------ */
  882 /* Function:    ipf_pool_create                                             */
  883 /* Returns:     int      - 0 = success, else error                          */
  884 /* Parameters:  softc(I) - pointer to soft context main structure           */
  885 /*              softp(I) - pointer to soft context pool information         */
  886 /*              op(I)    - pointer to iplookup struct with call details     */
  887 /* Locks:       WRITE(ipf_poolrw)                                           */
  888 /*                                                                          */
  889 /* Creates a new group according to the parameters passed in via the        */
  890 /* iplookupop structure.  Does not check to see if the group already exists */
  891 /* when being inserted - assume this has already been done.  If the pool is */
  892 /* marked as being anonymous, give it a new, unique, identifier.  Call any  */
  893 /* other functions required to initialise the structure.                    */
  894 /*                                                                          */
  895 /* If the structure is flagged for deletion then reset the flag and return, */
  896 /* as this likely means we've tried to free a pool that is in use (flush)   */
  897 /* and now want to repopulate it with "new" data.                           */
  898 /* ------------------------------------------------------------------------ */
  899 static int
  900 ipf_pool_create(ipf_main_softc_t *softc, ipf_pool_softc_t *softp,
  901         iplookupop_t *op)
  902 {
  903         char name[FR_GROUPLEN];
  904         int poolnum, unit;
  905         ip_pool_t *h;
  906 
  907         unit = op->iplo_unit;
  908 
  909         if ((op->iplo_arg & LOOKUP_ANON) == 0) {
  910                 h = ipf_pool_exists(softp, unit, op->iplo_name);
  911                 if (h != NULL) {
  912                         if ((h->ipo_flags & IPOOL_DELETE) == 0) {
  913                                 IPFERROR(70006);
  914                                 return (EEXIST);
  915                         }
  916                         h->ipo_flags &= ~IPOOL_DELETE;
  917                         return (0);
  918                 }
  919         }
  920 
  921         KMALLOC(h, ip_pool_t *);
  922         if (h == NULL) {
  923                 IPFERROR(70007);
  924                 return (ENOMEM);
  925         }
  926         bzero(h, sizeof(*h));
  927 
  928         if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) {
  929                 KFREE(h);
  930                 IPFERROR(70008);
  931                 return (ENOMEM);
  932         }
  933 
  934         if ((op->iplo_arg & LOOKUP_ANON) != 0) {
  935                 ip_pool_t *p;
  936 
  937                 h->ipo_flags |= IPOOL_ANON;
  938                 poolnum = LOOKUP_ANON;
  939 
  940                 (void)snprintf(name, sizeof(name), "%x", poolnum);
  941 
  942                 for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) {
  943                         if (strncmp(name, p->ipo_name,
  944                                     sizeof(p->ipo_name)) == 0) {
  945                                 poolnum++;
  946                                 (void)snprintf(name, sizeof(name), "%x", poolnum);
  947                                 p = softp->ipf_pool_list[unit + 1];
  948                         } else
  949                                 p = p->ipo_next;
  950                 }
  951 
  952                 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name));
  953                 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
  954         } else {
  955                 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
  956         }
  957 
  958         h->ipo_radix = softp->ipf_radix;
  959         h->ipo_ref = 1;
  960         h->ipo_list = NULL;
  961         h->ipo_tail = &h->ipo_list;
  962         h->ipo_unit = unit;
  963         h->ipo_next = softp->ipf_pool_list[unit + 1];
  964         if (softp->ipf_pool_list[unit + 1] != NULL)
  965                 softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next;
  966         h->ipo_pnext = &softp->ipf_pool_list[unit + 1];
  967         softp->ipf_pool_list[unit + 1] = h;
  968 
  969         softp->ipf_pool_stats.ipls_pools++;
  970 
  971         return (0);
  972 }
  973 
  974 
  975 /* ------------------------------------------------------------------------ */
  976 /* Function:    ipf_pool_remove_node                                        */
  977 /* Returns:     int      - 0 = success, else error                          */
  978 /* Parameters:  softc(I) - pointer to soft context main structure           */
  979 /*              ipo(I)   - pointer to the pool to remove the node from.     */
  980 /*              ipe(I)   - address being deleted as a node                  */
  981 /* Locks:       WRITE(ipf_poolrw)                                           */
  982 /*                                                                          */
  983 /* Remove a node from the pool given by ipo.                                */
  984 /* ------------------------------------------------------------------------ */
  985 static int
  986 ipf_pool_remove_node(ipf_main_softc_t *softc, ipf_pool_softc_t *softp,
  987         ip_pool_t *ipo, ip_pool_node_t *ipe)
  988 {
  989         void *ptr;
  990 
  991         if (ipo->ipo_tail == &ipe->ipn_next)
  992                 ipo->ipo_tail = ipe->ipn_pnext;
  993 
  994         if (ipe->ipn_pnext != NULL)
  995                 *ipe->ipn_pnext = ipe->ipn_next;
  996         if (ipe->ipn_next != NULL)
  997                 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
  998 
  999         if (ipe->ipn_pdnext != NULL)
 1000                 *ipe->ipn_pdnext = ipe->ipn_dnext;
 1001         if (ipe->ipn_dnext != NULL)
 1002                 ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext;
 1003 
 1004         ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr,
 1005                                      &ipe->ipn_mask);
 1006 
 1007         if (ptr != NULL) {
 1008                 ipf_pool_node_deref(softp, ipe);
 1009                 return (0);
 1010         }
 1011         IPFERROR(70027);
 1012         return (ESRCH);
 1013 }
 1014 
 1015 
 1016 /* ------------------------------------------------------------------------ */
 1017 /* Function:    ipf_pool_destroy                                            */
 1018 /* Returns:     int    - 0 = success, else error                            */
 1019 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1020 /*              softp(I) - pointer to soft context pool information         */
 1021 /*              unit(I)  - ipfilter device to which we are working on       */
 1022 /*              name(I)  - name of the pool                                 */
 1023 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
 1024 /*                                                                          */
 1025 /* Search for a pool using parameters passed in and if it's not otherwise   */
 1026 /* busy, free it.  If it is busy, clear all of its nodes, mark it for being */
 1027 /* deleted and return an error saying it is busy.                           */
 1028 /*                                                                          */
 1029 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
 1030 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
 1031 /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
 1032 /* ------------------------------------------------------------------------ */
 1033 static int
 1034 ipf_pool_destroy(ipf_main_softc_t *softc, ipf_pool_softc_t *softp,
 1035         int unit, char *name)
 1036 {
 1037         ip_pool_t *ipo;
 1038 
 1039         ipo = ipf_pool_exists(softp, unit, name);
 1040         if (ipo == NULL) {
 1041                 IPFERROR(70009);
 1042                 return (ESRCH);
 1043         }
 1044 
 1045         if (ipo->ipo_ref != 1) {
 1046                 ipf_pool_clearnodes(softc, softp, ipo);
 1047                 ipo->ipo_flags |= IPOOL_DELETE;
 1048                 return (0);
 1049         }
 1050 
 1051         ipf_pool_free(softc, softp, ipo);
 1052         return (0);
 1053 }
 1054 
 1055 
 1056 /* ------------------------------------------------------------------------ */
 1057 /* Function:    ipf_pool_flush                                              */
 1058 /* Returns:     int    - number of pools deleted                            */
 1059 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1060 /*              arg(I)   - pointer to local context to use                  */
 1061 /*              fp(I)    - which pool(s) to flush                           */
 1062 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
 1063 /*                                                                          */
 1064 /* Free all pools associated with the device that matches the unit number   */
 1065 /* passed in with operation.                                                */
 1066 /*                                                                          */
 1067 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
 1068 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
 1069 /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
 1070 /* ------------------------------------------------------------------------ */
 1071 static size_t
 1072 ipf_pool_flush(ipf_main_softc_t *softc, void *arg, iplookupflush_t *fp)
 1073 {
 1074         ipf_pool_softc_t *softp = arg;
 1075         int i, num = 0, unit, err;
 1076         ip_pool_t *p, *q;
 1077 
 1078         unit = fp->iplf_unit;
 1079         for (i = -1; i <= IPL_LOGMAX; i++) {
 1080                 if (unit != IPLT_ALL && i != unit)
 1081                         continue;
 1082                 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
 1083                         q = p->ipo_next;
 1084                         err = ipf_pool_destroy(softc, softp, i, p->ipo_name);
 1085                         if (err == 0)
 1086                                 num++;
 1087                 }
 1088         }
 1089         return (num);
 1090 }
 1091 
 1092 
 1093 /* ------------------------------------------------------------------------ */
 1094 /* Function:    ipf_pool_free                                               */
 1095 /* Returns:     void                                                        */
 1096 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1097 /*              softp(I) - pointer to soft context pool information         */
 1098 /*              ipo(I) - pointer to pool structure                          */
 1099 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
 1100 /*                                                                          */
 1101 /* Deletes the pool strucutre passed in from the list of pools and deletes  */
 1102 /* all of the address information stored in it, including any tree data     */
 1103 /* structures also allocated.                                               */
 1104 /*                                                                          */
 1105 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
 1106 /* may not be initialised, we can't use an ASSERT to enforce the locking    */
 1107 /* assertion that one of the two (ipf_poolrw,ipf_global) is held.           */
 1108 /* ------------------------------------------------------------------------ */
 1109 static void
 1110 ipf_pool_free(ipf_main_softc_t *softc, ipf_pool_softc_t *softp, ip_pool_t *ipo)
 1111 {
 1112 
 1113         ipf_pool_clearnodes(softc, softp, ipo);
 1114 
 1115         if (ipo->ipo_next != NULL)
 1116                 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
 1117         *ipo->ipo_pnext = ipo->ipo_next;
 1118         ipf_rx_freehead(ipo->ipo_head);
 1119         KFREE(ipo);
 1120 
 1121         softp->ipf_pool_stats.ipls_pools--;
 1122 }
 1123 
 1124 
 1125 /* ------------------------------------------------------------------------ */
 1126 /* Function:    ipf_pool_clearnodes                                         */
 1127 /* Returns:     void                                                        */
 1128 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1129 /*              softp(I) - pointer to soft context pool information         */
 1130 /*              ipo(I)   - pointer to pool structure                        */
 1131 /* Locks:       WRITE(ipf_poolrw) or WRITE(ipf_global)                      */
 1132 /*                                                                          */
 1133 /* Deletes all nodes stored in a pool structure.                            */
 1134 /* ------------------------------------------------------------------------ */
 1135 static void
 1136 ipf_pool_clearnodes(ipf_main_softc_t *softc, ipf_pool_softc_t *softp,
 1137         ip_pool_t *ipo)
 1138 {
 1139         ip_pool_node_t *n, **next;
 1140 
 1141         for (next = &ipo->ipo_list; (n = *next) != NULL; )
 1142                 ipf_pool_remove_node(softc, softp, ipo, n);
 1143 
 1144         ipo->ipo_list = NULL;
 1145 }
 1146 
 1147 
 1148 /* ------------------------------------------------------------------------ */
 1149 /* Function:    ipf_pool_deref                                              */
 1150 /* Returns:     void                                                        */
 1151 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1152 /*              arg(I)   - pointer to local context to use                  */
 1153 /*              pool(I)  - pointer to pool structure                        */
 1154 /* Locks:       WRITE(ipf_poolrw)                                           */
 1155 /*                                                                          */
 1156 /* Drop the number of known references to this pool structure by one and if */
 1157 /* we arrive at zero known references, free it.                             */
 1158 /* ------------------------------------------------------------------------ */
 1159 static int
 1160 ipf_pool_deref(ipf_main_softc_t *softc, void *arg, void *pool)
 1161 {
 1162         ip_pool_t *ipo = pool;
 1163 
 1164         ipo->ipo_ref--;
 1165 
 1166         if (ipo->ipo_ref == 0)
 1167                 ipf_pool_free(softc, arg, ipo);
 1168 
 1169         else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
 1170                 ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name);
 1171 
 1172         return (0);
 1173 }
 1174 
 1175 
 1176 /* ------------------------------------------------------------------------ */
 1177 /* Function:    ipf_pool_node_deref                                         */
 1178 /* Returns:     void                                                        */
 1179 /* Parameters:  softp(I) - pointer to soft context pool information         */
 1180 /*              ipn(I)   - pointer to pool structure                        */
 1181 /* Locks:       WRITE(ipf_poolrw)                                           */
 1182 /*                                                                          */
 1183 /* Drop a reference to the pool node passed in and if we're the last, free  */
 1184 /* it all up and adjust the stats accordingly.                              */
 1185 /* ------------------------------------------------------------------------ */
 1186 static void
 1187 ipf_pool_node_deref(ipf_pool_softc_t *softp, ip_pool_node_t *ipn)
 1188 {
 1189 
 1190         ipn->ipn_ref--;
 1191 
 1192         if (ipn->ipn_ref == 0) {
 1193                 KFREE(ipn);
 1194                 softp->ipf_pool_stats.ipls_nodes--;
 1195         }
 1196 }
 1197 
 1198 
 1199 /* ------------------------------------------------------------------------ */
 1200 /* Function:    ipf_pool_iter_next                                          */
 1201 /* Returns:     void                                                        */
 1202 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1203 /*              arg(I)   - pointer to local context to use                  */
 1204 /*              token(I) - pointer to pool structure                        */
 1205 /*              ilp(IO)  - pointer to pool iterating structure              */
 1206 /*                                                                          */
 1207 /* ------------------------------------------------------------------------ */
 1208 static int
 1209 ipf_pool_iter_next(ipf_main_softc_t *softc, void *arg, ipftoken_t *token,
 1210         ipflookupiter_t *ilp)
 1211 {
 1212         ipf_pool_softc_t *softp = arg;
 1213         ip_pool_node_t *node, zn, *nextnode;
 1214         ip_pool_t *ipo, zp, *nextipo;
 1215         void *pnext;
 1216         int err;
 1217 
 1218         err = 0;
 1219         node = NULL;
 1220         nextnode = NULL;
 1221         ipo = NULL;
 1222         nextipo = NULL;
 1223 
 1224         READ_ENTER(&softc->ipf_poolrw);
 1225 
 1226         switch (ilp->ili_otype)
 1227         {
 1228         case IPFLOOKUPITER_LIST :
 1229                 ipo = token->ipt_data;
 1230                 if (ipo == NULL) {
 1231                         nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1];
 1232                 } else {
 1233                         nextipo = ipo->ipo_next;
 1234                 }
 1235 
 1236                 if (nextipo != NULL) {
 1237                         ATOMIC_INC32(nextipo->ipo_ref);
 1238                         token->ipt_data = nextipo;
 1239                 } else {
 1240                         bzero((char *)&zp, sizeof(zp));
 1241                         nextipo = &zp;
 1242                         token->ipt_data = NULL;
 1243                 }
 1244                 pnext = nextipo->ipo_next;
 1245                 break;
 1246 
 1247         case IPFLOOKUPITER_NODE :
 1248                 node = token->ipt_data;
 1249                 if (node == NULL) {
 1250                         ipo = ipf_pool_exists(arg, ilp->ili_unit,
 1251                                               ilp->ili_name);
 1252                         if (ipo == NULL) {
 1253                                 IPFERROR(70010);
 1254                                 err = ESRCH;
 1255                         } else {
 1256                                 nextnode = ipo->ipo_list;
 1257                                 ipo = NULL;
 1258                         }
 1259                 } else {
 1260                         nextnode = node->ipn_next;
 1261                 }
 1262 
 1263                 if (nextnode != NULL) {
 1264                         ATOMIC_INC32(nextnode->ipn_ref);
 1265                         token->ipt_data = nextnode;
 1266                 } else {
 1267                         bzero((char *)&zn, sizeof(zn));
 1268                         nextnode = &zn;
 1269                         token->ipt_data = NULL;
 1270                 }
 1271                 pnext = nextnode->ipn_next;
 1272                 break;
 1273 
 1274         default :
 1275                 IPFERROR(70011);
 1276                 pnext = NULL;
 1277                 err = EINVAL;
 1278                 break;
 1279         }
 1280 
 1281         RWLOCK_EXIT(&softc->ipf_poolrw);
 1282         if (err != 0)
 1283                 return (err);
 1284 
 1285         switch (ilp->ili_otype)
 1286         {
 1287         case IPFLOOKUPITER_LIST :
 1288                 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
 1289                 if (err != 0)  {
 1290                         IPFERROR(70012);
 1291                         err = EFAULT;
 1292                 }
 1293                 if (ipo != NULL) {
 1294                         WRITE_ENTER(&softc->ipf_poolrw);
 1295                         ipf_pool_deref(softc, softp, ipo);
 1296                         RWLOCK_EXIT(&softc->ipf_poolrw);
 1297                 }
 1298                 break;
 1299 
 1300         case IPFLOOKUPITER_NODE :
 1301                 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
 1302                 if (err != 0) {
 1303                         IPFERROR(70013);
 1304                         err = EFAULT;
 1305                 }
 1306                 if (node != NULL) {
 1307                         WRITE_ENTER(&softc->ipf_poolrw);
 1308                         ipf_pool_node_deref(softp, node);
 1309                         RWLOCK_EXIT(&softc->ipf_poolrw);
 1310                 }
 1311                 break;
 1312         }
 1313         if (pnext == NULL)
 1314                 ipf_token_mark_complete(token);
 1315 
 1316         return (err);
 1317 }
 1318 
 1319 
 1320 /* ------------------------------------------------------------------------ */
 1321 /* Function:    ipf_pool_iterderef                                          */
 1322 /* Returns:     void                                                        */
 1323 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1324 /*              arg(I)   - pointer to local context to use                  */
 1325 /*              unit(I)  - ipfilter device to which we are working on       */
 1326 /* Locks:       WRITE(ipf_poolrw)                                           */
 1327 /*                                                                          */
 1328 /* ------------------------------------------------------------------------ */
 1329 static int
 1330 ipf_pool_iter_deref(ipf_main_softc_t *softc, void *arg, int otype, int unit,
 1331         void *data)
 1332 {
 1333         ipf_pool_softc_t *softp = arg;
 1334 
 1335         if (data == NULL)
 1336                 return (EINVAL);
 1337 
 1338         if (unit < 0 || unit > IPL_LOGMAX)
 1339                 return (EINVAL);
 1340 
 1341         switch (otype)
 1342         {
 1343         case IPFLOOKUPITER_LIST :
 1344                 ipf_pool_deref(softc, softp, (ip_pool_t *)data);
 1345                 break;
 1346 
 1347         case IPFLOOKUPITER_NODE :
 1348                 ipf_pool_node_deref(softp, (ip_pool_node_t *)data);
 1349                 break;
 1350         default :
 1351                 break;
 1352         }
 1353 
 1354         return (0);
 1355 }
 1356 
 1357 
 1358 /* ------------------------------------------------------------------------ */
 1359 /* Function:    ipf_pool_expire                                             */
 1360 /* Returns:     Nil                                                         */
 1361 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1362 /*              arg(I)   - pointer to local context to use                  */
 1363 /*                                                                          */
 1364 /* At present this function exists just to support temporary addition of    */
 1365 /* nodes to the address pool.                                               */
 1366 /* ------------------------------------------------------------------------ */
 1367 static void
 1368 ipf_pool_expire(ipf_main_softc_t *softc, void *arg)
 1369 {
 1370         ipf_pool_softc_t *softp = arg;
 1371         ip_pool_node_t *n;
 1372 
 1373         while ((n = softp->ipf_node_explist) != NULL) {
 1374                 /*
 1375                  * Because the list is kept sorted on insertion, the fist
 1376                  * one that dies in the future means no more work to do.
 1377                  */
 1378                 if (n->ipn_die > softc->ipf_ticks)
 1379                         break;
 1380                 ipf_pool_remove_node(softc, softp, n->ipn_owner, n);
 1381         }
 1382 }
 1383 
 1384 
 1385 
 1386 
 1387 #ifndef _KERNEL
 1388 void
 1389 ipf_pool_dump(softc, arg)
 1390         ipf_main_softc_t *softc;
 1391         void *arg;
 1392 {
 1393         ipf_pool_softc_t *softp = arg;
 1394         ip_pool_t *ipl;
 1395         int i;
 1396 
 1397         printf("List of configured pools\n");
 1398         for (i = 0; i <= LOOKUP_POOL_MAX; i++)
 1399                 for (ipl = softp->ipf_pool_list[i]; ipl != NULL;
 1400                      ipl = ipl->ipo_next)
 1401                         printpool(ipl, bcopywrap, NULL, opts, NULL);
 1402 }
 1403 #endif

Cache object: af0fea457f7de6130bb45ed1a895091c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.