summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/src/9/ip/ip.c322
-rw-r--r--sys/src/9/ip/ip.h5
-rw-r--r--sys/src/9/ip/ipaux.c4
-rw-r--r--sys/src/9/ip/ipv6.c328
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;