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/netinet6/frag6.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: frag6.c,v 1.26 2003/09/06 03:36:32 itojun Exp $        */
    2 /*      $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $  */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.26 2003/09/06 03:36:32 itojun Exp $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/domain.h>
   41 #include <sys/protosw.h>
   42 #include <sys/socket.h>
   43 #include <sys/errno.h>
   44 #include <sys/time.h>
   45 #include <sys/kernel.h>
   46 #include <sys/syslog.h>
   47 
   48 #include <net/if.h>
   49 #include <net/route.h>
   50 
   51 #include <netinet/in.h>
   52 #include <netinet/in_var.h>
   53 #include <netinet/ip6.h>
   54 #include <netinet6/in6_pcb.h>
   55 #include <netinet6/ip6_var.h>
   56 #include <netinet/icmp6.h>
   57 
   58 #include <net/net_osdep.h>
   59 
   60 /*
   61  * Define it to get a correct behavior on per-interface statistics.
   62  * You will need to perform an extra routing table lookup, per fragment,
   63  * to do it.  This may, or may not be, a performance hit.
   64  */
   65 #define IN6_IFSTAT_STRICT
   66 
   67 static void frag6_enq __P((struct ip6asfrag *, struct ip6asfrag *));
   68 static void frag6_deq __P((struct ip6asfrag *));
   69 static void frag6_insque __P((struct ip6q *, struct ip6q *));
   70 static void frag6_remque __P((struct ip6q *));
   71 static void frag6_freef __P((struct ip6q *));
   72 
   73 static int ip6q_locked;
   74 u_int frag6_nfragpackets;
   75 u_int frag6_nfrags;
   76 struct  ip6q ip6q;      /* ip6 reassemble queue */
   77 
   78 static __inline int ip6q_lock_try __P((void));
   79 static __inline void ip6q_unlock __P((void));
   80 
   81 static __inline int
   82 ip6q_lock_try()
   83 {
   84         int s;
   85 
   86         /*
   87          * Use splvm() -- we're bloking things that would cause
   88          * mbuf allocation.
   89          */
   90         s = splvm();
   91         if (ip6q_locked) {
   92                 splx(s);
   93                 return (0);
   94         }
   95         ip6q_locked = 1;
   96         splx(s);
   97         return (1);
   98 }
   99 
  100 static __inline void
  101 ip6q_unlock()
  102 {
  103         int s;
  104 
  105         s = splvm();
  106         ip6q_locked = 0;
  107         splx(s);
  108 }
  109 
  110 #ifdef DIAGNOSTIC
  111 #define IP6Q_LOCK()                                                     \
  112 do {                                                                    \
  113         if (ip6q_lock_try() == 0) {                                     \
  114                 printf("%s:%d: ip6q already locked\n", __FILE__, __LINE__); \
  115                 panic("ip6q_lock");                                     \
  116         }                                                               \
  117 } while (/*CONSTCOND*/ 0)
  118 #define IP6Q_LOCK_CHECK()                                               \
  119 do {                                                                    \
  120         if (ip6q_locked == 0) {                                         \
  121                 printf("%s:%d: ip6q lock not held\n", __FILE__, __LINE__); \
  122                 panic("ip6q lock check");                               \
  123         }                                                               \
  124 } while (/*CONSTCOND*/ 0)
  125 #else
  126 #define IP6Q_LOCK()             (void) ip6q_lock_try()
  127 #define IP6Q_LOCK_CHECK()       /* nothing */
  128 #endif
  129 
  130 #define IP6Q_UNLOCK()           ip6q_unlock()
  131 
  132 #ifndef offsetof                /* XXX */
  133 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
  134 #endif
  135 
  136 /*
  137  * Initialise reassembly queue and fragment identifier.
  138  */
  139 void
  140 frag6_init()
  141 {
  142 
  143         ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
  144 }
  145 
  146 /*
  147  * In RFC2460, fragment and reassembly rule do not agree with each other,
  148  * in terms of next header field handling in fragment header.
  149  * While the sender will use the same value for all of the fragmented packets,
  150  * receiver is suggested not to check the consistency.
  151  *
  152  * fragment rule (p20):
  153  *      (2) A Fragment header containing:
  154  *      The Next Header value that identifies the first header of
  155  *      the Fragmentable Part of the original packet.
  156  *              -> next header field is same for all fragments
  157  *
  158  * reassembly rule (p21):
  159  *      The Next Header field of the last header of the Unfragmentable
  160  *      Part is obtained from the Next Header field of the first
  161  *      fragment's Fragment header.
  162  *              -> should grab it from the first fragment only
  163  *
  164  * The following note also contradicts with fragment rule - noone is going to
  165  * send different fragment with different next header field.
  166  *
  167  * additional note (p22):
  168  *      The Next Header values in the Fragment headers of different
  169  *      fragments of the same original packet may differ.  Only the value
  170  *      from the Offset zero fragment packet is used for reassembly.
  171  *              -> should grab it from the first fragment only
  172  *
  173  * There is no explicit reason given in the RFC.  Historical reason maybe?
  174  */
  175 /*
  176  * Fragment input
  177  */
  178 int
  179 frag6_input(mp, offp, proto)
  180         struct mbuf **mp;
  181         int *offp, proto;
  182 {
  183         struct mbuf *m = *mp, *t;
  184         struct ip6_hdr *ip6;
  185         struct ip6_frag *ip6f;
  186         struct ip6q *q6;
  187         struct ip6asfrag *af6, *ip6af, *af6dwn;
  188         int offset = *offp, nxt, i, next;
  189         int first_frag = 0;
  190         int fragoff, frgpartlen;        /* must be larger than u_int16_t */
  191         struct ifnet *dstifp;
  192 #ifdef IN6_IFSTAT_STRICT
  193         static struct route_in6 ro;
  194         struct sockaddr_in6 *dst;
  195 #endif
  196 
  197         ip6 = mtod(m, struct ip6_hdr *);
  198         IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
  199         if (ip6f == NULL)
  200                 return IPPROTO_DONE;
  201 
  202         dstifp = NULL;
  203 #ifdef IN6_IFSTAT_STRICT
  204         /* find the destination interface of the packet. */
  205         dst = (struct sockaddr_in6 *)&ro.ro_dst;
  206         if (ro.ro_rt
  207          && ((ro.ro_rt->rt_flags & RTF_UP) == 0
  208           || !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst))) {
  209                 RTFREE(ro.ro_rt);
  210                 ro.ro_rt = (struct rtentry *)0;
  211         }
  212         if (ro.ro_rt == NULL) {
  213                 bzero(dst, sizeof(*dst));
  214                 dst->sin6_family = AF_INET6;
  215                 dst->sin6_len = sizeof(struct sockaddr_in6);
  216                 dst->sin6_addr = ip6->ip6_dst;
  217         }
  218         rtalloc((struct route *)&ro);
  219         if (ro.ro_rt != NULL && ro.ro_rt->rt_ifa != NULL)
  220                 dstifp = ((struct in6_ifaddr *)ro.ro_rt->rt_ifa)->ia_ifp;
  221 #else
  222         /* we are violating the spec, this is not the destination interface */
  223         if ((m->m_flags & M_PKTHDR) != 0)
  224                 dstifp = m->m_pkthdr.rcvif;
  225 #endif
  226 
  227         /* jumbo payload can't contain a fragment header */
  228         if (ip6->ip6_plen == 0) {
  229                 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
  230                 in6_ifstat_inc(dstifp, ifs6_reass_fail);
  231                 return IPPROTO_DONE;
  232         }
  233 
  234         /*
  235          * check whether fragment packet's fragment length is
  236          * multiple of 8 octets.
  237          * sizeof(struct ip6_frag) == 8
  238          * sizeof(struct ip6_hdr) = 40
  239          */
  240         if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
  241             (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
  242                 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
  243                     offsetof(struct ip6_hdr, ip6_plen));
  244                 in6_ifstat_inc(dstifp, ifs6_reass_fail);
  245                 return IPPROTO_DONE;
  246         }
  247 
  248         ip6stat.ip6s_fragments++;
  249         in6_ifstat_inc(dstifp, ifs6_reass_reqd);
  250 
  251         /* offset now points to data portion */
  252         offset += sizeof(struct ip6_frag);
  253 
  254         IP6Q_LOCK();
  255 
  256         /*
  257          * Enforce upper bound on number of fragments.
  258          * If maxfrag is 0, never accept fragments.
  259          * If maxfrag is -1, accept all fragments without limitation.
  260          */
  261         if (ip6_maxfrags < 0)
  262                 ;
  263         else if (frag6_nfrags >= (u_int)ip6_maxfrags)
  264                 goto dropfrag;
  265 
  266         for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
  267                 if (ip6f->ip6f_ident == q6->ip6q_ident &&
  268                     IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
  269                     IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst))
  270                         break;
  271 
  272         if (q6 == &ip6q) {
  273                 /*
  274                  * the first fragment to arrive, create a reassembly queue.
  275                  */
  276                 first_frag = 1;
  277 
  278                 /*
  279                  * Enforce upper bound on number of fragmented packets
  280                  * for which we attempt reassembly;
  281                  * If maxfragpackets is 0, never accept fragments.
  282                  * If maxfragpackets is -1, accept all fragments without
  283                  * limitation.
  284                  */
  285                 if (ip6_maxfragpackets < 0)
  286                         ;
  287                 else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
  288                         goto dropfrag;
  289                 frag6_nfragpackets++;
  290                 q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE,
  291                     M_DONTWAIT);
  292                 if (q6 == NULL)
  293                         goto dropfrag;
  294                 bzero(q6, sizeof(*q6));
  295 
  296                 frag6_insque(q6, &ip6q);
  297 
  298                 /* ip6q_nxt will be filled afterwards, from 1st fragment */
  299                 q6->ip6q_down   = q6->ip6q_up = (struct ip6asfrag *)q6;
  300 #ifdef notyet
  301                 q6->ip6q_nxtp   = (u_char *)nxtp;
  302 #endif
  303                 q6->ip6q_ident  = ip6f->ip6f_ident;
  304                 q6->ip6q_arrive = 0; /* Is it used anywhere? */
  305                 q6->ip6q_ttl    = IPV6_FRAGTTL;
  306                 q6->ip6q_src    = ip6->ip6_src;
  307                 q6->ip6q_dst    = ip6->ip6_dst;
  308                 q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */
  309 
  310                 q6->ip6q_nfrag = 0;
  311         }
  312 
  313         /*
  314          * If it's the 1st fragment, record the length of the
  315          * unfragmentable part and the next header of the fragment header.
  316          */
  317         fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
  318         if (fragoff == 0) {
  319                 q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) -
  320                     sizeof(struct ip6_frag);
  321                 q6->ip6q_nxt = ip6f->ip6f_nxt;
  322         }
  323 
  324         /*
  325          * Check that the reassembled packet would not exceed 65535 bytes
  326          * in size.
  327          * If it would exceed, discard the fragment and return an ICMP error.
  328          */
  329         frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
  330         if (q6->ip6q_unfrglen >= 0) {
  331                 /* The 1st fragment has already arrived. */
  332                 if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
  333                         icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
  334                             offset - sizeof(struct ip6_frag) +
  335                             offsetof(struct ip6_frag, ip6f_offlg));
  336                         IP6Q_UNLOCK();
  337                         return (IPPROTO_DONE);
  338                 }
  339         } else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
  340                 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
  341                             offset - sizeof(struct ip6_frag) +
  342                                 offsetof(struct ip6_frag, ip6f_offlg));
  343                 IP6Q_UNLOCK();
  344                 return (IPPROTO_DONE);
  345         }
  346         /*
  347          * If it's the first fragment, do the above check for each
  348          * fragment already stored in the reassembly queue.
  349          */
  350         if (fragoff == 0) {
  351                 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
  352                      af6 = af6dwn) {
  353                         af6dwn = af6->ip6af_down;
  354 
  355                         if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen >
  356                             IPV6_MAXPACKET) {
  357                                 struct mbuf *merr = IP6_REASS_MBUF(af6);
  358                                 struct ip6_hdr *ip6err;
  359                                 int erroff = af6->ip6af_offset;
  360 
  361                                 /* dequeue the fragment. */
  362                                 frag6_deq(af6);
  363                                 free(af6, M_FTABLE);
  364 
  365                                 /* adjust pointer. */
  366                                 ip6err = mtod(merr, struct ip6_hdr *);
  367 
  368                                 /*
  369                                  * Restore source and destination addresses
  370                                  * in the erroneous IPv6 header.
  371                                  */
  372                                 ip6err->ip6_src = q6->ip6q_src;
  373                                 ip6err->ip6_dst = q6->ip6q_dst;
  374 
  375                                 icmp6_error(merr, ICMP6_PARAM_PROB,
  376                                     ICMP6_PARAMPROB_HEADER,
  377                                     erroff - sizeof(struct ip6_frag) +
  378                                     offsetof(struct ip6_frag, ip6f_offlg));
  379                         }
  380                 }
  381         }
  382 
  383         ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FTABLE,
  384             M_DONTWAIT);
  385         if (ip6af == NULL)
  386                 goto dropfrag;
  387         bzero(ip6af, sizeof(*ip6af));
  388         ip6af->ip6af_head = ip6->ip6_flow;
  389         ip6af->ip6af_len = ip6->ip6_plen;
  390         ip6af->ip6af_nxt = ip6->ip6_nxt;
  391         ip6af->ip6af_hlim = ip6->ip6_hlim;
  392         ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG;
  393         ip6af->ip6af_off = fragoff;
  394         ip6af->ip6af_frglen = frgpartlen;
  395         ip6af->ip6af_offset = offset;
  396         IP6_REASS_MBUF(ip6af) = m;
  397 
  398         if (first_frag) {
  399                 af6 = (struct ip6asfrag *)q6;
  400                 goto insert;
  401         }
  402 
  403         /*
  404          * Find a segment which begins after this one does.
  405          */
  406         for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
  407              af6 = af6->ip6af_down)
  408                 if (af6->ip6af_off > ip6af->ip6af_off)
  409                         break;
  410 
  411 #if 0
  412         /*
  413          * If there is a preceding segment, it may provide some of
  414          * our data already.  If so, drop the data from the incoming
  415          * segment.  If it provides all of our data, drop us.
  416          */
  417         if (af6->ip6af_up != (struct ip6asfrag *)q6) {
  418                 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
  419                         - ip6af->ip6af_off;
  420                 if (i > 0) {
  421                         if (i >= ip6af->ip6af_frglen)
  422                                 goto dropfrag;
  423                         m_adj(IP6_REASS_MBUF(ip6af), i);
  424                         ip6af->ip6af_off += i;
  425                         ip6af->ip6af_frglen -= i;
  426                 }
  427         }
  428 
  429         /*
  430          * While we overlap succeeding segments trim them or,
  431          * if they are completely covered, dequeue them.
  432          */
  433         while (af6 != (struct ip6asfrag *)q6 &&
  434                ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) {
  435                 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
  436                 if (i < af6->ip6af_frglen) {
  437                         af6->ip6af_frglen -= i;
  438                         af6->ip6af_off += i;
  439                         m_adj(IP6_REASS_MBUF(af6), i);
  440                         break;
  441                 }
  442                 af6 = af6->ip6af_down;
  443                 m_freem(IP6_REASS_MBUF(af6->ip6af_up));
  444                 frag6_deq(af6->ip6af_up);
  445         }
  446 #else
  447         /*
  448          * If the incoming framgent overlaps some existing fragments in
  449          * the reassembly queue, drop it, since it is dangerous to override
  450          * existing fragments from a security point of view.
  451          * We don't know which fragment is the bad guy - here we trust
  452          * fragment that came in earlier, with no real reason.
  453          */
  454         if (af6->ip6af_up != (struct ip6asfrag *)q6) {
  455                 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
  456                         - ip6af->ip6af_off;
  457                 if (i > 0) {
  458 #if 0                           /* suppress the noisy log */
  459                         log(LOG_ERR, "%d bytes of a fragment from %s "
  460                             "overlaps the previous fragment\n",
  461                             i, ip6_sprintf(&q6->ip6q_src));
  462 #endif
  463                         free(ip6af, M_FTABLE);
  464                         goto dropfrag;
  465                 }
  466         }
  467         if (af6 != (struct ip6asfrag *)q6) {
  468                 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
  469                 if (i > 0) {
  470 #if 0                           /* suppress the noisy log */
  471                         log(LOG_ERR, "%d bytes of a fragment from %s "
  472                             "overlaps the succeeding fragment",
  473                             i, ip6_sprintf(&q6->ip6q_src));
  474 #endif
  475                         free(ip6af, M_FTABLE);
  476                         goto dropfrag;
  477                 }
  478         }
  479 #endif
  480 
  481 insert:
  482 
  483         /*
  484          * Stick new segment in its place;
  485          * check for complete reassembly.
  486          * Move to front of packet queue, as we are
  487          * the most recently active fragmented packet.
  488          */
  489         frag6_enq(ip6af, af6->ip6af_up);
  490         frag6_nfrags++;
  491         q6->ip6q_nfrag++;
  492 #if 0 /* xxx */
  493         if (q6 != ip6q.ip6q_next) {
  494                 frag6_remque(q6);
  495                 frag6_insque(q6, &ip6q);
  496         }
  497 #endif
  498         next = 0;
  499         for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
  500              af6 = af6->ip6af_down) {
  501                 if (af6->ip6af_off != next) {
  502                         IP6Q_UNLOCK();
  503                         return IPPROTO_DONE;
  504                 }
  505                 next += af6->ip6af_frglen;
  506         }
  507         if (af6->ip6af_up->ip6af_mff) {
  508                 IP6Q_UNLOCK();
  509                 return IPPROTO_DONE;
  510         }
  511 
  512         /*
  513          * Reassembly is complete; concatenate fragments.
  514          */
  515         ip6af = q6->ip6q_down;
  516         t = m = IP6_REASS_MBUF(ip6af);
  517         af6 = ip6af->ip6af_down;
  518         frag6_deq(ip6af);
  519         while (af6 != (struct ip6asfrag *)q6) {
  520                 af6dwn = af6->ip6af_down;
  521                 frag6_deq(af6);
  522                 while (t->m_next)
  523                         t = t->m_next;
  524                 t->m_next = IP6_REASS_MBUF(af6);
  525                 m_adj(t->m_next, af6->ip6af_offset);
  526                 free(af6, M_FTABLE);
  527                 af6 = af6dwn;
  528         }
  529 
  530         /* adjust offset to point where the original next header starts */
  531         offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);
  532         free(ip6af, M_FTABLE);
  533         ip6 = mtod(m, struct ip6_hdr *);
  534         ip6->ip6_plen = htons(next + offset - sizeof(struct ip6_hdr));
  535         ip6->ip6_src = q6->ip6q_src;
  536         ip6->ip6_dst = q6->ip6q_dst;
  537         nxt = q6->ip6q_nxt;
  538 #ifdef notyet
  539         *q6->ip6q_nxtp = (u_char)(nxt & 0xff);
  540 #endif
  541 
  542         /*
  543          * Delete frag6 header with as a few cost as possible.
  544          */
  545         if (offset < m->m_len) {
  546                 ovbcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag),
  547                         offset);
  548                 m->m_data += sizeof(struct ip6_frag);
  549                 m->m_len -= sizeof(struct ip6_frag);
  550         } else {
  551                 /* this comes with no copy if the boundary is on cluster */
  552                 if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {
  553                         frag6_remque(q6);
  554                         frag6_nfrags -= q6->ip6q_nfrag;
  555                         free(q6, M_FTABLE);
  556                         frag6_nfragpackets--;
  557                         goto dropfrag;
  558                 }
  559                 m_adj(t, sizeof(struct ip6_frag));
  560                 m_cat(m, t);
  561         }
  562 
  563         /*
  564          * Store NXT to the original.
  565          */
  566         {
  567                 u_int8_t *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */
  568                 *prvnxtp = nxt;
  569         }
  570 
  571         frag6_remque(q6);
  572         frag6_nfrags -= q6->ip6q_nfrag;
  573         free(q6, M_FTABLE);
  574         frag6_nfragpackets--;
  575 
  576         if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */
  577                 int plen = 0;
  578                 for (t = m; t; t = t->m_next)
  579                         plen += t->m_len;
  580                 m->m_pkthdr.len = plen;
  581         }
  582 
  583         ip6stat.ip6s_reassembled++;
  584         in6_ifstat_inc(dstifp, ifs6_reass_ok);
  585 
  586         /*
  587          * Tell launch routine the next header
  588          */
  589 
  590         *mp = m;
  591         *offp = offset;
  592 
  593         IP6Q_UNLOCK();
  594         return nxt;
  595 
  596  dropfrag:
  597         in6_ifstat_inc(dstifp, ifs6_reass_fail);
  598         ip6stat.ip6s_fragdropped++;
  599         m_freem(m);
  600         IP6Q_UNLOCK();
  601         return IPPROTO_DONE;
  602 }
  603 
  604 /*
  605  * Free a fragment reassembly header and all
  606  * associated datagrams.
  607  */
  608 void
  609 frag6_freef(q6)
  610         struct ip6q *q6;
  611 {
  612         struct ip6asfrag *af6, *down6;
  613 
  614         IP6Q_LOCK_CHECK();
  615 
  616         for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
  617              af6 = down6) {
  618                 struct mbuf *m = IP6_REASS_MBUF(af6);
  619 
  620                 down6 = af6->ip6af_down;
  621                 frag6_deq(af6);
  622 
  623                 /*
  624                  * Return ICMP time exceeded error for the 1st fragment.
  625                  * Just free other fragments.
  626                  */
  627                 if (af6->ip6af_off == 0) {
  628                         struct ip6_hdr *ip6;
  629 
  630                         /* adjust pointer */
  631                         ip6 = mtod(m, struct ip6_hdr *);
  632 
  633                         /* restoure source and destination addresses */
  634                         ip6->ip6_src = q6->ip6q_src;
  635                         ip6->ip6_dst = q6->ip6q_dst;
  636 
  637                         icmp6_error(m, ICMP6_TIME_EXCEEDED,
  638                                     ICMP6_TIME_EXCEED_REASSEMBLY, 0);
  639                 } else
  640                         m_freem(m);
  641                 free(af6, M_FTABLE);
  642         }
  643         frag6_remque(q6);
  644         frag6_nfrags -= q6->ip6q_nfrag;
  645         free(q6, M_FTABLE);
  646         frag6_nfragpackets--;
  647 }
  648 
  649 /*
  650  * Put an ip fragment on a reassembly chain.
  651  * Like insque, but pointers in middle of structure.
  652  */
  653 void
  654 frag6_enq(af6, up6)
  655         struct ip6asfrag *af6, *up6;
  656 {
  657 
  658         IP6Q_LOCK_CHECK();
  659 
  660         af6->ip6af_up = up6;
  661         af6->ip6af_down = up6->ip6af_down;
  662         up6->ip6af_down->ip6af_up = af6;
  663         up6->ip6af_down = af6;
  664 }
  665 
  666 /*
  667  * To frag6_enq as remque is to insque.
  668  */
  669 void
  670 frag6_deq(af6)
  671         struct ip6asfrag *af6;
  672 {
  673 
  674         IP6Q_LOCK_CHECK();
  675 
  676         af6->ip6af_up->ip6af_down = af6->ip6af_down;
  677         af6->ip6af_down->ip6af_up = af6->ip6af_up;
  678 }
  679 
  680 void
  681 frag6_insque(new, old)
  682         struct ip6q *new, *old;
  683 {
  684 
  685         IP6Q_LOCK_CHECK();
  686 
  687         new->ip6q_prev = old;
  688         new->ip6q_next = old->ip6q_next;
  689         old->ip6q_next->ip6q_prev= new;
  690         old->ip6q_next = new;
  691 }
  692 
  693 void
  694 frag6_remque(p6)
  695         struct ip6q *p6;
  696 {
  697 
  698         IP6Q_LOCK_CHECK();
  699 
  700         p6->ip6q_prev->ip6q_next = p6->ip6q_next;
  701         p6->ip6q_next->ip6q_prev = p6->ip6q_prev;
  702 }
  703 
  704 /*
  705  * IPv6 reassembling timer processing;
  706  * if a timer expires on a reassembly
  707  * queue, discard it.
  708  */
  709 void
  710 frag6_slowtimo()
  711 {
  712         struct ip6q *q6;
  713         int s = splsoftnet();
  714 
  715         IP6Q_LOCK();
  716         q6 = ip6q.ip6q_next;
  717         if (q6)
  718                 while (q6 != &ip6q) {
  719                         --q6->ip6q_ttl;
  720                         q6 = q6->ip6q_next;
  721                         if (q6->ip6q_prev->ip6q_ttl == 0) {
  722                                 ip6stat.ip6s_fragtimeout++;
  723                                 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
  724                                 frag6_freef(q6->ip6q_prev);
  725                         }
  726                 }
  727         /*
  728          * If we are over the maximum number of fragments
  729          * (due to the limit being lowered), drain off
  730          * enough to get down to the new limit.
  731          */
  732         while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&
  733             ip6q.ip6q_prev) {
  734                 ip6stat.ip6s_fragoverflow++;
  735                 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
  736                 frag6_freef(ip6q.ip6q_prev);
  737         }
  738         IP6Q_UNLOCK();
  739 
  740 #if 0
  741         /*
  742          * Routing changes might produce a better route than we last used;
  743          * make sure we notice eventually, even if forwarding only for one
  744          * destination and the cache is never replaced.
  745          */
  746         if (ip6_forward_rt.ro_rt) {
  747                 RTFREE(ip6_forward_rt.ro_rt);
  748                 ip6_forward_rt.ro_rt = 0;
  749         }
  750         if (ipsrcchk_rt.ro_rt) {
  751                 RTFREE(ipsrcchk_rt.ro_rt);
  752                 ipsrcchk_rt.ro_rt = 0;
  753         }
  754 #endif
  755 
  756         splx(s);
  757 }
  758 
  759 /*
  760  * Drain off all datagram fragments.
  761  */
  762 void
  763 frag6_drain()
  764 {
  765 
  766         if (ip6q_lock_try() == 0)
  767                 return;
  768         while (ip6q.ip6q_next != &ip6q) {
  769                 ip6stat.ip6s_fragdropped++;
  770                 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
  771                 frag6_freef(ip6q.ip6q_next);
  772         }
  773         IP6Q_UNLOCK();
  774 }

Cache object: 73ab4e5230b6331df0027a7f83b8769a


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