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_htable.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 /*      $FreeBSD$       */
    2 
    3 /*
    4  * Copyright (C) 2012 by Darren Reed.
    5  *
    6  * See the IPFILTER.LICENCE file for details on licencing.
    7  */
    8 #if defined(KERNEL) || defined(_KERNEL)
    9 # undef KERNEL
   10 # undef _KERNEL
   11 # define        KERNEL  1
   12 # define        _KERNEL 1
   13 #endif
   14 #include <sys/param.h>
   15 #include <sys/types.h>
   16 #include <sys/errno.h>
   17 #include <sys/time.h>
   18 #include <sys/file.h>
   19 #if !defined(_KERNEL)
   20 # include <stdlib.h>
   21 # include <string.h>
   22 # define _KERNEL
   23 # include <sys/uio.h>
   24 # undef _KERNEL
   25 #endif
   26 #include <sys/socket.h>
   27 #if defined(__FreeBSD__)
   28 # include <sys/malloc.h>
   29 #endif
   30 #if defined(__FreeBSD__)
   31 #  include <sys/cdefs.h>
   32 #  include <sys/proc.h>
   33 #endif
   34 #if !defined(__SVR4)
   35 # include <sys/mbuf.h>
   36 #endif
   37 #if defined(_KERNEL)
   38 # include <sys/systm.h>
   39 #else
   40 # include "ipf.h"
   41 #endif
   42 #include <netinet/in.h>
   43 #include <net/if.h>
   44 
   45 #include "netinet/ip_compat.h"
   46 #include "netinet/ip_fil.h"
   47 #include "netinet/ip_lookup.h"
   48 #include "netinet/ip_htable.h"
   49 /* END OF INCLUDES */
   50 
   51 #if !defined(lint)
   52 static const char rcsid[] = "@(#)$Id$";
   53 #endif
   54 
   55 # ifdef USE_INET6
   56 static iphtent_t *ipf_iphmfind6(iphtable_t *, i6addr_t *);
   57 # endif
   58 static iphtent_t *ipf_iphmfind(iphtable_t *, struct in_addr *);
   59 static int ipf_iphmfindip(ipf_main_softc_t *, void *, int, void *, u_int);
   60 static int ipf_htable_clear(ipf_main_softc_t *, void *, iphtable_t *);
   61 static int ipf_htable_create(ipf_main_softc_t *, void *, iplookupop_t *);
   62 static int ipf_htable_deref(ipf_main_softc_t *, void *, void *);
   63 static int ipf_htable_destroy(ipf_main_softc_t *, void *, int, char *);
   64 static void *ipf_htable_exists(void *, int, char *);
   65 static size_t ipf_htable_flush(ipf_main_softc_t *, void *,
   66                                     iplookupflush_t *);
   67 static void ipf_htable_free(void *, iphtable_t *);
   68 static int ipf_htable_iter_deref(ipf_main_softc_t *, void *, int,
   69                                       int, void *);
   70 static int ipf_htable_iter_next(ipf_main_softc_t *, void *, ipftoken_t *,
   71                                      ipflookupiter_t *);
   72 static int ipf_htable_node_add(ipf_main_softc_t *, void *,
   73                                     iplookupop_t *, int);
   74 static int ipf_htable_node_del(ipf_main_softc_t *, void *,
   75                                     iplookupop_t *, int);
   76 static int ipf_htable_remove(ipf_main_softc_t *, void *, iphtable_t *);
   77 static void *ipf_htable_soft_create(ipf_main_softc_t *);
   78 static void ipf_htable_soft_destroy(ipf_main_softc_t *, void *);
   79 static int ipf_htable_soft_init(ipf_main_softc_t *, void *);
   80 static void ipf_htable_soft_fini(ipf_main_softc_t *, void *);
   81 static int ipf_htable_stats_get(ipf_main_softc_t *, void *,
   82                                      iplookupop_t *);
   83 static int ipf_htable_table_add(ipf_main_softc_t *, void *,
   84                                      iplookupop_t *);
   85 static int ipf_htable_table_del(ipf_main_softc_t *, void *,
   86                                      iplookupop_t *);
   87 static int ipf_htent_deref(void *, iphtent_t *);
   88 static iphtent_t *ipf_htent_find(iphtable_t *, iphtent_t *);
   89 static int ipf_htent_insert(ipf_main_softc_t *, void *, iphtable_t *,
   90                                  iphtent_t *);
   91 static int ipf_htent_remove(ipf_main_softc_t *, void *, iphtable_t *,
   92                                  iphtent_t *);
   93 static void *ipf_htable_select_add_ref(void *, int, char *);
   94 static void ipf_htable_expire(ipf_main_softc_t *, void *);
   95 
   96 
   97 typedef struct ipf_htable_softc_s {
   98         u_long          ipht_nomem[LOOKUP_POOL_SZ];
   99         u_long          ipf_nhtables[LOOKUP_POOL_SZ];
  100         u_long          ipf_nhtnodes[LOOKUP_POOL_SZ];
  101         iphtable_t      *ipf_htables[LOOKUP_POOL_SZ];
  102         iphtent_t       *ipf_node_explist;
  103 } ipf_htable_softc_t;
  104 
  105 ipf_lookup_t ipf_htable_backend = {
  106         IPLT_HASH,
  107         ipf_htable_soft_create,
  108         ipf_htable_soft_destroy,
  109         ipf_htable_soft_init,
  110         ipf_htable_soft_fini,
  111         ipf_iphmfindip,
  112         ipf_htable_flush,
  113         ipf_htable_iter_deref,
  114         ipf_htable_iter_next,
  115         ipf_htable_node_add,
  116         ipf_htable_node_del,
  117         ipf_htable_stats_get,
  118         ipf_htable_table_add,
  119         ipf_htable_table_del,
  120         ipf_htable_deref,
  121         ipf_htable_exists,
  122         ipf_htable_select_add_ref,
  123         NULL,
  124         ipf_htable_expire,
  125         NULL
  126 };
  127 
  128 
  129 /* ------------------------------------------------------------------------ */
  130 /* Function:    ipf_htable_soft_create                                      */
  131 /* Returns:     void *   - NULL = failure, else pointer to local context    */
  132 /* Parameters:  softc(I) - pointer to soft context main structure           */
  133 /*                                                                          */
  134 /* Initialise the routing table data structures where required.             */
  135 /* ------------------------------------------------------------------------ */
  136 static void *
  137 ipf_htable_soft_create(ipf_main_softc_t *softc)
  138 {
  139         ipf_htable_softc_t *softh;
  140 
  141         KMALLOC(softh, ipf_htable_softc_t *);
  142         if (softh == NULL) {
  143                 IPFERROR(30026);
  144                 return (NULL);
  145         }
  146 
  147         bzero((char *)softh, sizeof(*softh));
  148 
  149         return (softh);
  150 }
  151 
  152 
  153 /* ------------------------------------------------------------------------ */
  154 /* Function:    ipf_htable_soft_destroy                                     */
  155 /* Returns:     Nil                                                         */
  156 /* Parameters:  softc(I) - pointer to soft context main structure           */
  157 /*              arg(I)   - pointer to local context to use                  */
  158 /*                                                                          */
  159 /* Clean up the pool by free'ing the radix tree associated with it and free */
  160 /* up the pool context too.                                                 */
  161 /* ------------------------------------------------------------------------ */
  162 static void
  163 ipf_htable_soft_destroy(ipf_main_softc_t *softc, void *arg)
  164 {
  165         ipf_htable_softc_t *softh = arg;
  166 
  167         KFREE(softh);
  168 }
  169 
  170 
  171 /* ------------------------------------------------------------------------ */
  172 /* Function:    ipf_htable_soft_init                                        */
  173 /* Returns:     int     - 0 = success, else error                           */
  174 /* Parameters:  softc(I) - pointer to soft context main structure           */
  175 /*              arg(I)   - pointer to local context to use                  */
  176 /*                                                                          */
  177 /* Initialise the hash table ready for use.                                 */
  178 /* ------------------------------------------------------------------------ */
  179 static int
  180 ipf_htable_soft_init(softc, arg)
  181         ipf_main_softc_t *softc;
  182         void *arg;
  183 {
  184         ipf_htable_softc_t *softh = arg;
  185 
  186         bzero((char *)softh, sizeof(*softh));
  187 
  188         return (0);
  189 }
  190 
  191 
  192 /* ------------------------------------------------------------------------ */
  193 /* Function:    ipf_htable_soft_fini                                        */
  194 /* Returns:     Nil                                                         */
  195 /* Parameters:  softc(I) - pointer to soft context main structure           */
  196 /*              arg(I)   - pointer to local context to use                  */
  197 /* Locks:       WRITE(ipf_global)                                           */
  198 /*                                                                          */
  199 /* Clean up all the pool data structures allocated and call the cleanup     */
  200 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
  201 /* used to delete the pools one by one to ensure they're properly freed up. */
  202 /* ------------------------------------------------------------------------ */
  203 static void
  204 ipf_htable_soft_fini(ipf_main_softc_t *softc, void *arg)
  205 {
  206         iplookupflush_t fop;
  207 
  208         fop.iplf_type = IPLT_HASH;
  209         fop.iplf_unit = IPL_LOGALL;
  210         fop.iplf_arg = 0;
  211         fop.iplf_count = 0;
  212         *fop.iplf_name = '\0';
  213         ipf_htable_flush(softc, arg, &fop);
  214 }
  215 
  216 
  217 /* ------------------------------------------------------------------------ */
  218 /* Function:    ipf_htable_stats_get                                        */
  219 /* Returns:     int - 0 = success, else error                               */
  220 /* Parameters:  softc(I) - pointer to soft context main structure           */
  221 /*              arg(I)   - pointer to local context to use                  */
  222 /*              op(I)    - pointer to lookup operation data                 */
  223 /*                                                                          */
  224 /* Copy the relevant statistics out of internal structures and into the     */
  225 /* structure used to export statistics.                                     */
  226 /* ------------------------------------------------------------------------ */
  227 static int
  228 ipf_htable_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
  229 {
  230         ipf_htable_softc_t *softh = arg;
  231         iphtstat_t stats;
  232         int err;
  233 
  234         if (op->iplo_size != sizeof(stats)) {
  235                 IPFERROR(30001);
  236                 return (EINVAL);
  237         }
  238 
  239         stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
  240         stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
  241         stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
  242         stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
  243 
  244         err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
  245         if (err != 0) {
  246                 IPFERROR(30013);
  247                 return (EFAULT);
  248         }
  249         return (0);
  250 
  251 }
  252 
  253 
  254 /* ------------------------------------------------------------------------ */
  255 /* Function:    ipf_htable_create                                           */
  256 /* Returns:     int - 0 = success, else error                               */
  257 /* Parameters:  softc(I) - pointer to soft context main structure           */
  258 /*              arg(I)   - pointer to local context to use                  */
  259 /*              op(I)    - pointer to lookup operation data                 */
  260 /*                                                                          */
  261 /* Create a new hash table using the template passed.                       */
  262 /* ------------------------------------------------------------------------ */
  263 static int
  264 ipf_htable_create(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
  265 {
  266         ipf_htable_softc_t *softh = arg;
  267         iphtable_t htab, *iph, *oiph;
  268         char name[FR_GROUPLEN];
  269         int err, i, unit;
  270 
  271         if (op->iplo_size != sizeof(htab)) {
  272                 IPFERROR(30024);
  273                 return (EINVAL);
  274         }
  275         err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
  276         if (err != 0) {
  277                 IPFERROR(30003);
  278                 return (EFAULT);
  279         }
  280 
  281         unit = op->iplo_unit;
  282         if (htab.iph_unit != unit) {
  283                 IPFERROR(30005);
  284                 return (EINVAL);
  285         }
  286         if (htab.iph_size < 1) {
  287                 IPFERROR(30025);
  288                 return (EINVAL);
  289         }
  290 
  291 
  292         if ((op->iplo_arg & IPHASH_ANON) == 0) {
  293                 iph = ipf_htable_exists(softh, unit, op->iplo_name);
  294                 if (iph != NULL) {
  295                         if ((iph->iph_flags & IPHASH_DELETE) == 0) {
  296                                 IPFERROR(30004);
  297                                 return (EEXIST);
  298                         }
  299                         iph->iph_flags &= ~IPHASH_DELETE;
  300                         iph->iph_ref++;
  301                         return (0);
  302                 }
  303         }
  304 
  305         KMALLOC(iph, iphtable_t *);
  306         if (iph == NULL) {
  307                 softh->ipht_nomem[op->iplo_unit + 1]++;
  308                 IPFERROR(30002);
  309                 return (ENOMEM);
  310         }
  311         *iph = htab;
  312 
  313         if ((op->iplo_arg & IPHASH_ANON) != 0) {
  314                 i = IPHASH_ANON;
  315                 do {
  316                         i++;
  317                         (void)snprintf(name, sizeof(name), "%u", i);
  318                         for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
  319                              oiph = oiph->iph_next)
  320                                 if (strncmp(oiph->iph_name, name,
  321                                             sizeof(oiph->iph_name)) == 0)
  322                                         break;
  323                 } while (oiph != NULL);
  324 
  325                 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
  326                 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
  327                 iph->iph_type |= IPHASH_ANON;
  328         } else {
  329                 (void)strncpy(iph->iph_name, op->iplo_name,
  330                               sizeof(iph->iph_name));
  331                 iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
  332         }
  333 
  334         KMALLOCS(iph->iph_table, iphtent_t **,
  335                  iph->iph_size * sizeof(*iph->iph_table));
  336         if (iph->iph_table == NULL) {
  337                 KFREE(iph);
  338                 softh->ipht_nomem[unit + 1]++;
  339                 IPFERROR(30006);
  340                 return (ENOMEM);
  341         }
  342 
  343         bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
  344         iph->iph_maskset[0] = 0;
  345         iph->iph_maskset[1] = 0;
  346         iph->iph_maskset[2] = 0;
  347         iph->iph_maskset[3] = 0;
  348 
  349         iph->iph_ref = 1;
  350         iph->iph_list = NULL;
  351         iph->iph_tail = &iph->iph_list;
  352         iph->iph_next = softh->ipf_htables[unit + 1];
  353         iph->iph_pnext = &softh->ipf_htables[unit + 1];
  354         if (softh->ipf_htables[unit + 1] != NULL)
  355                 softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
  356         softh->ipf_htables[unit + 1] = iph;
  357 
  358         softh->ipf_nhtables[unit + 1]++;
  359 
  360         return (0);
  361 }
  362 
  363 
  364 /* ------------------------------------------------------------------------ */
  365 /* Function:    ipf_htable_table_del                                        */
  366 /* Returns:     int      - 0 = success, else error                          */
  367 /* Parameters:  softc(I) - pointer to soft context main structure           */
  368 /*              arg(I)   - pointer to local context to use                  */
  369 /*              op(I)    - pointer to lookup operation data                 */
  370 /*                                                                          */
  371 /* ------------------------------------------------------------------------ */
  372 static int
  373 ipf_htable_table_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
  374 {
  375         return (ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name));
  376 }
  377 
  378 
  379 /* ------------------------------------------------------------------------ */
  380 /* Function:    ipf_htable_destroy                                          */
  381 /* Returns:     int      - 0 = success, else error                          */
  382 /* Parameters:  softc(I) - pointer to soft context main structure           */
  383 /*              arg(I)   - pointer to local context to use                  */
  384 /*              op(I)    - pointer to lookup operation data                 */
  385 /*                                                                          */
  386 /* Find the hash table that belongs to the relevant part of ipfilter with a */
  387 /* matching name and attempt to destroy it.  If it is in use, empty it out  */
  388 /* and mark it for deletion so that when all the references disappear, it   */
  389 /* can be removed.                                                          */
  390 /* ------------------------------------------------------------------------ */
  391 static int
  392 ipf_htable_destroy(ipf_main_softc_t *softc, void *arg, int unit, char *name)
  393 {
  394         iphtable_t *iph;
  395 
  396         iph = ipf_htable_find(arg, unit, name);
  397         if (iph == NULL) {
  398                 IPFERROR(30007);
  399                 return (ESRCH);
  400         }
  401 
  402         if (iph->iph_unit != unit) {
  403                 IPFERROR(30008);
  404                 return (EINVAL);
  405         }
  406 
  407         if (iph->iph_ref != 0) {
  408                 ipf_htable_clear(softc, arg, iph);
  409                 iph->iph_flags |= IPHASH_DELETE;
  410                 return (0);
  411         }
  412 
  413         ipf_htable_remove(softc, arg, iph);
  414 
  415         return (0);
  416 }
  417 
  418 
  419 /* ------------------------------------------------------------------------ */
  420 /* Function:    ipf_htable_clear                                            */
  421 /* Returns:     int      - 0 = success, else error                          */
  422 /* Parameters:  softc(I) - pointer to soft context main structure           */
  423 /*              arg(I)   - pointer to local context to use                  */
  424 /*              iph(I)   - pointer to hash table to destroy                 */
  425 /*                                                                          */
  426 /* Clean out the hash table by walking the list of entries and removing     */
  427 /* each one, one by one.                                                    */
  428 /* ------------------------------------------------------------------------ */
  429 static int
  430 ipf_htable_clear(ipf_main_softc_t *softc, void *arg, iphtable_t *iph)
  431 {
  432         iphtent_t *ipe;
  433 
  434         while ((ipe = iph->iph_list) != NULL)
  435                 if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
  436                         return (1);
  437         return (0);
  438 }
  439 
  440 
  441 /* ------------------------------------------------------------------------ */
  442 /* Function:    ipf_htable_free                                             */
  443 /* Returns:     Nil                                                         */
  444 /* Parameters:  arg(I) - pointer to local context to use                    */
  445 /*              iph(I) - pointer to hash table to destroy                   */
  446 /*                                                                          */
  447 /* ------------------------------------------------------------------------ */
  448 static void
  449 ipf_htable_free(void *arg, iphtable_t *iph)
  450 {
  451         ipf_htable_softc_t *softh = arg;
  452 
  453         if (iph->iph_next != NULL)
  454                 iph->iph_next->iph_pnext = iph->iph_pnext;
  455         if (iph->iph_pnext != NULL)
  456                 *iph->iph_pnext = iph->iph_next;
  457         iph->iph_pnext = NULL;
  458         iph->iph_next = NULL;
  459 
  460         softh->ipf_nhtables[iph->iph_unit + 1]--;
  461 
  462         KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
  463         KFREE(iph);
  464 }
  465 
  466 
  467 /* ------------------------------------------------------------------------ */
  468 /* Function:    ipf_htable_remove                                           */
  469 /* Returns:     int      - 0 = success, else error                          */
  470 /* Parameters:  softc(I) - pointer to soft context main structure           */
  471 /*              arg(I)   - pointer to local context to use                  */
  472 /*              iph(I)   - pointer to hash table to destroy                 */
  473 /*                                                                          */
  474 /* It is necessary to unlink here as well as free (called by deref) so that */
  475 /* the while loop in ipf_htable_flush() functions properly.                 */
  476 /* ------------------------------------------------------------------------ */
  477 static int
  478 ipf_htable_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph)
  479 {
  480 
  481         if (ipf_htable_clear(softc, arg, iph) != 0)
  482                 return (1);
  483 
  484         if (iph->iph_pnext != NULL)
  485                 *iph->iph_pnext = iph->iph_next;
  486         if (iph->iph_next != NULL)
  487                 iph->iph_next->iph_pnext = iph->iph_pnext;
  488         iph->iph_pnext = NULL;
  489         iph->iph_next = NULL;
  490 
  491         return (ipf_htable_deref(softc, arg, iph));
  492 }
  493 
  494 
  495 /* ------------------------------------------------------------------------ */
  496 /* Function:    ipf_htable_node_del                                         */
  497 /* Returns:     int      - 0 = success, else error                          */
  498 /* Parameters:  softc(I) - pointer to soft context main structure           */
  499 /*              arg(I)   - pointer to local context to use                  */
  500 /*              op(I)    - pointer to lookup operation data                 */
  501 /*              uid(I)   - real uid of process doing operation              */
  502 /*                                                                          */
  503 /* ------------------------------------------------------------------------ */
  504 static int
  505 ipf_htable_node_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
  506         int uid)
  507 {
  508         iphtable_t *iph;
  509         iphtent_t hte, *ent;
  510         int err;
  511 
  512         if (op->iplo_size != sizeof(hte)) {
  513                 IPFERROR(30014);
  514                 return (EINVAL);
  515         }
  516 
  517         err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
  518         if (err != 0) {
  519                 IPFERROR(30015);
  520                 return (EFAULT);
  521         }
  522 
  523         iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
  524         if (iph == NULL) {
  525                 IPFERROR(30016);
  526                 return (ESRCH);
  527         }
  528 
  529         ent = ipf_htent_find(iph, &hte);
  530         if (ent == NULL) {
  531                 IPFERROR(30022);
  532                 return (ESRCH);
  533         }
  534 
  535         if ((uid != 0) && (ent->ipe_uid != uid)) {
  536                 IPFERROR(30023);
  537                 return (EACCES);
  538         }
  539 
  540         err = ipf_htent_remove(softc, arg, iph, ent);
  541 
  542         return (err);
  543 }
  544 
  545 
  546 /* ------------------------------------------------------------------------ */
  547 /* Function:    ipf_htable_node_del                                         */
  548 /* Returns:     int      - 0 = success, else error                          */
  549 /* Parameters:  softc(I) - pointer to soft context main structure           */
  550 /*              arg(I)   - pointer to local context to use                  */
  551 /*              op(I)    - pointer to lookup operation data                 */
  552 /*                                                                          */
  553 /* ------------------------------------------------------------------------ */
  554 static int
  555 ipf_htable_table_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
  556 {
  557         int err;
  558 
  559         if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
  560                 IPFERROR(30017);
  561                 err = EEXIST;
  562         } else {
  563                 err = ipf_htable_create(softc, arg, op);
  564         }
  565 
  566         return (err);
  567 }
  568 
  569 
  570 /* ------------------------------------------------------------------------ */
  571 /* Function:    ipf_htent_remove                                            */
  572 /* Returns:     int      - 0 = success, else error                          */
  573 /* Parameters:  softc(I) - pointer to soft context main structure           */
  574 /*              arg(I)   - pointer to local context to use                  */
  575 /*              iph(I)   - pointer to hash table                            */
  576 /*              ipe(I)   - pointer to hash table entry to remove            */
  577 /*                                                                          */
  578 /* Delete an entry from a hash table.                                       */
  579 /* ------------------------------------------------------------------------ */
  580 static int
  581 ipf_htent_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph,
  582         iphtent_t *ipe)
  583 {
  584 
  585         if (iph->iph_tail == &ipe->ipe_next)
  586                 iph->iph_tail = ipe->ipe_pnext;
  587 
  588         if (ipe->ipe_hnext != NULL)
  589                 ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
  590         if (ipe->ipe_phnext != NULL)
  591                 *ipe->ipe_phnext = ipe->ipe_hnext;
  592         ipe->ipe_phnext = NULL;
  593         ipe->ipe_hnext = NULL;
  594 
  595         if (ipe->ipe_dnext != NULL)
  596                 ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
  597         if (ipe->ipe_pdnext != NULL)
  598                 *ipe->ipe_pdnext = ipe->ipe_dnext;
  599         ipe->ipe_pdnext = NULL;
  600         ipe->ipe_dnext = NULL;
  601 
  602         if (ipe->ipe_next != NULL)
  603                 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
  604         if (ipe->ipe_pnext != NULL)
  605                 *ipe->ipe_pnext = ipe->ipe_next;
  606         ipe->ipe_pnext = NULL;
  607         ipe->ipe_next = NULL;
  608 
  609         switch (iph->iph_type & ~IPHASH_ANON)
  610         {
  611         case IPHASH_GROUPMAP :
  612                 if (ipe->ipe_group != NULL)
  613                         ipf_group_del(softc, ipe->ipe_ptr, NULL);
  614                 break;
  615 
  616         default :
  617                 ipe->ipe_ptr = NULL;
  618                 ipe->ipe_value = 0;
  619                 break;
  620         }
  621 
  622         return (ipf_htent_deref(arg, ipe));
  623 }
  624 
  625 
  626 /* ------------------------------------------------------------------------ */
  627 /* Function:    ipf_htable_deref                                            */
  628 /* Returns:     int       - 0 = success, else error                         */
  629 /* Parameters:  softc(I)  - pointer to soft context main structure          */
  630 /*              arg(I)    - pointer to local context to use                 */
  631 /*              object(I) - pointer to hash table                           */
  632 /*                                                                          */
  633 /* ------------------------------------------------------------------------ */
  634 static int
  635 ipf_htable_deref(ipf_main_softc_t *softc, void *arg, void *object)
  636 {
  637         ipf_htable_softc_t *softh = arg;
  638         iphtable_t *iph = object;
  639         int refs;
  640 
  641         iph->iph_ref--;
  642         refs = iph->iph_ref;
  643 
  644         if (iph->iph_ref == 0) {
  645                 ipf_htable_free(softh, iph);
  646         }
  647 
  648         return (refs);
  649 }
  650 
  651 
  652 /* ------------------------------------------------------------------------ */
  653 /* Function:    ipf_htent_deref                                             */
  654 /* Parameters:  arg(I) - pointer to local context to use                    */
  655 /*              ipe(I) -                                                    */
  656 /*                                                                          */
  657 /* ------------------------------------------------------------------------ */
  658 static int
  659 ipf_htent_deref(void *arg, iphtent_t *ipe)
  660 {
  661         ipf_htable_softc_t *softh = arg;
  662 
  663         ipe->ipe_ref--;
  664         if (ipe->ipe_ref == 0) {
  665                 softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
  666                 KFREE(ipe);
  667 
  668                 return (0);
  669         }
  670 
  671         return (ipe->ipe_ref);
  672 }
  673 
  674 
  675 /* ------------------------------------------------------------------------ */
  676 /* Function:    ipf_htable_exists                                           */
  677 /* Parameters:  arg(I) - pointer to local context to use                    */
  678 /*                                                                          */
  679 /* ------------------------------------------------------------------------ */
  680 static void *
  681 ipf_htable_exists(void *arg, int unit, char *name)
  682 {
  683         ipf_htable_softc_t *softh = arg;
  684         iphtable_t *iph;
  685 
  686         if (unit == IPL_LOGALL) {
  687                 int i;
  688 
  689                 for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
  690                         for (iph = softh->ipf_htables[i]; iph != NULL;
  691                              iph = iph->iph_next) {
  692                                 if (strncmp(iph->iph_name, name,
  693                                             sizeof(iph->iph_name)) == 0)
  694                                         break;
  695                         }
  696                         if (iph != NULL)
  697                                 break;
  698                 }
  699         } else {
  700                 for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
  701                      iph = iph->iph_next) {
  702                         if (strncmp(iph->iph_name, name,
  703                                     sizeof(iph->iph_name)) == 0)
  704                                 break;
  705                 }
  706         }
  707         return (iph);
  708 }
  709 
  710 
  711 /* ------------------------------------------------------------------------ */
  712 /* Function:    ipf_htable_select_add_ref                                   */
  713 /* Returns:     void *  - NULL = failure, else pointer to the hash table    */
  714 /* Parameters:  arg(I)  - pointer to local context to use                   */
  715 /*              unit(I) - ipfilter device to which we are working on        */
  716 /*              name(I) - name of the hash table                            */
  717 /*                                                                          */
  718 /* ------------------------------------------------------------------------ */
  719 static void *
  720 ipf_htable_select_add_ref(void *arg, int unit, char *name)
  721 {
  722         iphtable_t *iph;
  723 
  724         iph = ipf_htable_exists(arg, unit, name);
  725         if (iph != NULL) {
  726                 ATOMIC_INC32(iph->iph_ref);
  727         }
  728         return (iph);
  729 }
  730 
  731 
  732 /* ------------------------------------------------------------------------ */
  733 /* Function:    ipf_htable_find                                             */
  734 /* Returns:     void *  - NULL = failure, else pointer to the hash table    */
  735 /* Parameters:  arg(I)  - pointer to local context to use                   */
  736 /*              unit(I) - ipfilter device to which we are working on        */
  737 /*              name(I) - name of the hash table                            */
  738 /*                                                                          */
  739 /* This function is exposed becaues it is used in the group-map feature.    */
  740 /* ------------------------------------------------------------------------ */
  741 iphtable_t *
  742 ipf_htable_find(void *arg, int unit, char *name)
  743 {
  744         iphtable_t *iph;
  745 
  746         iph = ipf_htable_exists(arg, unit, name);
  747         if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
  748                 return (iph);
  749 
  750         return (NULL);
  751 }
  752 
  753 
  754 /* ------------------------------------------------------------------------ */
  755 /* Function:    ipf_htable_flush                                            */
  756 /* Returns:     size_t   - number of entries flushed                        */
  757 /* Parameters:  softc(I) - pointer to soft context main structure           */
  758 /*              arg(I)   - pointer to local context to use                  */
  759 /*              op(I)    - pointer to lookup operation data                 */
  760 /*                                                                          */
  761 /* ------------------------------------------------------------------------ */
  762 static size_t
  763 ipf_htable_flush(ipf_main_softc_t *softc, void *arg, iplookupflush_t *op)
  764 {
  765         ipf_htable_softc_t *softh = arg;
  766         iphtable_t *iph;
  767         size_t freed;
  768         int i;
  769 
  770         freed = 0;
  771 
  772         for (i = -1; i <= IPL_LOGMAX; i++) {
  773                 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
  774                         while ((iph = softh->ipf_htables[i + 1]) != NULL) {
  775                                 if (ipf_htable_remove(softc, arg, iph) == 0) {
  776                                         freed++;
  777                                 } else {
  778                                         iph->iph_flags |= IPHASH_DELETE;
  779                                 }
  780                         }
  781                 }
  782         }
  783 
  784         return (freed);
  785 }
  786 
  787 
  788 /* ------------------------------------------------------------------------ */
  789 /* Function:    ipf_htable_node_add                                         */
  790 /* Returns:     int      - 0 = success, else error                          */
  791 /* Parameters:  softc(I) - pointer to soft context main structure           */
  792 /*              arg(I)   - pointer to local context to use                  */
  793 /*              op(I)    - pointer to lookup operation data                 */
  794 /*              uid(I)   - real uid of process doing operation              */
  795 /*                                                                          */
  796 /* ------------------------------------------------------------------------ */
  797 static int
  798 ipf_htable_node_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op,
  799         int uid)
  800 {
  801         iphtable_t *iph;
  802         iphtent_t hte;
  803         int err;
  804 
  805         if (op->iplo_size != sizeof(hte)) {
  806                 IPFERROR(30018);
  807                 return (EINVAL);
  808         }
  809 
  810         err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
  811         if (err != 0) {
  812                 IPFERROR(30019);
  813                 return (EFAULT);
  814         }
  815         hte.ipe_uid = uid;
  816 
  817         iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
  818         if (iph == NULL) {
  819                 IPFERROR(30020);
  820                 return (ESRCH);
  821         }
  822 
  823         if (ipf_htent_find(iph, &hte) != NULL) {
  824                 IPFERROR(30021);
  825                 return (EEXIST);
  826         }
  827 
  828         err = ipf_htent_insert(softc, arg, iph, &hte);
  829 
  830         return (err);
  831 }
  832 
  833 
  834 /* ------------------------------------------------------------------------ */
  835 /* Function:    ipf_htent_insert                                            */
  836 /* Returns:     int      - 0 = success, -1 =  error                         */
  837 /* Parameters:  softc(I) - pointer to soft context main structure           */
  838 /*              arg(I)   - pointer to local context to use                  */
  839 /*              op(I)    - pointer to lookup operation data                 */
  840 /*              ipeo(I)  -                                                  */
  841 /*                                                                          */
  842 /* Add an entry to a hash table.                                            */
  843 /* ------------------------------------------------------------------------ */
  844 static int
  845 ipf_htent_insert(ipf_main_softc_t *softc, void *arg, iphtable_t *iph,
  846         iphtent_t *ipeo)
  847 {
  848         ipf_htable_softc_t *softh = arg;
  849         iphtent_t *ipe;
  850         u_int hv;
  851         int bits;
  852 
  853         KMALLOC(ipe, iphtent_t *);
  854         if (ipe == NULL)
  855                 return (-1);
  856 
  857         bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
  858         ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
  859         if (ipe->ipe_family == AF_INET) {
  860                 bits = count4bits(ipe->ipe_mask.in4_addr);
  861                 ipe->ipe_addr.i6[1] = 0;
  862                 ipe->ipe_addr.i6[2] = 0;
  863                 ipe->ipe_addr.i6[3] = 0;
  864                 ipe->ipe_mask.i6[1] = 0;
  865                 ipe->ipe_mask.i6[2] = 0;
  866                 ipe->ipe_mask.i6[3] = 0;
  867                 hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
  868                                     ipe->ipe_mask.in4_addr, iph->iph_size);
  869         } else
  870 #ifdef USE_INET6
  871         if (ipe->ipe_family == AF_INET6) {
  872                 ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
  873                 ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
  874                 ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
  875 
  876                 bits = count6bits(ipe->ipe_mask.i6);
  877                 hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
  878                                     ipe->ipe_mask.i6, iph->iph_size);
  879         } else
  880 #endif
  881         {
  882                 KFREE(ipe);
  883                 return (-1);
  884         }
  885 
  886         ipe->ipe_owner = iph;
  887         ipe->ipe_ref = 1;
  888         ipe->ipe_hnext = iph->iph_table[hv];
  889         ipe->ipe_phnext = iph->iph_table + hv;
  890 
  891         if (iph->iph_table[hv] != NULL)
  892                 iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
  893         iph->iph_table[hv] = ipe;
  894 
  895         ipe->ipe_pnext = iph->iph_tail;
  896         *iph->iph_tail = ipe;
  897         iph->iph_tail = &ipe->ipe_next;
  898         ipe->ipe_next = NULL;
  899 
  900         if (ipe->ipe_die != 0) {
  901                 /*
  902                  * If the new node has a given expiration time, insert it
  903                  * into the list of expiring nodes with the ones to be
  904                  * removed first added to the front of the list. The
  905                  * insertion is O(n) but it is kept sorted for quick scans
  906                  * at expiration interval checks.
  907                  */
  908                 iphtent_t *n;
  909 
  910                 ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
  911                 for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
  912                         if (ipe->ipe_die < n->ipe_die)
  913                                 break;
  914                         if (n->ipe_dnext == NULL) {
  915                                 /*
  916                                  * We've got to the last node and everything
  917                                  * wanted to be expired before this new node,
  918                                  * so we have to tack it on the end...
  919                                  */
  920                                 n->ipe_dnext = ipe;
  921                                 ipe->ipe_pdnext = &n->ipe_dnext;
  922                                 n = NULL;
  923                                 break;
  924                         }
  925                 }
  926 
  927                 if (softh->ipf_node_explist == NULL) {
  928                         softh->ipf_node_explist = ipe;
  929                         ipe->ipe_pdnext = &softh->ipf_node_explist;
  930                 } else if (n != NULL) {
  931                         ipe->ipe_dnext = n;
  932                         ipe->ipe_pdnext = n->ipe_pdnext;
  933                         n->ipe_pdnext = &ipe->ipe_dnext;
  934                 }
  935         }
  936 
  937         if (ipe->ipe_family == AF_INET) {
  938                 ipf_inet_mask_add(bits, &iph->iph_v4_masks);
  939         }
  940 #ifdef USE_INET6
  941         else if (ipe->ipe_family == AF_INET6) {
  942                 ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
  943         }
  944 #endif
  945 
  946         switch (iph->iph_type & ~IPHASH_ANON)
  947         {
  948         case IPHASH_GROUPMAP :
  949                 ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
  950                                            iph->iph_flags, IPL_LOGIPF,
  951                                            softc->ipf_active);
  952                 break;
  953 
  954         default :
  955                 ipe->ipe_ptr = NULL;
  956                 ipe->ipe_value = 0;
  957                 break;
  958         }
  959 
  960         ipe->ipe_unit = iph->iph_unit;
  961         softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
  962 
  963         return (0);
  964 }
  965 
  966 
  967 /* ------------------------------------------------------------------------ */
  968 /* Function:    ipf_htent_find                                              */
  969 /* Returns:     int     - 0 = success, else error                           */
  970 /* Parameters:  iph(I)  - pointer to table to search                        */
  971 /*              ipeo(I) - pointer to entry to find                          */
  972 /*                                                                          */
  973 /* While it isn't absolutely necessary to for the address and mask to be    */
  974 /* passed in through an iphtent_t structure, one is always present when it  */
  975 /* is time to call this function, so it is just more convenient.            */
  976 /* ------------------------------------------------------------------------ */
  977 static iphtent_t *
  978 ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo)
  979 {
  980         iphtent_t ipe, *ent;
  981         u_int hv;
  982         int bits;
  983 
  984         bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
  985         ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
  986         ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
  987         ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
  988         ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
  989         if (ipe.ipe_family == AF_INET) {
  990                 bits = count4bits(ipe.ipe_mask.in4_addr);
  991                 ipe.ipe_addr.i6[1] = 0;
  992                 ipe.ipe_addr.i6[2] = 0;
  993                 ipe.ipe_addr.i6[3] = 0;
  994                 ipe.ipe_mask.i6[1] = 0;
  995                 ipe.ipe_mask.i6[2] = 0;
  996                 ipe.ipe_mask.i6[3] = 0;
  997                 hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
  998                                     ipe.ipe_mask.in4_addr, iph->iph_size);
  999         } else
 1000 #ifdef USE_INET6
 1001         if (ipe.ipe_family == AF_INET6) {
 1002                 bits = count6bits(ipe.ipe_mask.i6);
 1003                 hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
 1004                                     ipe.ipe_mask.i6, iph->iph_size);
 1005         } else
 1006 #endif
 1007                 return (NULL);
 1008 
 1009         for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
 1010                 if (ent->ipe_family != ipe.ipe_family)
 1011                         continue;
 1012                 if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
 1013                         continue;
 1014                 if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
 1015                         continue;
 1016                 break;
 1017         }
 1018 
 1019         return (ent);
 1020 }
 1021 
 1022 
 1023 /* ------------------------------------------------------------------------ */
 1024 /* Function:    ipf_iphmfindgroup                                           */
 1025 /* Returns:     int      - 0 = success, else error                          */
 1026 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1027 /*              tptr(I)  -                                                  */
 1028 /*              aptr(I)  -                                                  */
 1029 /*                                                                          */
 1030 /* Search a hash table for a matching entry and return the pointer stored   */
 1031 /* in it for use as the next group of rules to search.                      */
 1032 /*                                                                          */
 1033 /* This function is exposed becaues it is used in the group-map feature.    */
 1034 /* ------------------------------------------------------------------------ */
 1035 void *
 1036 ipf_iphmfindgroup(ipf_main_softc_t *softc, void *tptr, void *aptr)
 1037 {
 1038         struct in_addr *addr;
 1039         iphtable_t *iph;
 1040         iphtent_t *ipe;
 1041         void *rval;
 1042 
 1043         READ_ENTER(&softc->ipf_poolrw);
 1044         iph = tptr;
 1045         addr = aptr;
 1046 
 1047         ipe = ipf_iphmfind(iph, addr);
 1048         if (ipe != NULL)
 1049                 rval = ipe->ipe_ptr;
 1050         else
 1051                 rval = NULL;
 1052         RWLOCK_EXIT(&softc->ipf_poolrw);
 1053         return (rval);
 1054 }
 1055 
 1056 
 1057 /* ------------------------------------------------------------------------ */
 1058 /* Function:    ipf_iphmfindip                                              */
 1059 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
 1060 /* Parameters:  softc(I)     - pointer to soft context main structure       */
 1061 /*              tptr(I)      - pointer to the pool to search                */
 1062 /*              ipversion(I) - IP protocol version (4 or 6)                 */
 1063 /*              aptr(I)      - pointer to address information               */
 1064 /*              bytes(I)     - packet length                                */
 1065 /*                                                                          */
 1066 /* Search the hash table for a given address and return a search result.    */
 1067 /* ------------------------------------------------------------------------ */
 1068 static int
 1069 ipf_iphmfindip(ipf_main_softc_t *softc, void *tptr, int ipversion, void *aptr,
 1070         u_int bytes)
 1071 {
 1072         struct in_addr *addr;
 1073         iphtable_t *iph;
 1074         iphtent_t *ipe;
 1075         int rval;
 1076 
 1077         if (tptr == NULL || aptr == NULL)
 1078                 return (-1);
 1079 
 1080         iph = tptr;
 1081         addr = aptr;
 1082 
 1083         READ_ENTER(&softc->ipf_poolrw);
 1084         if (ipversion == 4) {
 1085                 ipe = ipf_iphmfind(iph, addr);
 1086 #ifdef USE_INET6
 1087         } else if (ipversion == 6) {
 1088                 ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
 1089 #endif
 1090         } else {
 1091                 ipe = NULL;
 1092         }
 1093 
 1094         if (ipe != NULL) {
 1095                 rval = 0;
 1096                 ipe->ipe_hits++;
 1097                 ipe->ipe_bytes += bytes;
 1098         } else {
 1099                 rval = 1;
 1100         }
 1101         RWLOCK_EXIT(&softc->ipf_poolrw);
 1102         return (rval);
 1103 }
 1104 
 1105 
 1106 /* ------------------------------------------------------------------------ */
 1107 /* Function:    ipf_iphmfindip                                              */
 1108 /* Parameters:  iph(I)  - pointer to hash table                             */
 1109 /*              addr(I) - pointer to IPv4 address                           */
 1110 /* Locks:  ipf_poolrw                                                       */
 1111 /*                                                                          */
 1112 /* ------------------------------------------------------------------------ */
 1113 static iphtent_t *
 1114 ipf_iphmfind(iphtable_t *iph, struct in_addr *addr)
 1115 {
 1116         u_32_t msk, ips;
 1117         iphtent_t *ipe;
 1118         u_int hv;
 1119         int i;
 1120 
 1121         i = 0;
 1122 maskloop:
 1123         msk = iph->iph_v4_masks.imt4_active[i];
 1124         ips = addr->s_addr & msk;
 1125         hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
 1126         for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
 1127                 if ((ipe->ipe_family != AF_INET) ||
 1128                     (ipe->ipe_mask.in4_addr != msk) ||
 1129                     (ipe->ipe_addr.in4_addr != ips)) {
 1130                         continue;
 1131                 }
 1132                 break;
 1133         }
 1134 
 1135         if (ipe == NULL) {
 1136                 i++;
 1137                 if (i < iph->iph_v4_masks.imt4_max)
 1138                         goto maskloop;
 1139         }
 1140         return (ipe);
 1141 }
 1142 
 1143 
 1144 /* ------------------------------------------------------------------------ */
 1145 /* Function:    ipf_htable_iter_next                                        */
 1146 /* Returns:     int      - 0 = success, else error                          */
 1147 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1148 /*              arg(I)   - pointer to local context to use                  */
 1149 /*              token(I) -                                                  */
 1150 /*              ilp(I)   -                                                  */
 1151 /*                                                                          */
 1152 /* ------------------------------------------------------------------------ */
 1153 static int
 1154 ipf_htable_iter_next(ipf_main_softc_t *softc, void *arg, ipftoken_t *token,
 1155         ipflookupiter_t *ilp)
 1156 {
 1157         ipf_htable_softc_t *softh = arg;
 1158         iphtent_t *node, zn, *nextnode;
 1159         iphtable_t *iph, zp, *nextiph;
 1160         void *hnext;
 1161         int err;
 1162 
 1163         err = 0;
 1164         iph = NULL;
 1165         node = NULL;
 1166         nextiph = NULL;
 1167         nextnode = NULL;
 1168 
 1169         READ_ENTER(&softc->ipf_poolrw);
 1170 
 1171         switch (ilp->ili_otype)
 1172         {
 1173         case IPFLOOKUPITER_LIST :
 1174                 iph = token->ipt_data;
 1175                 if (iph == NULL) {
 1176                         nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
 1177                 } else {
 1178                         nextiph = iph->iph_next;
 1179                 }
 1180 
 1181                 if (nextiph != NULL) {
 1182                         ATOMIC_INC(nextiph->iph_ref);
 1183                         token->ipt_data = nextiph;
 1184                 } else {
 1185                         bzero((char *)&zp, sizeof(zp));
 1186                         nextiph = &zp;
 1187                         token->ipt_data = NULL;
 1188                 }
 1189                 hnext = nextiph->iph_next;
 1190                 break;
 1191 
 1192         case IPFLOOKUPITER_NODE :
 1193                 node = token->ipt_data;
 1194                 if (node == NULL) {
 1195                         iph = ipf_htable_find(arg, ilp->ili_unit,
 1196                                               ilp->ili_name);
 1197                         if (iph == NULL) {
 1198                                 IPFERROR(30009);
 1199                                 err = ESRCH;
 1200                         } else {
 1201                                 nextnode = iph->iph_list;
 1202                         }
 1203                 } else {
 1204                         nextnode = node->ipe_next;
 1205                 }
 1206 
 1207                 if (nextnode != NULL) {
 1208                         ATOMIC_INC(nextnode->ipe_ref);
 1209                         token->ipt_data = nextnode;
 1210                 } else {
 1211                         bzero((char *)&zn, sizeof(zn));
 1212                         nextnode = &zn;
 1213                         token->ipt_data = NULL;
 1214                 }
 1215                 hnext = nextnode->ipe_next;
 1216                 break;
 1217 
 1218         default :
 1219                 IPFERROR(30010);
 1220                 err = EINVAL;
 1221                 hnext = NULL;
 1222                 break;
 1223         }
 1224 
 1225         RWLOCK_EXIT(&softc->ipf_poolrw);
 1226         if (err != 0)
 1227                 return (err);
 1228 
 1229         switch (ilp->ili_otype)
 1230         {
 1231         case IPFLOOKUPITER_LIST :
 1232                 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
 1233                 if (err != 0) {
 1234                         IPFERROR(30011);
 1235                         err = EFAULT;
 1236                 }
 1237                 if (iph != NULL) {
 1238                         WRITE_ENTER(&softc->ipf_poolrw);
 1239                         ipf_htable_deref(softc, softh, iph);
 1240                         RWLOCK_EXIT(&softc->ipf_poolrw);
 1241                 }
 1242                 break;
 1243 
 1244         case IPFLOOKUPITER_NODE :
 1245                 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
 1246                 if (err != 0) {
 1247                         IPFERROR(30012);
 1248                         err = EFAULT;
 1249                 }
 1250                 if (node != NULL) {
 1251                         WRITE_ENTER(&softc->ipf_poolrw);
 1252                         ipf_htent_deref(softc, node);
 1253                         RWLOCK_EXIT(&softc->ipf_poolrw);
 1254                 }
 1255                 break;
 1256         }
 1257 
 1258         if (hnext == NULL)
 1259                 ipf_token_mark_complete(token);
 1260 
 1261         return (err);
 1262 }
 1263 
 1264 
 1265 /* ------------------------------------------------------------------------ */
 1266 /* Function:    ipf_htable_iter_deref                                       */
 1267 /* Returns:     int      - 0 = success, else  error                         */
 1268 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1269 /*              arg(I)   - pointer to local context to use                  */
 1270 /*              otype(I) - which data structure type is being walked        */
 1271 /*              unit(I)  - ipfilter device to which we are working on       */
 1272 /*              data(I)  - pointer to old data structure                    */
 1273 /*                                                                          */
 1274 /* ------------------------------------------------------------------------ */
 1275 static int
 1276 ipf_htable_iter_deref(ipf_main_softc_t *softc, void *arg, int otype, int unit,
 1277         void *data)
 1278 {
 1279 
 1280         if (data == NULL)
 1281                 return (EFAULT);
 1282 
 1283         if (unit < -1 || unit > IPL_LOGMAX)
 1284                 return (EINVAL);
 1285 
 1286         switch (otype)
 1287         {
 1288         case IPFLOOKUPITER_LIST :
 1289                 ipf_htable_deref(softc, arg, (iphtable_t *)data);
 1290                 break;
 1291 
 1292         case IPFLOOKUPITER_NODE :
 1293                 ipf_htent_deref(arg, (iphtent_t *)data);
 1294                 break;
 1295         default :
 1296                 break;
 1297         }
 1298 
 1299         return (0);
 1300 }
 1301 
 1302 
 1303 #ifdef USE_INET6
 1304 /* ------------------------------------------------------------------------ */
 1305 /* Function:    ipf_iphmfind6                                               */
 1306 /* Parameters:  iph(I)  - pointer to hash table                             */
 1307 /*              addr(I) - pointer to IPv6 address                           */
 1308 /* Locks:  ipf_poolrw                                                       */
 1309 /*                                                                          */
 1310 /* ------------------------------------------------------------------------ */
 1311 static iphtent_t *
 1312 ipf_iphmfind6(iphtable_t *iph, i6addr_t *addr)
 1313 {
 1314         i6addr_t *msk, ips;
 1315         iphtent_t *ipe;
 1316         u_int hv;
 1317         int i;
 1318 
 1319         i = 0;
 1320 maskloop:
 1321         msk = iph->iph_v6_masks.imt6_active + i;
 1322         ips.i6[0] = addr->i6[0] & msk->i6[0];
 1323         ips.i6[1] = addr->i6[1] & msk->i6[1];
 1324         ips.i6[2] = addr->i6[2] & msk->i6[2];
 1325         ips.i6[3] = addr->i6[3] & msk->i6[3];
 1326         hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
 1327         for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
 1328                 if ((ipe->ipe_family != AF_INET6) ||
 1329                     IP6_NEQ(&ipe->ipe_mask, msk) ||
 1330                     IP6_NEQ(&ipe->ipe_addr, &ips)) {
 1331                         continue;
 1332                 }
 1333                 break;
 1334         }
 1335 
 1336         if (ipe == NULL) {
 1337                 i++;
 1338                 if (i < iph->iph_v6_masks.imt6_max)
 1339                         goto maskloop;
 1340         }
 1341         return (ipe);
 1342 }
 1343 #endif
 1344 
 1345 
 1346 static void
 1347 ipf_htable_expire(ipf_main_softc_t *softc, void *arg)
 1348 {
 1349         ipf_htable_softc_t *softh = arg;
 1350         iphtent_t *n;
 1351 
 1352         while ((n = softh->ipf_node_explist) != NULL) {
 1353                 if (n->ipe_die > softc->ipf_ticks)
 1354                         break;
 1355 
 1356                 ipf_htent_remove(softc, softh, n->ipe_owner, n);
 1357         }
 1358 }
 1359 
 1360 
 1361 #ifndef _KERNEL
 1362 
 1363 /* ------------------------------------------------------------------------ */
 1364 /*                                                                          */
 1365 /* ------------------------------------------------------------------------ */
 1366 void
 1367 ipf_htable_dump(ipf_main_softc_t *softc, void *arg)
 1368 {
 1369         ipf_htable_softc_t *softh = arg;
 1370         iphtable_t *iph;
 1371         int i;
 1372 
 1373         printf("List of configured hash tables\n");
 1374         for (i = 0; i < IPL_LOGSIZE; i++)
 1375                 for (iph = softh->ipf_htables[i]; iph != NULL;
 1376                      iph = iph->iph_next)
 1377                         printhash(iph, bcopywrap, NULL, opts, NULL);
 1378 
 1379 }
 1380 #endif

Cache object: f4ebfe7c991fd3c59e7a7c3485e1f1d3


[ 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.