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_frag.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/errno.h>
   15 #include <sys/types.h>
   16 #include <sys/param.h>
   17 #include <sys/time.h>
   18 #include <sys/file.h>
   19 #if !defined(_KERNEL)
   20 # include <stdio.h>
   21 # include <string.h>
   22 # include <stdlib.h>
   23 # define _KERNEL
   24 # include <sys/uio.h>
   25 # undef _KERNEL
   26 #endif
   27 #if defined(_KERNEL) && defined(__FreeBSD__)
   28 # include <sys/filio.h>
   29 # include <sys/fcntl.h>
   30 #else
   31 # include <sys/ioctl.h>
   32 #endif
   33 # include <sys/protosw.h>
   34 #include <sys/socket.h>
   35 #if defined(_KERNEL)
   36 # include <sys/systm.h>
   37 # if !defined(__SVR4)
   38 #  include <sys/mbuf.h>
   39 # endif
   40 #endif
   41 #if !defined(__SVR4)
   42 # if defined(_KERNEL)
   43 #  include <sys/kernel.h>
   44 # endif
   45 #else
   46 # include <sys/byteorder.h>
   47 # ifdef _KERNEL
   48 #  include <sys/dditypes.h>
   49 # endif
   50 # include <sys/stream.h>
   51 # include <sys/kmem.h>
   52 #endif
   53 #include <net/if.h>
   54 #ifdef sun
   55 # include <net/af.h>
   56 #endif
   57 #include <netinet/in.h>
   58 #include <netinet/in_systm.h>
   59 #include <netinet/ip.h>
   60 # include <netinet/ip_var.h>
   61 #include <netinet/tcp.h>
   62 #include <netinet/udp.h>
   63 #include <netinet/ip_icmp.h>
   64 #include "netinet/ip_compat.h"
   65 #include <netinet/tcpip.h>
   66 #include "netinet/ip_fil.h"
   67 #include "netinet/ip_nat.h"
   68 #include "netinet/ip_frag.h"
   69 #include "netinet/ip_state.h"
   70 #include "netinet/ip_auth.h"
   71 #include "netinet/ip_lookup.h"
   72 #include "netinet/ip_proxy.h"
   73 #include "netinet/ip_sync.h"
   74 /* END OF INCLUDES */
   75 
   76 #if !defined(lint)
   77 static const char sccsid[] = "@(#)ip_frag.c     1.11 3/24/96 (C) 1993-2000 Darren Reed";
   78 static const char rcsid[] = "@(#)$FreeBSD$";
   79 /* static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $"; */
   80 #endif
   81 
   82 
   83 #ifdef USE_MUTEXES
   84 static ipfr_t *ipfr_frag_new(ipf_main_softc_t *, ipf_frag_softc_t *,
   85                                   fr_info_t *, u_32_t, ipfr_t **,
   86                                   ipfrwlock_t *);
   87 static ipfr_t *ipf_frag_lookup(ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **, ipfrwlock_t *);
   88 static void ipf_frag_deref(void *, ipfr_t **, ipfrwlock_t *);
   89 static int ipf_frag_next(ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
   90                               ipfr_t **, ipfrwlock_t *);
   91 #else
   92 static ipfr_t *ipfr_frag_new(ipf_main_softc_t *, ipf_frag_softc_t *,
   93                                   fr_info_t *, u_32_t, ipfr_t **);
   94 static ipfr_t *ipf_frag_lookup(ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **);
   95 static void ipf_frag_deref(void *, ipfr_t **);
   96 static int ipf_frag_next(ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
   97                               ipfr_t **);
   98 #endif
   99 static void ipf_frag_delete(ipf_main_softc_t *, ipfr_t *, ipfr_t ***);
  100 static void ipf_frag_free(ipf_frag_softc_t *, ipfr_t *);
  101 
  102 static frentry_t ipfr_block;
  103 
  104 static ipftuneable_t ipf_frag_tuneables[] = {
  105         { { (void *)offsetof(ipf_frag_softc_t, ipfr_size) },
  106                 "frag_size",            1,      0x7fffffff,
  107                 stsizeof(ipf_frag_softc_t, ipfr_size),
  108                 IPFT_WRDISABLED,        NULL,   NULL },
  109         { { (void *)offsetof(ipf_frag_softc_t, ipfr_ttl) },
  110                 "frag_ttl",             1,      0x7fffffff,
  111                 stsizeof(ipf_frag_softc_t, ipfr_ttl),
  112                 0,                      NULL,   NULL },
  113         { { NULL },
  114                 NULL,                   0,      0,
  115                 0,
  116                 0,                      NULL,   NULL }
  117 };
  118 
  119 #define FBUMP(x)        softf->ipfr_stats.x++
  120 #define FBUMPD(x)       do { softf->ipfr_stats.x++; DT(x); } while (0)
  121 
  122 
  123 /* ------------------------------------------------------------------------ */
  124 /* Function:    ipf_frag_main_load                                          */
  125 /* Returns:     int - 0 == success, -1 == error                             */
  126 /* Parameters:  Nil                                                         */
  127 /*                                                                          */
  128 /* Initialise the filter rule associted with blocked packets - everyone can */
  129 /* use it.                                                                  */
  130 /* ------------------------------------------------------------------------ */
  131 int
  132 ipf_frag_main_load(void)
  133 {
  134         bzero((char *)&ipfr_block, sizeof(ipfr_block));
  135         ipfr_block.fr_flags = FR_BLOCK|FR_QUICK;
  136         ipfr_block.fr_ref = 1;
  137 
  138         return (0);
  139 }
  140 
  141 
  142 /* ------------------------------------------------------------------------ */
  143 /* Function:    ipf_frag_main_unload                                        */
  144 /* Returns:     int - 0 == success, -1 == error                             */
  145 /* Parameters:  Nil                                                         */
  146 /*                                                                          */
  147 /* A null-op function that exists as a placeholder so that the flow in      */
  148 /* other functions is obvious.                                              */
  149 /* ------------------------------------------------------------------------ */
  150 int
  151 ipf_frag_main_unload(void)
  152 {
  153         return (0);
  154 }
  155 
  156 
  157 /* ------------------------------------------------------------------------ */
  158 /* Function:    ipf_frag_soft_create                                        */
  159 /* Returns:     void *   - NULL = failure, else pointer to local context    */
  160 /* Parameters:  softc(I) - pointer to soft context main structure           */
  161 /*                                                                          */
  162 /* Allocate a new soft context structure to track fragment related info.    */
  163 /* ------------------------------------------------------------------------ */
  164 /*ARGSUSED*/
  165 void *
  166 ipf_frag_soft_create(ipf_main_softc_t *softc)
  167 {
  168         ipf_frag_softc_t *softf;
  169 
  170         KMALLOC(softf, ipf_frag_softc_t *);
  171         if (softf == NULL)
  172                 return (NULL);
  173 
  174         bzero((char *)softf, sizeof(*softf));
  175 
  176         RWLOCK_INIT(&softf->ipfr_ipidfrag, "frag ipid lock");
  177         RWLOCK_INIT(&softf->ipfr_frag, "ipf fragment rwlock");
  178         RWLOCK_INIT(&softf->ipfr_natfrag, "ipf NAT fragment rwlock");
  179 
  180         softf->ipf_frag_tune = ipf_tune_array_copy(softf,
  181                                                    sizeof(ipf_frag_tuneables),
  182                                                    ipf_frag_tuneables);
  183         if (softf->ipf_frag_tune == NULL) {
  184                 ipf_frag_soft_destroy(softc, softf);
  185                 return (NULL);
  186         }
  187         if (ipf_tune_array_link(softc, softf->ipf_frag_tune) == -1) {
  188                 ipf_frag_soft_destroy(softc, softf);
  189                 return (NULL);
  190         }
  191 
  192         softf->ipfr_size = IPFT_SIZE;
  193         softf->ipfr_ttl = IPF_TTLVAL(60);
  194         softf->ipfr_lock = 1;
  195         softf->ipfr_tail = &softf->ipfr_list;
  196         softf->ipfr_nattail = &softf->ipfr_natlist;
  197         softf->ipfr_ipidtail = &softf->ipfr_ipidlist;
  198 
  199         return (softf);
  200 }
  201 
  202 
  203 /* ------------------------------------------------------------------------ */
  204 /* Function:    ipf_frag_soft_destroy                                       */
  205 /* Returns:     Nil                                                         */
  206 /* Parameters:  softc(I) - pointer to soft context main structure           */
  207 /*              arg(I)   - pointer to local context to use                  */
  208 /*                                                                          */
  209 /* Initialise the hash tables for the fragment cache lookups.               */
  210 /* ------------------------------------------------------------------------ */
  211 void
  212 ipf_frag_soft_destroy(ipf_main_softc_t *softc, void *arg)
  213 {
  214         ipf_frag_softc_t *softf = arg;
  215 
  216         RW_DESTROY(&softf->ipfr_ipidfrag);
  217         RW_DESTROY(&softf->ipfr_frag);
  218         RW_DESTROY(&softf->ipfr_natfrag);
  219 
  220         if (softf->ipf_frag_tune != NULL) {
  221                 ipf_tune_array_unlink(softc, softf->ipf_frag_tune);
  222                 KFREES(softf->ipf_frag_tune, sizeof(ipf_frag_tuneables));
  223                 softf->ipf_frag_tune = NULL;
  224         }
  225 
  226         KFREE(softf);
  227 }
  228 
  229 
  230 /* ------------------------------------------------------------------------ */
  231 /* Function:    ipf_frag_soft_init                                          */
  232 /* Returns:     int      - 0 == success, -1 == error                        */
  233 /* Parameters:  softc(I) - pointer to soft context main structure           */
  234 /*              arg(I)   - pointer to local context to use                  */
  235 /*                                                                          */
  236 /* Initialise the hash tables for the fragment cache lookups.               */
  237 /* ------------------------------------------------------------------------ */
  238 /*ARGSUSED*/
  239 int
  240 ipf_frag_soft_init(ipf_main_softc_t *softc, void *arg)
  241 {
  242         ipf_frag_softc_t *softf = arg;
  243 
  244         KMALLOCS(softf->ipfr_heads, ipfr_t **,
  245                  softf->ipfr_size * sizeof(ipfr_t *));
  246         if (softf->ipfr_heads == NULL)
  247                 return (-1);
  248 
  249         bzero((char *)softf->ipfr_heads, softf->ipfr_size * sizeof(ipfr_t *));
  250 
  251         KMALLOCS(softf->ipfr_nattab, ipfr_t **,
  252                  softf->ipfr_size * sizeof(ipfr_t *));
  253         if (softf->ipfr_nattab == NULL)
  254                 return (-2);
  255 
  256         bzero((char *)softf->ipfr_nattab, softf->ipfr_size * sizeof(ipfr_t *));
  257 
  258         KMALLOCS(softf->ipfr_ipidtab, ipfr_t **,
  259                  softf->ipfr_size * sizeof(ipfr_t *));
  260         if (softf->ipfr_ipidtab == NULL)
  261                 return (-3);
  262 
  263         bzero((char *)softf->ipfr_ipidtab,
  264               softf->ipfr_size * sizeof(ipfr_t *));
  265 
  266         softf->ipfr_lock = 0;
  267         softf->ipfr_inited = 1;
  268 
  269         return (0);
  270 }
  271 
  272 
  273 /* ------------------------------------------------------------------------ */
  274 /* Function:    ipf_frag_soft_fini                                          */
  275 /* Returns:     int      - 0 == success, -1 == error                        */
  276 /* Parameters:  softc(I) - pointer to soft context main structure           */
  277 /*              arg(I)   - pointer to local context to use                  */
  278 /*                                                                          */
  279 /* Free all memory allocated whilst running and from initialisation.        */
  280 /* ------------------------------------------------------------------------ */
  281 int
  282 ipf_frag_soft_fini(ipf_main_softc_t *softc, void *arg)
  283 {
  284         ipf_frag_softc_t *softf = arg;
  285 
  286         softf->ipfr_lock = 1;
  287 
  288         if (softf->ipfr_inited == 1) {
  289                 ipf_frag_clear(softc);
  290 
  291                 softf->ipfr_inited = 0;
  292         }
  293 
  294         if (softf->ipfr_heads != NULL)
  295                 KFREES(softf->ipfr_heads,
  296                        softf->ipfr_size * sizeof(ipfr_t *));
  297         softf->ipfr_heads = NULL;
  298 
  299         if (softf->ipfr_nattab != NULL)
  300                 KFREES(softf->ipfr_nattab,
  301                        softf->ipfr_size * sizeof(ipfr_t *));
  302         softf->ipfr_nattab = NULL;
  303 
  304         if (softf->ipfr_ipidtab != NULL)
  305                 KFREES(softf->ipfr_ipidtab,
  306                        softf->ipfr_size * sizeof(ipfr_t *));
  307         softf->ipfr_ipidtab = NULL;
  308 
  309         return (0);
  310 }
  311 
  312 
  313 /* ------------------------------------------------------------------------ */
  314 /* Function:    ipf_frag_set_lock                                           */
  315 /* Returns:     Nil                                                         */
  316 /* Parameters:  arg(I) - pointer to local context to use                    */
  317 /*              tmp(I) - new value for lock                                 */
  318 /*                                                                          */
  319 /* Stub function that allows for external manipulation of ipfr_lock         */
  320 /* ------------------------------------------------------------------------ */
  321 void
  322 ipf_frag_setlock(void *arg, int tmp)
  323 {
  324         ipf_frag_softc_t *softf = arg;
  325 
  326         softf->ipfr_lock = tmp;
  327 }
  328 
  329 
  330 /* ------------------------------------------------------------------------ */
  331 /* Function:    ipf_frag_stats                                              */
  332 /* Returns:     ipfrstat_t* - pointer to struct with current frag stats     */
  333 /* Parameters:  arg(I) - pointer to local context to use                    */
  334 /*                                                                          */
  335 /* Updates ipfr_stats with current information and returns a pointer to it  */
  336 /* ------------------------------------------------------------------------ */
  337 ipfrstat_t *
  338 ipf_frag_stats(void *arg)
  339 {
  340         ipf_frag_softc_t *softf = arg;
  341 
  342         softf->ipfr_stats.ifs_table = softf->ipfr_heads;
  343         softf->ipfr_stats.ifs_nattab = softf->ipfr_nattab;
  344         return (&softf->ipfr_stats);
  345 }
  346 
  347 
  348 /* ------------------------------------------------------------------------ */
  349 /* Function:    ipfr_frag_new                                               */
  350 /* Returns:     ipfr_t * - pointer to fragment cache state info or NULL     */
  351 /* Parameters:  fin(I)   - pointer to packet information                    */
  352 /*              table(I) - pointer to frag table to add to                  */
  353 /*              lock(I)  - pointer to lock to get a write hold of           */
  354 /*                                                                          */
  355 /* Add a new entry to the fragment cache, registering it as having come     */
  356 /* through this box, with the result of the filter operation.               */
  357 /*                                                                          */
  358 /* If this function succeeds, it returns with a write lock held on "lock".  */
  359 /* If it fails, no lock is held on return.                                  */
  360 /* ------------------------------------------------------------------------ */
  361 static ipfr_t *
  362 ipfr_frag_new(ipf_main_softc_t *softc, ipf_frag_softc_t *softf,
  363         fr_info_t *fin, u_32_t pass, ipfr_t *table[]
  364 #ifdef USE_MUTEXES
  365 , ipfrwlock_t *lock
  366 #endif
  367 )
  368 {
  369         ipfr_t *fra, frag, *fran;
  370         u_int idx, off;
  371         frentry_t *fr;
  372 
  373         if (softf->ipfr_stats.ifs_inuse >= softf->ipfr_size) {
  374                 FBUMPD(ifs_maximum);
  375                 return (NULL);
  376         }
  377 
  378         if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) {
  379                 FBUMPD(ifs_newbad);
  380                 return (NULL);
  381         }
  382 
  383         if (pass & FR_FRSTRICT) {
  384                 if (fin->fin_off != 0) {
  385                         FBUMPD(ifs_newrestrictnot0);
  386                         return (NULL);
  387                 }
  388         }
  389 
  390         memset(&frag, 0, sizeof(frag));
  391         frag.ipfr_v = fin->fin_v;
  392         idx = fin->fin_v;
  393         frag.ipfr_p = fin->fin_p;
  394         idx += fin->fin_p;
  395         frag.ipfr_id = fin->fin_id;
  396         idx += fin->fin_id;
  397         frag.ipfr_source = fin->fin_fi.fi_src;
  398         idx += frag.ipfr_src.s_addr;
  399         frag.ipfr_dest = fin->fin_fi.fi_dst;
  400         idx += frag.ipfr_dst.s_addr;
  401         frag.ipfr_ifp = fin->fin_ifp;
  402         idx *= 127;
  403         idx %= softf->ipfr_size;
  404 
  405         frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
  406         frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
  407         frag.ipfr_auth = fin->fin_fi.fi_auth;
  408 
  409         off = fin->fin_off >> 3;
  410         if (off == 0) {
  411                 char *ptr;
  412                 int end;
  413 
  414 #ifdef USE_INET6
  415                 if (fin->fin_v == 6) {
  416 
  417                         ptr = (char *)fin->fin_fraghdr +
  418                               sizeof(struct ip6_frag);
  419                 } else
  420 #endif
  421                 {
  422                         ptr = fin->fin_dp;
  423                 }
  424                 end = fin->fin_plen - (ptr - (char *)fin->fin_ip);
  425                 frag.ipfr_firstend = end >> 3;
  426         } else {
  427                 frag.ipfr_firstend = 0;
  428         }
  429 
  430         /*
  431          * allocate some memory, if possible, if not, just record that we
  432          * failed to do so.
  433          */
  434         KMALLOC(fran, ipfr_t *);
  435         if (fran == NULL) {
  436                 FBUMPD(ifs_nomem);
  437                 return (NULL);
  438         }
  439         memset(fran, 0, sizeof(*fran));
  440 
  441         WRITE_ENTER(lock);
  442 
  443         /*
  444          * first, make sure it isn't already there...
  445          */
  446         for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
  447                 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
  448                           IPFR_CMPSZ)) {
  449                         RWLOCK_EXIT(lock);
  450                         FBUMPD(ifs_exists);
  451                         KFREE(fran);
  452                         return (NULL);
  453                 }
  454 
  455         fra = fran;
  456         fran = NULL;
  457         fr = fin->fin_fr;
  458         fra->ipfr_rule = fr;
  459         if (fr != NULL) {
  460                 MUTEX_ENTER(&fr->fr_lock);
  461                 fr->fr_ref++;
  462                 MUTEX_EXIT(&fr->fr_lock);
  463         }
  464 
  465         /*
  466          * Insert the fragment into the fragment table, copy the struct used
  467          * in the search using bcopy rather than reassign each field.
  468          * Set the ttl to the default.
  469          */
  470         if ((fra->ipfr_hnext = table[idx]) != NULL)
  471                 table[idx]->ipfr_hprev = &fra->ipfr_hnext;
  472         fra->ipfr_hprev = table + idx;
  473         fra->ipfr_data = NULL;
  474         table[idx] = fra;
  475         bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
  476         fra->ipfr_v = fin->fin_v;
  477         fra->ipfr_p = fin->fin_p;
  478         fra->ipfr_ttl = softc->ipf_ticks + softf->ipfr_ttl;
  479         fra->ipfr_firstend = frag.ipfr_firstend;
  480 
  481         /*
  482          * Compute the offset of the expected start of the next packet.
  483          */
  484         if (off == 0)
  485                 fra->ipfr_seen0 = 1;
  486         fra->ipfr_off = off + (fin->fin_dlen >> 3);
  487         fra->ipfr_pass = pass;
  488         fra->ipfr_ref = 1;
  489         fra->ipfr_pkts = 1;
  490         fra->ipfr_bytes = fin->fin_plen;
  491         FBUMP(ifs_inuse);
  492         FBUMP(ifs_new);
  493         return (fra);
  494 }
  495 
  496 
  497 /* ------------------------------------------------------------------------ */
  498 /* Function:    ipf_frag_new                                                */
  499 /* Returns:     int - 0 == success, -1 == error                             */
  500 /* Parameters:  fin(I)  - pointer to packet information                     */
  501 /*                                                                          */
  502 /* Add a new entry to the fragment cache table based on the current packet  */
  503 /* ------------------------------------------------------------------------ */
  504 int
  505 ipf_frag_new(ipf_main_softc_t *softc, fr_info_t *fin, u_32_t pass)
  506 {
  507         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
  508         ipfr_t  *fra;
  509 
  510         if (softf->ipfr_lock != 0)
  511                 return (-1);
  512 
  513 #ifdef USE_MUTEXES
  514         fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads, &softc->ipf_frag);
  515 #else
  516         fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads);
  517 #endif
  518         if (fra != NULL) {
  519                 *softf->ipfr_tail = fra;
  520                 fra->ipfr_prev = softf->ipfr_tail;
  521                 softf->ipfr_tail = &fra->ipfr_next;
  522                 fra->ipfr_next = NULL;
  523                 RWLOCK_EXIT(&softc->ipf_frag);
  524         }
  525         return (fra ? 0 : -1);
  526 }
  527 
  528 
  529 /* ------------------------------------------------------------------------ */
  530 /* Function:    ipf_frag_natnew                                             */
  531 /* Returns:     int - 0 == success, -1 == error                             */
  532 /* Parameters:  fin(I)  - pointer to packet information                     */
  533 /*              nat(I)  - pointer to NAT structure                          */
  534 /*                                                                          */
  535 /* Create a new NAT fragment cache entry based on the current packet and    */
  536 /* the NAT structure for this "session".                                    */
  537 /* ------------------------------------------------------------------------ */
  538 int
  539 ipf_frag_natnew(ipf_main_softc_t *softc, fr_info_t *fin, u_32_t pass,
  540         nat_t *nat)
  541 {
  542         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
  543         ipfr_t  *fra;
  544 
  545         if (softf->ipfr_lock != 0)
  546                 return (0);
  547 
  548 #ifdef USE_MUTEXES
  549         fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab,
  550                             &softf->ipfr_natfrag);
  551 #else
  552         fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab);
  553 #endif
  554         if (fra != NULL) {
  555                 fra->ipfr_data = nat;
  556                 nat->nat_data = fra;
  557                 *softf->ipfr_nattail = fra;
  558                 fra->ipfr_prev = softf->ipfr_nattail;
  559                 softf->ipfr_nattail = &fra->ipfr_next;
  560                 fra->ipfr_next = NULL;
  561                 RWLOCK_EXIT(&softf->ipfr_natfrag);
  562                 return (0);
  563         }
  564         return (-1);
  565 }
  566 
  567 
  568 /* ------------------------------------------------------------------------ */
  569 /* Function:    ipf_frag_ipidnew                                            */
  570 /* Returns:     int - 0 == success, -1 == error                             */
  571 /* Parameters:  fin(I)  - pointer to packet information                     */
  572 /*              ipid(I) - new IP ID for this fragmented packet              */
  573 /*                                                                          */
  574 /* Create a new fragment cache entry for this packet and store, as a data   */
  575 /* pointer, the new IP ID value.                                            */
  576 /* ------------------------------------------------------------------------ */
  577 int
  578 ipf_frag_ipidnew(fr_info_t *fin, u_32_t ipid)
  579 {
  580         ipf_main_softc_t *softc = fin->fin_main_soft;
  581         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
  582         ipfr_t  *fra;
  583 
  584         if (softf->ipfr_lock)
  585                 return (0);
  586 
  587 #ifdef USE_MUTEXES
  588         fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab, &softf->ipfr_ipidfrag);
  589 #else
  590         fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab);
  591 #endif
  592         if (fra != NULL) {
  593                 fra->ipfr_data = (void *)(intptr_t)ipid;
  594                 *softf->ipfr_ipidtail = fra;
  595                 fra->ipfr_prev = softf->ipfr_ipidtail;
  596                 softf->ipfr_ipidtail = &fra->ipfr_next;
  597                 fra->ipfr_next = NULL;
  598                 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
  599         }
  600         return (fra ? 0 : -1);
  601 }
  602 
  603 
  604 /* ------------------------------------------------------------------------ */
  605 /* Function:    ipf_frag_lookup                                             */
  606 /* Returns:     ipfr_t * - pointer to ipfr_t structure if there's a         */
  607 /*                         matching entry in the frag table, else NULL      */
  608 /* Parameters:  fin(I)   - pointer to packet information                    */
  609 /*              table(I) - pointer to fragment cache table to search        */
  610 /*                                                                          */
  611 /* Check the fragment cache to see if there is already a record of this     */
  612 /* packet with its filter result known.                                     */
  613 /*                                                                          */
  614 /* If this function succeeds, it returns with a write lock held on "lock".  */
  615 /* If it fails, no lock is held on return.                                  */
  616 /* ------------------------------------------------------------------------ */
  617 static ipfr_t *
  618 ipf_frag_lookup(ipf_main_softc_t *softc, ipf_frag_softc_t *softf,
  619         fr_info_t *fin, ipfr_t *table[]
  620 #ifdef USE_MUTEXES
  621 , ipfrwlock_t *lock
  622 #endif
  623 )
  624 {
  625         ipfr_t *f, frag;
  626         u_int idx;
  627 
  628         /*
  629          * We don't want to let short packets match because they could be
  630          * compromising the security of other rules that want to match on
  631          * layer 4 fields (and can't because they have been fragmented off.)
  632          * Why do this check here?  The counter acts as an indicator of this
  633          * kind of attack, whereas if it was elsewhere, it wouldn't know if
  634          * other matching packets had been seen.
  635          */
  636         if (fin->fin_flx & FI_SHORT) {
  637                 FBUMPD(ifs_short);
  638                 return (NULL);
  639         }
  640 
  641         if ((fin->fin_flx & FI_BAD) != 0) {
  642                 FBUMPD(ifs_bad);
  643                 return (NULL);
  644         }
  645 
  646         /*
  647          * For fragments, we record protocol, packet id, TOS and both IP#'s
  648          * (these should all be the same for all fragments of a packet).
  649          *
  650          * build up a hash value to index the table with.
  651          */
  652         memset(&frag, 0, sizeof(frag));
  653         frag.ipfr_v = fin->fin_v;
  654         idx = fin->fin_v;
  655         frag.ipfr_p = fin->fin_p;
  656         idx += fin->fin_p;
  657         frag.ipfr_id = fin->fin_id;
  658         idx += fin->fin_id;
  659         frag.ipfr_source = fin->fin_fi.fi_src;
  660         idx += frag.ipfr_src.s_addr;
  661         frag.ipfr_dest = fin->fin_fi.fi_dst;
  662         idx += frag.ipfr_dst.s_addr;
  663         frag.ipfr_ifp = fin->fin_ifp;
  664         idx *= 127;
  665         idx %= softf->ipfr_size;
  666 
  667         frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
  668         frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
  669         frag.ipfr_auth = fin->fin_fi.fi_auth;
  670 
  671         READ_ENTER(lock);
  672 
  673         /*
  674          * check the table, careful to only compare the right amount of data
  675          */
  676         for (f = table[idx]; f; f = f->ipfr_hnext) {
  677                 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
  678                           IPFR_CMPSZ)) {
  679                         u_short off;
  680 
  681                         /*
  682                          * XXX - We really need to be guarding against the
  683                          * retransmission of (src,dst,id,offset-range) here
  684                          * because a fragmented packet is never resent with
  685                          * the same IP ID# (or shouldn't).
  686                          */
  687                         off = fin->fin_off >> 3;
  688                         if (f->ipfr_seen0) {
  689                                 if (off == 0) {
  690                                         FBUMPD(ifs_retrans0);
  691                                         continue;
  692                                 }
  693 
  694                                 /*
  695                                  * Case 3. See comment for frpr_fragment6.
  696                                  */
  697                                 if ((f->ipfr_firstend != 0) &&
  698                                     (off < f->ipfr_firstend)) {
  699                                         FBUMP(ifs_overlap);
  700                                         DT2(ifs_overlap, u_short, off,
  701                                             ipfr_t *, f);
  702                                         DT3(ipf_fi_bad_ifs_overlap, fr_info_t *, fin, u_short, off,
  703                                             ipfr_t *, f);
  704                                         fin->fin_flx |= FI_BAD;
  705                                         break;
  706                                 }
  707                         } else if (off == 0)
  708                                 f->ipfr_seen0 = 1;
  709 
  710                         if (f != table[idx] && MUTEX_TRY_UPGRADE(lock)) {
  711                                 ipfr_t **fp;
  712 
  713                                 /*
  714                                  * Move fragment info. to the top of the list
  715                                  * to speed up searches.  First, delink...
  716                                  */
  717                                 fp = f->ipfr_hprev;
  718                                 (*fp) = f->ipfr_hnext;
  719                                 if (f->ipfr_hnext != NULL)
  720                                         f->ipfr_hnext->ipfr_hprev = fp;
  721                                 /*
  722                                  * Then put back at the top of the chain.
  723                                  */
  724                                 f->ipfr_hnext = table[idx];
  725                                 table[idx]->ipfr_hprev = &f->ipfr_hnext;
  726                                 f->ipfr_hprev = table + idx;
  727                                 table[idx] = f;
  728                                 MUTEX_DOWNGRADE(lock);
  729                         }
  730 
  731                         /*
  732                          * If we've follwed the fragments, and this is the
  733                          * last (in order), shrink expiration time.
  734                          */
  735                         if (off == f->ipfr_off) {
  736                                 f->ipfr_off = (fin->fin_dlen >> 3) + off;
  737 
  738                                 /*
  739                                  * Well, we could shrink the expiration time
  740                                  * but only if every fragment has been seen
  741                                  * in order upto this, the last. ipfr_badorder
  742                                  * is used here to count those out of order
  743                                  * and if it equals 0 when we get to the last
  744                                  * fragment then we can assume all of the
  745                                  * fragments have been seen and in order.
  746                                  */
  747 #if 0
  748                                 /*
  749                                  * Doing this properly requires moving it to
  750                                  * the head of the list which is infesible.
  751                                  */
  752                                 if ((more == 0) && (f->ipfr_badorder == 0))
  753                                         f->ipfr_ttl = softc->ipf_ticks + 1;
  754 #endif
  755                         } else {
  756                                 f->ipfr_badorder++;
  757                                 FBUMPD(ifs_unordered);
  758                                 if (f->ipfr_pass & FR_FRSTRICT) {
  759                                         FBUMPD(ifs_strict);
  760                                         continue;
  761                                 }
  762                         }
  763                         f->ipfr_pkts++;
  764                         f->ipfr_bytes += fin->fin_plen;
  765                         FBUMP(ifs_hits);
  766                         return (f);
  767                 }
  768         }
  769 
  770         RWLOCK_EXIT(lock);
  771         FBUMP(ifs_miss);
  772         return (NULL);
  773 }
  774 
  775 
  776 /* ------------------------------------------------------------------------ */
  777 /* Function:    ipf_frag_natknown                                           */
  778 /* Returns:     nat_t* - pointer to 'parent' NAT structure if frag table    */
  779 /*                       match found, else NULL                             */
  780 /* Parameters:  fin(I)  - pointer to packet information                     */
  781 /*                                                                          */
  782 /* Functional interface for NAT lookups of the NAT fragment cache           */
  783 /* ------------------------------------------------------------------------ */
  784 nat_t *
  785 ipf_frag_natknown(fr_info_t *fin)
  786 {
  787         ipf_main_softc_t *softc = fin->fin_main_soft;
  788         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
  789         nat_t   *nat;
  790         ipfr_t  *ipf;
  791 
  792         if ((softf->ipfr_lock) || !softf->ipfr_natlist)
  793                 return (NULL);
  794 #ifdef USE_MUTEXES
  795         ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab,
  796                               &softf->ipfr_natfrag);
  797 #else
  798         ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab);
  799 #endif
  800         if (ipf != NULL) {
  801                 nat = ipf->ipfr_data;
  802                 /*
  803                  * This is the last fragment for this packet.
  804                  */
  805                 if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) {
  806                         nat->nat_data = NULL;
  807                         ipf->ipfr_data = NULL;
  808                 }
  809                 RWLOCK_EXIT(&softf->ipfr_natfrag);
  810         } else
  811                 nat = NULL;
  812         return (nat);
  813 }
  814 
  815 
  816 /* ------------------------------------------------------------------------ */
  817 /* Function:    ipf_frag_ipidknown                                          */
  818 /* Returns:     u_32_t - IPv4 ID for this packet if match found, else       */
  819 /*                       return 0xfffffff to indicate no match.             */
  820 /* Parameters:  fin(I) - pointer to packet information                      */
  821 /*                                                                          */
  822 /* Functional interface for IP ID lookups of the IP ID fragment cache       */
  823 /* ------------------------------------------------------------------------ */
  824 u_32_t
  825 ipf_frag_ipidknown(fr_info_t *fin)
  826 {
  827         ipf_main_softc_t *softc = fin->fin_main_soft;
  828         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
  829         ipfr_t  *ipf;
  830         u_32_t  id;
  831 
  832         if (softf->ipfr_lock || !softf->ipfr_ipidlist)
  833                 return (0xffffffff);
  834 
  835 #ifdef USE_MUTEXES
  836         ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab,
  837                               &softf->ipfr_ipidfrag);
  838 #else
  839         ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab);
  840 #endif
  841         if (ipf != NULL) {
  842                 id = (u_32_t)(intptr_t)ipf->ipfr_data;
  843                 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
  844         } else
  845                 id = 0xffffffff;
  846         return (id);
  847 }
  848 
  849 
  850 /* ------------------------------------------------------------------------ */
  851 /* Function:    ipf_frag_known                                              */
  852 /* Returns:     frentry_t* - pointer to filter rule if a match is found in  */
  853 /*                           the frag cache table, else NULL.               */
  854 /* Parameters:  fin(I)   - pointer to packet information                    */
  855 /*              passp(O) - pointer to where to store rule flags resturned   */
  856 /*                                                                          */
  857 /* Functional interface for normal lookups of the fragment cache.  If a     */
  858 /* match is found, return the rule pointer and flags from the rule, except  */
  859 /* that if FR_LOGFIRST is set, reset FR_LOG.                                */
  860 /* ------------------------------------------------------------------------ */
  861 frentry_t *
  862 ipf_frag_known(fr_info_t *fin, u_32_t *passp)
  863 {
  864         ipf_main_softc_t *softc = fin->fin_main_soft;
  865         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
  866         frentry_t *fr = NULL;
  867         ipfr_t  *fra;
  868         u_32_t pass;
  869 
  870         if ((softf->ipfr_lock) || (softf->ipfr_list == NULL))
  871                 return (NULL);
  872 
  873 #ifdef USE_MUTEXES
  874         fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads,
  875                               &softc->ipf_frag);
  876 #else
  877         fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads);
  878 #endif
  879         if (fra != NULL) {
  880                 if (fin->fin_flx & FI_BAD) {
  881                         fr = &ipfr_block;
  882                         fin->fin_reason = FRB_BADFRAG;
  883                         DT2(ipf_frb_badfrag, fr_info_t *, fin, uint, fra);
  884                 } else {
  885                         fr = fra->ipfr_rule;
  886                 }
  887                 fin->fin_fr = fr;
  888                 if (fr != NULL) {
  889                         pass = fr->fr_flags;
  890                         if ((pass & FR_KEEPSTATE) != 0) {
  891                                 fin->fin_flx |= FI_STATE;
  892                                 /*
  893                                  * Reset the keep state flag here so that we
  894                                  * don't try and add a new state entry because
  895                                  * of a match here. That leads to blocking of
  896                                  * the packet later because the add fails.
  897                                  */
  898                                 pass &= ~FR_KEEPSTATE;
  899                         }
  900                         if ((pass & FR_LOGFIRST) != 0)
  901                                 pass &= ~(FR_LOGFIRST|FR_LOG);
  902                         *passp = pass;
  903                 }
  904                 RWLOCK_EXIT(&softc->ipf_frag);
  905         }
  906         return (fr);
  907 }
  908 
  909 
  910 /* ------------------------------------------------------------------------ */
  911 /* Function:    ipf_frag_natforget                                          */
  912 /* Returns:     Nil                                                         */
  913 /* Parameters:  softc(I) - pointer to soft context main structure           */
  914 /*              ptr(I) - pointer to data structure                          */
  915 /*                                                                          */
  916 /* Search through all of the fragment cache entries for NAT and wherever a  */
  917 /* pointer  is found to match ptr, reset it to NULL.                        */
  918 /* ------------------------------------------------------------------------ */
  919 void
  920 ipf_frag_natforget(ipf_main_softc_t *softc, void *ptr)
  921 {
  922         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
  923         ipfr_t  *fr;
  924 
  925         WRITE_ENTER(&softf->ipfr_natfrag);
  926         for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next)
  927                 if (fr->ipfr_data == ptr)
  928                         fr->ipfr_data = NULL;
  929         RWLOCK_EXIT(&softf->ipfr_natfrag);
  930 }
  931 
  932 
  933 /* ------------------------------------------------------------------------ */
  934 /* Function:    ipf_frag_delete                                             */
  935 /* Returns:     Nil                                                         */
  936 /* Parameters:  softc(I) - pointer to soft context main structure           */
  937 /*              fra(I)   - pointer to fragment structure to delete          */
  938 /*              tail(IO) - pointer to the pointer to the tail of the frag   */
  939 /*                         list                                             */
  940 /*                                                                          */
  941 /* Remove a fragment cache table entry from the table & list.  Also free    */
  942 /* the filter rule it is associated with it if it is no longer used as a    */
  943 /* result of decreasing the reference count.                                */
  944 /* ------------------------------------------------------------------------ */
  945 static void
  946 ipf_frag_delete(ipf_main_softc_t *softc, ipfr_t *fra, ipfr_t ***tail)
  947 {
  948         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
  949 
  950         if (fra->ipfr_next)
  951                 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
  952         *fra->ipfr_prev = fra->ipfr_next;
  953         if (*tail == &fra->ipfr_next)
  954                 *tail = fra->ipfr_prev;
  955 
  956         if (fra->ipfr_hnext)
  957                 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
  958         *fra->ipfr_hprev = fra->ipfr_hnext;
  959 
  960         if (fra->ipfr_rule != NULL) {
  961                 (void) ipf_derefrule(softc, &fra->ipfr_rule);
  962         }
  963 
  964         if (fra->ipfr_ref <= 0)
  965                 ipf_frag_free(softf, fra);
  966 }
  967 
  968 
  969 /* ------------------------------------------------------------------------ */
  970 /* Function:    ipf_frag_free                                               */
  971 /* Returns:     Nil                                                         */
  972 /* Parameters:  softf(I) - pointer to fragment context information          */
  973 /*              fra(I)   - pointer to fragment structure to free            */
  974 /*                                                                          */
  975 /* Free up a fragment cache entry and bump relevent statistics.             */
  976 /* ------------------------------------------------------------------------ */
  977 static void
  978 ipf_frag_free(ipf_frag_softc_t *softf, ipfr_t *fra)
  979 {
  980         KFREE(fra);
  981         FBUMP(ifs_expire);
  982         softf->ipfr_stats.ifs_inuse--;
  983 }
  984 
  985 
  986 /* ------------------------------------------------------------------------ */
  987 /* Function:    ipf_frag_clear                                              */
  988 /* Returns:     Nil                                                         */
  989 /* Parameters:  softc(I) - pointer to soft context main structure           */
  990 /*                                                                          */
  991 /* Free memory in use by fragment state information kept.  Do the normal    */
  992 /* fragment state stuff first and then the NAT-fragment table.              */
  993 /* ------------------------------------------------------------------------ */
  994 void
  995 ipf_frag_clear(ipf_main_softc_t *softc)
  996 {
  997         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
  998         ipfr_t  *fra;
  999         nat_t   *nat;
 1000 
 1001         WRITE_ENTER(&softc->ipf_frag);
 1002         while ((fra = softf->ipfr_list) != NULL) {
 1003                 fra->ipfr_ref--;
 1004                 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
 1005         }
 1006         softf->ipfr_tail = &softf->ipfr_list;
 1007         RWLOCK_EXIT(&softc->ipf_frag);
 1008 
 1009         WRITE_ENTER(&softc->ipf_nat);
 1010         WRITE_ENTER(&softf->ipfr_natfrag);
 1011         while ((fra = softf->ipfr_natlist) != NULL) {
 1012                 nat = fra->ipfr_data;
 1013                 if (nat != NULL) {
 1014                         if (nat->nat_data == fra)
 1015                                 nat->nat_data = NULL;
 1016                 }
 1017                 fra->ipfr_ref--;
 1018                 ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
 1019         }
 1020         softf->ipfr_nattail = &softf->ipfr_natlist;
 1021         RWLOCK_EXIT(&softf->ipfr_natfrag);
 1022         RWLOCK_EXIT(&softc->ipf_nat);
 1023 }
 1024 
 1025 
 1026 /* ------------------------------------------------------------------------ */
 1027 /* Function:    ipf_frag_expire                                             */
 1028 /* Returns:     Nil                                                         */
 1029 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1030 /*                                                                          */
 1031 /* Expire entries in the fragment cache table that have been there too long */
 1032 /* ------------------------------------------------------------------------ */
 1033 void
 1034 ipf_frag_expire(ipf_main_softc_t *softc)
 1035 {
 1036         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 1037         ipfr_t  **fp, *fra;
 1038         nat_t   *nat;
 1039         SPL_INT(s);
 1040 
 1041         if (softf->ipfr_lock)
 1042                 return;
 1043 
 1044         SPL_NET(s);
 1045         WRITE_ENTER(&softc->ipf_frag);
 1046         /*
 1047          * Go through the entire table, looking for entries to expire,
 1048          * which is indicated by the ttl being less than or equal to ipf_ticks.
 1049          */
 1050         for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) {
 1051                 if (fra->ipfr_ttl > softc->ipf_ticks)
 1052                         break;
 1053                 fra->ipfr_ref--;
 1054                 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
 1055         }
 1056         RWLOCK_EXIT(&softc->ipf_frag);
 1057 
 1058         WRITE_ENTER(&softf->ipfr_ipidfrag);
 1059         for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) {
 1060                 if (fra->ipfr_ttl > softc->ipf_ticks)
 1061                         break;
 1062                 fra->ipfr_ref--;
 1063                 ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail);
 1064         }
 1065         RWLOCK_EXIT(&softf->ipfr_ipidfrag);
 1066 
 1067         /*
 1068          * Same again for the NAT table, except that if the structure also
 1069          * still points to a NAT structure, and the NAT structure points back
 1070          * at the one to be free'd, NULL the reference from the NAT struct.
 1071          * NOTE: We need to grab both mutex's early, and in this order so as
 1072          * to prevent a deadlock if both try to expire at the same time.
 1073          * The extra if() statement here is because it locks out all NAT
 1074          * operations - no need to do that if there are no entries in this
 1075          * list, right?
 1076          */
 1077         if (softf->ipfr_natlist != NULL) {
 1078                 WRITE_ENTER(&softc->ipf_nat);
 1079                 WRITE_ENTER(&softf->ipfr_natfrag);
 1080                 for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) {
 1081                         if (fra->ipfr_ttl > softc->ipf_ticks)
 1082                                 break;
 1083                         nat = fra->ipfr_data;
 1084                         if (nat != NULL) {
 1085                                 if (nat->nat_data == fra)
 1086                                         nat->nat_data = NULL;
 1087                         }
 1088                         fra->ipfr_ref--;
 1089                         ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
 1090                 }
 1091                 RWLOCK_EXIT(&softf->ipfr_natfrag);
 1092                 RWLOCK_EXIT(&softc->ipf_nat);
 1093         }
 1094         SPL_X(s);
 1095 }
 1096 
 1097 
 1098 /* ------------------------------------------------------------------------ */
 1099 /* Function:    ipf_frag_pkt_next                                           */
 1100 /* Returns:     int      - 0 == success, else error                         */
 1101 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1102 /*              token(I) - pointer to token information for this caller     */
 1103 /*              itp(I)   - pointer to generic iterator from caller          */
 1104 /*                                                                          */
 1105 /* This function is used to step through the fragment cache list used for   */
 1106 /* filter rules. The hard work is done by the more generic ipf_frag_next.   */
 1107 /* ------------------------------------------------------------------------ */
 1108 int
 1109 ipf_frag_pkt_next(ipf_main_softc_t *softc, ipftoken_t *token,
 1110         ipfgeniter_t *itp)
 1111 {
 1112         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 1113 
 1114 #ifdef USE_MUTEXES
 1115         return (ipf_frag_next(softc, token, itp, &softf->ipfr_list,
 1116                              &softf->ipfr_frag));
 1117 #else
 1118         return (ipf_frag_next(softc, token, itp, &softf->ipfr_list));
 1119 #endif
 1120 }
 1121 
 1122 
 1123 /* ------------------------------------------------------------------------ */
 1124 /* Function:    ipf_frag_nat_next                                           */
 1125 /* Returns:     int      - 0 == success, else error                         */
 1126 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1127 /*              token(I) - pointer to token information for this caller     */
 1128 /*              itp(I)   - pointer to generic iterator from caller          */
 1129 /*                                                                          */
 1130 /* This function is used to step through the fragment cache list used for   */
 1131 /* NAT. The hard work is done by the more generic ipf_frag_next.            */
 1132 /* ------------------------------------------------------------------------ */
 1133 int
 1134 ipf_frag_nat_next(ipf_main_softc_t *softc, ipftoken_t *token,
 1135         ipfgeniter_t *itp)
 1136 {
 1137         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 1138 
 1139 #ifdef USE_MUTEXES
 1140         return (ipf_frag_next(softc, token, itp, &softf->ipfr_natlist,
 1141                              &softf->ipfr_natfrag));
 1142 #else
 1143         return (ipf_frag_next(softc, token, itp, &softf->ipfr_natlist));
 1144 #endif
 1145 }
 1146 
 1147 /* ------------------------------------------------------------------------ */
 1148 /* Function:    ipf_frag_next                                               */
 1149 /* Returns:     int      - 0 == success, else error                         */
 1150 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1151 /*              token(I) - pointer to token information for this caller     */
 1152 /*              itp(I)   - pointer to generic iterator from caller          */
 1153 /*              top(I)   - top of the fragment list                         */
 1154 /*              lock(I)  - fragment cache lock                              */
 1155 /*                                                                          */
 1156 /* This function is used to interate through the list of entries in the     */
 1157 /* fragment cache.  It increases the reference count on the one currently   */
 1158 /* being returned so that the caller can come back and resume from it later.*/
 1159 /*                                                                          */
 1160 /* This function is used for both the NAT fragment cache as well as the ipf */
 1161 /* fragment cache - hence the reason for passing in top and lock.           */
 1162 /* ------------------------------------------------------------------------ */
 1163 static int
 1164 ipf_frag_next(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp,
 1165         ipfr_t **top
 1166 #ifdef USE_MUTEXES
 1167 , ipfrwlock_t *lock
 1168 #endif
 1169 )
 1170 {
 1171         ipfr_t *frag, *next, zero;
 1172         int error = 0;
 1173 
 1174         if (itp->igi_data == NULL) {
 1175                 IPFERROR(20001);
 1176                 return (EFAULT);
 1177         }
 1178 
 1179         if (itp->igi_nitems != 1) {
 1180                 IPFERROR(20003);
 1181                 return (EFAULT);
 1182         }
 1183 
 1184         frag = token->ipt_data;
 1185 
 1186         READ_ENTER(lock);
 1187 
 1188         if (frag == NULL)
 1189                 next = *top;
 1190         else
 1191                 next = frag->ipfr_next;
 1192 
 1193         if (next != NULL) {
 1194                 ATOMIC_INC(next->ipfr_ref);
 1195                 token->ipt_data = next;
 1196         } else {
 1197                 bzero(&zero, sizeof(zero));
 1198                 next = &zero;
 1199                 token->ipt_data = NULL;
 1200         }
 1201         if (next->ipfr_next == NULL)
 1202                 ipf_token_mark_complete(token);
 1203 
 1204         RWLOCK_EXIT(lock);
 1205 
 1206         error = COPYOUT(next, itp->igi_data, sizeof(*next));
 1207         if (error != 0)
 1208                 IPFERROR(20002);
 1209 
 1210         if (frag != NULL) {
 1211 #ifdef USE_MUTEXES
 1212                 ipf_frag_deref(softc, &frag, lock);
 1213 #else
 1214                 ipf_frag_deref(softc, &frag);
 1215 #endif
 1216         }
 1217         return (error);
 1218 }
 1219 
 1220 
 1221 /* ------------------------------------------------------------------------ */
 1222 /* Function:    ipf_frag_pkt_deref                                          */
 1223 /* Returns:     Nil                                                         */
 1224 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1225 /*              data(I)  - pointer to frag cache pointer                    */
 1226 /*                                                                          */
 1227 /* This function is the external interface for dropping a reference to a    */
 1228 /* fragment cache entry used by filter rules.                               */
 1229 /* ------------------------------------------------------------------------ */
 1230 void
 1231 ipf_frag_pkt_deref(ipf_main_softc_t *softc, void *data)
 1232 {
 1233         ipfr_t **frp = data;
 1234 
 1235 #ifdef USE_MUTEXES
 1236         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 1237 
 1238         ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag);
 1239 #else
 1240         ipf_frag_deref(softc->ipf_frag_soft, frp);
 1241 #endif
 1242 }
 1243 
 1244 
 1245 /* ------------------------------------------------------------------------ */
 1246 /* Function:    ipf_frag_nat_deref                                          */
 1247 /* Returns:     Nil                                                         */
 1248 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1249 /*              data(I)  - pointer to frag cache pointer                    */
 1250 /*                                                                          */
 1251 /* This function is the external interface for dropping a reference to a    */
 1252 /* fragment cache entry used by NAT table entries.                          */
 1253 /* ------------------------------------------------------------------------ */
 1254 void
 1255 ipf_frag_nat_deref(ipf_main_softc_t *softc, void *data)
 1256 {
 1257         ipfr_t **frp = data;
 1258 
 1259 #ifdef USE_MUTEXES
 1260         ipf_frag_softc_t *softf = softc->ipf_frag_soft;
 1261 
 1262         ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag);
 1263 #else
 1264         ipf_frag_deref(softc->ipf_frag_soft, frp);
 1265 #endif
 1266 }
 1267 
 1268 
 1269 /* ------------------------------------------------------------------------ */
 1270 /* Function:    ipf_frag_deref                                              */
 1271 /* Returns:     Nil                                                         */
 1272 /* Parameters:  frp(IO) - pointer to fragment structure to deference        */
 1273 /*              lock(I) - lock associated with the fragment                 */
 1274 /*                                                                          */
 1275 /* This function dereferences a fragment structure (ipfr_t).  The pointer   */
 1276 /* passed in will always be reset back to NULL, even if the structure is    */
 1277 /* not freed, to enforce the notion that the caller is no longer entitled   */
 1278 /* to use the pointer it is dropping the reference to.                      */
 1279 /* ------------------------------------------------------------------------ */
 1280 static void
 1281 ipf_frag_deref(void *arg, ipfr_t **frp
 1282 #ifdef USE_MUTEXES
 1283 , ipfrwlock_t *lock
 1284 #endif
 1285 )
 1286 {
 1287         ipf_frag_softc_t *softf = arg;
 1288         ipfr_t *fra;
 1289 
 1290         fra = *frp;
 1291         *frp = NULL;
 1292 
 1293         WRITE_ENTER(lock);
 1294         fra->ipfr_ref--;
 1295         if (fra->ipfr_ref <= 0)
 1296                 ipf_frag_free(softf, fra);
 1297         RWLOCK_EXIT(lock);
 1298 }

Cache object: 573e32022fa73e2453e98df480f34b84


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