diff options
| -rw-r--r-- | sys/src/9/ip/ip.c | 322 | ||||
| -rw-r--r-- | sys/src/9/ip/ip.h | 5 | ||||
| -rw-r--r-- | sys/src/9/ip/ipaux.c | 4 | ||||
| -rw-r--r-- | sys/src/9/ip/ipv6.c | 328 |
4 files changed, 341 insertions, 318 deletions
diff --git a/sys/src/9/ip/ip.c b/sys/src/9/ip/ip.c index 5be4bb5eb..a198e7dd7 100644 --- a/sys/src/9/ip/ip.c +++ b/sys/src/9/ip/ip.c @@ -7,8 +7,6 @@ #include "ip.h" -#define BLKIPVER(xp) (((Ip4hdr*)((xp)->rp))->vihl&0xF0) - static char *statnames[] = { [Forwarding] "Forwarding", @@ -32,41 +30,11 @@ static char *statnames[] = [FragCreates] "FragCreates", }; -#define BLKIP(xp) ((Ip4hdr*)((xp)->rp)) -/* - * 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)) - -ushort ipcsum(uchar*); -Block* ip4reassemble(IP*, int, Block*, Ip4hdr*); -void ipfragfree4(IP*, Fragment4*); -Fragment4* ipfragallo4(IP*); - -void -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) / 1000; - - v6p->hp.rxmithost = 1000; /* v6 RETRANS_TIMER */ +static Block* ip4reassemble(IP*, int, Block*); +static void ipfragfree4(IP*, Fragment4*); +static Fragment4* ipfragallo4(IP*); - f->v6p = v6p; -} - -void +static void initfrag(IP *ip, int size) { Fragment4 *fq4, *eq4; @@ -124,41 +92,28 @@ ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) ulong fragoff; Block *xp, *nb; Ip4hdr *eh, *feh; - int lid, len, seglen, chunk, dlen, blklen, offset, medialen; + int lid, len, seglen, chunk, hlen, dlen, blklen, offset, medialen; Route *r; IP *ip; int rv = 0; ip = f->ip; - - /* Fill out the ip header */ - eh = (Ip4hdr*)(bp->rp); - ip->stats[OutRequests]++; - /* Number of uchars in data and ip header to write */ + /* Fill out the ip header */ + eh = (Ip4hdr*)bp->rp; + assert(BLEN(bp) >= IP4HDR); len = blocklen(bp); - - if(gating){ - chunk = nhgets(eh->length); - if(chunk > len){ - ip->stats[OutDiscards]++; - netlog(f, Logip, "short gated packet\n"); - goto free; - } - if(chunk < len) - len = chunk; - } if(len >= IP_MAX){ ip->stats[OutDiscards]++; - netlog(f, Logip, "exceeded ip max size %V\n", eh->dst); + netlog(f, Logip, "%V -> %V: exceeded ip max size: %d\n", eh->src, eh->dst, len); goto free; } r = v4lookup(f, eh->dst, eh->src, rh); if(r == nil || (ifc = r->ifc) == nil){ ip->stats[OutNoRoutes]++; - netlog(f, Logip, "no interface %V -> %V\n", eh->src, eh->dst); + netlog(f, Logip, "%V -> %V: no interface\n", eh->src, eh->dst); rv = -1; goto free; } @@ -168,67 +123,65 @@ ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) else gate = r->v4.gate; - if(!gating) - eh->vihl = IP_VER4|IP_HLEN4; - eh->ttl = ttl; - if(!gating) - eh->tos = tos; - if(!canrlock(ifc)) goto free; if(waserror()){ runlock(ifc); nexterror(); } - if(ifc->m == nil) goto raise; + if(!gating){ + eh->vihl = IP_VER4|IP_HLEN4; + eh->tos = tos; + } + eh->ttl = ttl; + /* If we dont need to fragment just send it */ medialen = ifc->maxtu - ifc->m->hsize; if(len <= medialen) { - if(!gating) - hnputs(eh->id, incref(&ip->id4)); hnputs(eh->length, len); if(!gating){ + hnputs(eh->id, incref(&ip->id4)); eh->frag[0] = 0; eh->frag[1] = 0; } eh->cksum[0] = 0; eh->cksum[1] = 0; hnputs(eh->cksum, ipcsum(&eh->vihl)); + ipifcoput(ifc, bp, V4, gate); runlock(ifc); poperror(); return 0; } -if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst); - if(eh->frag[0] & (IP_DF>>8)){ ip->stats[FragFails]++; ip->stats[OutDiscards]++; icmpcantfrag(f, bp, medialen); - netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst); + netlog(f, Logip, "%V -> %V: can't fragment with DF flag set\n", eh->src, eh->dst); goto raise; } - seglen = (medialen - IP4HDR) & ~7; + hlen = (eh->vihl & 0xF)<<2; + seglen = (medialen - hlen) & ~7; if(seglen < 8){ ip->stats[FragFails]++; ip->stats[OutDiscards]++; - netlog(f, Logip, "%V seglen < 8\n", eh->dst); + netlog(f, Logip, "%V -> %V: can't fragment with seglen < 8\n", eh->src, eh->dst); goto raise; } - dlen = len - IP4HDR; + dlen = len - hlen; xp = bp; if(gating) lid = nhgets(eh->id); else lid = incref(&ip->id4); - offset = IP4HDR; + offset = hlen; while(offset && offset >= BLEN(xp)) { offset -= BLEN(xp); xp = xp->next; @@ -241,11 +194,11 @@ if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst); fragoff = 0; dlen += fragoff; for(; fragoff < dlen; fragoff += seglen) { - nb = allocb(IP4HDR+seglen); - feh = (Ip4hdr*)(nb->rp); + nb = allocb(hlen+seglen); + feh = (Ip4hdr*)nb->rp; - memmove(nb->wp, eh, IP4HDR); - nb->wp += IP4HDR; + memmove(nb->wp, eh, hlen); + nb->wp += hlen; if((fragoff + seglen) >= dlen) { seglen = dlen - fragoff; @@ -254,17 +207,17 @@ if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst); else hnputs(feh->frag, (fragoff>>3)|IP_MF); - hnputs(feh->length, seglen + IP4HDR); + hnputs(feh->length, seglen + hlen); hnputs(feh->id, lid); /* Copy up the data area */ chunk = seglen; while(chunk) { - if(!xp) { + if(xp == nil) { ip->stats[OutDiscards]++; ip->stats[FragFails]++; freeblist(nb); - netlog(f, Logip, "!xp: chunk %d\n", chunk); + netlog(f, Logip, "xp == nil: chunk %d\n", chunk); goto raise; } blklen = chunk; @@ -281,6 +234,7 @@ if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst); feh->cksum[0] = 0; feh->cksum[1] = 0; hnputs(feh->cksum, ipcsum(&feh->vihl)); + ipifcoput(ifc, nb, V4, gate); ip->stats[FragCreates]++; } @@ -296,16 +250,14 @@ free: void ipiput4(Fs *f, Ipifc *ifc, Block *bp) { - int hl; - int hop, tos, proto, olen; + int hl, len, hop, tos, proto; + uchar v6dst[IPaddrlen]; + ushort frag; Ip4hdr *h; Proto *p; - ushort frag; - int notforme; - uchar *dp, v6dst[IPaddrlen]; IP *ip; - if(BLKIPVER(bp) != IP_VER4) { + if((bp->rp[0]&0xF0) != IP_VER4) { ipiput6(f, ifc, bp); return; } @@ -329,39 +281,31 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp) return; } - h = (Ip4hdr*)(bp->rp); - - /* dump anything that whose header doesn't checksum */ + h = (Ip4hdr*)bp->rp; + hl = (h->vihl & 0xF)<<2; + if(hl < IP4HDR || hl > BLEN(bp)) { + ip->stats[InHdrErrors]++; + netlog(f, Logip, "%V -> %V: bad ip header length: %d\n", h->src, h->dst, hl); + goto drop; + } if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) { ip->stats[InHdrErrors]++; - netlog(f, Logip, "ip: checksum error %V\n", h->src); + netlog(f, Logip, "%V -> %V: bad ip header checksum\n", h->src, h->dst); goto drop; } - v4tov6(v6dst, h->dst); - notforme = ipforme(f, v6dst) == 0; - - /* Check header length and version */ - if((h->vihl&0x0F) != IP_HLEN4) { - hl = (h->vihl&0xF)<<2; - if(hl < (IP_HLEN4<<2)) { - ip->stats[InHdrErrors]++; - netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl); + len = nhgets(h->length); + if(len < hl || (bp = trimblock(bp, 0, len)) == nil){ + ip->stats[InHdrErrors]++; + netlog(f, Logip, "%V -> %V: bogus packet length: %d\n", h->src, h->dst, len); + if(bp != nil) goto drop; - } - /* If this is not routed strip off the options */ - if(notforme == 0) { - olen = nhgets(h->length); - dp = bp->rp + (hl - (IP_HLEN4<<2)); - memmove(dp, h, IP_HLEN4<<2); - bp->rp = dp; - h = (Ip4hdr*)(bp->rp); - h->vihl = (IP_VER4|IP_HLEN4); - hnputs(h->length, olen-hl+(IP_HLEN4<<2)); - } + return; } + h = (Ip4hdr*)bp->rp; /* route */ - if(notforme) { + v4tov6(v6dst, h->dst); + if(!ipforme(f, v6dst)) { Route *r; Routehint rh; Ipifc *nifc; @@ -393,10 +337,10 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp) h->tos = 0; if(frag & IP_MF) h->tos = 1; - bp = ip4reassemble(ip, frag, bp, h); + bp = ip4reassemble(ip, frag, bp); if(bp == nil) return; - h = (Ip4hdr*)(bp->rp); + h = (Ip4hdr*)bp->rp; } } @@ -407,15 +351,26 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp) return; } + /* If this is not routed strip off the options */ + if(hl > IP4HDR) { + hl -= IP4HDR; + len -= hl; + bp->rp += hl; + memmove(bp->rp, h, IP4HDR); + h = (Ip4hdr*)bp->rp; + h->vihl = IP_VER4|IP_HLEN4; + hnputs(h->length, len); + } + frag = nhgets(h->frag); if(frag & ~IP_DF) { h->tos = 0; if(frag & IP_MF) h->tos = 1; - bp = ip4reassemble(ip, frag, bp, h); + bp = ip4reassemble(ip, frag, bp); if(bp == nil) return; - h = (Ip4hdr*)(bp->rp); + h = (Ip4hdr*)bp->rp; } /* don't let any frag info go up the stack */ @@ -450,27 +405,30 @@ ipstats(Fs *f, char *buf, int len) return p - buf; } -Block* -ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) +static Block* +ip4reassemble(IP *ip, int offset, Block *bp) { int fend; ushort id; Fragment4 *f, *fnext; + Ip4hdr *ih; ulong src, dst; - Block *bl, **l, *last, *prev; + Ipfrag *fp, *fq; + Block *bl, **l, *prev; int ovlap, len, fragsize, pktposn; - src = nhgetl(ih->src); - dst = nhgetl(ih->dst); - id = nhgets(ih->id); - /* * block lists are too hard, pullupblock into a single block */ - if(bp->next != nil){ + if(bp->next != nil) bp = pullupblock(bp, blocklen(bp)); - ih = (Ip4hdr*)(bp->rp); - } + + ih = (Ip4hdr*)bp->rp; + src = nhgetl(ih->src); + dst = nhgetl(ih->dst); + id = nhgets(ih->id); + len = nhgets(ih->length); + fragsize = len - ((ih->vihl&0xF)<<2); qlock(&ip->fraglock4); @@ -492,22 +450,24 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) * and get rid of any fragments that might go * with it. */ - if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) { + if(ih->tos == 0 && (offset & ~(IP_MF|IP_DF)) == 0) { if(f != nil) { - ipfragfree4(ip, f); ip->stats[ReasmFails]++; + ipfragfree4(ip, f); } qunlock(&ip->fraglock4); return bp; } - if(bp->base+IPFRAGSZ >= bp->rp){ + if(bp->base+IPFRAGSZ > bp->rp){ bp = padblock(bp, IPFRAGSZ); bp->rp += IPFRAGSZ; } - BKFG(bp)->foff = offset<<3; - BKFG(bp)->flen = nhgets(ih->length)-IP4HDR; + fp = (Ipfrag*)bp->base; + fp->foff = (offset & 0x1fff)<<3; + fp->flen = fragsize; + fp->hlen = len - fragsize; /* First fragment allocates a reassembly queue */ if(f == nil) { @@ -518,8 +478,9 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) f->blist = bp; - qunlock(&ip->fraglock4); ip->stats[ReasmReqds]++; + qunlock(&ip->fraglock4); + return nil; } @@ -529,7 +490,7 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) prev = nil; l = &f->blist; bl = f->blist; - while(bl != nil && BKFG(bp)->foff > BKFG(bl)->foff) { + while(bl != nil && fp->foff > ((Ipfrag*)bl->base)->foff) { prev = bl; l = &bl->next; bl = bl->next; @@ -537,14 +498,15 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) /* Check overlap of a previous fragment - trim away as necessary */ if(prev != nil) { - ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff; + fq = (Ipfrag*)prev->base; + ovlap = fq->foff + fq->flen - fp->foff; if(ovlap > 0) { - if(ovlap >= BKFG(bp)->flen) { - freeblist(bp); + if(ovlap >= fp->flen) { qunlock(&ip->fraglock4); + freeb(bp); return nil; } - BKFG(prev)->flen -= ovlap; + fq->flen -= ovlap; } } @@ -555,24 +517,24 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) /* Check to see if succeeding segments overlap */ if(bp->next != nil) { l = &bp->next; - fend = BKFG(bp)->foff + BKFG(bp)->flen; + fend = fp->foff + fp->flen; /* Take completely covered segments out */ - while(*l != nil) { - ovlap = fend - BKFG(*l)->foff; + while((bl = *l) != nil) { + fq = (Ipfrag*)bl->base; + ovlap = fend - fq->foff; if(ovlap <= 0) break; - if(ovlap < BKFG(*l)->flen) { - BKFG(*l)->flen -= ovlap; - BKFG(*l)->foff += ovlap; - /* move up ih hdrs */ - memmove((*l)->rp + ovlap, (*l)->rp, IP4HDR); - (*l)->rp += ovlap; + if(ovlap < fq->flen) { + fq->flen -= ovlap; + fq->foff += ovlap; + /* move up ip header */ + memmove(bl->rp + ovlap, bl->rp, fq->hlen); + bl->rp += ovlap; break; } - last = (*l)->next; - (*l)->next = nil; - freeblist(*l); - *l = last; + *l = bl->next; + bl->next = nil; + freeb(bl); } } @@ -581,34 +543,50 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) * without IP_MF set, we're done. */ pktposn = 0; - for(bl = f->blist; bl != nil; bl = bl->next) { - if(BKFG(bl)->foff != pktposn) + for(bl = f->blist; bl != nil; bl = bl->next, pktposn += fp->flen) { + fp = (Ipfrag*)bl->base; + if(fp->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 != nil; bl = bl->next) { - fragsize = BKFG(bl)->flen; - len += fragsize; - bl->rp += IP4HDR; - bl->wp = bl->rp + fragsize; - } - bl = f->blist; - f->blist = nil; + ih = (Ip4hdr*)bl->rp; + if(ih->frag[0]&(IP_MF>>8)) + continue; + + bl = f->blist; + fq = (Ipfrag*)bl->base; + len = fq->hlen + fq->flen; + bl->wp = bl->rp + len; + + /* + * Pullup all the fragment headers and + * return a complete packet + */ + for(bl = bl->next; bl != nil && len < IP_MAX; bl = bl->next) { + fq = (Ipfrag*)bl->base; + fragsize = fq->flen; + len += fragsize; + bl->rp += fq->hlen; + bl->wp = bl->rp + fragsize; + } + + if(len >= IP_MAX){ ipfragfree4(ip, f); - ih = BLKIP(bl); - hnputs(ih->length, len); + ip->stats[ReasmFails]++; qunlock(&ip->fraglock4); - ip->stats[ReasmOKs]++; - return bl; + return nil; } - pktposn += BKFG(bl)->flen; + + bl = f->blist; + f->blist = nil; + ipfragfree4(ip, f); + + ih = (Ip4hdr*)bl->rp; + hnputs(ih->length, len); + + ip->stats[ReasmOKs]++; + qunlock(&ip->fraglock4); + + return bl; } qunlock(&ip->fraglock4); return nil; @@ -617,7 +595,7 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih) /* * ipfragfree4 - Free a list of fragments - assume hold fraglock4 */ -void +static void ipfragfree4(IP *ip, Fragment4 *frag) { Fragment4 *fl, **l; @@ -646,7 +624,7 @@ ipfragfree4(IP *ip, Fragment4 *frag) /* * ipfragallo4 - allocate a reassembly queue - assume hold fraglock4 */ -Fragment4 * +static Fragment4* ipfragallo4(IP *ip) { Fragment4 *f; diff --git a/sys/src/9/ip/ip.h b/sys/src/9/ip/ip.h index a1233ec46..017a8ad2f 100644 --- a/sys/src/9/ip/ip.h +++ b/sys/src/9/ip/ip.h @@ -57,7 +57,7 @@ enum IP_HLEN4= 5, /* v4: Header length in words */ IP_DF= 0x4000, /* v4: Don't fragment */ IP_MF= 0x2000, /* v4: More fragments */ - IP4HDR= 20, /* sizeof(Ip4hdr) */ + IP4HDR= IP_HLEN4<<2, /* sizeof(Ip4hdr) */ IP_MAX= 64*1024, /* Max. Internet packet size, v4 & v6 */ /* 2^Lroot trees in the root table */ @@ -123,9 +123,9 @@ struct Fragment6 struct Ipfrag { + ushort hlen; ushort foff; ushort flen; - uchar payload[]; }; @@ -693,6 +693,7 @@ extern int ipstats(Fs*, char*, int); extern ushort ptclbsum(uchar*, int); extern ushort ptclcsum(Block*, int, int); extern void ip_init(Fs*); +extern void ip_init_6(Fs*); /* * bootp.c diff --git a/sys/src/9/ip/ipaux.c b/sys/src/9/ip/ipaux.c index e16249546..549df1f6e 100644 --- a/sys/src/9/ip/ipaux.c +++ b/sys/src/9/ip/ipaux.c @@ -151,7 +151,7 @@ ptclcsum(Block *bp, int offset, int len) if(bp->next == nil) { if(blocklen < len) len = blocklen; - return ~ptclbsum(addr, len) & 0xffff; + return ptclbsum(addr, len) ^ 0xffff; } losum = 0; @@ -183,7 +183,7 @@ ptclcsum(Block *bp, int offset, int len) while((csum = losum>>16) != 0) losum = csum + (losum & 0xffff); - return ~losum & 0xffff; + return losum ^ 0xffff; } enum diff --git a/sys/src/9/ip/ipv6.c b/sys/src/9/ip/ipv6.c index 6b6d4eeca..3c29a935f 100644 --- a/sys/src/9/ip/ipv6.c +++ b/sys/src/9/ip/ipv6.c @@ -13,19 +13,34 @@ enum IP6FHDR = 8, /* sizeof(Fraghdr6) */ }; -#define IPV6CLASS(hdr) (((hdr)->vcf[0]&0x0F)<<2 | ((hdr)->vcf[1]&0xF0)>>2) -#define BLKIPVER(xp) (((Ip6hdr*)((xp)->rp))->vcf[0] & 0xF0) -/* - * This sleazy macro is stolen shamelessly from ip.c, see comment there. - */ -#define BKFG(xp) ((Ipfrag*)((xp)->base)) +static Block* ip6reassemble(IP*, int, Block*); +static Fragment6* ipfragallo6(IP*); +static void ipfragfree6(IP*, Fragment6*); +static Block* procopts(Block *bp); +static Block* procxtns(IP *ip, Block *bp, int doreasm); +static int unfraglen(Block *bp, uchar *nexthdr, int setfh); + +void +ip_init_6(Fs *f) +{ + v6params *v6p; + + v6p = smalloc(sizeof(v6params)); -Block* ip6reassemble(IP*, int, Block*, Ip6hdr*); -Fragment6* ipfragallo6(IP*); -void ipfragfree6(IP*, Fragment6*); -Block* procopts(Block *bp); -static Block* procxtns(IP *ip, Block *bp, int doreasm); -int unfraglen(Block *bp, uchar *nexthdr, int setfh); + 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) / 1000; + + v6p->hp.rxmithost = 1000; /* v6 RETRANS_TIMER */ + + f->v6p = v6p; +} int ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) @@ -41,36 +56,22 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) Route *r; ip = f->ip; - - /* Fill out the ip header */ - eh = (Ip6hdr*)(bp->rp); - ip->stats[OutRequests]++; - /* Number of uchars in data and ip header to write */ + /* Fill out the ip header */ + eh = (Ip6hdr*)bp->rp; + assert(BLEN(bp) >= IP6HDR); len = blocklen(bp); - - if(gating){ - chunk = nhgets(eh->ploadlen); - if(chunk > len){ - ip->stats[OutDiscards]++; - netlog(f, Logip, "short gated packet\n"); - goto free; - } - if(chunk + IP6HDR < len) - len = chunk + IP6HDR; - } - if(len >= IP_MAX){ ip->stats[OutDiscards]++; - netlog(f, Logip, "exceeded ip max size %I\n", eh->dst); + netlog(f, Logip, "%I -> %I: exceeded ip max size: %d\n", eh->src, eh->dst, len); goto free; } r = v6lookup(f, eh->dst, eh->src, rh); if(r == nil || (r->type & Rv4) != 0 || (ifc = r->ifc) == nil){ ip->stats[OutNoRoutes]++; - netlog(f, Logip, "no interface %I -> %I\n", eh->src, eh->dst); + netlog(f, Logip, "%I -> %I: no interface\n", eh->src, eh->dst); rv = -1; goto free; } @@ -80,14 +81,6 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) else gate = r->v6.gate; - if(!gating) - eh->vcf[0] = IP_VER6; - eh->ttl = ttl; - if(!gating) { - eh->vcf[0] |= tos >> 4; - eh->vcf[1] = tos << 4; - } - if(!canrlock(ifc)) goto free; @@ -99,6 +92,13 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) if(ifc->m == nil) goto raise; + if(!gating){ + eh->vcf[0] = IP_VER6; + eh->vcf[0] |= tos >> 4; + eh->vcf[1] = tos << 4; + } + eh->ttl = ttl; + /* If we dont need to fragment just send it */ medialen = ifc->maxtu - ifc->m->hsize; if(len <= medialen) { @@ -117,16 +117,16 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) */ ip->stats[OutDiscards]++; icmppkttoobig6(f, ifc, bp); - netlog(f, Logip, "%I: gated pkts not fragmented\n", eh->dst); + netlog(f, Logip, "%I -> %I: gated pkts not fragmented\n", eh->src, eh->dst); goto raise; } /* start v6 fragmentation */ uflen = unfraglen(bp, &nexthdr, 1); - if(uflen > medialen) { + if(uflen < 0 || uflen > medialen) { ip->stats[FragFails]++; ip->stats[OutDiscards]++; - netlog(f, Logip, "%I: unfragmentable part too big\n", eh->dst); + netlog(f, Logip, "%I -> %I: unfragmentable part too big: %d\n", eh->src, eh->dst, uflen); goto raise; } @@ -135,7 +135,7 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) if(seglen < 8) { ip->stats[FragFails]++; ip->stats[OutDiscards]++; - netlog(f, Logip, "%I: seglen < 8\n", eh->dst); + netlog(f, Logip, "%I -> %I: seglen < 8\n", eh->src, eh->dst); goto raise; } @@ -175,11 +175,11 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) /* Copy data */ chunk = seglen; while (chunk) { - if(!xp) { + if(xp == nil) { ip->stats[OutDiscards]++; ip->stats[FragFails]++; freeblist(nb); - netlog(f, Logip, "!xp: chunk in v6%d\n", chunk); + netlog(f, Logip, "xp == nil: chunk in v6%d\n", chunk); goto raise; } blklen = chunk; @@ -209,7 +209,7 @@ free: void ipiput6(Fs *f, Ipifc *ifc, Block *bp) { - int hl, hop, tos; + int hl, len, hop, tos; uchar proto; IP *ip; Ip6hdr *h; @@ -235,15 +235,22 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) } /* Check header version */ - h = (Ip6hdr *)bp->rp; - if(BLKIPVER(bp) != IP_VER6) { + h = (Ip6hdr*)bp->rp; + if((h->vcf[0] & 0xF0) != IP_VER6) { ip->stats[InHdrErrors]++; netlog(f, Logip, "ip: bad version %ux\n", (h->vcf[0]&0xF0)>>2); goto drop; } + len = IP6HDR + nhgets(h->ploadlen); + if((bp = trimblock(bp, 0, len)) == nil){ + ip->stats[InHdrErrors]++; + netlog(f, Logip, "%I -> %I: bogus packet length: %d\n", h->src, h->dst, len); + return; + } + h = (Ip6hdr*)bp->rp; /* route */ - if(ipforme(f, h->dst) == 0) { + if(!ipforme(f, h->dst)) { Route *r; Routehint rh; Ipifc *nifc; @@ -281,8 +288,8 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) return; ip->stats[ForwDatagrams]++; - h = (Ip6hdr *)bp->rp; - tos = IPV6CLASS(h); + h = (Ip6hdr*)bp->rp; + tos = (h->vcf[0]&0x0F)<<2 | (h->vcf[1]&0xF0)>>2; hop = h->ttl; ipoput6(f, bp, 1, hop-1, tos, &rh); return; @@ -293,7 +300,7 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) if(bp == nil) return; - h = (Ip6hdr *) (bp->rp); + h = (Ip6hdr*)bp->rp; proto = h->proto; p = Fsrcvpcol(f, proto); if(p != nil && p->rcv != nil) { @@ -311,7 +318,7 @@ drop: /* * ipfragfree6 - copied from ipfragfree4 - assume hold fraglock6 */ -void +static void ipfragfree6(IP *ip, Fragment6 *frag) { Fragment6 *fl, **l; @@ -339,7 +346,7 @@ ipfragfree6(IP *ip, Fragment6 *frag) /* * ipfragallo6 - copied from ipfragalloc4 */ -Fragment6* +static Fragment6* ipfragallo6(IP *ip) { Fragment6 *f; @@ -362,20 +369,22 @@ ipfragallo6(IP *ip) static Block* procxtns(IP *ip, Block *bp, int doreasm) { - int offset; uchar proto; - Ip6hdr *h; + int offset; - h = (Ip6hdr *)bp->rp; offset = unfraglen(bp, &proto, 0); - - if(proto == FH && doreasm != 0) { - bp = ip6reassemble(ip, offset, bp, h); + if(offset >= 0 && proto == FH && doreasm != 0) { + bp = ip6reassemble(ip, offset, bp); if(bp == nil) return nil; offset = unfraglen(bp, &proto, 0); + if(proto == FH) + offset = -1; + } + if(offset < 0){ + freeblist(bp); + return nil; } - if(proto == DOH || offset > IP6HDR) bp = procopts(bp); return bp; @@ -386,63 +395,69 @@ procxtns(IP *ip, Block *bp, int doreasm) * hop-by-hop & routing headers if present; *nexthdr is set to nexthdr value * of the last header in the "Unfragmentable part"; if setfh != 0, nexthdr * field of the last header in the "Unfragmentable part" is set to FH. + * returns -1 on error. */ -int +static int unfraglen(Block *bp, uchar *nexthdr, int setfh) { - uchar *p, *q; - int ufl, hs; + uchar *e, *p, *q; + e = bp->wp; p = bp->rp; q = p+6; /* proto, = p+sizeof(Ip6hdr.vcf)+sizeof(Ip6hdr.ploadlen) */ *nexthdr = *q; - ufl = IP6HDR; - p += ufl; - - while (*nexthdr == HBH || *nexthdr == RH) { - *nexthdr = *p; - hs = ((int)*(p+1) + 1) * 8; - ufl += hs; + p += IP6HDR; + while(*nexthdr == HBH || *nexthdr == RH){ + if(p+2 > e) + return -1; q = p; - p += hs; + *nexthdr = *q; + p += ((int)p[1] + 1) * 8; } - - if(*nexthdr == FH) + if(p > e) + return -1; + if(*nexthdr == FH){ + if(setfh || p+IP6FHDR > e || *p == FH) + return -1; *q = *p; - if(setfh) + } else if(setfh) *q = FH; - return ufl; + return p - bp->rp; } -Block* +static Block* procopts(Block *bp) { return bp; } -Block* -ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih) +static Block* +ip6reassemble(IP* ip, int uflen, Block* bp) { int fend, offset, ovlap, len, fragsize, pktposn; uint id; uchar src[IPaddrlen], dst[IPaddrlen]; - Block *bl, **l, *last, *prev; + Block *bl, **l, *prev; Fraghdr6 *fraghdr; Fragment6 *f, *fnext; - - fraghdr = (Fraghdr6 *)(bp->rp + uflen); - memmove(src, ih->src, IPaddrlen); - memmove(dst, ih->dst, IPaddrlen); - id = nhgetl(fraghdr->id); - offset = nhgets(fraghdr->offsetRM) & ~7; + Ipfrag *fp, *fq; + Ip6hdr* ih; /* * block lists are too hard, pullupblock into a single block */ - if(bp->next != nil){ + if(bp->next != nil) bp = pullupblock(bp, blocklen(bp)); - ih = (Ip6hdr *)bp->rp; - } + + ih = (Ip6hdr*)bp->rp; + fraghdr = (Fraghdr6*)(bp->rp + uflen); + id = nhgetl(fraghdr->id); + offset = nhgets(fraghdr->offsetRM); + len = nhgets(ih->ploadlen); + fragsize = (len + IP6HDR) - (uflen + IP6FHDR); + + memmove(src, ih->src, IPaddrlen); + memmove(dst, ih->dst, IPaddrlen); qlock(&ip->fraglock6); @@ -451,7 +466,7 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih) */ for(f = ip->flisthead6; f != nil; f = fnext){ fnext = f->next; - if(ipcmp(f->src, src)==0 && ipcmp(f->dst, dst)==0 && f->id == id) + if(ipcmp(f->src, src) == 0 && ipcmp(f->dst, dst) == 0 && f->id == id) break; if(f->age < NOW){ ip->stats[ReasmTimeout]++; @@ -464,22 +479,30 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih) * and get rid of any fragments that might go * with it. */ - if(nhgets(fraghdr->offsetRM) == 0) { /* 1st frag is also last */ - if(f) { - ipfragfree6(ip, f); + if(offset == 0) { /* 1st frag is also last */ + if(f != nil) { ip->stats[ReasmFails]++; + ipfragfree6(ip, f); } qunlock(&ip->fraglock6); + + /* get rid of frag header */ + memmove(bp->rp + IP6FHDR, bp->rp, uflen); + bp->rp += IP6FHDR; + hnputs(ih->ploadlen, len-IP6FHDR); + return bp; } - if(bp->base+IPFRAGSZ >= bp->rp){ + if(bp->base+IPFRAGSZ > bp->rp){ bp = padblock(bp, IPFRAGSZ); bp->rp += IPFRAGSZ; } - BKFG(bp)->foff = offset; - BKFG(bp)->flen = nhgets(ih->ploadlen) + IP6HDR - uflen - IP6FHDR; + fp = (Ipfrag*)bp->base; + fp->hlen = uflen; + fp->foff = offset & ~7; + fp->flen = fragsize; /* First fragment allocates a reassembly queue */ if(f == nil) { @@ -490,8 +513,9 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih) f->blist = bp; - qunlock(&ip->fraglock6); ip->stats[ReasmReqds]++; + qunlock(&ip->fraglock6); + return nil; } @@ -501,7 +525,7 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih) prev = nil; l = &f->blist; bl = f->blist; - while(bl != nil && BKFG(bp)->foff > BKFG(bl)->foff) { + while(bl != nil && fp->foff > ((Ipfrag*)bl->base)->foff) { prev = bl; l = &bl->next; bl = bl->next; @@ -509,14 +533,15 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih) /* Check overlap of a previous fragment - trim away as necessary */ if(prev != nil) { - ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff; + fq = (Ipfrag*)prev->base; + ovlap = fq->foff + fq->flen - fp->foff; if(ovlap > 0) { - if(ovlap >= BKFG(bp)->flen) { - freeblist(bp); + if(ovlap >= fp->flen) { qunlock(&ip->fraglock6); + freeb(bp); return nil; } - BKFG(prev)->flen -= ovlap; + fq->flen -= ovlap; } } @@ -527,25 +552,25 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih) /* Check to see if succeeding segments overlap */ if(bp->next != nil) { l = &bp->next; - fend = BKFG(bp)->foff + BKFG(bp)->flen; + fend = fp->foff + fp->flen; /* Take completely covered segments out */ - while(*l != nil) { - ovlap = fend - BKFG(*l)->foff; + while((bl = *l) != nil) { + fq = (Ipfrag*)bl->base; + ovlap = fend - fq->foff; if(ovlap <= 0) break; - if(ovlap < BKFG(*l)->flen) { - BKFG(*l)->flen -= ovlap; - BKFG(*l)->foff += ovlap; - /* move up ih hdrs */ - memmove((*l)->rp + ovlap, (*l)->rp, uflen); - (*l)->rp += ovlap; + if(ovlap < fq->flen) { + fq->flen -= ovlap; + fq->foff += ovlap; + /* move up ip and frag header */ + memmove(bl->rp + ovlap, bl->rp, fq->hlen + IP6FHDR); + bl->rp += ovlap; break; } - last = (*l)->next; - (*l)->next = nil; - freeblist(*l); - *l = last; + *l = bl->next; + bl->next = nil; + freeb(bl); } } @@ -554,37 +579,56 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih) * with the trailing bit of fraghdr->offsetRM[1] set, we're done. */ pktposn = 0; - for(bl = f->blist; bl != nil && BKFG(bl)->foff == pktposn; bl = bl->next) { - fraghdr = (Fraghdr6 *)(bl->rp + uflen); - if((fraghdr->offsetRM[1] & 1) == 0) { - bl = f->blist; - - /* get rid of frag header in first fragment */ - memmove(bl->rp + IP6FHDR, bl->rp, uflen); - bl->rp += IP6FHDR; - len = nhgets(((Ip6hdr*)bl->rp)->ploadlen) - IP6FHDR; - bl->wp = bl->rp + len + IP6HDR; - /* - * Pullup all the fragment headers and - * return a complete packet - */ - for(bl = bl->next; bl != nil; bl = bl->next) { - fragsize = BKFG(bl)->flen; - len += fragsize; - bl->rp += uflen + IP6FHDR; - bl->wp = bl->rp + fragsize; - } + for(bl = f->blist; bl != nil; bl = bl->next, pktposn += fp->flen) { + fp = (Ipfrag*)bl->base; + if(fp->foff != pktposn) + break; + + fraghdr = (Fraghdr6*)(bl->rp + fp->hlen); + if(fraghdr->offsetRM[1] & 1) + continue; + + bl = f->blist; + fq = (Ipfrag*)bl->base; + + /* get rid of frag header in first fragment */ + memmove(bl->rp + IP6FHDR, bl->rp, fq->hlen); + bl->rp += IP6FHDR; + len = fq->hlen + fq->flen; + bl->wp = bl->rp + len; + + /* + * Pullup all the fragment headers and + * return a complete packet + */ + for(bl = bl->next; bl != nil && len < IP_MAX; bl = bl->next) { + fq = (Ipfrag*)bl->base; + fragsize = fq->flen; + len += fragsize; + bl->rp += fq->hlen + IP6FHDR; + bl->wp = bl->rp + fragsize; + } - bl = f->blist; - f->blist = nil; + if(len >= IP_MAX){ ipfragfree6(ip, f); - ih = (Ip6hdr*)bl->rp; - hnputs(ih->ploadlen, len); + + ip->stats[ReasmFails]++; qunlock(&ip->fraglock6); - ip->stats[ReasmOKs]++; - return bl; + + return nil; } - pktposn += BKFG(bl)->flen; + + bl = f->blist; + f->blist = nil; + ipfragfree6(ip, f); + + ih = (Ip6hdr*)bl->rp; + hnputs(ih->ploadlen, len-IP6HDR); + + ip->stats[ReasmOKs]++; + qunlock(&ip->fraglock6); + + return bl; } qunlock(&ip->fraglock6); return nil; |
