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