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/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 /*      $NetBSD: ip_frag.c,v 1.36 2004/03/28 12:12:28 martin Exp $      */
    2 
    3 /*
    4  * Copyright (C) 1993-2003 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 #ifdef __hpux
   20 # include <sys/timeout.h>
   21 #endif
   22 #if !defined(_KERNEL)
   23 # include <stdio.h>
   24 # include <string.h>
   25 # include <stdlib.h>
   26 # define _KERNEL
   27 # ifdef __OpenBSD__
   28 struct file;
   29 # endif
   30 # include <sys/uio.h>
   31 # undef _KERNEL
   32 #endif
   33 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
   34 # include <sys/filio.h>
   35 # include <sys/fcntl.h>
   36 #else
   37 # include <sys/ioctl.h>
   38 #endif
   39 #if !defined(linux)
   40 # include <sys/protosw.h>
   41 #endif
   42 #include <sys/socket.h>
   43 #if defined(_KERNEL)
   44 # include <sys/systm.h>
   45 # if !defined(__SVR4) && !defined(__svr4__)
   46 #  include <sys/mbuf.h>
   47 # endif
   48 #endif
   49 #if !defined(__SVR4) && !defined(__svr4__)
   50 # if defined(_KERNEL) && !defined(__sgi)
   51 #  include <sys/kernel.h>
   52 # endif
   53 #else
   54 # include <sys/byteorder.h>
   55 # ifdef _KERNEL
   56 #  include <sys/dditypes.h>
   57 # endif
   58 # include <sys/stream.h>
   59 # include <sys/kmem.h>
   60 #endif
   61 #include <net/if.h>
   62 #ifdef sun
   63 # include <net/af.h>
   64 #endif
   65 #include <net/route.h>
   66 #include <netinet/in.h>
   67 #include <netinet/in_systm.h>
   68 #include <netinet/ip.h>
   69 #if !defined(linux)
   70 # include <netinet/ip_var.h>
   71 #endif
   72 #include <netinet/tcp.h>
   73 #include <netinet/udp.h>
   74 #include <netinet/ip_icmp.h>
   75 #include "netinet/ip_compat.h"
   76 #include <netinet/tcpip.h>
   77 #include "netinet/ip_fil.h"
   78 #include "netinet/ip_nat.h"
   79 #include "netinet/ip_frag.h"
   80 #include "netinet/ip_state.h"
   81 #include "netinet/ip_auth.h"
   82 #include "netinet/ip_proxy.h"
   83 #if (__FreeBSD_version >= 300000)
   84 # include <sys/malloc.h>
   85 # if defined(_KERNEL)
   86 #  ifndef IPFILTER_LKM
   87 #   include <sys/libkern.h>
   88 #   include <sys/systm.h>
   89 #  endif
   90 extern struct callout_handle fr_slowtimer_ch;
   91 # endif
   92 #endif
   93 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
   94 # include <sys/callout.h>
   95 extern struct callout fr_slowtimer_ch;
   96 #endif
   97 #if defined(__OpenBSD__)
   98 # include <sys/timeout.h>
   99 extern struct timeout fr_slowtimer_ch;
  100 #endif
  101 /* END OF INCLUDES */
  102 
  103 #if !defined(lint)
  104 #if defined(__NetBSD__)
  105 #include <sys/cdefs.h>
  106 __KERNEL_RCSID(0, "$NetBSD: ip_frag.c,v 1.36 2004/03/28 12:12:28 martin Exp $");
  107 #else
  108 static const char sccsid[] = "@(#)ip_frag.c     1.11 3/24/96 (C) 1993-2000 Darren Reed";
  109 static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77 2004/01/27 00:24:54 darrenr Exp";
  110 #endif
  111 #endif
  112 
  113 
  114 static ipfr_t   *ipfr_list = NULL;
  115 static ipfr_t   **ipfr_tail = &ipfr_list;
  116 static ipfr_t   **ipfr_heads;
  117 
  118 static ipfr_t   *ipfr_natlist = NULL;
  119 static ipfr_t   **ipfr_nattail = &ipfr_natlist;
  120 static ipfr_t   **ipfr_nattab;
  121 
  122 static ipfr_t   *ipfr_ipidlist = NULL;
  123 static ipfr_t   **ipfr_ipidtail = &ipfr_ipidlist;
  124 static ipfr_t   **ipfr_ipidtab;
  125 
  126 static ipfrstat_t ipfr_stats;
  127 static int      ipfr_inuse = 0;
  128 int             ipfr_size = IPFT_SIZE;
  129 
  130 int     fr_ipfrttl = 120;       /* 60 seconds */
  131 int     fr_frag_lock = 0;
  132 int     fr_frag_init = 0;
  133 u_long  fr_ticks = 0;
  134 
  135 
  136 static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **));
  137 static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **));
  138 static void fr_fragdelete __P((ipfr_t *, ipfr_t ***));
  139 
  140 
  141 /* ------------------------------------------------------------------------ */
  142 /* Function:    fr_fraginit                                                 */
  143 /* Returns:     int - 0 == success, -1 == error                             */
  144 /* Parameters:  Nil                                                         */
  145 /*                                                                          */
  146 /* Initialise the hash tables for the fragment cache lookups.               */
  147 /* ------------------------------------------------------------------------ */
  148 int fr_fraginit()
  149 {
  150         KMALLOCS(ipfr_heads, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
  151         if (ipfr_heads == NULL)
  152                 return -1;
  153         bzero((char *)ipfr_heads, ipfr_size * sizeof(ipfr_t *));
  154 
  155         KMALLOCS(ipfr_nattab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
  156         if (ipfr_nattab == NULL)
  157                 return -1;
  158         bzero((char *)ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
  159 
  160         KMALLOCS(ipfr_ipidtab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
  161         if (ipfr_ipidtab == NULL)
  162                 return -1;
  163         bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
  164 
  165         RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock");
  166         fr_frag_init = 1;
  167 
  168         return 0;
  169 }
  170 
  171 
  172 /* ------------------------------------------------------------------------ */
  173 /* Function:    fr_fragunload                                               */
  174 /* Returns:     Nil                                                         */
  175 /* Parameters:  Nil                                                         */
  176 /*                                                                          */
  177 /* Free all memory allocated whilst running and from initialisation.        */
  178 /* ------------------------------------------------------------------------ */
  179 void fr_fragunload()
  180 {
  181         if (fr_frag_init == 1) {
  182                 fr_fragclear();
  183 
  184                 RW_DESTROY(&ipf_frag);
  185                 fr_frag_init = 0;
  186         }
  187 
  188         if (ipfr_heads != NULL)
  189                 KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *));
  190         ipfr_heads = NULL;
  191 
  192         if (ipfr_nattab != NULL)
  193                 KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
  194         ipfr_nattab = NULL;
  195 
  196         if (ipfr_ipidtab != NULL)
  197                 KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
  198         ipfr_ipidtab = NULL;
  199 }
  200 
  201 
  202 /* ------------------------------------------------------------------------ */
  203 /* Function:    fr_fragstats                                                */
  204 /* Returns:     ipfrstat_t* - pointer to struct with current frag stats     */
  205 /* Parameters:  Nil                                                         */
  206 /*                                                                          */
  207 /* Updates ipfr_stats with current information and returns a pointer to it  */
  208 /* ------------------------------------------------------------------------ */
  209 ipfrstat_t *fr_fragstats()
  210 {
  211         ipfr_stats.ifs_table = ipfr_heads;
  212         ipfr_stats.ifs_nattab = ipfr_nattab;
  213         ipfr_stats.ifs_inuse = ipfr_inuse;
  214         return &ipfr_stats;
  215 }
  216 
  217 
  218 /* ------------------------------------------------------------------------ */
  219 /* Function:    ipfr_newfrag                                                */
  220 /* Returns:     ipfr_t * - pointer to fragment cache state info or NULL     */
  221 /* Parameters:  fin(I)   - pointer to packet information                    */
  222 /*              table(I) - pointer to frag table to add to                  */
  223 /*                                                                          */
  224 /* Add a new entry to the fragment cache, registering it as having come     */
  225 /* through this box, with the result of the filter operation.               */
  226 /* ------------------------------------------------------------------------ */
  227 static ipfr_t *ipfr_newfrag(fin, pass, table)
  228 fr_info_t *fin;
  229 u_32_t pass;
  230 ipfr_t *table[];
  231 {
  232         ipfr_t *fra, frag;
  233         u_int idx, off;
  234         ip_t *ip;
  235 
  236         if (ipfr_inuse >= IPFT_SIZE)
  237                 return NULL;
  238 
  239         if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
  240                 return NULL;
  241 
  242         ip = fin->fin_ip;
  243 
  244         if (pass & FR_FRSTRICT)
  245                 if ((ip->ip_off & IP_OFFMASK) != 0)
  246                         return NULL;
  247 
  248         frag.ipfr_p = ip->ip_p;
  249         idx = ip->ip_p;
  250         frag.ipfr_id = ip->ip_id;
  251         idx += ip->ip_id;
  252         frag.ipfr_tos = ip->ip_tos;
  253         frag.ipfr_src.s_addr = ip->ip_src.s_addr;
  254         idx += ip->ip_src.s_addr;
  255         frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
  256         idx += ip->ip_dst.s_addr;
  257         frag.ipfr_ifp = fin->fin_ifp;
  258         idx *= 127;
  259         idx %= IPFT_SIZE;
  260 
  261         frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
  262         frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
  263         frag.ipfr_auth = fin->fin_fi.fi_auth;
  264 
  265         /*
  266          * first, make sure it isn't already there...
  267          */
  268         for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
  269                 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
  270                           IPFR_CMPSZ)) {
  271                         ipfr_stats.ifs_exists++;
  272                         return NULL;
  273                 }
  274 
  275         /*
  276          * allocate some memory, if possible, if not, just record that we
  277          * failed to do so.
  278          */
  279         KMALLOC(fra, ipfr_t *);
  280         if (fra == NULL) {
  281                 ipfr_stats.ifs_nomem++;
  282                 return NULL;
  283         }
  284 
  285         if ((fra->ipfr_rule = fin->fin_fr) != NULL)
  286                 fin->fin_fr->fr_ref++;
  287 
  288         /*
  289          * Insert the fragment into the fragment table, copy the struct used
  290          * in the search using bcopy rather than reassign each field.
  291          * Set the ttl to the default.
  292          */
  293         if ((fra->ipfr_hnext = table[idx]) != NULL)
  294                 table[idx]->ipfr_hprev = &fra->ipfr_hnext;
  295         fra->ipfr_hprev = table + idx;
  296         fra->ipfr_data = NULL;
  297         table[idx] = fra;
  298         bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
  299         fra->ipfr_ttl = fr_ticks + fr_ipfrttl;
  300 
  301         /*
  302          * Compute the offset of the expected start of the next packet.
  303          */
  304         off = ip->ip_off & IP_OFFMASK;
  305         if (off == 0)
  306                 fra->ipfr_seen0 = 1;
  307         fra->ipfr_off = off + (fin->fin_dlen >> 3);
  308         fra->ipfr_pass = pass;
  309         ipfr_stats.ifs_new++;
  310         ipfr_inuse++;
  311         return fra;
  312 }
  313 
  314 
  315 /* ------------------------------------------------------------------------ */
  316 /* Function:    fr_newfrag                                                  */
  317 /* Returns:     int - 0 == success, -1 == error                             */
  318 /* Parameters:  fin(I)  - pointer to packet information                     */
  319 /*                                                                          */
  320 /* Add a new entry to the fragment cache table based on the current packet  */
  321 /* ------------------------------------------------------------------------ */
  322 int fr_newfrag(fin, pass)
  323 u_32_t pass;
  324 fr_info_t *fin;
  325 {
  326         ipfr_t  *fra;
  327 
  328         if ((fin->fin_v != 4) || (fr_frag_lock != 0))
  329                 return -1;
  330 
  331         WRITE_ENTER(&ipf_frag);
  332         fra = ipfr_newfrag(fin, pass, ipfr_heads);
  333         if (fra != NULL) {
  334                 *ipfr_tail = fra;
  335                 fra->ipfr_prev = ipfr_tail;
  336                 ipfr_tail = &fra->ipfr_next;
  337                 if (ipfr_list == NULL)
  338                         ipfr_list = fra;
  339                 fra->ipfr_next = NULL;
  340         }
  341         RWLOCK_EXIT(&ipf_frag);
  342         return fra ? 0 : -1;
  343 }
  344 
  345 
  346 /* ------------------------------------------------------------------------ */
  347 /* Function:    fr_nat_newfrag                                              */
  348 /* Returns:     int - 0 == success, -1 == error                             */
  349 /* Parameters:  fin(I)  - pointer to packet information                     */
  350 /*              nat(I)  - pointer to NAT structure                          */
  351 /*                                                                          */
  352 /* Create a new NAT fragment cache entry based on the current packet and    */
  353 /* the NAT structure for this "session".                                    */
  354 /* ------------------------------------------------------------------------ */
  355 int fr_nat_newfrag(fin, pass, nat)
  356 fr_info_t *fin;
  357 u_32_t pass;
  358 nat_t *nat;
  359 {
  360         ipfr_t  *fra;
  361 
  362         if ((fin->fin_v != 4) || (fr_frag_lock != 0))
  363                 return 0;
  364 
  365         WRITE_ENTER(&ipf_natfrag);
  366         fra = ipfr_newfrag(fin, pass, ipfr_nattab);
  367         if (fra != NULL) {
  368                 fra->ipfr_data = nat;
  369                 nat->nat_data = fra;
  370                 *ipfr_nattail = fra;
  371                 fra->ipfr_prev = ipfr_nattail;
  372                 ipfr_nattail = &fra->ipfr_next;
  373                 fra->ipfr_next = NULL;
  374         }
  375         RWLOCK_EXIT(&ipf_natfrag);
  376         return fra ? 0 : -1;
  377 }
  378 
  379 
  380 /* ------------------------------------------------------------------------ */
  381 /* Function:    fr_ipid_newfrag                                             */
  382 /* Returns:     int - 0 == success, -1 == error                             */
  383 /* Parameters:  fin(I)  - pointer to packet information                     */
  384 /*              ipid(I) - new IP ID for this fragmented packet              */
  385 /*                                                                          */
  386 /* Create a new fragment cache entry for this packet and store, as a data   */
  387 /* pointer, the new IP ID value.                                            */
  388 /* ------------------------------------------------------------------------ */
  389 int fr_ipid_newfrag(fin, ipid)
  390 fr_info_t *fin;
  391 u_32_t ipid;
  392 {
  393         ipfr_t  *fra;
  394 
  395         if ((fin->fin_v != 4) || (fr_frag_lock))
  396                 return 0;
  397 
  398         WRITE_ENTER(&ipf_ipidfrag);
  399         fra = ipfr_newfrag(fin, 0, ipfr_ipidtab);
  400         if (fra != NULL) {
  401                 fra->ipfr_data = (void *)(intptr_t)ipid;
  402                 *ipfr_ipidtail = fra;
  403                 fra->ipfr_prev = ipfr_ipidtail;
  404                 ipfr_ipidtail = &fra->ipfr_next;
  405                 fra->ipfr_next = NULL;
  406         }
  407         RWLOCK_EXIT(&ipf_ipidfrag);
  408         return fra ? 0 : -1;
  409 }
  410 
  411 
  412 /* ------------------------------------------------------------------------ */
  413 /* Function:    fr_fraglookup                                               */
  414 /* Returns:     ipfr_t * - pointer to ipfr_t structure if there's a         */
  415 /*                         matching entry in the frag table, else NULL      */
  416 /* Parameters:  fin(I)   - pointer to packet information                    */
  417 /*              table(I) - pointer to fragment cache table to search        */
  418 /*                                                                          */
  419 /* Check the fragment cache to see if there is already a record of this     */
  420 /* packet with its filter result known.                                     */
  421 /* ------------------------------------------------------------------------ */
  422 static ipfr_t *fr_fraglookup(fin, table)
  423 fr_info_t *fin;
  424 ipfr_t *table[];
  425 {
  426         ipfr_t *f, frag;
  427         u_int idx;
  428         ip_t *ip;
  429 
  430         if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
  431                 return NULL;
  432 
  433         /*
  434          * For fragments, we record protocol, packet id, TOS and both IP#'s
  435          * (these should all be the same for all fragments of a packet).
  436          *
  437          * build up a hash value to index the table with.
  438          */
  439         ip = fin->fin_ip;
  440         frag.ipfr_p = ip->ip_p;
  441         idx = ip->ip_p;
  442         frag.ipfr_id = ip->ip_id;
  443         idx += ip->ip_id;
  444         frag.ipfr_tos = ip->ip_tos;
  445         frag.ipfr_src.s_addr = ip->ip_src.s_addr;
  446         idx += ip->ip_src.s_addr;
  447         frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
  448         idx += ip->ip_dst.s_addr;
  449         frag.ipfr_ifp = fin->fin_ifp;
  450         idx *= 127;
  451         idx %= IPFT_SIZE;
  452 
  453         frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
  454         frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
  455         frag.ipfr_auth = fin->fin_fi.fi_auth;
  456 
  457         /*
  458          * check the table, careful to only compare the right amount of data
  459          */
  460         for (f = table[idx]; f; f = f->ipfr_hnext)
  461                 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
  462                           IPFR_CMPSZ)) {
  463                         u_short off;
  464 
  465                         /*
  466                          * We don't want to let short packets match because
  467                          * they could be compromising the security of other
  468                          * rules that want to match on layer 4 fields (and
  469                          * can't because they have been fragmented off.)
  470                          * Why do this check here?  The counter acts as an
  471                          * indicator of this kind of attack, whereas if it was
  472                          * elsewhere, it wouldn't know if other matching
  473                          * packets had been seen.
  474                          */
  475                         if (fin->fin_flx & FI_SHORT) {
  476                                 ATOMIC_INCL(ipfr_stats.ifs_short);
  477                                 continue;
  478                         }
  479 
  480                         /*
  481                          * XXX - We really need to be guarding against the
  482                          * retransmission of (src,dst,id,offset-range) here
  483                          * because a fragmented packet is never resent with
  484                          * the same IP ID# (or shouldn't).
  485                          */
  486                         off = ip->ip_off & IP_OFFMASK;
  487                         if (f->ipfr_seen0) {
  488                                 if (off == 0) {
  489                                         ATOMIC_INCL(ipfr_stats.ifs_retrans0);
  490                                         continue;
  491                                 }
  492                         } else if (off == 0)
  493                                 f->ipfr_seen0 = 1;
  494 
  495                         if (f != table[idx]) {
  496                                 ipfr_t **fp;
  497 
  498                                 /*
  499                                  * Move fragment info. to the top of the list
  500                                  * to speed up searches.  First, delink...
  501                                  */
  502                                 fp = f->ipfr_hprev;
  503                                 (*fp) = f->ipfr_hnext;
  504                                 if (f->ipfr_hnext != NULL)
  505                                         f->ipfr_hnext->ipfr_hprev = fp;
  506                                 /*
  507                                  * Then put back at the top of the chain.
  508                                  */
  509                                 f->ipfr_hnext = table[idx];
  510                                 table[idx]->ipfr_hprev = &f->ipfr_hnext;
  511                                 f->ipfr_hprev = table + idx;
  512                                 table[idx] = f;
  513                         }
  514 
  515                         /*
  516                          * If we've follwed the fragments, and this is the
  517                          * last (in order), shrink expiration time.
  518                          */
  519                         if (off == f->ipfr_off) {
  520                                 if (!(ip->ip_off & IP_MF))
  521                                         f->ipfr_ttl = fr_ticks + 1;
  522                                 f->ipfr_off = (fin->fin_dlen >> 3) + off;
  523                         } else if (f->ipfr_pass & FR_FRSTRICT)
  524                                 continue;
  525                         ATOMIC_INCL(ipfr_stats.ifs_hits);
  526                         return f;
  527                 }
  528         return NULL;
  529 }
  530 
  531 
  532 /* ------------------------------------------------------------------------ */
  533 /* Function:    fr_nat_knownfrag                                            */
  534 /* Returns:     nat_t* - pointer to 'parent' NAT structure if frag table    */
  535 /*                       match found, else NULL                             */
  536 /* Parameters:  fin(I)  - pointer to packet information                     */
  537 /*                                                                          */
  538 /* Functional interface for NAT lookups of the NAT fragment cache           */
  539 /* ------------------------------------------------------------------------ */
  540 nat_t *fr_nat_knownfrag(fin)
  541 fr_info_t *fin;
  542 {
  543         nat_t   *nat;
  544         ipfr_t  *ipf;
  545 
  546         if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist)
  547                 return NULL;
  548         READ_ENTER(&ipf_natfrag);
  549         ipf = fr_fraglookup(fin, ipfr_nattab);
  550         if (ipf != NULL) {
  551                 nat = ipf->ipfr_data;
  552                 /*
  553                  * This is the last fragment for this packet.
  554                  */
  555                 if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) {
  556                         nat->nat_data = NULL;
  557                         ipf->ipfr_data = NULL;
  558                 }
  559         } else
  560                 nat = NULL;
  561         RWLOCK_EXIT(&ipf_natfrag);
  562         return nat;
  563 }
  564 
  565 
  566 /* ------------------------------------------------------------------------ */
  567 /* Function:    fr_ipid_knownfrag                                           */
  568 /* Returns:     u_32_t - IPv4 ID for this packet if match found, else       */
  569 /*                       return 0xfffffff to indicate no match.             */
  570 /* Parameters:  fin(I) - pointer to packet information                      */
  571 /*                                                                          */
  572 /* Functional interface for IP ID lookups of the IP ID fragment cache       */
  573 /* ------------------------------------------------------------------------ */
  574 u_32_t fr_ipid_knownfrag(fin)
  575 fr_info_t *fin;
  576 {
  577         ipfr_t  *ipf;
  578         u_32_t  id;
  579 
  580         if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist)
  581                 return 0xffffffff;
  582 
  583         READ_ENTER(&ipf_ipidfrag);
  584         ipf = fr_fraglookup(fin, ipfr_ipidtab);
  585         if (ipf != NULL)
  586                 id = (u_32_t)(intptr_t)ipf->ipfr_data;
  587         else
  588                 id = 0xffffffff;
  589         RWLOCK_EXIT(&ipf_ipidfrag);
  590         return id;
  591 }
  592 
  593 
  594 /* ------------------------------------------------------------------------ */
  595 /* Function:    fr_knownfrag                                                */
  596 /* Returns:     frentry_t* - pointer to filter rule if a match is found in  */
  597 /*                           the frag cache table, else NULL.               */
  598 /* Parameters:  fin(I)   - pointer to packet information                    */
  599 /*              passp(O) - pointer to where to store rule flags resturned   */
  600 /*                                                                          */
  601 /* Functional interface for normal lookups of the fragment cache.  If a     */
  602 /* match is found, return the rule pointer and flags from the rule, except  */
  603 /* that if FR_LOGFIRST is set, reset FR_LOG.                                */
  604 /* ------------------------------------------------------------------------ */
  605 frentry_t *fr_knownfrag(fin, passp)
  606 fr_info_t *fin;
  607 u_32_t *passp;
  608 {
  609         frentry_t *fr = NULL;
  610         ipfr_t  *fra;
  611         u_32_t pass;
  612 
  613         if ((fin->fin_v != 4) || (fr_frag_lock) || (ipfr_list == NULL))
  614                 return NULL;
  615 
  616         READ_ENTER(&ipf_frag);
  617         fra = fr_fraglookup(fin, ipfr_heads);
  618         if (fra != NULL) {
  619                 fr = fra->ipfr_rule;
  620                 fin->fin_fr = fr;
  621                 if (fr != NULL) {
  622                         pass = fr->fr_flags;
  623                         if ((pass & FR_LOGFIRST) != 0)
  624                                 pass &= ~(FR_LOGFIRST|FR_LOG);
  625                         *passp = pass;
  626                 }
  627         }
  628         RWLOCK_EXIT(&ipf_frag);
  629         return fr;
  630 }
  631 
  632 
  633 /* ------------------------------------------------------------------------ */
  634 /* Function:    fr_forget                                                   */
  635 /* Returns:     Nil                                                         */
  636 /* Parameters:  ptr(I) - pointer to data structure                          */
  637 /*                                                                          */
  638 /* Search through all of the fragment cache entries and wherever a pointer  */
  639 /* is found to match ptr, reset it to NULL.                                 */
  640 /* ------------------------------------------------------------------------ */
  641 void fr_forget(ptr)
  642 void *ptr;
  643 {
  644         ipfr_t  *fr;
  645 
  646         WRITE_ENTER(&ipf_frag);
  647         for (fr = ipfr_list; fr; fr = fr->ipfr_next)
  648                 if (fr->ipfr_data == ptr)
  649                         fr->ipfr_data = NULL;
  650         RWLOCK_EXIT(&ipf_frag);
  651 }
  652 
  653 
  654 /* ------------------------------------------------------------------------ */
  655 /* Function:    fr_forgetnat                                                */
  656 /* Returns:     Nil                                                         */
  657 /* Parameters:  ptr(I) - pointer to data structure                          */
  658 /*                                                                          */
  659 /* Search through all of the fragment cache entries for NAT and wherever a  */
  660 /* pointer  is found to match ptr, reset it to NULL.                        */
  661 /* ------------------------------------------------------------------------ */
  662 void fr_forgetnat(ptr)
  663 void *ptr;
  664 {
  665         ipfr_t  *fr;
  666 
  667         WRITE_ENTER(&ipf_natfrag);
  668         for (fr = ipfr_natlist; fr; fr = fr->ipfr_next)
  669                 if (fr->ipfr_data == ptr)
  670                         fr->ipfr_data = NULL;
  671         RWLOCK_EXIT(&ipf_natfrag);
  672 }
  673 
  674 
  675 /* ------------------------------------------------------------------------ */
  676 /* Function:    fr_fragdelete                                               */
  677 /* Returns:     Nil                                                         */
  678 /* Parameters:  fra(I)   - pointer to fragment structure to delete          */
  679 /*              tail(IO) - pointer to the pointer to the tail of the frag   */
  680 /*                         list                                             */
  681 /*                                                                          */
  682 /* Remove a fragment cache table entry from the table & list.  Also free    */
  683 /* the filter rule it is associated with it if it is no longer used as a    */
  684 /* result of decreasing the reference count.                                */
  685 /* ------------------------------------------------------------------------ */
  686 static void fr_fragdelete(fra, tail)
  687 ipfr_t *fra, ***tail;
  688 {
  689         frentry_t *fr;
  690 
  691         fr = fra->ipfr_rule;
  692         if (fr != NULL)
  693                 (void)fr_derefrule(&fr);
  694 
  695         if (fra->ipfr_next)
  696                 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
  697         *fra->ipfr_prev = fra->ipfr_next;
  698         if (*tail == &fra->ipfr_next)
  699                 *tail = fra->ipfr_prev;
  700 
  701         if (fra->ipfr_hnext)
  702                 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
  703         *fra->ipfr_hprev = fra->ipfr_hnext;
  704         KFREE(fra);
  705 }
  706 
  707 
  708 /* ------------------------------------------------------------------------ */
  709 /* Function:    fr_fragclear                                                */
  710 /* Returns:     Nil                                                         */
  711 /* Parameters:  Nil                                                         */
  712 /*                                                                          */
  713 /* Free memory in use by fragment state information kept.  Do the normal    */
  714 /* fragment state stuff first and then the NAT-fragment table.              */
  715 /* ------------------------------------------------------------------------ */
  716 void fr_fragclear()
  717 {
  718         ipfr_t  *fra;
  719         nat_t   *nat;
  720 
  721         WRITE_ENTER(&ipf_frag);
  722         while ((fra = ipfr_list) != NULL)
  723                 fr_fragdelete(fra, &ipfr_tail);
  724         ipfr_tail = &ipfr_list;
  725         RWLOCK_EXIT(&ipf_frag);
  726 
  727         WRITE_ENTER(&ipf_nat);
  728         WRITE_ENTER(&ipf_natfrag);
  729         while ((fra = ipfr_natlist) != NULL) {
  730                 nat = fra->ipfr_data;
  731                 if (nat != NULL) {
  732                         if (nat->nat_data == fra)
  733                                 nat->nat_data = NULL;
  734                 }
  735                 fr_fragdelete(fra, &ipfr_nattail);
  736         }
  737         ipfr_nattail = &ipfr_natlist;
  738         RWLOCK_EXIT(&ipf_natfrag);
  739         RWLOCK_EXIT(&ipf_nat);
  740 }
  741 
  742 
  743 /* ------------------------------------------------------------------------ */
  744 /* Function:    fr_fragexpire                                               */
  745 /* Returns:     Nil                                                         */
  746 /* Parameters:  Nil                                                         */
  747 /*                                                                          */
  748 /* Expire entries in the fragment cache table that have been there too long */
  749 /* ------------------------------------------------------------------------ */
  750 void fr_fragexpire()
  751 {
  752         ipfr_t  **fp, *fra;
  753         nat_t   *nat;
  754 #if defined(USE_SPL) && defined(_KERNEL)
  755         int     s;
  756 #endif
  757 
  758         if (fr_frag_lock)
  759                 return;
  760 
  761         SPL_NET(s);
  762         WRITE_ENTER(&ipf_frag);
  763         /*
  764          * Go through the entire table, looking for entries to expire,
  765          * which is indicated by the ttl being less than or equal to fr_ticks.
  766          */
  767         for (fp = &ipfr_list; ((fra = *fp) != NULL); ) {
  768                 if (fra->ipfr_ttl > fr_ticks)
  769                         break;
  770                 fr_fragdelete(fra, &ipfr_tail);
  771                 ipfr_stats.ifs_expire++;
  772                 ipfr_inuse--;
  773         }
  774         RWLOCK_EXIT(&ipf_frag);
  775 
  776         WRITE_ENTER(&ipf_ipidfrag);
  777         for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) {
  778                 if (fra->ipfr_ttl > fr_ticks)
  779                         break;
  780                 fr_fragdelete(fra, &ipfr_ipidtail);
  781                 ipfr_stats.ifs_expire++;
  782                 ipfr_inuse--;
  783         }
  784         RWLOCK_EXIT(&ipf_ipidfrag);
  785 
  786         /*
  787          * Same again for the NAT table, except that if the structure also
  788          * still points to a NAT structure, and the NAT structure points back
  789          * at the one to be free'd, NULL the reference from the NAT struct.
  790          * NOTE: We need to grab both mutex's early, and in this order so as
  791          * to prevent a deadlock if both try to expire at the same time.
  792          */
  793         WRITE_ENTER(&ipf_nat);
  794         WRITE_ENTER(&ipf_natfrag);
  795         for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) {
  796                 if (fra->ipfr_ttl > fr_ticks)
  797                         break;
  798                 nat = fra->ipfr_data;
  799                 if (nat != NULL) {
  800                         if (nat->nat_data == fra)
  801                                 nat->nat_data = NULL;
  802                 }
  803                 fr_fragdelete(fra, &ipfr_nattail);
  804                 ipfr_stats.ifs_expire++;
  805                 ipfr_inuse--;
  806         }
  807         RWLOCK_EXIT(&ipf_natfrag);
  808         RWLOCK_EXIT(&ipf_nat);
  809         SPL_X(s);
  810 }
  811 
  812 
  813 /* ------------------------------------------------------------------------ */
  814 /* Function:    fr_slowtimer                                                */
  815 /* Returns:     Nil                                                         */
  816 /* Parameters:  Nil                                                         */
  817 /*                                                                          */
  818 /* Slowly expire held state for fragments.  Timeouts are set * in           */
  819 /* expectation of this being called twice per second.                       */
  820 /* ------------------------------------------------------------------------ */
  821 #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \
  822                           !defined(__osf__))
  823 # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
  824 void fr_slowtimer __P((void *ptr))
  825 # else
  826 int fr_slowtimer()
  827 # endif
  828 {
  829         READ_ENTER(&ipf_global);
  830 
  831         fr_fragexpire();
  832         fr_timeoutstate();
  833         fr_natexpire();
  834         fr_authexpire();
  835         fr_ticks++;
  836         if (fr_running <= 0)
  837                 goto done;
  838 # ifdef _KERNEL
  839 #  if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
  840         callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL);
  841 #  else
  842 #   if defined(__OpenBSD__)
  843         timeout_add(&fr_slowtimer_ch, hz/2);
  844 #   else
  845 #    if (__FreeBSD_version >= 300000)
  846         fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2);
  847 #    else
  848 #     ifdef linux
  849         ;
  850 #     else
  851         timeout(fr_slowtimer, NULL, hz/2);
  852 #     endif
  853 #    endif /* FreeBSD */
  854 #   endif /* OpenBSD */
  855 #  endif /* NetBSD */
  856 # endif
  857 done:
  858         RWLOCK_EXIT(&ipf_global);
  859 # if (BSD < 199103) || !defined(_KERNEL)
  860         return 0;
  861 # endif
  862 }
  863 #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */

Cache object: b43dff740c17c1b073f3bdc80207d23e


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