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

Cache object: ba050bfb19a2e52b9e0601000470feb1


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