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/ip/ipv6.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 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "../port/error.h"
    7 
    8 #include        "ip.h"
    9 #include        "ipv6.h"
   10 
   11 enum
   12 {
   13         IP6FHDR         = 8,            /* sizeof(Fraghdr6) */
   14 };
   15 
   16 #define IPV6CLASS(hdr)  (((hdr)->vcf[0]&0x0F)<<2 | ((hdr)->vcf[1]&0xF0)>>2)
   17 #define BLKIPVER(xp)    (((Ip6hdr*)((xp)->rp))->vcf[0] & 0xF0)
   18 /*
   19  * This sleazy macro is stolen shamelessly from ip.c, see comment there.
   20  */
   21 #define BKFG(xp)        ((Ipfrag*)((xp)->base))
   22 
   23 typedef struct  IP      IP;
   24 typedef struct  Fragment4       Fragment4;
   25 typedef struct  Fragment6       Fragment6;
   26 typedef struct  Ipfrag  Ipfrag;
   27 
   28 Block*          ip6reassemble(IP*, int, Block*, Ip6hdr*);
   29 Fragment6*      ipfragallo6(IP*);
   30 void            ipfragfree6(IP*, Fragment6*);
   31 Block*          procopts(Block *bp);
   32 static Block*   procxtns(IP *ip, Block *bp, int doreasm);
   33 int             unfraglen(Block *bp, uchar *nexthdr, int setfh);
   34 
   35 /* MIB II counters */
   36 enum
   37 {
   38         Forwarding,
   39         DefaultTTL,
   40         InReceives,
   41         InHdrErrors,
   42         InAddrErrors,
   43         ForwDatagrams,
   44         InUnknownProtos,
   45         InDiscards,
   46         InDelivers,
   47         OutRequests,
   48         OutDiscards,
   49         OutNoRoutes,
   50         ReasmTimeout,
   51         ReasmReqds,
   52         ReasmOKs,
   53         ReasmFails,
   54         FragOKs,
   55         FragFails,
   56         FragCreates,
   57 
   58         Nstats,
   59 };
   60 
   61 static char *statnames[] =
   62 {
   63 [Forwarding]    "Forwarding",
   64 [DefaultTTL]    "DefaultTTL",
   65 [InReceives]    "InReceives",
   66 [InHdrErrors]   "InHdrErrors",
   67 [InAddrErrors]  "InAddrErrors",
   68 [ForwDatagrams] "ForwDatagrams",
   69 [InUnknownProtos]       "InUnknownProtos",
   70 [InDiscards]    "InDiscards",
   71 [InDelivers]    "InDelivers",
   72 [OutRequests]   "OutRequests",
   73 [OutDiscards]   "OutDiscards",
   74 [OutNoRoutes]   "OutNoRoutes",
   75 [ReasmTimeout]  "ReasmTimeout",
   76 [ReasmReqds]    "ReasmReqds",
   77 [ReasmOKs]      "ReasmOKs",
   78 [ReasmFails]    "ReasmFails",
   79 [FragOKs]       "FragOKs",
   80 [FragFails]     "FragFails",
   81 [FragCreates]   "FragCreates",
   82 };
   83 
   84 struct Fragment4
   85 {
   86         Block*  blist;
   87         Fragment4*      next;
   88         ulong   src;
   89         ulong   dst;
   90         ushort  id;
   91         ulong   age;
   92 };
   93 
   94 struct Fragment6
   95 {
   96         Block*  blist;
   97         Fragment6*      next;
   98         uchar   src[IPaddrlen];
   99         uchar   dst[IPaddrlen];
  100         uint    id;
  101         ulong   age;
  102 };
  103 
  104 struct Ipfrag
  105 {
  106         ushort  foff;
  107         ushort  flen;
  108 };
  109 
  110 /* an instance of IP */
  111 struct IP
  112 {
  113         ulong           stats[Nstats];
  114 
  115         QLock           fraglock4;
  116         Fragment4*      flisthead4;
  117         Fragment4*      fragfree4;
  118         Ref             id4;
  119 
  120         QLock           fraglock6;
  121         Fragment6*      flisthead6;
  122         Fragment6*      fragfree6;
  123         Ref             id6;
  124 
  125         int             iprouting;      /* true if we route like a gateway */
  126 };
  127 
  128 int
  129 ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
  130 {
  131         int medialen, len, chunk, uflen, flen, seglen, lid, offset, fragoff;
  132         int morefrags, blklen, rv = 0, tentative;
  133         uchar *gate, nexthdr;
  134         Block *xp, *nb;
  135         Fraghdr6 fraghdr;
  136         IP *ip;
  137         Ip6hdr *eh;
  138         Ipifc *ifc;
  139         Route *r, *sr;
  140 
  141         ip = f->ip;
  142 
  143         /* Fill out the ip header */
  144         eh = (Ip6hdr*)(bp->rp);
  145 
  146         ip->stats[OutRequests]++;
  147 
  148         /* Number of uchars in data and ip header to write */
  149         len = blocklen(bp);
  150 
  151         tentative = iptentative(f, eh->src);
  152         if(tentative){
  153                 netlog(f, Logip, "reject tx of packet with tentative src address %I\n",
  154                         eh->src);
  155                 goto free;
  156         }
  157 
  158         if(gating){
  159                 chunk = nhgets(eh->ploadlen);
  160                 if(chunk > len){
  161                         ip->stats[OutDiscards]++;
  162                         netlog(f, Logip, "short gated packet\n");
  163                         goto free;
  164                 }
  165                 if(chunk + IP6HDR < len)
  166                         len = chunk + IP6HDR;
  167         }
  168 
  169         if(len >= IP_MAX){
  170                 ip->stats[OutDiscards]++;
  171                 netlog(f, Logip, "exceeded ip max size %I\n", eh->dst);
  172                 goto free;
  173         }
  174 
  175         r = v6lookup(f, eh->dst, c);
  176         if(r == nil){
  177 //              print("no route for %I, src %I free\n", eh->dst, eh->src);
  178                 ip->stats[OutNoRoutes]++;
  179                 netlog(f, Logip, "no interface %I\n", eh->dst);
  180                 rv = -1;
  181                 goto free;
  182         }
  183 
  184         ifc = r->ifc;
  185         if(r->type & (Rifc|Runi))
  186                 gate = eh->dst;
  187         else if(r->type & (Rbcast|Rmulti)) {
  188                 gate = eh->dst;
  189                 sr = v6lookup(f, eh->src, nil);
  190                 if(sr && (sr->type & Runi))
  191                         ifc = sr->ifc;
  192         }
  193         else
  194                 gate = r->v6.gate;
  195 
  196         if(!gating)
  197                 eh->vcf[0] = IP_VER6;
  198         eh->ttl = ttl;
  199         if(!gating) {
  200                 eh->vcf[0] |= tos >> 4;
  201                 eh->vcf[1]  = tos << 4;
  202         }
  203 
  204         if(!canrlock(ifc))
  205                 goto free;
  206 
  207         if(waserror()){
  208                 runlock(ifc);
  209                 nexterror();
  210         }
  211 
  212         if(ifc->m == nil)
  213                 goto raise;
  214 
  215         /* If we dont need to fragment just send it */
  216         medialen = ifc->maxtu - ifc->m->hsize;
  217         if(len <= medialen) {
  218                 hnputs(eh->ploadlen, len - IP6HDR);
  219                 ifc->m->bwrite(ifc, bp, V6, gate);
  220                 runlock(ifc);
  221                 poperror();
  222                 return 0;
  223         }
  224 
  225         if(gating && ifc->reassemble <= 0) {
  226                 /*
  227                  * v6 intermediate nodes are not supposed to fragment pkts;
  228                  * we fragment if ifc->reassemble is turned on; an exception
  229                  * needed for nat.
  230                  */
  231                 ip->stats[OutDiscards]++;
  232                 icmppkttoobig6(f, ifc, bp);
  233                 netlog(f, Logip, "%I: gated pkts not fragmented\n", eh->dst);
  234                 goto raise;
  235         }
  236 
  237         /* start v6 fragmentation */
  238         uflen = unfraglen(bp, &nexthdr, 1);
  239         if(uflen > medialen) {
  240                 ip->stats[FragFails]++;
  241                 ip->stats[OutDiscards]++;
  242                 netlog(f, Logip, "%I: unfragmentable part too big\n", eh->dst);
  243                 goto raise;
  244         }
  245 
  246         flen = len - uflen;
  247         seglen = (medialen - (uflen + IP6FHDR)) & ~7;
  248         if(seglen < 8) {
  249                 ip->stats[FragFails]++;
  250                 ip->stats[OutDiscards]++;
  251                 netlog(f, Logip, "%I: seglen < 8\n", eh->dst);
  252                 goto raise;
  253         }
  254 
  255         lid = incref(&ip->id6);
  256         fraghdr.nexthdr = nexthdr;
  257         fraghdr.res = 0;
  258         hnputl(fraghdr.id, lid);
  259 
  260         xp = bp;
  261         offset = uflen;
  262         while (xp && offset && offset >= BLEN(xp)) {
  263                 offset -= BLEN(xp);
  264                 xp = xp->next;
  265         }
  266         xp->rp += offset;
  267 
  268         fragoff = 0;
  269         morefrags = 1;
  270 
  271         for(; fragoff < flen; fragoff += seglen) {
  272                 nb = allocb(uflen + IP6FHDR + seglen);
  273 
  274                 if(fragoff + seglen >= flen) {
  275                         seglen = flen - fragoff;
  276                         morefrags = 0;
  277                 }
  278 
  279                 hnputs(eh->ploadlen, seglen+IP6FHDR);
  280                 memmove(nb->wp, eh, uflen);
  281                 nb->wp += uflen;
  282 
  283                 hnputs(fraghdr.offsetRM, fragoff); /* last 3 bits must be 0 */
  284                 fraghdr.offsetRM[1] |= morefrags;
  285                 memmove(nb->wp, &fraghdr, IP6FHDR);
  286                 nb->wp += IP6FHDR;
  287 
  288                 /* Copy data */
  289                 chunk = seglen;
  290                 while (chunk) {
  291                         if(!xp) {
  292                                 ip->stats[OutDiscards]++;
  293                                 ip->stats[FragFails]++;
  294                                 freeblist(nb);
  295                                 netlog(f, Logip, "!xp: chunk in v6%d\n", chunk);
  296                                 goto raise;
  297                         }
  298                         blklen = chunk;
  299                         if(BLEN(xp) < chunk)
  300                                 blklen = BLEN(xp);
  301                         memmove(nb->wp, xp->rp, blklen);
  302 
  303                         nb->wp += blklen;
  304                         xp->rp += blklen;
  305                         chunk -= blklen;
  306                         if(xp->rp == xp->wp)
  307                                 xp = xp->next;
  308                 }
  309 
  310                 ifc->m->bwrite(ifc, nb, V6, gate);
  311                 ip->stats[FragCreates]++;
  312         }
  313         ip->stats[FragOKs]++;
  314 
  315 raise:
  316         runlock(ifc);
  317         poperror();
  318 free:
  319         freeblist(bp);
  320         return rv;
  321 }
  322 
  323 void
  324 ipiput6(Fs *f, Ipifc *ifc, Block *bp)
  325 {
  326         int hl, hop, tos, notforme, tentative;
  327         uchar proto;
  328         uchar v6dst[IPaddrlen];
  329         IP *ip;
  330         Ip6hdr *h;
  331         Proto *p;
  332         Route *r, *sr;
  333 
  334         ip = f->ip;
  335         ip->stats[InReceives]++;
  336 
  337         /*
  338          *  Ensure we have all the header info in the first
  339          *  block.  Make life easier for other protocols by
  340          *  collecting up to the first 64 bytes in the first block.
  341          */
  342         if(BLEN(bp) < 64) {
  343                 hl = blocklen(bp);
  344                 if(hl < IP6HDR)
  345                         hl = IP6HDR;
  346                 if(hl > 64)
  347                         hl = 64;
  348                 bp = pullupblock(bp, hl);
  349                 if(bp == nil)
  350                         return;
  351         }
  352 
  353         h = (Ip6hdr *)bp->rp;
  354 
  355         memmove(&v6dst[0], &h->dst[0], IPaddrlen);
  356         notforme = ipforme(f, v6dst) == 0;
  357         tentative = iptentative(f, v6dst);
  358 
  359         if(tentative && h->proto != ICMPv6) {
  360                 print("tentative addr, drop\n");
  361                 freeblist(bp);
  362                 return;
  363         }
  364 
  365         /* Check header version */
  366         if(BLKIPVER(bp) != IP_VER6) {
  367                 ip->stats[InHdrErrors]++;
  368                 netlog(f, Logip, "ip: bad version %ux\n", (h->vcf[0]&0xF0)>>2);
  369                 freeblist(bp);
  370                 return;
  371         }
  372 
  373         /* route */
  374         if(notforme) {
  375                 if(!ip->iprouting){
  376                         freeb(bp);
  377                         return;
  378                 }
  379 
  380                 /* don't forward to link-local destinations */
  381                 if(islinklocal(h->dst) ||
  382                    (isv6mcast(h->dst) && (h->dst[1]&0xF) <= Link_local_scop)){
  383                         ip->stats[OutDiscards]++;
  384                         freeblist(bp);
  385                         return;
  386                 }
  387                         
  388                 /* don't forward to source's network */
  389                 sr = v6lookup(f, h->src, nil);
  390                 r  = v6lookup(f, h->dst, nil);
  391 
  392                 if(r == nil || sr == r){
  393                         ip->stats[OutDiscards]++;
  394                         freeblist(bp);
  395                         return;
  396                 }
  397 
  398                 /* don't forward if packet has timed out */
  399                 hop = h->ttl;
  400                 if(hop < 1) {
  401                         ip->stats[InHdrErrors]++;
  402                         icmpttlexceeded6(f, ifc, bp);
  403                         freeblist(bp);
  404                         return;
  405                 }
  406 
  407                 /* process headers & reassemble if the interface expects it */
  408                 bp = procxtns(ip, bp, r->ifc->reassemble);
  409                 if(bp == nil)
  410                         return;
  411 
  412                 ip->stats[ForwDatagrams]++;
  413                 h = (Ip6hdr *)bp->rp;
  414                 tos = IPV6CLASS(h);
  415                 hop = h->ttl;
  416                 ipoput6(f, bp, 1, hop-1, tos, nil);
  417                 return;
  418         }
  419 
  420         /* reassemble & process headers if needed */
  421         bp = procxtns(ip, bp, 1);
  422         if(bp == nil)
  423                 return;
  424 
  425         h = (Ip6hdr *) (bp->rp);
  426         proto = h->proto;
  427         p = Fsrcvpcol(f, proto);
  428         if(p && p->rcv) {
  429                 ip->stats[InDelivers]++;
  430                 (*p->rcv)(p, ifc, bp);
  431                 return;
  432         }
  433 
  434         ip->stats[InDiscards]++;
  435         ip->stats[InUnknownProtos]++;
  436         freeblist(bp);
  437 }
  438 
  439 /*
  440  * ipfragfree6 - copied from ipfragfree4 - assume hold fraglock6
  441  */
  442 void
  443 ipfragfree6(IP *ip, Fragment6 *frag)
  444 {
  445         Fragment6 *fl, **l;
  446 
  447         if(frag->blist)
  448                 freeblist(frag->blist);
  449 
  450         memset(frag->src, 0, IPaddrlen);
  451         frag->id = 0;
  452         frag->blist = nil;
  453 
  454         l = &ip->flisthead6;
  455         for(fl = *l; fl; fl = fl->next) {
  456                 if(fl == frag) {
  457                         *l = frag->next;
  458                         break;
  459                 }
  460                 l = &fl->next;
  461         }
  462 
  463         frag->next = ip->fragfree6;
  464         ip->fragfree6 = frag;
  465 }
  466 
  467 /*
  468  * ipfragallo6 - copied from ipfragalloc4
  469  */
  470 Fragment6*
  471 ipfragallo6(IP *ip)
  472 {
  473         Fragment6 *f;
  474 
  475         while(ip->fragfree6 == nil) {
  476                 /* free last entry on fraglist */
  477                 for(f = ip->flisthead6; f->next; f = f->next)
  478                         ;
  479                 ipfragfree6(ip, f);
  480         }
  481         f = ip->fragfree6;
  482         ip->fragfree6 = f->next;
  483         f->next = ip->flisthead6;
  484         ip->flisthead6 = f;
  485         f->age = NOW + 30000;
  486 
  487         return f;
  488 }
  489 
  490 static Block*
  491 procxtns(IP *ip, Block *bp, int doreasm)
  492 {
  493         int offset;
  494         uchar proto;
  495         Ip6hdr *h;
  496 
  497         h = (Ip6hdr *)bp->rp;
  498         offset = unfraglen(bp, &proto, 0);
  499 
  500         if(proto == FH && doreasm != 0) {
  501                 bp = ip6reassemble(ip, offset, bp, h);
  502                 if(bp == nil)
  503                         return nil;
  504                 offset = unfraglen(bp, &proto, 0);
  505         }
  506 
  507         if(proto == DOH || offset > IP6HDR)
  508                 bp = procopts(bp);
  509         return bp;
  510 }
  511 
  512 /*
  513  * returns length of "Unfragmentable part", i.e., sum of lengths of ipv6 hdr,
  514  * hop-by-hop & routing headers if present; *nexthdr is set to nexthdr value
  515  * of the last header in the "Unfragmentable part"; if setfh != 0, nexthdr
  516  * field of the last header in the "Unfragmentable part" is set to FH.
  517  */
  518 int
  519 unfraglen(Block *bp, uchar *nexthdr, int setfh)
  520 {
  521         uchar *p, *q;
  522         int ufl, hs;
  523 
  524         p = bp->rp;
  525         q = p+6;   /* proto, = p+sizeof(Ip6hdr.vcf)+sizeof(Ip6hdr.ploadlen) */
  526         *nexthdr = *q;
  527         ufl = IP6HDR;
  528         p += ufl;
  529 
  530         while (*nexthdr == HBH || *nexthdr == RH) {
  531                 *nexthdr = *p;
  532                 hs = ((int)*(p+1) + 1) * 8;
  533                 ufl += hs;
  534                 q = p;
  535                 p += hs;
  536         }
  537 
  538         if(*nexthdr == FH)
  539                 *q = *p;
  540         if(setfh)
  541                 *q = FH;
  542         return ufl;
  543 }
  544 
  545 Block*
  546 procopts(Block *bp)
  547 {
  548         return bp;
  549 }
  550 
  551 Block*
  552 ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
  553 {
  554         int fend, offset, ovlap, len, fragsize, pktposn;
  555         uint id;
  556         uchar src[IPaddrlen], dst[IPaddrlen];
  557         Block *bl, **l, *last, *prev;
  558         Fraghdr6 *fraghdr;
  559         Fragment6 *f, *fnext;
  560 
  561         fraghdr = (Fraghdr6 *)(bp->rp + uflen);
  562         memmove(src, ih->src, IPaddrlen);
  563         memmove(dst, ih->dst, IPaddrlen);
  564         id = nhgetl(fraghdr->id);
  565         offset = nhgets(fraghdr->offsetRM) & ~7;
  566 
  567         /*
  568          *  block lists are too hard, pullupblock into a single block
  569          */
  570         if(bp->next){
  571                 bp = pullupblock(bp, blocklen(bp));
  572                 ih = (Ip6hdr *)bp->rp;
  573         }
  574 
  575         qlock(&ip->fraglock6);
  576 
  577         /*
  578          *  find a reassembly queue for this fragment
  579          */
  580         for(f = ip->flisthead6; f; f = fnext){
  581                 fnext = f->next;
  582                 if(ipcmp(f->src, src)==0 && ipcmp(f->dst, dst)==0 && f->id == id)
  583                         break;
  584                 if(f->age < NOW){
  585                         ip->stats[ReasmTimeout]++;
  586                         ipfragfree6(ip, f);
  587                 }
  588         }
  589 
  590         /*
  591          *  if this isn't a fragmented packet, accept it
  592          *  and get rid of any fragments that might go
  593          *  with it.
  594          */
  595         if(nhgets(fraghdr->offsetRM) == 0) {    /* 1st frag is also last */
  596                 if(f) {
  597                         ipfragfree6(ip, f);
  598                         ip->stats[ReasmFails]++;
  599                 }
  600                 qunlock(&ip->fraglock6);
  601                 return bp;
  602         }
  603 
  604         if(bp->base+sizeof(Ipfrag) >= bp->rp){
  605                 bp = padblock(bp, sizeof(Ipfrag));
  606                 bp->rp += sizeof(Ipfrag);
  607         }
  608 
  609         BKFG(bp)->foff = offset;
  610         BKFG(bp)->flen = nhgets(ih->ploadlen) + IP6HDR - uflen - IP6FHDR;
  611 
  612         /* First fragment allocates a reassembly queue */
  613         if(f == nil) {
  614                 f = ipfragallo6(ip);
  615                 f->id = id;
  616                 memmove(f->src, src, IPaddrlen);
  617                 memmove(f->dst, dst, IPaddrlen);
  618 
  619                 f->blist = bp;
  620 
  621                 qunlock(&ip->fraglock6);
  622                 ip->stats[ReasmReqds]++;
  623                 return nil;
  624         }
  625 
  626         /*
  627          *  find the new fragment's position in the queue
  628          */
  629         prev = nil;
  630         l = &f->blist;
  631         bl = f->blist;
  632         while(bl != nil && BKFG(bp)->foff > BKFG(bl)->foff) {
  633                 prev = bl;
  634                 l = &bl->next;
  635                 bl = bl->next;
  636         }
  637 
  638         /* Check overlap of a previous fragment - trim away as necessary */
  639         if(prev) {
  640                 ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff;
  641                 if(ovlap > 0) {
  642                         if(ovlap >= BKFG(bp)->flen) {
  643                                 freeblist(bp);
  644                                 qunlock(&ip->fraglock6);
  645                                 return nil;
  646                         }
  647                         BKFG(prev)->flen -= ovlap;
  648                 }
  649         }
  650 
  651         /* Link onto assembly queue */
  652         bp->next = *l;
  653         *l = bp;
  654 
  655         /* Check to see if succeeding segments overlap */
  656         if(bp->next) {
  657                 l = &bp->next;
  658                 fend = BKFG(bp)->foff + BKFG(bp)->flen;
  659 
  660                 /* Take completely covered segments out */
  661                 while(*l) {
  662                         ovlap = fend - BKFG(*l)->foff;
  663                         if(ovlap <= 0)
  664                                 break;
  665                         if(ovlap < BKFG(*l)->flen) {
  666                                 BKFG(*l)->flen -= ovlap;
  667                                 BKFG(*l)->foff += ovlap;
  668                                 /* move up ih hdrs */
  669                                 memmove((*l)->rp + ovlap, (*l)->rp, uflen);
  670                                 (*l)->rp += ovlap;
  671                                 break;
  672                         }
  673                         last = (*l)->next;
  674                         (*l)->next = nil;
  675                         freeblist(*l);
  676                         *l = last;
  677                 }
  678         }
  679 
  680         /*
  681          *  look for a complete packet.  if we get to a fragment
  682          *  with the trailing bit of fraghdr->offsetRM[1] set, we're done.
  683          */
  684         pktposn = 0;
  685         for(bl = f->blist; bl && BKFG(bl)->foff == pktposn; bl = bl->next) {
  686                 fraghdr = (Fraghdr6 *)(bl->rp + uflen);
  687                 if((fraghdr->offsetRM[1] & 1) == 0) {
  688                         bl = f->blist;
  689 
  690                         /* get rid of frag header in first fragment */
  691                         memmove(bl->rp + IP6FHDR, bl->rp, uflen);
  692                         bl->rp += IP6FHDR;
  693                         len = nhgets(((Ip6hdr*)bl->rp)->ploadlen) - IP6FHDR;
  694                         bl->wp = bl->rp + len + IP6HDR;
  695                         /*
  696                          * Pullup all the fragment headers and
  697                          * return a complete packet
  698                          */
  699                         for(bl = bl->next; bl; bl = bl->next) {
  700                                 fragsize = BKFG(bl)->flen;
  701                                 len += fragsize;
  702                                 bl->rp += uflen + IP6FHDR;
  703                                 bl->wp = bl->rp + fragsize;
  704                         }
  705 
  706                         bl = f->blist;
  707                         f->blist = nil;
  708                         ipfragfree6(ip, f);
  709                         ih = (Ip6hdr*)bl->rp;
  710                         hnputs(ih->ploadlen, len);
  711                         qunlock(&ip->fraglock6);
  712                         ip->stats[ReasmOKs]++;
  713                         return bl;
  714                 }
  715                 pktposn += BKFG(bl)->flen;
  716         }
  717         qunlock(&ip->fraglock6);
  718         return nil;
  719 }

Cache object: 78e8c0db82cc2ff090c036c11e7a1daf


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