| plan 9 kernel history: overview | file list | diff list |
2003/0216/ip/ip.c (diff list | history)
| ip/ip.c on 1997/0327 | ||
| 1997/0327 | #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" | |
| 2002/0507 | #include "ip.h" | |
| 1997/0327 | ||
| 2002/0507 | typedef struct Ip4hdr Ip4hdr; typedef struct IP IP; typedef struct Fragment4 Fragment4; typedef struct Fragment6 Fragment6; typedef struct Ipfrag Ipfrag; | |
| 1997/0327 | enum { | |
| 2002/0507 | IP4HDR = 20, /* sizeof(Ip4hdr) */ IP6HDR = 40, /* sizeof(Ip6hdr) */ IP_HLEN4 = 0x05, /* Header length in words */ | |
| 1997/0327 | IP_DF = 0x4000, /* Don't fragment */ IP_MF = 0x2000, /* More fragments */ | |
| 2002/0507 | IP6FHDR = 8, /* sizeof(Fraghdr6) */ | |
| 2002/0615 | IP_MAX = 64*1024, /* Maximum Internet packet size */ | |
| 1997/0327 | }; | |
| 2002/0507 | #define BLKIPVER(xp) (((Ip4hdr*)((xp)->rp))->vihl&0xF0) struct Ip4hdr | |
| 1997/0327 | { | |
| 1998/0306 | uchar vihl; /* Version and header length */ uchar tos; /* Type of service */ uchar length[2]; /* packet length */ | |
| 1998/0313 | uchar id[2]; /* ip->identification */ | |
| 1998/0306 | uchar frag[2]; /* Fragment information */ | |
| 2002/0507 | uchar ttl; /* Time to live */ | |
| 1998/0306 | uchar proto; /* Protocol */ uchar cksum[2]; /* Header checksum */ | |
| 1998/0313 | uchar src[4]; /* IP source */ uchar dst[4]; /* IP destination */ | |
| 1997/0327 | }; | |
| 1998/0313 | /* MIB II counters */ | |
| 2000/0706 | enum | |
| 1998/0313 | { | |
| 2000/0706 | Forwarding, DefaultTTL, InReceives, InHdrErrors, InAddrErrors, ForwDatagrams, InUnknownProtos, InDiscards, InDelivers, OutRequests, OutDiscards, OutNoRoutes, ReasmTimeout, ReasmReqds, ReasmOKs, ReasmFails, FragOKs, FragFails, FragCreates, Nstats, | |
| 1998/0313 | }; | |
| 1997/0327 | ||
| 2002/0507 | struct Fragment4 { Block* blist; Fragment4* next; ulong src; ulong dst; ushort id; ulong age; }; struct Fragment6 { Block* blist; Fragment6* next; uchar src[IPaddrlen]; uchar dst[IPaddrlen]; uint id; ulong age; }; struct Ipfrag { ushort foff; ushort flen; }; /* an instance of IP */ struct IP { ulong stats[Nstats]; QLock fraglock4; Fragment4* flisthead4; Fragment4* fragfree4; Ref id4; QLock fraglock6; Fragment6* flisthead6; Fragment6* fragfree6; Ref id6; int iprouting; /* true if we route like a gateway */ }; | |
| 2000/0706 | static char *statnames[] = { [Forwarding] "Forwarding", [DefaultTTL] "DefaultTTL", [InReceives] "InReceives", [InHdrErrors] "InHdrErrors", [InAddrErrors] "InAddrErrors", [ForwDatagrams] "ForwDatagrams", [InUnknownProtos] "InUnknownProtos", [InDiscards] "InDiscards", [InDelivers] "InDelivers", [OutRequests] "OutRequests", [OutDiscards] "OutDiscards", [OutNoRoutes] "OutNoRoutes", [ReasmTimeout] "ReasmTimeout", [ReasmReqds] "ReasmReqds", [ReasmOKs] "ReasmOKs", [ReasmFails] "ReasmFails", [FragOKs] "FragOKs", [FragFails] "FragFails", [FragCreates] "FragCreates", }; | |
| 2002/0507 | #define BLKIP(xp) ((Ip4hdr*)((xp)->rp)) | |
| 1997/0327 | /* * This sleazy macro relies on the media header size being * larger than sizeof(Ipfrag). ipreassemble checks this is true */ #define BKFG(xp) ((Ipfrag*)((xp)->base)) | |
| 1998/0313 | ushort ipcsum(uchar*); | |
| 2002/0507 | Block* ip4reassemble(IP*, int, Block*, Ip4hdr*); void ipfragfree4(IP*, Fragment4*); Fragment4* ipfragallo4(IP*); | |
| 1998/0313 | ||
| 2002/0507 | ||
| 1998/0313 | void | |
| 2002/0507 | ip_init_6(Fs *f) { v6params *v6p; v6p = smalloc(sizeof(v6params)); v6p->rp.mflag = 0; // default not managed v6p->rp.oflag = 0; v6p->rp.maxraint = 600000; // millisecs v6p->rp.minraint = 200000; v6p->rp.linkmtu = 0; // no mtu sent v6p->rp.reachtime = 0; v6p->rp.rxmitra = 0; v6p->rp.ttl = MAXTTL; v6p->rp.routerlt = 3*(v6p->rp.maxraint); v6p->hp.rxmithost = 1000; // v6 RETRANS_TIMER v6p->cdrouter = -1; f->v6p = v6p; } void initfrag(IP *ip, int size) { Fragment4 *fq4, *eq4; Fragment6 *fq6, *eq6; ip->fragfree4 = (Fragment4*)malloc(sizeof(Fragment4) * size); if(ip->fragfree4 == nil) panic("initfrag"); eq4 = &ip->fragfree4[size]; for(fq4 = ip->fragfree4; fq4 < eq4; fq4++) fq4->next = fq4+1; ip->fragfree4[size-1].next = nil; ip->fragfree6 = (Fragment6*)malloc(sizeof(Fragment6) * size); if(ip->fragfree6 == nil) panic("initfrag"); eq6 = &ip->fragfree6[size]; for(fq6 = ip->fragfree6; fq6 < eq6; fq6++) fq6->next = fq6+1; ip->fragfree6[size-1].next = nil; } void | |
| 1998/0313 | ip_init(Fs *f) | |
| 1997/0916 | { | |
| 1998/0313 | IP *ip; | |
| 1997/0916 | ||
| 1998/0313 | ip = smalloc(sizeof(IP)); initfrag(ip, 100); f->ip = ip; | |
| 2002/0507 | ip_init_6(f); | |
| 1998/0313 | } | |
| 1997/0327 | void | |
| 1998/0314 | iprouting(Fs *f, int on) { f->ip->iprouting = on; | |
| 1998/0813 | if(f->ip->iprouting==0) | |
| 2000/0706 | f->ip->stats[Forwarding] = 2; | |
| 1998/0813 | else | |
| 2000/0706 | f->ip->stats[Forwarding] = 1; | |
| 1998/0314 | } void | |
| 2002/0507 | ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos) | |
| 1997/0327 | { | |
| 1998/0306 | Ipifc *ifc; uchar *gate; | |
| 2001/1007 | ulong fragoff; | |
| 1997/0327 | Block *xp, *nb; | |
| 2002/0507 | Ip4hdr *eh, *feh; | |
| 1997/0327 | int lid, len, seglen, chunk, dlen, blklen, offset, medialen; | |
| 1998/0313 | Route *r, *sr; IP *ip; | |
| 2003/0214 | Proto *pr; | |
| 1997/0327 | ||
| 1998/0313 | ip = f->ip; | |
| 1997/0327 | /* Fill out the ip header */ | |
| 2002/0507 | eh = (Ip4hdr*)(bp->rp); | |
| 1997/0327 | ||
| 2000/0706 | ip->stats[OutRequests]++; | |
| 1998/0313 | ||
| 1998/0306 | /* Number of uchars in data and ip header to write */ | |
| 1997/0327 | len = blocklen(bp); | |
| 1998/0313 | ||
| 1997/0327 | if(gating){ chunk = nhgets(eh->length); if(chunk > len){ | |
| 2000/0706 | ip->stats[OutDiscards]++; | |
| 1998/0313 | netlog(f, Logip, "short gated packet\n"); | |
| 1998/0308 | goto free; | |
| 1997/0327 | } if(chunk < len) len = chunk; } | |
| 1998/0306 | if(len >= IP_MAX){ | |
| 2000/0706 | ip->stats[OutDiscards]++; | |
| 1998/0313 | netlog(f, Logip, "exceeded ip max size %V\n", eh->dst); | |
| 1998/0308 | goto free; | |
| 1997/0327 | } | |
| 1998/0313 | r = v4lookup(f, eh->dst); | |
| 1998/0306 | if(r == nil){ | |
| 2000/0706 | ip->stats[OutNoRoutes]++; | |
| 1998/0313 | netlog(f, Logip, "no interface %V\n", eh->dst); | |
| 2003/0214 | if(!gating){ | |
| 2003/0216 | freeblist(bp); print("ipoput4: no route\n"); | |
| 2003/0214 | error("no route"); } | |
| 1998/0308 | goto free; | |
| 1997/0327 | } | |
| 1998/0313 | ifc = r->ifc; if(r->type & (Rifc|Runi)) | |
| 1998/0306 | gate = eh->dst; else | |
| 1998/0313 | if(r->type & (Rbcast|Rmulti)) { gate = eh->dst; sr = v4lookup(f, eh->src); if(sr != nil && (sr->type & Runi)) ifc = sr->ifc; } else | |
| 1998/0306 | gate = r->v4.gate; | |
| 1998/0313 | ||
| 1999/10041 | if(!gating) | |
| 2002/0507 | eh->vihl = IP_VER4|IP_HLEN4; | |
| 1999/10041 | eh->ttl = ttl; | |
| 2001/0430 | if(!gating) eh->tos = tos; | |
| 1997/0327 | ||
| 1999/0302 | if(!canrlock(ifc)) goto free; | |
| 1998/0307 | if(waserror()){ runlock(ifc); nexterror(); } if(ifc->m == nil) goto raise; | |
| 1997/0327 | /* If we dont need to fragment just send it */ | |
| 2003/0209 | medialen = ifc->maxtu - ifc->m->hsize; | |
| 1997/0327 | if(len <= medialen) { if(!gating) | |
| 2002/0507 | hnputs(eh->id, incref(&ip->id4)); | |
| 1997/0327 | hnputs(eh->length, len); | |
| 2001/0430 | if(!gating){ eh->frag[0] = 0; eh->frag[1] = 0; } | |
| 1997/0327 | eh->cksum[0] = 0; eh->cksum[1] = 0; hnputs(eh->cksum, ipcsum(&eh->vihl)); | |
| 1998/0306 | ifc->m->bwrite(ifc, bp, V4, gate); | |
| 1998/0307 | runlock(ifc); poperror(); | |
| 1997/0327 | return; } | |
| 2002/1204 | if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst); | |
| 1997/0327 | if(eh->frag[0] & (IP_DF>>8)){ | |
| 2000/0706 | ip->stats[FragFails]++; ip->stats[OutDiscards]++; | |
| 2002/1207 | icmpcantfrag(f, bp, medialen); | |
| 1998/0313 | netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst); | |
| 1997/0327 | goto raise; } | |
| 2002/0507 | seglen = (medialen - IP4HDR) & ~7; | |
| 1997/0327 | if(seglen < 8){ | |
| 2000/0706 | ip->stats[FragFails]++; ip->stats[OutDiscards]++; | |
| 1998/0313 | netlog(f, Logip, "%V seglen < 8\n", eh->dst); | |
| 1997/0327 | goto raise; } | |
| 2002/0507 | dlen = len - IP4HDR; | |
| 1997/0327 | xp = bp; if(gating) lid = nhgets(eh->id); else | |
| 2002/0507 | lid = incref(&ip->id4); | |
| 1997/0327 | ||
| 2002/0507 | offset = IP4HDR; | |
| 1997/0327 | while(xp != nil && offset && offset >= BLEN(xp)) { offset -= BLEN(xp); xp = xp->next; } xp->rp += offset; | |
| 2001/0430 | if(gating) | |
| 2001/1007 | fragoff = nhgets(eh->frag)<<3; | |
| 2001/0430 | else fragoff = 0; dlen += fragoff; for(; fragoff < dlen; fragoff += seglen) { | |
| 2002/0507 | nb = allocb(IP4HDR+seglen); feh = (Ip4hdr*)(nb->rp); | |
| 1997/0327 | ||
| 2002/0507 | memmove(nb->wp, eh, IP4HDR); nb->wp += IP4HDR; | |
| 1997/0327 | if((fragoff + seglen) >= dlen) { seglen = dlen - fragoff; hnputs(feh->frag, fragoff>>3); } else hnputs(feh->frag, (fragoff>>3)|IP_MF); | |
| 2002/0507 | hnputs(feh->length, seglen + IP4HDR); | |
| 1997/0327 | hnputs(feh->id, lid); /* Copy up the data area */ chunk = seglen; while(chunk) { if(!xp) { | |
| 2000/0706 | ip->stats[OutDiscards]++; ip->stats[FragFails]++; | |
| 1997/0327 | freeblist(nb); | |
| 1998/0313 | netlog(f, Logip, "!xp: chunk %d\n", chunk); | |
| 1997/0327 | goto raise; } blklen = chunk; if(BLEN(xp) < chunk) blklen = BLEN(xp); memmove(nb->wp, xp->rp, blklen); nb->wp += blklen; xp->rp += blklen; chunk -= blklen; if(xp->rp == xp->wp) xp = xp->next; | |
| 1998/0313 | } | |
| 1997/0327 | feh->cksum[0] = 0; feh->cksum[1] = 0; hnputs(feh->cksum, ipcsum(&feh->vihl)); | |
| 1998/0306 | ifc->m->bwrite(ifc, nb, V4, gate); | |
| 2000/0706 | ip->stats[FragCreates]++; | |
| 1997/0327 | } | |
| 2000/0706 | ip->stats[FragOKs]++; | |
| 1997/0327 | raise: | |
| 1998/0307 | runlock(ifc); poperror(); | |
| 1998/0308 | free: | |
| 1997/0327 | freeblist(bp); } void | |
| 2002/0507 | ipiput4(Fs *f, Ipifc *ifc, Block *bp) | |
| 1997/0327 | { | |
| 1998/0313 | int hl; | |
| 2002/0507 | int hop, tos, proto, olen; Ip4hdr *h; | |
| 1997/0327 | Proto *p; ushort frag; int notforme; | |
| 1998/0313 | uchar *dp, v6dst[IPaddrlen]; IP *ip; | |
| 1998/1209 | Route *r, *sr; | |
| 1997/0327 | ||
| 2002/0507 | if(BLKIPVER(bp) != IP_VER4) { ipiput6(f, ifc, bp); return; } | |
| 1998/0313 | ip = f->ip; | |
| 2000/0706 | ip->stats[InReceives]++; | |
| 1998/0313 | ||
| 1998/0326 | /* | |
| 1998/0331 | * Ensure we have all the header info in the first | |
| 1998/0326 | * block. Make life easier for other protocols by * collecting up to the first 64 bytes in the first block. */ if(BLEN(bp) < 64) { hl = blocklen(bp); | |
| 2002/0507 | if(hl < IP4HDR) hl = IP4HDR; | |
| 1998/0326 | if(hl > 64) hl = 64; bp = pullupblock(bp, hl); | |
| 1997/0327 | if(bp == nil) return; } | |
| 2002/0507 | h = (Ip4hdr*)(bp->rp); | |
| 1998/0306 | /* dump anything that whose header doesn't checksum */ | |
| 2003/0213 | if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) { | |
| 2000/0706 | ip->stats[InHdrErrors]++; | |
| 1998/1208 | netlog(f, Logip, "ip: checksum error %V\n", h->src); | |
| 1997/0327 | freeblist(bp); return; } | |
| 1998/0306 | v4tov6(v6dst, h->dst); | |
| 1998/0313 | notforme = ipforme(f, v6dst) == 0; /* Check header length and version */ | |
| 2002/0507 | if((h->vihl&0x0F) != IP_HLEN4) { | |
| 1998/0313 | hl = (h->vihl&0xF)<<2; | |
| 2002/0507 | if(hl < (IP_HLEN4<<2)) { | |
| 2000/0706 | ip->stats[InHdrErrors]++; | |
| 1998/0313 | netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl); freeblist(bp); return; } | |
| 2002/0507 | /* If this is not routed strip off the options */ | |
| 1998/0313 | if(notforme == 0) { | |
| 2002/0424 | olen = nhgets(h->length); | |
| 2002/0507 | dp = bp->rp + (hl - (IP_HLEN4<<2)); memmove(dp, h, IP_HLEN4<<2); | |
| 1998/0313 | bp->rp = dp; | |
| 2002/0507 | h = (Ip4hdr*)(bp->rp); h->vihl = (IP_VER4|IP_HLEN4); hnputs(h->length, olen-hl+(IP_HLEN4<<2)); | |
| 1998/0313 | } } /* route */ | |
| 1998/0306 | if(notforme) { | |
| 1998/1209 | if(!ip->iprouting){ | |
| 2000/0220 | freeb(bp); | |
| 1998/1209 | return; } /* don't forward to source's network */ sr = v4lookup(f, h->src); r = v4lookup(f, h->dst); | |
| 2002/0507 | ||
| 1998/1209 | if(r == nil || sr == r){ | |
| 2000/0706 | ip->stats[OutDiscards]++; | |
| 1998/1209 | freeblist(bp); return; } /* don't forward if packet has timed out */ | |
| 2002/0507 | hop = h->ttl; if(hop < 1) { | |
| 2000/0706 | ip->stats[InHdrErrors]++; | |
| 2002/0507 | icmpttlexceeded(f, ifc->lifc->local, bp); | |
| 1998/1209 | freeblist(bp); return; } | |
| 2002/0507 | ||
| 2001/1117 | /* reassemble if the interface expects it */ if(r->ifc->reassemble){ frag = nhgets(h->frag); if(frag) { h->tos = 0; if(frag & IP_MF) h->tos = 1; | |
| 2002/0507 | bp = ip4reassemble(ip, frag, bp, h); | |
| 2001/1117 | if(bp == nil) return; | |
| 2002/0507 | h = (Ip4hdr*)(bp->rp); | |
| 2001/1117 | } } | |
| 1998/1209 | ||
| 2000/0706 | ip->stats[ForwDatagrams]++; | |
| 2002/0507 | tos = h->tos; hop = h->ttl; ipoput4(f, bp, 1, hop - 1, tos); | |
| 1998/0306 | return; } | |
| 1997/0327 | frag = nhgets(h->frag); if(frag) { h->tos = 0; if(frag & IP_MF) h->tos = 1; | |
| 2002/0507 | bp = ip4reassemble(ip, frag, bp, h); | |
| 1997/0327 | if(bp == nil) return; | |
| 2002/0507 | h = (Ip4hdr*)(bp->rp); | |
| 1997/0327 | } | |
| 2002/1207 | /* don't let any frag info go up the stack */ h->frag[0] = 0; h->frag[1] = 0; | |
| 1997/0327 | ||
| 2002/0507 | proto = h->proto; p = Fsrcvpcol(f, proto); | |
| 1998/0313 | if(p != nil && p->rcv != nil) { | |
| 2000/0706 | ip->stats[InDelivers]++; | |
| 2001/0623 | (*p->rcv)(p, ifc, bp); | |
| 1998/0313 | return; } | |
| 2000/0706 | ip->stats[InDiscards]++; ip->stats[InUnknownProtos]++; | |
| 1998/0313 | freeblist(bp); | |
| 1997/0327 | } int | |
| 1998/0313 | ipstats(Fs *f, char *buf, int len) | |
| 1997/0327 | { | |
| 1998/0313 | IP *ip; | |
| 2000/0706 | char *p, *e; int i; | |
| 1997/0327 | ||
| 1998/0313 | ip = f->ip; | |
| 2000/0706 | ip->stats[DefaultTTL] = MAXTTL; p = buf; e = p+len; for(i = 0; i < Nstats; i++) p = seprint(p, e, "%s: %lud\n", statnames[i], ip->stats[i]); return p - buf; | |
| 1997/0327 | } Block* | |
| 2002/0507 | ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) | |
| 1997/0327 | { int fend; ushort id; | |
| 2002/0507 | Fragment4 *f, *fnext; | |
| 1998/0306 | ulong src, dst; | |
| 1997/0327 | Block *bl, **l, *last, *prev; int ovlap, len, fragsize, pktposn; | |
| 1998/0313 | src = nhgetl(ih->src); dst = nhgetl(ih->dst); id = nhgets(ih->id); | |
| 1997/0327 | /* * block lists are too hard, pullupblock into a single block */ if(bp->next){ bp = pullupblock(bp, blocklen(bp)); | |
| 2002/0507 | ih = (Ip4hdr*)(bp->rp); | |
| 1997/0327 | } | |
| 2002/0507 | qlock(&ip->fraglock4); | |
| 1997/0327 | /* * find a reassembly queue for this fragment */ | |
| 2002/0507 | for(f = ip->flisthead4; f; f = fnext){ fnext = f->next; /* because ipfragfree4 changes the list */ | |
| 1997/0327 | if(f->src == src && f->dst == dst && f->id == id) break; | |
| 2002/0710 | if(f->age < NOW){ | |
| 2000/0706 | ip->stats[ReasmTimeout]++; | |
| 2002/0507 | ipfragfree4(ip, f); | |
| 1997/0916 | } | |
| 1997/0327 | } /* * if this isn't a fragmented packet, accept it * and get rid of any fragments that might go * with it. */ | |
| 1998/0313 | if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) { if(f != nil) { | |
| 2002/0507 | ipfragfree4(ip, f); | |
| 2000/0706 | ip->stats[ReasmFails]++; | |
| 1998/0313 | } | |
| 2002/0507 | qunlock(&ip->fraglock4); | |
| 1997/0327 | return bp; } | |
| 1997/0504 | if(bp->base+sizeof(Ipfrag) >= bp->rp){ bp = padblock(bp, sizeof(Ipfrag)); bp->rp += sizeof(Ipfrag); } | |
| 1997/0327 | BKFG(bp)->foff = offset<<3; | |
| 2002/0507 | BKFG(bp)->flen = nhgets(ih->length)-IP4HDR; | |
| 1997/0327 | /* First fragment allocates a reassembly queue */ if(f == nil) { | |
| 2002/0507 | f = ipfragallo4(ip); | |
| 1997/0327 | f->id = id; f->src = src; f->dst = dst; f->blist = bp; | |
| 2002/0507 | qunlock(&ip->fraglock4); | |
| 2000/0706 | ip->stats[ReasmReqds]++; | |
| 1997/0327 | return nil; } /* * find the new fragment's position in the queue */ prev = nil; l = &f->blist; bl = f->blist; while(bl != nil && BKFG(bp)->foff > BKFG(bl)->foff) { prev = bl; l = &bl->next; bl = bl->next; } /* Check overlap of a previous fragment - trim away as necessary */ if(prev) { ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff; if(ovlap > 0) { if(ovlap >= BKFG(bp)->flen) { freeblist(bp); | |
| 2002/0507 | qunlock(&ip->fraglock4); | |
| 1997/0327 | return nil; } BKFG(prev)->flen -= ovlap; } } /* Link onto assembly queue */ bp->next = *l; *l = bp; /* Check to see if succeeding segments overlap */ if(bp->next) { l = &bp->next; fend = BKFG(bp)->foff + BKFG(bp)->flen; /* Take completely covered segments out */ while(*l) { ovlap = fend - BKFG(*l)->foff; if(ovlap <= 0) break; if(ovlap < BKFG(*l)->flen) { BKFG(*l)->flen -= ovlap; BKFG(*l)->foff += ovlap; | |
| 1998/0313 | /* move up ih hdrs */ | |
| 2002/0507 | memmove((*l)->rp + ovlap, (*l)->rp, IP4HDR); | |
| 1997/0327 | (*l)->rp += ovlap; break; } last = (*l)->next; (*l)->next = nil; freeblist(*l); *l = last; } } /* * look for a complete packet. if we get to a fragment * without IP_MF set, we're done. */ pktposn = 0; for(bl = f->blist; bl; bl = bl->next) { if(BKFG(bl)->foff != pktposn) break; if((BLKIP(bl)->frag[0]&(IP_MF>>8)) == 0) { bl = f->blist; len = nhgets(BLKIP(bl)->length); bl->wp = bl->rp + len; /* Pullup all the fragment headers and * return a complete packet */ for(bl = bl->next; bl; bl = bl->next) { fragsize = BKFG(bl)->flen; len += fragsize; | |
| 2002/0507 | bl->rp += IP4HDR; | |
| 1997/0327 | bl->wp = bl->rp + fragsize; } bl = f->blist; f->blist = nil; | |
| 2002/0507 | ipfragfree4(ip, f); | |
| 1998/0313 | ih = BLKIP(bl); hnputs(ih->length, len); | |
| 2002/0507 | qunlock(&ip->fraglock4); | |
| 2000/0706 | ip->stats[ReasmOKs]++; | |
| 1997/0327 | return bl; } pktposn += BKFG(bl)->flen; } | |
| 2002/0507 | qunlock(&ip->fraglock4); | |
| 1997/0327 | return nil; } /* | |
| 2002/0507 | * ipfragfree4 - Free a list of fragments - assume hold fraglock4 | |
| 1997/0327 | */ void | |
| 2002/0507 | ipfragfree4(IP *ip, Fragment4 *frag) | |
| 1997/0327 | { | |
| 2002/0507 | Fragment4 *fl, **l; | |
| 1997/0327 | if(frag->blist) freeblist(frag->blist); frag->src = 0; frag->id = 0; frag->blist = nil; | |
| 2002/0507 | l = &ip->flisthead4; | |
| 1997/0327 | for(fl = *l; fl; fl = fl->next) { if(fl == frag) { *l = frag->next; break; } l = &fl->next; } | |
| 2002/0507 | frag->next = ip->fragfree4; ip->fragfree4 = frag; | |
| 1997/0327 | } /* | |
| 2002/0507 | * ipfragallo4 - allocate a reassembly queue - assume hold fraglock4 | |
| 1997/0327 | */ | |
| 2002/0507 | Fragment4 * ipfragallo4(IP *ip) | |
| 1997/0327 | { | |
| 2002/0507 | Fragment4 *f; | |
| 1997/0327 | ||
| 2002/0507 | while(ip->fragfree4 == nil) { | |
| 1997/0529 | /* free last entry on fraglist */ | |
| 2002/0507 | for(f = ip->flisthead4; f->next; f = f->next) | |
| 1997/0529 | ; | |
| 2002/0507 | ipfragfree4(ip, f); | |
| 1997/0327 | } | |
| 2002/0507 | f = ip->fragfree4; ip->fragfree4 = f->next; f->next = ip->flisthead4; ip->flisthead4 = f; | |
| 2002/0710 | f->age = NOW + 30000; | |
| 1997/0327 | return f; } ushort | |
| 1998/0306 | ipcsum(uchar *addr) | |
| 1997/0327 | { int len; ulong sum; sum = 0; len = (addr[0]&0xf)<<2; while(len > 0) { sum += addr[0]<<8 | addr[1] ; len -= 2; addr += 2; } sum = (sum & 0xffff) + (sum >> 16); sum = (sum & 0xffff) + (sum >> 16); return (sum^0xffff); | |
| 2001/1117 | } | |