summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/src/9/ip/ipv6.c57
-rw-r--r--sys/src/9/ip/ipv6.h1
2 files changed, 31 insertions, 27 deletions
diff --git a/sys/src/9/ip/ipv6.c b/sys/src/9/ip/ipv6.c
index 62927e23a..406558999 100644
--- a/sys/src/9/ip/ipv6.c
+++ b/sys/src/9/ip/ipv6.c
@@ -8,17 +8,12 @@
#include "ip.h"
#include "ipv6.h"
-enum
-{
- IP6FHDR = 8, /* sizeof(Fraghdr6) */
-};
-
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);
+static int unfraglen(Block *bp, uchar *nexthdr, int setfh, int popfh);
void
ip_init_6(Fs *f)
@@ -122,8 +117,14 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh)
}
/* start v6 fragmentation */
- uflen = unfraglen(bp, &nexthdr, 1);
- if(uflen < 0 || uflen > medialen) {
+ uflen = unfraglen(bp, &nexthdr, 1, 0);
+ if(uflen < IP6HDR || nexthdr == FH) {
+ ip->stats[FragFails]++;
+ ip->stats[OutDiscards]++;
+ netlog(f, Logip, "%I -> %I: fragment header botch\n", eh->src, eh->dst);
+ goto raise;
+ }
+ if(uflen > medialen) {
ip->stats[FragFails]++;
ip->stats[OutDiscards]++;
netlog(f, Logip, "%I -> %I: unfragmentable part too big: %d\n", eh->src, eh->dst, uflen);
@@ -210,7 +211,6 @@ void
ipiput6(Fs *f, Ipifc *ifc, Block *bp)
{
int hl, len, hop, tos;
- uchar proto;
IP *ip;
Ip6hdr *h;
Proto *p;
@@ -301,8 +301,7 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
return;
h = (Ip6hdr*)bp->rp;
- proto = h->proto;
- p = Fsrcvpcol(f, proto);
+ p = Fsrcvpcol(f, h->proto);
if(p != nil && p->rcv != nil) {
ip->stats[InDelivers]++;
(*p->rcv)(p, ifc, bp);
@@ -323,15 +322,15 @@ ipfragfree6(IP *ip, Fragment6 *frag)
{
Fragment6 *fl, **l;
- if(frag->blist)
+ if(frag->blist != nil)
freeblist(frag->blist);
-
- memset(frag->src, 0, IPaddrlen);
- frag->id = 0;
frag->blist = nil;
+ frag->id = 0;
+ memset(frag->src, 0, IPaddrlen);
+ memset(frag->dst, 0, IPaddrlen);
l = &ip->flisthead6;
- for(fl = *l; fl; fl = fl->next) {
+ for(fl = *l; fl != nil; fl = fl->next) {
if(fl == frag) {
*l = frag->next;
break;
@@ -353,7 +352,7 @@ ipfragallo6(IP *ip)
while(ip->fragfree6 == nil) {
/* free last entry on fraglist */
- for(f = ip->flisthead6; f->next; f = f->next)
+ for(f = ip->flisthead6; f->next != nil; f = f->next)
;
ipfragfree6(ip, f);
}
@@ -372,16 +371,18 @@ procxtns(IP *ip, Block *bp, int doreasm)
uchar proto;
int offset;
- offset = unfraglen(bp, &proto, 0);
- if(offset >= 0 && proto == FH && doreasm != 0) {
+ offset = unfraglen(bp, &proto, 0, doreasm);
+ if(offset >= IP6HDR && proto == FH && doreasm) {
bp = ip6reassemble(ip, offset, bp);
if(bp == nil)
return nil;
- offset = unfraglen(bp, &proto, 0);
+ offset = unfraglen(bp, &proto, 0, 0);
if(proto == FH)
offset = -1;
}
- if(offset < 0){
+ if(offset < IP6HDR){
+ ip->stats[InHdrErrors]++;
+ ip->stats[InDiscards]++;
freeblist(bp);
return nil;
}
@@ -395,10 +396,12 @@ 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.
+ * When the last header is a fragment header and popfh != 0 then set
+ * the nexthdr value of the previous header to the nexthdr value of the
+ * fragment header. returns -1 on error.
*/
static int
-unfraglen(Block *bp, uchar *nexthdr, int setfh)
+unfraglen(Block *bp, uchar *nexthdr, int setfh, int popfh)
{
uchar *e, *p, *q;
@@ -417,9 +420,10 @@ unfraglen(Block *bp, uchar *nexthdr, int setfh)
if(p > e)
return -1;
if(*nexthdr == FH){
- if(setfh || p+IP6FHDR > e || *p == FH)
+ if(p+IP6FHDR > e || *p == FH)
return -1;
- *q = *p;
+ if(popfh)
+ *q = *p;
} else if(setfh)
*q = FH;
return p - bp->rp;
@@ -464,7 +468,7 @@ ip6reassemble(IP* ip, int uflen, Block* bp)
*/
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(f->id == id && ipcmp(f->src, src) == 0 && ipcmp(f->dst, dst) == 0)
break;
if(f->age < NOW){
ip->stats[ReasmTimeout]++;
@@ -607,7 +611,6 @@ ip6reassemble(IP* ip, int uflen, Block* bp)
if(len >= IP_MAX){
ipfragfree6(ip, f);
-
ip->stats[ReasmFails]++;
qunlock(&ip->fraglock6);
diff --git a/sys/src/9/ip/ipv6.h b/sys/src/9/ip/ipv6.h
index 6d9537d58..489d8903c 100644
--- a/sys/src/9/ip/ipv6.h
+++ b/sys/src/9/ip/ipv6.h
@@ -79,6 +79,7 @@ enum {
v6MINTU = 1280,
HOP_LIMIT = 255,
IP6HDR = 40, /* sizeof(Ip6hdr) = 8 + 2*16 */
+ IP6FHDR = 8, /* sizeof(Fraghdr6) */
/* option types */