M ip/arp.c => ip/arp.c +377 -71
@@ 6,6 6,7 @@
#include "../port/error.h"
#include "ip.h"
+#include "ipv6.h"
/*
* address resolution tables
@@ 27,12 28,6 @@ char *arpstate[] =
"WAIT",
};
-enum
-{
- CMadd,
- CMflush,
-};
-
/*
* one per Fs
*/
@@ 42,24 37,27 @@ struct Arp
Fs *f;
Arpent *hash[NHASH];
Arpent cache[NCACHE];
-};
-
-static
-Cmdtab arpcmd[] =
-{
- CMadd, "add", 0,
- CMflush, "flush", 1,
+ Arpent *rxmt;
+ Proc *rxmitp; /* neib sol re-transmit proc */
+ Rendez rxmtq;
+ Block *dropf, *dropl;
};
char *Ebadarp = "bad arp";
#define haship(s) ((s)[IPaddrlen-1]%NHASH)
+extern int ReTransTimer = RETRANS_TIMER;
+static void rxmitproc(void *v);
+
void
arpinit(Fs *f)
{
f->arp = smalloc(sizeof(Arp));
f->arp->f = f;
+ f->arp->rxmt = nil;
+ f->arp->dropf = f->arp->dropl = nil;
+ kproc("rxmitproc", rxmitproc, f->arp);
}
static Arpent*
@@ 83,6 81,7 @@ newarp(Arp *arp, uchar *ip, Medium *m)
/* dump waiting packets */
xp = a->hold;
a->hold = nil;
+
while(xp){
next = xp->list;
freeblist(xp);
@@ 92,7 91,74 @@ newarp(Arp *arp, uchar *ip, Medium *m)
/* take out of current chain */
l = &arp->hash[haship(a->ip)];
for(f = *l; f; f = f->hash){
- if(f == a) {
+ if(f == a){
+ *l = a->hash;
+ break;
+ }
+ l = &f->hash;
+ }
+
+ /* insert into new chain */
+ l = &arp->hash[haship(ip)];
+ a->hash = *l;
+ *l = a;
+ memmove(a->ip, ip, sizeof(a->ip));
+ a->used = msec;
+ a->time = 0;
+ a->type = m;
+
+ return a;
+}
+
+static Arpent*
+newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
+{
+ uint t;
+ Block *next, *xp;
+ Arpent *a, *e, *f, **l;
+ Medium *m = ifc->m;
+ int empty;
+
+ /* find oldest entry */
+ e = &arp->cache[NCACHE];
+ a = arp->cache;
+ t = a->used;
+ for(f = a; f < e; f++){
+ if(f->used < t){
+ t = f->used;
+ a = f;
+ }
+ }
+
+ /* dump waiting packets */
+ xp = a->hold;
+ a->hold = nil;
+
+ if(isv4(a->ip)){
+ while(xp){
+ next = xp->list;
+ freeblist(xp);
+ xp = next;
+ }
+ }
+ else { // queue icmp unreachable for rxmitproc later on, w/o arp lock
+ if(xp){
+ if(arp->dropl == nil)
+ arp->dropf = xp;
+ else
+ arp->dropl->list = xp;
+
+ for(next = xp->list; next; next = next->list)
+ xp = next;
+ arp->dropl = xp;
+ wakeup(&arp->rxmtq);
+ }
+ }
+
+ /* take out of current chain */
+ l = &arp->hash[haship(a->ip)];
+ for(f = *l; f; f = f->hash){
+ if(f == a){
*l = a->hash;
break;
}
@@ 103,36 169,107 @@ newarp(Arp *arp, uchar *ip, Medium *m)
l = &arp->hash[haship(ip)];
a->hash = *l;
*l = a;
+
memmove(a->ip, ip, sizeof(a->ip));
a->used = msec;
a->time = 0;
a->type = m;
+ a->rxtat = msec + ReTransTimer;
+ a->rxtsrem = MAX_MULTICAST_SOLICIT;
+ a->ifc = ifc;
+ a->ifcid = ifc->ifcid;
+
+ /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
+ if(!ipismulticast(a->ip) && addrxt){
+ l = &arp->rxmt;
+ empty = (*l==nil);
+
+ for(f = *l; f; f = f->nextrxt){
+ if(f == a){
+ *l = a->nextrxt;
+ break;
+ }
+ l = &f->nextrxt;
+ }
+ for(f = *l; f; f = f->nextrxt){
+ l = &f->nextrxt;
+ }
+ *l = a;
+ if(empty)
+ wakeup(&arp->rxmtq);
+ }
+
+ a->nextrxt = nil;
+
return a;
}
+/* called with arp qlocked */
+
+void
+cleanarpent(Arp *arp, Arpent *a)
+{
+ Arpent *f, **l;
+
+ a->used = 0;
+ a->time = 0;
+ a->type = 0;
+ a->state = 0;
+
+ /* take out of current chain */
+ l = &arp->hash[haship(a->ip)];
+ for(f = *l; f; f = f->hash){
+ if(f == a){
+ *l = a->hash;
+ break;
+ }
+ l = &f->hash;
+ }
+
+ /* take out of re-transmit chain */
+ l = &arp->rxmt;
+ for(f = *l; f; f = f->nextrxt){
+ if(f == a){
+ *l = a->nextrxt;
+ break;
+ }
+ l = &f->nextrxt;
+ }
+ a->nextrxt = nil;
+ a->hash = nil;
+ a->hold = nil;
+ a->last = nil;
+ a->ifc = nil;
+}
+
Arpent*
-arpget(Arp *arp, Block *bp, int version, Medium *type, uchar *ip, uchar *mac)
+arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
{
int hash;
Arpent *a;
+ Medium *type = ifc->m;
uchar v6ip[IPaddrlen];
- if(version == V4) {
+ if(version == V4){
v4tov6(v6ip, ip);
ip = v6ip;
}
qlock(arp);
hash = haship(ip);
- for(a = arp->hash[hash]; a; a = a->hash) {
+ for(a = arp->hash[hash]; a; a = a->hash){
if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
if(type == a->type)
break;
}
if(a == nil){
- a = newarp(arp, ip, type);
+ //a = newarp6(arp, ip, ifc, (version != V4));
+ if(version == V4)
+ a = newarp(arp, ip, type);
+ else
+ a = newarp6(arp, ip, ifc, 1);
a->state = AWAIT;
}
a->used = msec;
@@ 169,6 306,18 @@ Block*
arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
{
Block *bp;
+ Arpent *f, **l;
+
+ if(!isv4(a->ip)){
+ l = &arp->rxmt;
+ for(f = *l; f; f = f->nextrxt){
+ if(f == a){
+ *l = a->nextrxt;
+ break;
+ }
+ l = &f->nextrxt;
+ }
+ }
memmove(a->mac, mac, type->maclen);
a->type = type;
@@ 186,7 335,7 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
{
Arp *arp;
Route *r;
- Arpent *a;
+ Arpent *a, *f, **l;
Ipifc *ifc;
Medium *type;
Block *bp, *next;
@@ 194,12 343,12 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
arp = fs->arp;
- if(n != 6) {
+ if(n != 6){
// print("arp: len = %d\n", n);
return;
}
- if(version == V4) {
+ if(version == V4){
r = v4lookup(fs, ip);
v4tov6(v6ip, ip);
ip = v6ip;
@@ 207,7 356,7 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
else
r = v6lookup(fs, ip);
- if(r == nil) {
+ if(r == nil){
// print("arp: no route for entry\n");
return;
}
@@ 216,19 365,35 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
type = ifc->m;
qlock(arp);
- for(a = arp->hash[haship(ip)]; a; a = a->hash) {
+ for(a = arp->hash[haship(ip)]; a; a = a->hash){
if(a->type != type || (a->state != AWAIT && a->state != AOK))
continue;
- if(ipcmp(a->ip, ip) == 0) {
+ if(ipcmp(a->ip, ip) == 0){
a->state = AOK;
memmove(a->mac, mac, type->maclen);
+
+ if(version == V6){
+ /* take out of re-transmit chain */
+ l = &arp->rxmt;
+ for(f = *l; f; f = f->nextrxt){
+ if(f == a){
+ *l = a->nextrxt;
+ break;
+ }
+ l = &f->nextrxt;
+ }
+ }
+
+ a->hold = nil;
+ a->ifc = ifc;
+ a->ifcid = ifc->ifcid;
bp = a->hold;
a->hold = nil;
if(version == V4)
ip += IPv4off;
qunlock(arp);
- while(bp) {
+ while(bp){
next = bp->list;
if(ifc != nil){
if(waserror()){
@@ 252,7 417,12 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
}
if(refresh == 0){
- a = newarp(arp, ip, type);
+ //a = newarp6(arp, ip, ifc, 0);
+ if(version == 4)
+ a = newarp(arp, ip, type);
+ else
+ a = newarp6(arp, ip, ifc, 0);
+
a->state = AOK;
a->type = type;
memmove(a->mac, mac, type->maclen);
@@ 269,40 439,63 @@ arpwrite(Fs *fs, char *s, int len)
Arp *arp;
Block *bp;
Arpent *a;
- Cmdbuf *cb;
- Cmdtab *ct;
Medium *m;
+ char *f[4], buf[256];
uchar ip[IPaddrlen], mac[MAClen];
arp = fs->arp;
- cb = parsecmd(s, len);
- if(waserror()){
- free(cb);
- nexterror();
- }
-
- ct = lookupcmd(cb, arpcmd, nelem(arpcmd));
-
- switch(ct->index){
- case CMadd:
- switch(cb->nf) {
+ if(len == 0)
+ error(Ebadarp);
+ if(len >= sizeof(buf))
+ len = sizeof(buf)-1;
+ strncpy(buf, s, len);
+ buf[len] = 0;
+ if(len > 0 && buf[len-1] == '\n')
+ buf[len-1] = 0;
+
+ n = getfields(buf, f, 4, 1, " ");
+ if(strcmp(f[0], "flush") == 0){
+ qlock(arp);
+ for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
+ memset(a->ip, 0, sizeof(a->ip));
+ memset(a->mac, 0, sizeof(a->mac));
+ a->hash = nil;
+ a->state = 0;
+ a->used = 0;
+ while(a->hold != nil){
+ bp = a->hold->list;
+ freeblist(a->hold);
+ a->hold = bp;
+ }
+ }
+ memset(arp->hash, 0, sizeof(arp->hash));
+// clear all pkts on these lists (rxmt, dropf/l)
+ arp->rxmt = nil;
+ arp->dropf = nil;
+ arp->dropl = nil;
+ qunlock(arp);
+ } else if(strcmp(f[0], "add") == 0){
+ switch(n){
default:
- cmderror(cb, Ecmdargs);
+ error(Ebadarg);
case 3:
- parseip(ip, cb->f[1]);
- r = v4lookup(fs, ip+IPv4off);
+ parseip(ip, f[1]);
+ if(isv4(ip))
+ r = v4lookup(fs, ip+IPv4off);
+ else
+ r = v6lookup(fs, ip);
if(r == nil)
- error("destination unreachable");
+ error("Destination unreachable");
m = r->ifc->m;
- n = parsemac(mac, cb->f[2], m->maclen);
+ n = parsemac(mac, f[2], m->maclen);
break;
case 4:
- m = ipfindmedium(cb->f[1]);
+ m = ipfindmedium(f[1]);
if(m == nil)
error(Ebadarp);
- parseip(ip, cb->f[2]);
- n = parsemac(mac, cb->f[3], m->maclen);
+ parseip(ip, f[2]);
+ n = parsemac(mac, f[3], m->maclen);
break;
}
@@ 310,38 503,18 @@ arpwrite(Fs *fs, char *s, int len)
error(Ebadarp);
m->ares(fs, V6, ip, mac, n, 0);
- break;
-
- case CMflush:
- qlock(arp);
- for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
- memset(a->ip, 0, sizeof(a->ip));
- memset(a->mac, 0, sizeof(a->mac));
- a->hash = nil;
- a->state = 0;
- a->used = 0;
- while(a->hold != nil) {
- bp = a->hold->list;
- freeblist(a->hold);
- a->hold = bp;
- }
- }
- memset(arp->hash, 0, sizeof(arp->hash));
- qunlock(arp);
- break;
- }
+ } else
+ error(Ebadarp);
- poperror();
- free(cb);
return len;
}
enum
{
- Alinelen= 66,
+ Alinelen= 90,
};
-char *aformat = "%-6.6s %-8.8s %-16.16I %-32.32s\n";
+char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
static void
convmac(char *p, uchar *mac, int n)
@@ 380,3 553,136 @@ arpread(Arp *arp, char *p, ulong offset, int len)
return n;
}
+
+extern int
+rxmitsols(Arp *arp)
+{
+ uint sflag;
+ Block *next, *xp;
+ Arpent *a, *b, **l;
+ Fs *f;
+ uchar ipsrc[IPaddrlen];
+ Ipifc *ifc = nil;
+ long nrxt;
+
+ qlock(arp);
+ f = arp->f;
+
+ a = arp->rxmt;
+ if(a==nil){
+ nrxt = 0;
+ goto dodrops; //return nrxt;
+ }
+ nrxt = a->rxtat - msec;
+ if(nrxt > 3*ReTransTimer/4)
+ goto dodrops; //return nrxt;
+
+ for(; a; a = a->nextrxt){
+ ifc = a->ifc;
+ assert(ifc != nil);
+ if((a->rxtsrem <= 0) || !(canrlock(ifc)) || (a->ifcid != ifc->ifcid)){
+ xp = a->hold;
+ a->hold = nil;
+
+ if(xp){
+ if(arp->dropl == nil)
+ arp->dropf = xp;
+ else
+ arp->dropl->list = xp;
+ }
+
+ cleanarpent(arp, a);
+ }
+ else
+ break;
+ }
+
+ /* need to unlock arp, else will deadlock when icmpns
+ * wants to lock arp later.
+ */
+
+ qunlock(arp);
+
+ if(a == nil)
+ goto dodrops; // return 0;
+
+ if(sflag = ipv6anylocal(ifc, ipsrc))
+ icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
+
+ runlock(ifc);
+
+ /* grab lock on arp again */
+
+ qlock(arp);
+
+ /* put to the end of re-transmit chain */
+ l = &arp->rxmt;
+ for(b = *l; b; b = b->nextrxt){
+ if(b == a){
+ *l = a->nextrxt;
+ break;
+ }
+ l = &b->nextrxt;
+ }
+ for(b = *l; b; b = b->nextrxt){
+ l = &b->nextrxt;
+ }
+ *l = a;
+ a->rxtsrem--;
+ a->nextrxt = nil;
+ a->time = msec;
+ a->rxtat = msec + ReTransTimer;
+
+ a = arp->rxmt;
+ if(a==nil)
+ nrxt = 0;
+ else
+ nrxt = a->rxtat - msec;
+
+dodrops:
+ xp = arp->dropf;
+ arp->dropf = nil;
+ arp->dropl = nil;
+ qunlock(arp);
+
+ for(; xp; xp = next){
+ next = xp->list;
+ icmphostunr(f, ifc, xp, icmp6_adr_unreach, 1);
+ }
+
+ return nrxt;
+
+}
+
+static int
+rxready(void *v)
+{
+ Arp *arp = (Arp *) v;
+ int x;
+
+ x = ((arp->rxmt != nil) || (arp->dropf != nil));
+
+ return x;
+}
+
+static void
+rxmitproc(void *v)
+{
+ Arp *arp = v;
+ long wakeupat;
+
+ arp->rxmitp = up;
+ print("arp rxmitproc started\n");
+ if(waserror()){
+ arp->rxmitp = 0;
+ pexit("hangup", 1);
+ }
+ for(;;){
+ wakeupat = rxmitsols(arp);
+ if(wakeupat == 0)
+ sleep(&arp->rxmtq, rxready, v);
+ else if(wakeupat > ReTransTimer/4)
+ tsleep(&arp->rxmtq, return0, 0, wakeupat);
+ }
+}
+
M ip/devip.c => ip/devip.c +51 -80
@@ 15,6 15,7 @@ enum
Qndb,
Qiproute,
Qipselftab,
+ Qipgate6,
Qlog,
Qprotodir, /* directory for a protocol */
@@ 54,30 55,6 @@ QLock fslock;
Fs *ipfs[Nfs]; /* attached fs's */
Queue *qlog;
-enum
-{
- CMaddmulti,
- CMannounce,
- CMbind,
- CMconnect,
- CMremmulti,
- CMtos,
- CMttl,
- CMwildcard,
-};
-
-Cmdtab ipctlmsg[] =
-{
- CMaddmulti, "addmulti", 0,
- CMannounce, "announce", 0,
- CMbind, "bind", 0,
- CMconnect, "connect", 0,
- CMremmulti, "remmulti", 0,
- CMtos, "tos", 0,
- CMttl, "ttl", 0,
- CMwildcard, "*", 0,
-};
-
extern void nullmediumlink(void);
extern void pktmediumlink(void);
long ndbwrite(Fs *f, char *a, ulong off, int n);
@@ 166,7 143,6 @@ ip1gen(Chan *c, int i, Dir *dp)
case Qndb:
p = "ndb";
len = strlen(f->ndb);
- q.vers = f->ndbvers;
break;
case Qiproute:
p = "iproute";
@@ 175,13 151,15 @@ ip1gen(Chan *c, int i, Dir *dp)
p = "ipselftab";
prot = 0444;
break;
+ case Qipgate6:
+ p = "ipgate6";
+ prot = 0444;
+ break;
case Qlog:
p = "log";
break;
}
devdir(c, q, p, len, network, prot, dp);
- if(i == Qndb)
- dp->mtime = f->ndbmtime;
return 1;
}
@@ 217,6 195,7 @@ ipgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
case Qlog:
case Qiproute:
case Qipselftab:
+ case Qipgate6:
return ip1gen(c, TYPE(c->qid), dp);
case Qprotodir:
if(s == DEVDOTDOT){
@@ 346,6 325,7 @@ ipwalk(Chan* c, Chan *nc, char **name, int nname)
return w;
}
+
static int
ipstat(Chan* c, uchar* db, int n)
{
@@ 384,12 364,10 @@ ipopen(Chan* c, int omode)
default:
break;
case Qndb:
- if((omode & (OWRITE|OTRUNC)) && !iseve())
+ if(omode & (OWRITE|OTRUNC) && !iseve())
error(Eperm);
- if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)){
+ if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))
f->ndb[0] = 0;
- f->ndbvers++;
- }
break;
case Qlog:
netlogopen(f);
@@ 405,6 383,7 @@ ipopen(Chan* c, int omode)
case Qstats:
case Qbootp:
case Qipselftab:
+ case Qipgate6:
if(omode != OREAD)
error(Eperm);
break;
@@ 497,14 476,25 @@ ipopen(Chan* c, int omode)
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
- c->iounit = qiomaxatomic;
return c;
}
+static void
+ipcreate(Chan*, char*, int, ulong)
+{
+ error(Eperm);
+}
+
+static void
+ipremove(Chan*)
+{
+ error(Eperm);
+}
+
static int
ipwstat(Chan *c, uchar *dp, int n)
{
- Dir *d;
+ Dir d;
Conv *cv;
Fs *f;
Proto *p;
@@ 519,26 509,16 @@ ipwstat(Chan *c, uchar *dp, int n)
break;
}
- d = smalloc(n + sizeof(Dir));
- if(waserror()){
- free(d);
- nexterror();
+ n = convM2D(dp, n, &d, nil);
+ if(n > 0){
+ p = f->p[PROTO(c->qid)];
+ cv = p->conv[CONV(c->qid)];
+ if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
+ error(Eperm);
+ if(d.uid[0])
+ kstrdup(&cv->owner, d.uid);
+ cv->perm = d.mode & 0777;
}
- n = convM2D(dp, n, d, nil);
- if(n == 0)
- error(Eshortstat);
-
- p = f->p[PROTO(c->qid)];
- cv = p->conv[CONV(c->qid)];
- if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
- error(Eperm);
- if(!emptystr(d->uid))
- kstrdup(&cv->owner, d->uid);
- if(d->mode != ~0UL)
- cv->perm = d->mode & 0777;
-
- poperror();
- free(d);
return n;
}
@@ 631,6 611,8 @@ ipread(Chan *ch, void *a, long n, vlong off)
return routeread(f, a, offset, n);
case Qipselftab:
return ipselftabread(f, a, offset, n);
+ case Qipgate6:
+ return ipgateread6(f, a, offset, n);
case Qlog:
return netlogread(f, a, offset, n);
case Qctl:
@@ 749,6 731,7 @@ setluniqueport(Conv* c, int lport)
return nil;
}
+
/*
* pick a local port and set it
*/
@@ 1037,7 1020,6 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
Proto *x;
char *p;
Cmdbuf *cb;
- Cmdtab *ct;
uchar ia[IPaddrlen], ma[IPaddrlen];
Fs *f;
char *a;
@@ 1080,26 1062,21 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
free(cb);
nexterror();
}
- ct = lookupcmd(cb, ipctlmsg, nelem(ipctlmsg));
- switch(ct->index){
- case CMconnect:
+ if(cb->nf < 1)
+ error("short control request");
+ if(strcmp(cb->f[0], "connect") == 0)
connectctlmsg(x, c, cb);
- break;
- case CMannounce:
+ else if(strcmp(cb->f[0], "announce") == 0)
announcectlmsg(x, c, cb);
- break;
- case CMbind:
+ else if(strcmp(cb->f[0], "bind") == 0)
bindctlmsg(x, c, cb);
- break;
- case CMttl:
+ else if(strcmp(cb->f[0], "ttl") == 0)
ttlctlmsg(c, cb);
- break;
- case CMtos:
+ else if(strcmp(cb->f[0], "tos") == 0)
tosctlmsg(c, cb);
- break;
- case CMaddmulti:
- if(cb->nf != 2 && cb->nf != 3)
- cmderror(cb, Ecmdargs);
+ else if(strcmp(cb->f[0], "addmulti") == 0){
+ if(cb->nf < 2)
+ error("addmulti needs interface address");
if(cb->nf == 2){
if(!ipismulticast(c->raddr))
error("addmulti for a non multicast address");
@@ 1112,23 1089,19 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
parseip(ia, cb->f[1]);
ipifcaddmulti(c, ma, ia);
}
- break;
- case CMremmulti:
+ } else if(strcmp(cb->f[0], "remmulti") == 0){
if(cb->nf < 2)
error("remmulti needs interface address");
if(!ipismulticast(c->raddr))
error("remmulti for a non multicast address");
parseip(ia, cb->f[1]);
ipifcremmulti(c, c->raddr, ia);
- break;
- case CMwildcard:
- if(x->ctl == nil)
- cmderror(cb, "unknown control request");
+ } else if(x->ctl != nil) {
p = x->ctl(c, cb->f, cb->nf);
if(p != nil)
error(p);
- }
-
+ } else
+ error("unknown control request");
qunlock(c);
free(cb);
poperror();
@@ 1175,13 1148,13 @@ Dev ipdevtab = {
ipwalk,
ipstat,
ipopen,
- devcreate,
+ ipcreate,
ipclose,
ipread,
ipbread,
ipwrite,
ipbwrite,
- devremove,
+ ipremove,
ipwstat,
};
@@ 1375,8 1348,6 @@ ndbwrite(Fs *f, char *a, ulong off, int n)
error(Eio);
memmove(f->ndb+off, a, n);
f->ndb[off+n] = 0;
- f->ndbvers++;
- f->ndbmtime = seconds();
return n;
}
M ip/esp.c => ip/esp.c +4 -3
@@ 23,7 23,7 @@ enum
{
IP_ESPPROTO = 50,
EsphdrSize = 28, // includes IP header
- IphdrSize = 20, // options have been stripped
+ IphdrSize = 20, // options have been striped
EsptailSize = 2, // does not include pad or auth data
UserhdrSize = 4, // user visable header size - if enabled
};
@@ 285,6 285,7 @@ espkick(Conv *c)
auth = bp->rp + EsphdrSize + payload + pad + EsptailSize;
// fill in head
+ eh->vihl = IP_VER4;
hnputl(eh->espspi, ecb->spi);
hnputl(eh->espseq, ++ecb->seq);
v6tov4(eh->espsrc, c->laddr);
@@ 296,8 297,8 @@ espkick(Conv *c)
ecb->auth(ecb, bp->rp+IphdrSize, (EsphdrSize-IphdrSize)+payload+pad+EsptailSize, auth);
qunlock(c);
-//print("esp: pass down: %uld\n", BLEN(bp));
- ipoput(c->p->f, bp, 0, c->ttl, c->tos);
+ //print("esp: pass down: %uld\n", BLEN(bp));
+ ipoput4(c->p->f, bp, 0, c->ttl, c->tos);
}
void
M ip/ethermedium.c => ip/ethermedium.c +187 -64
@@ 6,6 6,7 @@
#include "../port/error.h"
#include "ip.h"
+#include "ipv6.h"
typedef struct Etherhdr Etherhdr;
struct Etherhdr
@@ 15,7 16,8 @@ struct Etherhdr
uchar t[2];
};
-static void etherread(void *a);
+static void etherread4(void *a);
+static void etherread6(void *a);
static void etherbind(Ipifc *ifc, int argc, char **argv);
static void etherunbind(Ipifc *ifc);
static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
@@ 26,6 28,8 @@ static void sendarp(Ipifc *ifc, Arpent *a);
static void sendgarp(Ipifc *ifc, uchar*);
static int multicastea(uchar *ea, uchar *ip);
static void recvarpproc(void*);
+static void resolveaddr6(Ipifc *ifc, Arpent *a);
+static void etherpref2addr(uchar *pref, uchar *ea);
Medium ethermedium =
{
@@ 41,6 45,7 @@ Medium ethermedium =
.remmulti= etherremmulti,
.ares= arpenter,
.areg= sendgarp,
+.pref2addr= etherpref2addr,
};
Medium gbemedium =
@@ 57,6 62,7 @@ Medium gbemedium =
.remmulti= etherremmulti,
.ares= arpenter,
.areg= sendgarp,
+.pref2addr= etherpref2addr,
};
typedef struct Etherrock Etherrock;
@@ 64,10 70,13 @@ struct Etherrock
{
Fs *f; /* file system we belong to */
Proc *arpp; /* arp process */
- Proc *readp; /* reading process */
- Chan *mchan; /* Data channel */
+ Proc *read4p; /* reading process (v4)*/
+ Proc *read6p; /* reading process (v6)*/
+ Chan *mchan4; /* Data channel for v4 */
Chan *achan; /* Arp channel */
- Chan *cchan; /* Control channel */
+ Chan *cchan4; /* Control channel for v4 */
+ Chan *mchan6; /* Data channel for v6 */
+ Chan *cchan6; /* Control channel for v6 */
};
/*
@@ 76,10 85,12 @@ struct Etherrock
enum
{
ETARP = 0x0806,
- ETIP = 0x0800,
+ ETIP4 = 0x0800,
+ ETIP6 = 0x86DD,
ARPREQUEST = 1,
ARPREPLY = 2,
};
+
typedef struct Etherarp Etherarp;
struct Etherarp
{
@@ 97,7 108,6 @@ struct Etherarp
uchar tpa[4];
};
-
/*
* called to bind an IP ifc to an ethernet device
* called with ifc wlock'd
@@ 105,9 115,9 @@ struct Etherarp
static void
etherbind(Ipifc *ifc, int argc, char **argv)
{
- Chan *mchan, *cchan, *achan;
- char addr[Maxpath];
- char dir[Maxpath];
+ Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6;
+ char addr[Maxpath]; //char addr[2*KNAMELEN];
+ char dir[Maxpath]; //char dir[2*KNAMELEN];
char *buf;
int n;
char *ptr;
@@ 116,15 126,19 @@ etherbind(Ipifc *ifc, int argc, char **argv)
if(argc < 2)
error(Ebadarg);
- mchan = cchan = achan = nil;
+ mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
buf = nil;
if(waserror()){
- if(mchan != nil)
- cclose(mchan);
- if(cchan != nil)
- cclose(cchan);
+ if(mchan4 != nil)
+ cclose(mchan4);
+ if(cchan4 != nil)
+ cclose(cchan4);
if(achan != nil)
cclose(achan);
+ if(mchan6 != nil)
+ cclose(mchan6);
+ if(cchan6 != nil)
+ cclose(cchan6);
if(buf != nil)
free(buf);
nexterror();
@@ 137,7 151,7 @@ etherbind(Ipifc *ifc, int argc, char **argv)
* this device.
*/
snprint(addr, sizeof(addr), "%s!0x800", argv[2]);
- mchan = chandial(addr, nil, dir, &cchan);
+ mchan4 = chandial(addr, nil, dir, &cchan4);
/*
* get mac address
@@ 162,18 176,30 @@ etherbind(Ipifc *ifc, int argc, char **argv)
snprint(addr, sizeof(addr), "%s!0x806", argv[2]);
achan = chandial(addr, nil, nil, nil);
+ /*
+ * open ip conversation
+ *
+ * the dial will fail if the type is already open on
+ * this device.
+ */
+ snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]);
+ mchan6 = chandial(addr, nil, dir, &cchan6);
+
er = smalloc(sizeof(*er));
- er->mchan = mchan;
- er->cchan = cchan;
+ er->mchan4 = mchan4;
+ er->cchan4 = cchan4;
er->achan = achan;
+ er->mchan6 = mchan6;
+ er->cchan6 = cchan6;
er->f = ifc->conv->p->f;
ifc->arg = er;
free(buf);
poperror();
- kproc("etherread", etherread, ifc);
+ kproc("etherread4", etherread4, ifc);
kproc("recvarpproc", recvarpproc, ifc);
+ kproc("etherread6", etherread6, ifc);
}
/*
@@ 184,21 210,27 @@ etherunbind(Ipifc *ifc)
{
Etherrock *er = ifc->arg;
- if(er->readp)
- postnote(er->readp, 1, "unbind", 0);
+ if(er->read4p)
+ postnote(er->read4p, 1, "unbind", 0);
+ if(er->read6p)
+ postnote(er->read6p, 1, "unbind", 0);
if(er->arpp)
postnote(er->arpp, 1, "unbind", 0);
/* wait for readers to die */
- while(er->arpp != 0 || er->readp != 0)
+ while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
tsleep(&up->sleep, return0, 0, 300);
- if(er->mchan != nil)
- cclose(er->mchan);
+ if(er->mchan4 != nil)
+ cclose(er->mchan4);
if(er->achan != nil)
cclose(er->achan);
- if(er->cchan != nil)
- cclose(er->cchan);
+ if(er->cchan4 != nil)
+ cclose(er->cchan4);
+ if(er->mchan6 != nil)
+ cclose(er->mchan6);
+ if(er->cchan6 != nil)
+ cclose(er->cchan6);
free(er);
}
@@ 215,12 247,15 @@ etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
Etherrock *er = ifc->arg;
/* get mac address of destination */
- a = arpget(er->f->arp, bp, version, ifc->m, ip, mac);
+ a = arpget(er->f->arp, bp, version, ifc, ip, mac);
if(a){
/* check for broadcast or multicast */
bp = multicastarp(er->f, a, ifc->m, mac);
- if(bp == nil){
- sendarp(ifc, a);
+ if(bp==nil){
+ if(version == V4)
+ sendarp(ifc, a);
+ else
+ resolveaddr6(ifc, a);
return;
}
}
@@ 236,26 271,67 @@ etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
/* copy in mac addresses and ether type */
memmove(eh->s, ifc->mac, sizeof(eh->s));
memmove(eh->d, mac, sizeof(eh->d));
- switch(version){
+
+ switch(version){
case V4:
eh->t[0] = 0x08;
eh->t[1] = 0x00;
+ devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
break;
case V6:
eh->t[0] = 0x86;
eh->t[1] = 0xDD;
+ devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
break;
}
-
- devtab[er->mchan->type]->bwrite(er->mchan, bp, 0);
ifc->out++;
}
+
/*
* process to read from the ethernet
*/
static void
-etherread(void *a)
+etherread4(void *a)
+{
+ Ipifc *ifc;
+ Block *bp;
+ Etherrock *er;
+
+ ifc = a;
+ er = ifc->arg;
+ er->read4p = up; /* hide identity under a rock for unbind */
+ if(waserror()){
+ er->read4p = 0;
+ pexit("hangup", 1);
+ }
+ for(;;){
+ bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxmtu, 0);
+ if(!canrlock(ifc)){
+ freeb(bp);
+ continue;
+ }
+ if(waserror()){
+ runlock(ifc);
+ nexterror();
+ }
+ ifc->in++;
+ bp->rp += ifc->m->hsize;
+ if(ifc->lifc == nil)
+ freeb(bp);
+ else
+ ipiput4(er->f, ifc, bp);
+ runlock(ifc);
+ poperror();
+ }
+}
+
+
+/*
+ * process to read from the ethernet, IPv6
+ */
+static void
+etherread6(void *a)
{
Ipifc *ifc;
Block *bp;
@@ 263,13 339,13 @@ etherread(void *a)
ifc = a;
er = ifc->arg;
- er->readp = up; /* hide identity under a rock for unbind */
+ er->read6p = up; /* hide identity under a rock for unbind */
if(waserror()){
- er->readp = 0;
+ er->read6p = 0;
pexit("hangup", 1);
}
for(;;){
- bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxmtu, 0);
+ bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxmtu, 0);
if(!canrlock(ifc)){
freeb(bp);
continue;
@@ 283,7 359,7 @@ etherread(void *a)
if(ifc->lifc == nil)
freeb(bp);
else
- ipiput(er->f, ifc, bp);
+ ipiput6(er->f, ifc, bp);
runlock(ifc);
poperror();
}
@@ 295,10 371,14 @@ etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
uchar mac[6];
char buf[64];
Etherrock *er = ifc->arg;
+ int type;
- multicastea(mac, a);
+ type = multicastea(mac, a);
sprint(buf, "addmulti %E", mac);
- devtab[er->cchan->type]->write(er->cchan, buf, strlen(buf), 0);
+ if(type == V4)
+ devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
+ else if(type == V6)
+ devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
}
static void
@@ 307,10 387,14 @@ etherremmulti(Ipifc *ifc, uchar *a, uchar *)
uchar mac[6];
char buf[64];
Etherrock *er = ifc->arg;
+ int type;
- multicastea(mac, a);
+ type = multicastea(mac, a);
sprint(buf, "remmulti %E", mac);
- devtab[er->cchan->type]->write(er->cchan, buf, strlen(buf), 0);
+ if(type == V4)
+ devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
+ else if(type == V6)
+ devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
}
/*
@@ 357,7 441,7 @@ sendarp(Ipifc *ifc, Arpent *a)
hnputs(e->type, ETARP);
hnputs(e->hrd, 1);
- hnputs(e->pro, ETIP);
+ hnputs(e->pro, ETIP4);
e->hln = sizeof(e->sha);
e->pln = sizeof(e->spa);
hnputs(e->op, ARPREQUEST);
@@ 368,6 452,43 @@ sendarp(Ipifc *ifc, Arpent *a)
print("arp: send: %r\n");
}
+static void
+resolveaddr6(Ipifc *ifc, Arpent *a)
+{
+ int sflag;
+ Block *bp;
+ Etherrock *er = ifc->arg;
+ uchar ipsrc[IPaddrlen];
+
+ /* don't do anything if it's been less than a second since the last */
+ if(msec - a->time < ReTransTimer){
+ arprelease(er->f->arp, a);
+ return;
+ }
+
+ /* remove all but the last message */
+ while((bp = a->hold) != nil){
+ if(bp == a->last)
+ break;
+ a->hold = bp->list;
+ freeblist(bp);
+ }
+
+ /* try to keep it around for a second more */
+ a->time = msec;
+ a->rxtat = msec + ReTransTimer;
+ if(a->rxtsrem <= 0) {
+ arprelease(er->f->arp, a);
+ return;
+ }
+
+ a->rxtsrem--;
+ arprelease(er->f->arp, a);
+
+ if(sflag = ipv6anylocal(ifc, ipsrc))
+ icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
+}
+
/*
* send a gratuitous arp to refresh arp caches
*/
@@ 397,7 518,7 @@ sendgarp(Ipifc *ifc, uchar *ip)
hnputs(e->type, ETARP);
hnputs(e->hrd, 1);
- hnputs(e->pro, ETIP);
+ hnputs(e->pro, ETIP4);
e->hln = sizeof(e->sha);
e->pln = sizeof(e->spa);
hnputs(e->op, ARPREQUEST);
@@ 429,13 550,6 @@ recvarp(Ipifc *ifc)
break;
case ARPREPLY:
- if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
- if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
- print("arprep: 0x%E/0x%E also has ip addr %V\n",
- e->s, e->sha, e->spa);
- break;
- }
- }
arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
break;
@@ 447,11 561,8 @@ recvarp(Ipifc *ifc)
/* check for someone that think's they're me */
v4tov6(ip, e->spa);
if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
- if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
- print("arpreq: 0x%E/0x%E also has ip addr %V\n",
- e->s, e->sha, e->spa);
- break;
- }
+ if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0)
+ print("arp: 0x%E also has ip addr %V\n", e->sha, e->spa);
} else {
if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
print("arp: %V also has ether addr %E\n", e->spa, e->sha);
@@ 468,8 579,6 @@ recvarp(Ipifc *ifc)
if(!ipproxyifc(er->f, ifc, ip))
break;
-/* print("arp: rem %I %E (for %I)\n", e->spa, e->sha, e->tpa); /**/
-
n = sizeof(Etherarp);
if(n < ifc->minmtu)
n = ifc->minmtu;
@@ 478,7 587,7 @@ recvarp(Ipifc *ifc)
memset(r, 0, sizeof(Etherarp));
hnputs(r->type, ETARP);
hnputs(r->hrd, 1);
- hnputs(r->pro, ETIP);
+ hnputs(r->pro, ETIP4);
r->hln = sizeof(r->sha);
r->pln = sizeof(r->spa);
hnputs(r->op, ARPREPLY);
@@ 526,14 635,14 @@ multicastea(uchar *ea, uchar *ip)
ea[4] = ip[14];
ea[5] = ip[15];
break;
- case V6:
- ea[0] = 0x33;
- ea[1] = 0x33;
- ea[2] = ip[12];
+ case V6:
+ ea[0] = 0x33;
+ ea[1] = 0x33;
+ ea[2] = ip[12];
ea[3] = ip[13];
- ea[4] = ip[14];
- ea[5] = ip[15];
- break;
+ ea[4] = ip[14];
+ ea[5] = ip[15];
+ break;
}
return x;
}
@@ 573,3 682,17 @@ ethermediumlink(void)
addipmedium(ðermedium);
addipmedium(&gbemedium);
}
+
+
+static void
+etherpref2addr(uchar *pref, uchar *ea)
+{
+ pref[8] = ea[0] | 0x2;
+ pref[9] = ea[1];
+ pref[10] = ea[2];
+ pref[11] = 0xFF;
+ pref[12] = 0xFE;
+ pref[13] = ea[3];
+ pref[14] = ea[4];
+ pref[15] = ea[5];
+}
M ip/gre.c => ip/gre.c +2 -1
@@ 140,6 140,7 @@ grekick(Conv *c)
return;
ghp = (GREhdr *)(bp->rp);
+ ghp->vihl = IP_VER4;
v4tov6(raddr, ghp->dst);
if(ipcmp(raddr, v4prefix) == 0)
@@ 156,7 157,7 @@ grekick(Conv *c)
ghp->frag[0] = 0;
ghp->frag[1] = 0;
- ipoput(c->p->f, bp, 0, c->ttl, c->tos);
+ ipoput4(c->p->f, bp, 0, c->ttl, c->tos);
}
static void
M ip/icmp.c => ip/icmp.c +19 -38
@@ 28,7 28,6 @@ typedef struct Icmp {
enum { /* Packet Types */
EchoReply = 0,
- UnreachableV6 = 1,
Unreachable = 3,
SrcQuench = 4,
Redirect = 5,
@@ 52,7 51,6 @@ enum
char *icmpnames[Maxtype+1] =
{
-[UnreachableV6] "UnreachableV6",
[EchoReply] "EchoReply",
[Unreachable] "Unreachable",
[SrcQuench] "SrcQuench",
@@ 106,7 104,7 @@ struct Icmppriv
ulong out[Maxtype+1];
};
-static char*
+extern char*
icmpconnect(Conv *c, char **argv, int argc)
{
char *e;
@@ 117,21 115,21 @@ icmpconnect(Conv *c, char **argv, int argc)
return e;
}
-static int
+extern int
icmpstate(Conv *c, char *state, int n)
{
USED(c);
return snprint(state, n, "%s", "Datagram");
}
-static void
+extern void
icmpcreate(Conv *c)
{
c->rq = qopen(64*1024, 1, 0, c);
c->wq = qopen(64*1024, 0, 0, 0);
}
-static char*
+extern char*
icmpannounce(Conv *c, char **argv, int argc)
{
char *e;
@@ 144,7 142,7 @@ icmpannounce(Conv *c, char **argv, int argc)
return nil;
}
-static void
+extern void
icmpclose(Conv *c)
{
qclose(c->rq);
@@ 154,7 152,7 @@ icmpclose(Conv *c)
c->lport = 0;
}
-static void
+extern void
icmpkick(Conv *c)
{
Icmp *p;
@@ 170,6 168,7 @@ icmpkick(Conv *c)
return;
}
p = (Icmp *)(bp->rp);
+ p->vihl = IP_VER4;
ipriv = c->p->priv;
if(p->type <= Maxtype)
ipriv->out[p->type]++;
@@ 181,23 180,24 @@ icmpkick(Conv *c)
memset(p->cksum, 0, sizeof(p->cksum));
hnputs(p->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE));
ipriv->stats[OutMsgs]++;
- ipoput(c->p->f, bp, 0, c->ttl, c->tos);
+ ipoput4(c->p->f, bp, 0, c->ttl, c->tos);
}
extern void
-icmpttlexceeded(Fs *f, Ipifc *ifc, Block *bp)
+icmpttlexceeded(Fs *f, uchar *ia, Block *bp)
{
Block *nbp;
Icmp *p, *np;
p = (Icmp *)bp->rp;
+ p->vihl = IP_VER4;
netlog(f, Logicmp, "sending icmpttlexceeded -> %V\n", p->src);
nbp = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8);
nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8;
np = (Icmp *)nbp->rp;
memmove(np->dst, p->src, sizeof(np->dst));
- v6tov4(np->src, ifc->lifc->local);
+ v6tov4(np->src, ia);
memmove(np->data, bp->rp, ICMP_IPSIZE + 8);
np->type = TimeExceed;
np->code = 0;
@@ 206,7 206,7 @@ icmpttlexceeded(Fs *f, Ipifc *ifc, Block *bp)
hnputs(np->seq, 0);
memset(np->cksum, 0, sizeof(np->cksum));
hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE));
- ipoput(f, nbp, 0, MAXTTL, DFLTTOS);
+ ipoput4(f, nbp, 0, MAXTTL, DFLTTOS);
}
@@ 219,6 219,7 @@ icmpnoconv(Fs *f, Block *bp)
uchar addr[IPaddrlen];
p = (Icmp *)bp->rp;
+ p->vihl = IP_VER4;
/* only do this for unicast sources and destinations */
v4tov6(addr, p->dst);
@@ 244,7 245,7 @@ icmpnoconv(Fs *f, Block *bp)
hnputs(np->seq, 0);
memset(np->cksum, 0, sizeof(np->cksum));
hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE));
- ipoput(f, nbp, 0, MAXTTL, DFLTTOS);
+ ipoput4(f, nbp, 0, MAXTTL, DFLTTOS);
}
static void
@@ 279,6 280,7 @@ mkechoreply(Block *bp)
uchar ip[4];
q = (Icmp *)bp->rp;
+ q->vihl = IP_VER4;
memmove(ip, q->src, sizeof(q->dst));
memmove(q->src, q->dst, sizeof(q->src));
memmove(q->dst, ip, sizeof(q->dst));
@@ 295,7 297,7 @@ static char *unreachcode[] =
[1] "host unreachable",
[2] "protocol unreachable",
[3] "port unreachable",
-[4] "unfragmentable",
+[4] "fragmentation needed and DF set",
[5] "source route failed",
};
@@ 309,9 311,6 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
char *msg;
char m2[128];
Icmppriv *ipriv;
- int code;
- ushort x;
- uchar dst[IPaddrlen];
ipriv = icmp->priv;
@@ 346,27 345,13 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
case EchoRequest:
r = mkechoreply(bp);
ipriv->out[EchoReply]++;
- ipoput(icmp->f, r, 0, MAXTTL, DFLTTOS);
+ ipoput4(icmp->f, r, 0, MAXTTL, DFLTTOS);
break;
case Unreachable:
- code = p->code;
- x = 0;
- switch(code){
- default:
+ if(p->code > 5 || p->code < 0)
msg = unreachcode[1];
- break;
- case 5:
- x = nhgets(p->seq);
- msg = unreachcode[p->code];
- break;
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
+ else
msg = unreachcode[p->code];
- break;
- }
bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
if(blocklen(bp) < MinAdvise){
@@ 374,10 359,6 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
goto raise;
}
p = (Icmp *)bp->rp;
- if(code == 5){
- v4tov6(dst, p->dst);
- update_mtucache(dst, x);
- }
pr = Fsrcvpcolx(icmp->f, p->proto);
if(pr != nil && pr->advise != nil) {
(*pr->advise)(pr, bp, msg);
A ip/icmp6.c => ip/icmp6.c +923 -0
@@ 0,0 1,923 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "ip.h"
+#include "ipv6.h"
+
+typedef struct ICMPpkt ICMPpkt;
+typedef struct IPICMP IPICMP;
+typedef struct Ndpkt Ndpkt;
+typedef struct NdiscC NdiscC;
+
+struct ICMPpkt {
+ uchar type;
+ uchar code;
+ uchar cksum[2];
+ uchar icmpid[2];
+ uchar seq[2];
+};
+
+struct IPICMP {
+ Ip6hdr;
+ ICMPpkt;
+};
+
+struct NdiscC
+{
+ IPICMP;
+ uchar target[IPaddrlen];
+};
+
+struct Ndpkt
+{
+ NdiscC;
+ uchar otype;
+ uchar olen; // length in units of 8 octets(incl type, code),
+ // 1 for IEEE 802 addresses
+ uchar lnaddr[6]; // link-layer address
+};
+
+enum {
+ // ICMPv6 types
+ EchoReply = 0,
+ UnreachableV6 = 1,
+ PacketTooBigV6 = 2,
+ TimeExceedV6 = 3,
+ SrcQuench = 4,
+ ParamProblemV6 = 4,
+ Redirect = 5,
+ EchoRequest = 8,
+ TimeExceed = 11,
+ InParmProblem = 12,
+ Timestamp = 13,
+ TimestampReply = 14,
+ InfoRequest = 15,
+ InfoReply = 16,
+ AddrMaskRequest = 17,
+ AddrMaskReply = 18,
+ EchoRequestV6 = 128,
+ EchoReplyV6 = 129,
+ RouterSolicit = 133,
+ RouterAdvert = 134,
+ NbrSolicit = 135,
+ NbrAdvert = 136,
+ RedirectV6 = 137,
+
+ Maxtype6 = 137,
+};
+
+char *icmpnames6[Maxtype6+1] =
+{
+[EchoReply] "EchoReply",
+[UnreachableV6] "UnreachableV6",
+[PacketTooBigV6] "PacketTooBigV6",
+[TimeExceedV6] "TimeExceedV6",
+[SrcQuench] "SrcQuench",
+[Redirect] "Redirect",
+[EchoRequest] "EchoRequest",
+[TimeExceed] "TimeExceed",
+[InParmProblem] "InParmProblem",
+[Timestamp] "Timestamp",
+[TimestampReply] "TimestampReply",
+[InfoRequest] "InfoRequest",
+[InfoReply] "InfoReply",
+[AddrMaskRequest] "AddrMaskRequest",
+[AddrMaskReply] "AddrMaskReply",
+[EchoRequestV6] "EchoRequestV6",
+[EchoReplyV6] "EchoReplyV6",
+[RouterSolicit] "RouterSolicit",
+[RouterAdvert] "RouterAdvert",
+[NbrSolicit] "NbrSolicit",
+[NbrAdvert] "NbrAdvert",
+[RedirectV6] "RedirectV6",
+};
+
+enum
+{
+ InMsgs6,
+ InErrors6,
+ OutMsgs6,
+ CsumErrs6,
+ LenErrs6,
+ HlenErrs6,
+ HoplimErrs6,
+ IcmpCodeErrs6,
+ TargetErrs6,
+ OptlenErrs6,
+ AddrmxpErrs6,
+ RouterAddrErrs6,
+
+ Nstats6,
+};
+
+static char *statnames6[Nstats6] =
+{
+[InMsgs6] "InMsgs",
+[InErrors6] "InErrors",
+[OutMsgs6] "OutMsgs",
+[CsumErrs6] "CsumErrs",
+[LenErrs6] "LenErrs",
+[HlenErrs6] "HlenErrs",
+[HoplimErrs6] "HoplimErrs",
+[IcmpCodeErrs6] "IcmpCodeErrs",
+[TargetErrs6] "TargetErrs",
+[OptlenErrs6] "OptlenErrs",
+[AddrmxpErrs6] "AddrmxpErrs",
+[RouterAddrErrs6] "RouterAddrErrs",
+};
+
+typedef struct Icmppriv6
+{
+ ulong stats[Nstats6];
+
+ /* message counts */
+ ulong in[Maxtype6+1];
+ ulong out[Maxtype6+1];
+} Icmppriv6;
+
+typedef struct Icmpcb6
+{
+ QLock;
+ uchar headers;
+} Icmpcb6;
+
+static char *unreachcode[] =
+{
+[icmp6_no_route] "no route to destination",
+[icmp6_ad_prohib] "comm with destination administratively prohibited",
+[icmp6_unassigned] "icmp unreachable: unassigned error code (2)",
+[icmp6_adr_unreach] "address unreachable",
+[icmp6_port_unreach] "port unreachable",
+[icmp6_unkn_code] "icmp unreachable: unknown code",
+};
+
+enum {
+ ICMP_USEAD6 = 40,
+};
+
+enum {
+ Oflag = 1<<5,
+ Sflag = 1<<6,
+ Rflag = 1<<7,
+};
+
+enum {
+ slladd = 1,
+ tlladd = 2,
+ prfinfo = 3,
+ redhdr = 4,
+ mtuopt = 5,
+};
+
+static void
+set_cksum(Block *bp)
+{
+ IPICMP *p = (IPICMP *)(bp->rp);
+
+ hnputl(p->vcf, 0); // borrow IP header as pseudoheader
+ hnputs(p->ploadlen, blocklen(bp)-IPV6HDR_LEN);
+ p->proto = 0;
+ p->ttl = ICMPv6; // ttl gets set later
+ hnputs(p->cksum, 0);
+ hnputs(p->cksum, ptclcsum(bp, 0, blocklen(bp)));
+ p->proto = ICMPv6;
+}
+
+static Block *
+newIPICMP(int packetlen)
+{
+ Block *nbp;
+ nbp = allocb(packetlen);
+ nbp->wp += packetlen;
+ memset(nbp->rp, 0, packetlen);
+ return nbp;
+}
+
+
+char*
+icmpconnect6(Conv *c, char **argv, int argc)
+{
+ char *e;
+
+ e = Fsstdconnect(c, argv, argc);
+ Fsconnected(c, e);
+
+ return e;
+}
+
+void
+icmpadvise6(Proto *icmp, Block *bp, char *msg)
+{
+ Conv **c, *s;
+ IPICMP *p;
+ ushort recid;
+
+ p = (IPICMP *) bp->rp;
+ recid = nhgets(p->icmpid);
+
+ for(c = icmp->conv; *c; c++) {
+ s = *c;
+ if(s->lport == recid)
+ if(ipcmp(s->raddr, p->dst) == 0){
+ qhangup(s->rq, msg);
+ qhangup(s->wq, msg);
+ break;
+ }
+ }
+ freeblist(bp);
+}
+
+void
+icmpkick6(Conv *c)
+{
+ IPICMP *p;
+ Block *bp;
+ uchar laddr[IPaddrlen], raddr[IPaddrlen];
+ Icmppriv6 *ipriv = c->p->priv;
+ Icmpcb6 *icb = (Icmpcb6*)c->ptcl;
+
+ bp = qget(c->wq);
+ if(bp == nil)
+ return;
+
+ if(icb->headers==6) {
+ /* get user specified addresses */
+//print("icmpkick6: headers\n");
+ bp = pullupblock(bp, ICMP_USEAD6);
+ if(bp == nil)
+ return;
+ bp->rp += 8;
+ ipmove(laddr, bp->rp);
+ bp->rp += IPaddrlen;
+ ipmove(raddr, bp->rp);
+ bp->rp += IPaddrlen;
+ bp = padblock(bp, sizeof(Ip6hdr));
+ }
+
+ if(blocklen(bp) < sizeof(IPICMP)){
+ freeblist(bp);
+ return;
+ }
+ p = (IPICMP *)(bp->rp);
+ if(icb->headers == 6) {
+ ipmove(p->dst, raddr);
+ ipmove(p->src, laddr);
+ } else {
+ ipmove(p->dst, c->raddr);
+ ipmove(p->src, c->laddr);
+ hnputs(p->icmpid, c->lport);
+ }
+
+ set_cksum(bp);
+ p->vcf[0] = 0x06 << 4;
+ if(p->type <= Maxtype6)
+ ipriv->out[p->type]++;
+//print("icmpkick6: src %I dst %I\n", p->src, p->dst);
+ ipoput6(c->p->f, bp, 0, c->ttl, c->tos);
+}
+
+char*
+icmpctl6(Conv *c, char **argv, int argc)
+{
+ Icmpcb6 *icb;
+
+ icb = (Icmpcb6*) c->ptcl;
+
+ if(argc==1) {
+ if(strcmp(argv[0], "headers")==0) {
+ icb->headers = 6;
+ return nil;
+ }
+ }
+ return "unknown control request";
+}
+
+static void
+goticmpkt6(Proto *icmp, Block *bp, int muxkey)
+{
+ Conv **c, *s;
+ IPICMP *p = (IPICMP *)bp->rp;
+ ushort recid;
+ uchar *addr;
+
+ if(muxkey == 0) {
+ recid = nhgets(p->icmpid);
+ addr = p->src;
+ }
+ else {
+ recid = muxkey;
+ addr = p->dst;
+ }
+
+ for(c = icmp->conv; *c; c++){
+ s = *c;
+ if(s->lport == recid && ipcmp(s->raddr, addr) == 0){
+ bp = concatblock(bp);
+ if(bp != nil)
+ qpass(s->rq, bp);
+ return;
+ }
+ }
+
+ freeblist(bp);
+}
+
+static Block *
+mkechoreply6(Block *bp)
+{
+ IPICMP *p = (IPICMP *)(bp->rp);
+ uchar addr[IPaddrlen];
+
+ ipmove(addr, p->src);
+ ipmove(p->src, p->dst);
+ ipmove(p->dst, addr);
+ p->type = EchoReplyV6;
+ set_cksum(bp);
+ return bp;
+}
+
+/*
+ * sends out an ICMPv6 neighbor solicitation
+ * suni == SRC_UNSPEC or SRC_UNI,
+ * tuni == TARG_MULTI => multicast for address resolution,
+ * and tflag == TARG_UNI => neighbor reachability.
+ */
+
+extern void
+icmpns(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac)
+{
+ Block *nbp;
+ Ndpkt *np;
+ Proto *icmp = f->t2p[ICMPv6];
+ Icmppriv6 *ipriv = icmp->priv;
+
+
+ nbp = newIPICMP(sizeof(Ndpkt));
+ np = (Ndpkt*) nbp->rp;
+
+
+ if(suni == SRC_UNSPEC)
+ memmove(np->src, v6Unspecified, IPaddrlen);
+ else
+ memmove(np->src, src, IPaddrlen);
+
+ if(tuni == TARG_UNI)
+ memmove(np->dst, targ, IPaddrlen);
+ else
+ ipv62smcast(np->dst, targ);
+
+ np->type = NbrSolicit;
+ np->code = 0;
+ memmove(np->target, targ, IPaddrlen);
+ if(suni != SRC_UNSPEC) {
+ np->otype = SRC_LLADDRESS;
+ np->olen = 1; /* 1+1+6 = 8 = 1 8-octet */
+ memmove(np->lnaddr, mac, sizeof(np->lnaddr));
+ }
+ else {
+ int r = sizeof(Ndpkt)-sizeof(NdiscC);
+ nbp->wp -= r;
+ }
+
+ set_cksum(nbp);
+ np = (Ndpkt*) nbp->rp;
+ np->ttl = HOP_LIMIT;
+ np->vcf[0] = 0x06 << 4;
+ ipriv->out[NbrSolicit]++;
+ netlog(f, Logicmp, "sending neighbor solicitation %I\n", targ);
+ ipoput6(f, nbp, 0, MAXTTL, DFLTTOS);
+}
+
+/*
+ * sends out an ICMPv6 neighbor advertisement. pktflags == RSO flags.
+ */
+extern void
+icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags)
+{
+ Block *nbp;
+ Ndpkt *np;
+ Proto *icmp = f->t2p[ICMPv6];
+ Icmppriv6 *ipriv = icmp->priv;
+
+ nbp = newIPICMP(sizeof(Ndpkt));
+ np = (Ndpkt*) nbp->rp;
+
+ memmove(np->src, src, IPaddrlen);
+ memmove(np->dst, dst, IPaddrlen);
+
+ np->type = NbrAdvert;
+ np->code = 0;
+ np->icmpid[0] = flags;
+ memmove(np->target, targ, IPaddrlen);
+
+ np->otype = TARGET_LLADDRESS;
+ np->olen = 1;
+ memmove(np->lnaddr, mac, sizeof(np->lnaddr));
+
+ set_cksum(nbp);
+ np = (Ndpkt*) nbp->rp;
+ np->ttl = HOP_LIMIT;
+ np->vcf[0] = 0x06 << 4;
+ ipriv->out[NbrAdvert]++;
+ netlog(f, Logicmp, "sending neighbor advertisement %I\n", src);
+ ipoput6(f, nbp, 0, MAXTTL, DFLTTOS);
+}
+
+extern void
+icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free)
+{
+ Block *nbp;
+ IPICMP *np;
+ Ip6hdr *p;
+ int osz = BLEN(bp);
+ int sz = MIN(sizeof(IPICMP) + osz, v6MINTU);
+ Proto *icmp = f->t2p[ICMPv6];
+ Icmppriv6 *ipriv = icmp->priv;
+
+ p = (Ip6hdr *) bp->rp;
+
+ if(isv6mcast(p->src))
+ goto clean;
+
+ nbp = newIPICMP(sz);
+ np = (IPICMP *) nbp->rp;
+
+ rlock(ifc);
+ if(ipv6anylocal(ifc, np->src)) {
+ netlog(f, Logicmp, "send icmphostunr -> s%I d%I\n", p->src, p->dst);
+ }
+ else {
+ netlog(f, Logicmp, "icmphostunr fail -> s%I d%I\n", p->src, p->dst);
+ freeblist(nbp);
+ if(free)
+ goto clean;
+ else
+ return;
+ }
+
+ memmove(np->dst, p->src, IPaddrlen);
+ np->type = UnreachableV6;
+ np->code = code;
+ memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP));
+ set_cksum(nbp);
+ np->ttl = HOP_LIMIT;
+ np->vcf[0] = 0x06 << 4;
+ ipriv->out[UnreachableV6]++;
+
+ if(free)
+ ipiput6(f, ifc, nbp);
+ else {
+ ipoput6(f, nbp, 0, MAXTTL, DFLTTOS);
+ return;
+ }
+
+clean:
+ runlock(ifc);
+ freeblist(bp);
+}
+
+extern void
+icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp)
+{
+ Block *nbp;
+ IPICMP *np;
+ Ip6hdr *p;
+ int osz = BLEN(bp);
+ int sz = MIN(sizeof(IPICMP) + osz, v6MINTU);
+ Proto *icmp = f->t2p[ICMPv6];
+ Icmppriv6 *ipriv = icmp->priv;
+
+ p = (Ip6hdr *) bp->rp;
+
+ if(isv6mcast(p->src))
+ return;
+
+ nbp = newIPICMP(sz);
+ np = (IPICMP *) nbp->rp;
+
+ if(ipv6anylocal(ifc, np->src)) {
+ netlog(f, Logicmp, "send icmpttlexceeded6 -> s%I d%I\n", p->src, p->dst);
+ }
+ else {
+ netlog(f, Logicmp, "icmpttlexceeded6 fail -> s%I d%I\n", p->src, p->dst);
+ return;
+ }
+
+ memmove(np->dst, p->src, IPaddrlen);
+ np->type = TimeExceedV6;
+ np->code = 0;
+ memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP));
+ set_cksum(nbp);
+ np->ttl = HOP_LIMIT;
+ np->vcf[0] = 0x06 << 4;
+ ipriv->out[TimeExceedV6]++;
+ ipoput6(f, nbp, 0, MAXTTL, DFLTTOS);
+}
+
+extern void
+icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp)
+{
+ Block *nbp;
+ IPICMP *np;
+ Ip6hdr *p;
+ int osz = BLEN(bp);
+ int sz = MIN(sizeof(IPICMP) + osz, v6MINTU);
+ Proto *icmp = f->t2p[ICMPv6];
+ Icmppriv6 *ipriv = icmp->priv;
+
+ p = (Ip6hdr *) bp->rp;
+
+ if(isv6mcast(p->src))
+ return;
+
+ nbp = newIPICMP(sz);
+ np = (IPICMP *) nbp->rp;
+
+ if(ipv6anylocal(ifc, np->src)) {
+ netlog(f, Logicmp, "send icmppkttoobig6 -> s%I d%I\n", p->src, p->dst);
+ }
+ else {
+ netlog(f, Logicmp, "icmppkttoobig6 fail -> s%I d%I\n", p->src, p->dst);
+ return;
+ }
+
+ memmove(np->dst, p->src, IPaddrlen);
+ np->type = PacketTooBigV6;
+ np->code = 0;
+ hnputl(np->icmpid, ifc->maxmtu - ifc->m->hsize);
+ memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP));
+ set_cksum(nbp);
+ np->ttl = HOP_LIMIT;
+ np->vcf[0] = 0x06 << 4;
+ ipriv->out[PacketTooBigV6]++;
+ ipoput6(f, nbp, 0, MAXTTL, DFLTTOS);
+}
+
+/*
+ * RFC 2461, pages 39-40, pages 57-58.
+ */
+static int
+valid(Proto *icmp, Ipifc *ifc, Block *bp, Icmppriv6 *ipriv) {
+ int sz, osz, unsp, n, ttl, iplen;
+ int pktsz = BLEN(bp);
+ uchar *packet = bp->rp;
+ IPICMP *p = (IPICMP *) packet;
+ Ndpkt *np;
+
+ USED(ifc);
+ n = blocklen(bp);
+ if(n < sizeof(IPICMP)) {
+ ipriv->stats[HlenErrs6]++;
+ netlog(icmp->f, Logicmp, "icmp hlen %d\n", n);
+ goto err;
+ }
+
+ iplen = nhgets(p->ploadlen);
+ if(iplen > n-IPV6HDR_LEN || (iplen % 1)) {
+ ipriv->stats[LenErrs6]++;
+ netlog(icmp->f, Logicmp, "icmp length %d\n", iplen);
+ goto err;
+ }
+
+ // Rather than construct explicit pseudoheader, overwrite IPv6 header
+ if(p->proto != ICMPv6) {
+ // This code assumes no extension headers!!!
+ netlog(icmp->f, Logicmp, "icmp error: extension header\n");
+ goto err;
+ }
+ memset(packet, 0, 4);
+ ttl = p->ttl;
+ p->ttl = p->proto;
+ p->proto = 0;
+ if(ptclcsum(bp, 0, iplen + IPV6HDR_LEN)) {
+ ipriv->stats[CsumErrs6]++;
+ netlog(icmp->f, Logicmp, "icmp checksum error\n");
+ goto err;
+ }
+ p->proto = p->ttl;
+ p->ttl = ttl;
+
+ /* additional tests for some pkt types */
+ if( (p->type == NbrSolicit) ||
+ (p->type == NbrAdvert) ||
+ (p->type == RouterAdvert) ||
+ (p->type == RouterSolicit) ||
+ (p->type == RedirectV6) ) {
+
+ if(p->ttl != HOP_LIMIT) {
+ ipriv->stats[HoplimErrs6]++;
+ goto err;
+ }
+ if(p->code != 0) {
+ ipriv->stats[IcmpCodeErrs6]++;
+ goto err;
+ }
+
+ switch (p->type) {
+ case NbrSolicit:
+ case NbrAdvert:
+ np = (Ndpkt*) p;
+ if(isv6mcast(np->target)) {
+ ipriv->stats[TargetErrs6]++;
+ goto err;
+ }
+ if(optexsts(np) && (np->olen == 0)) {
+ ipriv->stats[OptlenErrs6]++;
+ goto err;
+ }
+
+ if(p->type == NbrSolicit) {
+ if(ipcmp(np->src, v6Unspecified) == 0) {
+ if(!issmcast(np->dst) || optexsts(np)) {
+ ipriv->stats[AddrmxpErrs6]++;
+ goto err;
+ }
+ }
+ }
+
+ if(p->type == NbrAdvert) {
+ if((isv6mcast(np->dst))&&(nhgets(np->icmpid) & Sflag)){
+ ipriv->stats[AddrmxpErrs6]++;
+ goto err;
+ }
+ }
+ break;
+
+ case RouterAdvert:
+ if(pktsz - sizeof(Ip6hdr) < 16) {
+ ipriv->stats[HlenErrs6]++;
+ goto err;
+ }
+ if(!islinklocal(p->src)) {
+ ipriv->stats[RouterAddrErrs6]++;
+ goto err;
+ }
+ sz = sizeof(IPICMP) + 8;
+ while ((sz+1) < pktsz) {
+ osz = *(packet+sz+1);
+ if(osz <= 0) {
+ ipriv->stats[OptlenErrs6]++;
+ goto err;
+ }
+ sz += 8*osz;
+ }
+ break;
+
+ case RouterSolicit:
+ if(pktsz - sizeof(Ip6hdr) < 8) {
+ ipriv->stats[HlenErrs6]++;
+ goto err;
+ }
+ unsp = (ipcmp(p->src, v6Unspecified) == 0);
+ sz = sizeof(IPICMP) + 8;
+ while ((sz+1) < pktsz) {
+ osz = *(packet+sz+1);
+ if((osz <= 0) ||
+ (unsp && (*(packet+sz) == slladd)) ) {
+ ipriv->stats[OptlenErrs6]++;
+ goto err;
+ }
+ sz += 8*osz;
+ }
+ break;
+
+ case RedirectV6:
+ //to be filled in
+ break;
+
+ default:
+ goto err;
+ }
+ }
+
+ return 1;
+
+err:
+ ipriv->stats[InErrors6]++;
+ return 0;
+}
+
+static int
+targettype(Fs *f, Ipifc *ifc, uchar *target)
+{
+ Iplifc *lifc;
+ int t;
+
+ rlock(ifc);
+ if(ipproxyifc(f, ifc, target)) {
+ runlock(ifc);
+ return t_uniproxy;
+ }
+
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
+ if(ipcmp(lifc->local, target) == 0) {
+ t = (lifc->tentative) ? t_unitent : t_unirany;
+ runlock(ifc);
+ return t;
+ }
+ }
+
+ runlock(ifc);
+ return 0;
+}
+
+static void
+icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp)
+{
+ uchar *packet = bp->rp;
+ IPICMP *p = (IPICMP *)packet;
+ Icmppriv6 *ipriv = icmp->priv;
+ Block *r;
+ Proto *pr;
+ char *msg, m2[128];
+ Ndpkt* np;
+ uchar pktflags;
+ uchar lsrc[IPaddrlen];
+ int refresh = 1;
+ Iplifc *lifc;
+
+ if(!valid(icmp, ipifc, bp, ipriv))
+ goto raise;
+
+ if(p->type <= Maxtype6)
+ ipriv->in[p->type]++;
+
+ switch(p->type) {
+ case EchoRequestV6:
+ r = mkechoreply6(bp);
+ ipriv->out[EchoReply]++;
+ ipoput6(icmp->f, r, 0, MAXTTL, DFLTTOS);
+ break;
+
+ case UnreachableV6:
+ if(p->code > 4 || p->code < 0)
+ msg = unreachcode[icmp6_unkn_code];
+ else
+ msg = unreachcode[p->code];
+
+ bp->rp += sizeof(IPICMP);
+ if(blocklen(bp) < 8){
+ ipriv->stats[LenErrs6]++;
+ goto raise;
+ }
+ p = (IPICMP *)bp->rp;
+ pr = Fsrcvpcolx(icmp->f, p->proto);
+ if(pr != nil && pr->advise != nil) {
+ (*pr->advise)(pr, bp, msg);
+ return;
+ }
+
+ bp->rp -= sizeof(IPICMP);
+ goticmpkt6(icmp, bp, 0);
+ break;
+
+ case TimeExceedV6:
+ if(p->code == 0){
+ sprint(m2, "ttl exceeded at %I", p->src);
+
+ bp->rp += sizeof(IPICMP);
+ if(blocklen(bp) < 8){
+ ipriv->stats[LenErrs6]++;
+ goto raise;
+ }
+ p = (IPICMP *)bp->rp;
+ pr = Fsrcvpcolx(icmp->f, p->proto);
+ if(pr != nil && pr->advise != nil) {
+ (*pr->advise)(pr, bp, m2);
+ return;
+ }
+ bp->rp -= sizeof(IPICMP);
+ }
+
+ goticmpkt6(icmp, bp, 0);
+ break;
+
+ case RouterAdvert:
+ case RouterSolicit:
+ /* using lsrc as a temp, munge hdr for goticmp6
+ memmove(lsrc, p->src, IPaddrlen);
+ memmove(p->src, p->dst, IPaddrlen);
+ memmove(p->dst, lsrc, IPaddrlen); */
+
+ goticmpkt6(icmp, bp, p->type);
+ break;
+
+ case NbrSolicit:
+ np = (Ndpkt*) p;
+ pktflags = 0;
+ switch (targettype(icmp->f, ipifc, np->target)) {
+ case t_unirany:
+ pktflags |= Oflag;
+ /* fall through */
+
+ case t_uniproxy:
+ if(ipcmp(np->src, v6Unspecified) != 0) {
+ arpenter(icmp->f, V6, np->src, np->lnaddr, 8*np->olen-2, 0);
+ pktflags |= Sflag;
+ }
+ if(ipv6local(ipifc, lsrc)) {
+ icmpna(icmp->f, lsrc,
+ (ipcmp(np->src, v6Unspecified)==0)?v6allnodesL:np->src,
+ np->target, ipifc->mac, pktflags);
+ }
+ else
+ freeblist(bp);
+ break;
+
+ case t_unitent:
+ /* not clear what needs to be done. send up
+ * an icmp mesg saying don't use this address? */
+
+ default:
+ freeblist(bp);
+ }
+
+ ipriv->out[NbrSolicit]++;
+ break;
+
+ case NbrAdvert:
+ np = (Ndpkt*) p;
+
+ /* if the target address matches one of the local interface
+ * address and the local interface address has tentative bit set,
+ * then insert into ARP table. this is so the duplication address
+ * detection part of ipconfig can discover duplication through
+ * the arp table
+ */
+ lifc = iplocalonifc(ipifc, np->target);
+ if(lifc && lifc->tentative)
+ refresh = 0;
+ arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, refresh);
+ freeblist(bp);
+ break;
+
+ case PacketTooBigV6:
+
+ default:
+ goticmpkt6(icmp, bp, 0);
+ break;
+ }
+ return;
+
+raise:
+ freeblist(bp);
+
+}
+
+int
+icmpstats6(Proto *icmp6, char *buf, int len)
+{
+ Icmppriv6 *priv;
+ char *p, *e;
+ int i;
+
+ priv = icmp6->priv;
+ p = buf;
+ e = p+len;
+ for(i = 0; i < Nstats6; i++)
+ p = seprint(p, e, "%s: %lud\n", statnames6[i], priv->stats[i]);
+ for(i = 0; i <= Maxtype6; i++){
+ if(icmpnames6[i])
+ p = seprint(p, e, "%s: %lud %lud\n", icmpnames6[i], priv->in[i], priv->out[i]);
+/* else
+ p = seprint(p, e, "%d: %lud %lud\n", i, priv->in[i], priv->out[i]);
+*/
+ }
+ return p - buf;
+}
+
+
+// need to import from icmp.c
+extern int icmpstate(Conv *c, char *state, int n);
+extern char* icmpannounce(Conv *c, char **argv, int argc);
+extern void icmpcreate(Conv *c);
+extern void icmpclose(Conv *c);
+
+void
+icmp6init(Fs *fs)
+{
+ Proto *icmp6 = smalloc(sizeof(Proto));
+
+ icmp6->priv = smalloc(sizeof(Icmppriv6));
+ icmp6->name = "icmpv6";
+ icmp6->kick = icmpkick6;
+ icmp6->connect = icmpconnect6;
+ icmp6->announce = icmpannounce;
+ icmp6->state = icmpstate;
+ icmp6->create = icmpcreate;
+ icmp6->close = icmpclose;
+ icmp6->rcv = icmpiput6;
+ icmp6->stats = icmpstats6;
+ icmp6->ctl = icmpctl6;
+ icmp6->advise = icmpadvise6;
+ icmp6->gc = nil;
+ icmp6->ipproto = ICMPv6;
+ icmp6->nc = 16;
+ icmp6->ptclsize = sizeof(Icmpcb6);
+
+ Fsproto(fs, icmp6);
+}
+
M ip/igmp.c => ip/igmp.c +3 -2
@@ 86,6 86,7 @@ igmpsendreport(Media *m, byte *addr)
if(bp == nil)
return;
p = (IGMPpkt*)bp->wp;
+ p->vihl = IP_VER4;
bp->wp += sizeof(IGMPpkt);
memset(bp->rp, 0, sizeof(IGMPpkt));
hnputl(p->src, Mediagetaddr(m));
@@ 96,7 97,7 @@ igmpsendreport(Media *m, byte *addr)
hnputs(p->igmpcksum, ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE));
netlog(Logigmp, "igmpreport %I\n", p->group);
stats.outreports++;
- ipoput(bp, 0, 1, DFLTTOS); /* TTL of 1 */
+ ipoput4(bp, 0, 1, DFLTTOS); /* TTL of 1 */
}
static int
@@ 166,7 167,7 @@ igmpproc(void *a)
}
void
-igmpiput(Media *m, Ipifc*, Block *bp)
+igmpiput(Media *m, Ipifc *, Block *bp)
{
int n;
IGMPpkt *ghp;
M ip/il.c => ip/il.c +9 -4
@@ 367,6 367,7 @@ ilkick(Conv *c)
/* Make space to fit il & ip */
bp = padblock(bp, IL_IPSIZE+IL_HDRSIZE);
ih = (Ilhdr *)(bp->rp);
+ ih->vihl = IP_VER4;
/* Ip fields */
ih->frag[0] = 0;
@@ 408,7 409,7 @@ ilkick(Conv *c)
if(later(msec, ic->timeout, nil))
ilsettimeout(ic);
- ipoput(f, bp, 0, c->ttl, c->tos);
+ ipoput4(f, bp, 0, c->ttl, c->tos);
priv->stats[OutMsgs]++;
}
@@ 803,6 804,7 @@ ilrexmit(Ilcb *ic)
return;
h = (Ilhdr*)nb->rp;
+ h->vihl = IP_VER4;
h->iltype = Ildataquery;
hnputl(h->ilack, ic->recvd);
@@ 819,7 821,7 @@ ilrexmit(Ilcb *ic)
ilbackoff(ic);
- ipoput(c->p->f, nb, 0, ic->conv->ttl, ic->conv->tos);
+ ipoput4(c->p->f, nb, 0, ic->conv->ttl, ic->conv->tos);
/* statistics */
ic->rxtot++;
@@ 979,6 981,7 @@ ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec)
bp->wp += IL_IPSIZE+IL_HDRSIZE;
ih = (Ilhdr *)(bp->rp);
+ ih->vihl = IP_VER4;
/* Ip fields */
ih->proto = IP_ILPROTO;
@@ 1015,6 1018,7 @@ ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec)
if(ilcksum)
hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE));
+
if(ipc==nil)
panic("ipc is nil caller is %.8lux", getcallerpc(&ipc));
if(ipc->p==nil)
@@ 1024,7 1028,7 @@ if(ipc->p==nil)
iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack),
nhgets(ih->ilsrc), nhgets(ih->ildst));
- ipoput(ipc->p->f, bp, 0, ttl, tos);
+ ipoput4(ipc->p->f, bp, 0, ttl, tos);
}
void
@@ 1037,6 1041,7 @@ ilreject(Fs *f, Ilhdr *inih)
bp->wp += IL_IPSIZE+IL_HDRSIZE;
ih = (Ilhdr *)(bp->rp);
+ ih->vihl = IP_VER4;
/* Ip fields */
ih->proto = IP_ILPROTO;
@@ 1057,7 1062,7 @@ ilreject(Fs *f, Ilhdr *inih)
if(ilcksum)
hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE));
- ipoput(f, bp, 0, MAXTTL, DFLTTOS);
+ ipoput4(f, bp, 0, MAXTTL, DFLTTOS);
}
void
M ip/ip.c => ip/ip.c +200 -208
@@ 5,52 5,41 @@
#include "fns.h"
#include "../port/error.h"
-#include "../ip/ip.h"
+#include "ip.h"
-typedef struct Iphdr Iphdr;
-typedef struct Fragment Fragment;
-typedef struct Ipfrag Ipfrag;
+typedef struct Ip4hdr Ip4hdr;
+typedef struct IP IP;
+typedef struct Fragment4 Fragment4;
+typedef struct Fragment6 Fragment6;
+typedef struct Ipfrag Ipfrag;
enum
{
- IPHDR = 20, /* sizeof(Iphdr) */
- IP_VER = 0x40, /* Using IP version 4 */
- IP_HLEN = 0x05, /* Header length in words */
+ IP4HDR = 20, /* sizeof(Ip4hdr) */
+ IP6HDR = 40, /* sizeof(Ip6hdr) */
+ IP_HLEN4 = 0x05, /* Header length in words */
IP_DF = 0x4000, /* Don't fragment */
IP_MF = 0x2000, /* More fragments */
+ IP6FHDR = 8, /* sizeof(Fraghdr6) */
IP_MAX = (32*1024), /* Maximum Internet packet size */
};
-struct Iphdr
+#define BLKIPVER(xp) (((Ip4hdr*)((xp)->rp))->vihl&0xF0)
+
+struct Ip4hdr
{
uchar vihl; /* Version and header length */
uchar tos; /* Type of service */
uchar length[2]; /* packet length */
uchar id[2]; /* ip->identification */
uchar frag[2]; /* Fragment information */
- uchar ttl; /* Time to live */
+ uchar ttl; /* Time to live */
uchar proto; /* Protocol */
uchar cksum[2]; /* Header checksum */
uchar src[4]; /* IP source */
uchar dst[4]; /* IP destination */
};
-struct Fragment
-{
- Block* blist;
- Fragment* next;
- ulong src;
- ulong dst;
- ushort id;
- ulong age;
-};
-
-struct Ipfrag
-{
- ushort foff;
- ushort flen;
-};
-
/* MIB II counters */
enum
{
@@ 77,6 66,50 @@ enum
Nstats,
};
+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 */
+};
+
static char *statnames[] =
{
[Forwarding] "Forwarding",
@@ 100,20 133,7 @@ static char *statnames[] =
[FragCreates] "FragCreates",
};
-/* an instance of IP */
-struct IP
-{
- ulong stats[Nstats];
-
- QLock fraglock;
- Fragment* flisthead;
- Fragment* fragfree;
-
- Ref id;
- int iprouting; /* true if we route like a gateway */
-};
-
-#define BLKIP(xp) ((Iphdr*)((xp)->rp))
+#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
@@ 121,9 141,62 @@ struct IP
#define BKFG(xp) ((Ipfrag*)((xp)->base))
ushort ipcsum(uchar*);
-Block* ipreassemble(IP*, int, Block*, Iphdr*);
-void ipfragfree(IP*, Fragment*);
-Fragment* ipfragallo(IP*);
+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);
+
+ 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
ip_init(Fs *f)
@@ 133,6 206,8 @@ ip_init(Fs *f)
ip = smalloc(sizeof(IP));
initfrag(ip, 100);
f->ip = ip;
+
+ ip_init_6(f);
}
void
@@ 146,13 221,13 @@ iprouting(Fs *f, int on)
}
void
-ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
+ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos)
{
Ipifc *ifc;
uchar *gate;
ulong fragoff;
Block *xp, *nb;
- Iphdr *eh, *feh;
+ Ip4hdr *eh, *feh;
int lid, len, seglen, chunk, dlen, blklen, offset, medialen;
Route *r, *sr;
IP *ip;
@@ 160,7 235,7 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
ip = f->ip;
/* Fill out the ip header */
- eh = (Iphdr*)(bp->rp);
+ eh = (Ip4hdr*)(bp->rp);
ip->stats[OutRequests]++;
@@ 204,7 279,7 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
gate = r->v4.gate;
if(!gating)
- eh->vihl = IP_VER|IP_HLEN;
+ eh->vihl = IP_VER4|IP_HLEN4;
eh->ttl = ttl;
if(!gating)
eh->tos = tos;
@@ 222,7 297,7 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
medialen = ifc->maxmtu - ifc->m->hsize;
if(len <= medialen) {
if(!gating)
- hnputs(eh->id, incref(&ip->id));
+ hnputs(eh->id, incref(&ip->id4));
hnputs(eh->length, len);
if(!gating){
eh->frag[0] = 0;
@@ 231,8 306,6 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
eh->cksum[0] = 0;
eh->cksum[1] = 0;
hnputs(eh->cksum, ipcsum(&eh->vihl));
-
-/* print("ipoput %V->%V via %V\n", eh->src, eh->dst, gate); /**/
ifc->m->bwrite(ifc, bp, V4, gate);
runlock(ifc);
poperror();
@@ 246,7 319,7 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
goto raise;
}
- seglen = (medialen - IPHDR) & ~7;
+ seglen = (medialen - IP4HDR) & ~7;
if(seglen < 8){
ip->stats[FragFails]++;
ip->stats[OutDiscards]++;
@@ 254,14 327,14 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
goto raise;
}
- dlen = len - IPHDR;
+ dlen = len - IP4HDR;
xp = bp;
if(gating)
lid = nhgets(eh->id);
else
- lid = incref(&ip->id);
+ lid = incref(&ip->id4);
- offset = IPHDR;
+ offset = IP4HDR;
while(xp != nil && offset && offset >= BLEN(xp)) {
offset -= BLEN(xp);
xp = xp->next;
@@ 274,11 347,11 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
fragoff = 0;
dlen += fragoff;
for(; fragoff < dlen; fragoff += seglen) {
- nb = allocb(IPHDR+seglen);
- feh = (Iphdr*)(nb->rp);
+ nb = allocb(IP4HDR+seglen);
+ feh = (Ip4hdr*)(nb->rp);
- memmove(nb->wp, eh, IPHDR);
- nb->wp += IPHDR;
+ memmove(nb->wp, eh, IP4HDR);
+ nb->wp += IP4HDR;
if((fragoff + seglen) >= dlen) {
seglen = dlen - fragoff;
@@ 287,7 360,7 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
else
hnputs(feh->frag, (fragoff>>3)|IP_MF);
- hnputs(feh->length, seglen + IPHDR);
+ hnputs(feh->length, seglen + IP4HDR);
hnputs(feh->id, lid);
/* Copy up the data area */
@@ 326,43 399,26 @@ free:
}
void
-initfrag(IP *ip, int size)
-{
- Fragment *fq, *eq;
-
- ip->fragfree = (Fragment*)malloc(sizeof(Fragment) * size);
- if(ip->fragfree == nil)
- panic("initfrag");
-
- eq = &ip->fragfree[size];
- for(fq = ip->fragfree; fq < eq; fq++)
- fq->next = fq+1;
-
- ip->fragfree[size-1].next = nil;
-}
-
-#define DBG(x) if((logmask & Logipmsg) && (iponly == 0 || x == iponly))netlog
-
-void
-ipiput(Fs *f, Ipifc *ifc, Block *bp)
+ipiput4(Fs *f, Ipifc *ifc, Block *bp)
{
int hl;
- Iphdr *h;
+ int hop, tos, proto, olen;
+ Ip4hdr *h;
Proto *p;
ushort frag;
int notforme;
uchar *dp, v6dst[IPaddrlen];
IP *ip;
Route *r, *sr;
- int olen;
+
+ if(BLKIPVER(bp) != IP_VER4) {
+ ipiput6(f, ifc, bp);
+ return;
+ }
ip = f->ip;
ip->stats[InReceives]++;
-// h = (Iphdr *)(bp->rp);
-// DBG(nhgetl(h->src))(Logipmsg, "ipiput %V %V len %d proto %d\n",
-// h->src, h->dst, BLEN(bp), h->proto);
-
/*
* Ensure we have all the header info in the first
* block. Make life easier for other protocols by
@@ 370,15 426,16 @@ ipiput(Fs *f, Ipifc *ifc, Block *bp)
*/
if(BLEN(bp) < 64) {
hl = blocklen(bp);
- if(hl < IPHDR)
- hl = IPHDR;
+ if(hl < IP4HDR)
+ hl = IP4HDR;
if(hl > 64)
hl = 64;
bp = pullupblock(bp, hl);
if(bp == nil)
return;
}
- h = (Iphdr *)(bp->rp);
+
+ h = (Ip4hdr*)(bp->rp);
/* dump anything that whose header doesn't checksum */
if(ipcsum(&h->vihl)) {
@@ 387,28 444,27 @@ ipiput(Fs *f, Ipifc *ifc, Block *bp)
freeblist(bp);
return;
}
-
v4tov6(v6dst, h->dst);
notforme = ipforme(f, v6dst) == 0;
/* Check header length and version */
- if(h->vihl != (IP_VER|IP_HLEN)) {
+ if((h->vihl&0x0F) != IP_HLEN4) {
hl = (h->vihl&0xF)<<2;
- if((h->vihl&0xF0) != IP_VER || hl < (IP_HLEN<<2)) {
+ if(hl < (IP_HLEN4<<2)) {
ip->stats[InHdrErrors]++;
netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl);
freeblist(bp);
return;
}
- /* If this is not routed strip off the options */
+ /* If this is not routed strip off the options */
if(notforme == 0) {
olen = nhgets(h->length);
- dp = bp->rp + (hl - (IP_HLEN<<2));
- memmove(dp, h, IP_HLEN<<2);
+ dp = bp->rp + (hl - (IP_HLEN4<<2));
+ memmove(dp, h, IP_HLEN4<<2);
bp->rp = dp;
- h = (Iphdr *)(bp->rp);
- h->vihl = (IP_VER|IP_HLEN);
- hnputs(h->length, olen-hl+(IP_HLEN<<2));
+ h = (Ip4hdr*)(bp->rp);
+ h->vihl = (IP_VER4|IP_HLEN4);
+ hnputs(h->length, olen-hl+(IP_HLEN4<<2));
}
}
@@ 418,10 474,10 @@ ipiput(Fs *f, Ipifc *ifc, Block *bp)
freeb(bp);
return;
}
-
/* don't forward to source's network */
sr = v4lookup(f, h->src);
r = v4lookup(f, h->dst);
+
if(r == nil || sr == r){
ip->stats[OutDiscards]++;
freeblist(bp);
@@ 429,13 485,14 @@ ipiput(Fs *f, Ipifc *ifc, Block *bp)
}
/* don't forward if packet has timed out */
- if(h->ttl <= 1){
+ hop = h->ttl;
+ if(hop < 1) {
ip->stats[InHdrErrors]++;
- icmpttlexceeded(f, ifc, bp);
+ icmpttlexceeded(f, ifc->lifc->local, bp);
freeblist(bp);
return;
}
-
+
/* reassemble if the interface expects it */
if(r->ifc->reassemble){
frag = nhgets(h->frag);
@@ 443,32 500,33 @@ ipiput(Fs *f, Ipifc *ifc, Block *bp)
h->tos = 0;
if(frag & IP_MF)
h->tos = 1;
- bp = ipreassemble(ip, frag, bp, h);
+ bp = ip4reassemble(ip, frag, bp, h);
if(bp == nil)
return;
- h = (Iphdr *)(bp->rp);
+ h = (Ip4hdr*)(bp->rp);
}
}
ip->stats[ForwDatagrams]++;
- ipoput(f, bp, 1, h->ttl - 1, h->tos);
-
+ tos = h->tos;
+ hop = h->ttl;
+ ipoput4(f, bp, 1, hop - 1, tos);
return;
}
- /* reassemble */
frag = nhgets(h->frag);
if(frag) {
h->tos = 0;
if(frag & IP_MF)
h->tos = 1;
- bp = ipreassemble(ip, frag, bp, h);
+ bp = ip4reassemble(ip, frag, bp, h);
if(bp == nil)
return;
- h = (Iphdr *)(bp->rp);
+ h = (Ip4hdr*)(bp->rp);
}
- p = Fsrcvpcol(f, h->proto);
+ proto = h->proto;
+ p = Fsrcvpcol(f, proto);
if(p != nil && p->rcv != nil) {
ip->stats[InDelivers]++;
(*p->rcv)(p, ifc, bp);
@@ 497,11 555,11 @@ ipstats(Fs *f, char *buf, int len)
}
Block*
-ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih)
+ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
{
int fend;
ushort id;
- Fragment *f, *fnext;
+ Fragment4 *f, *fnext;
ulong src, dst;
Block *bl, **l, *last, *prev;
int ovlap, len, fragsize, pktposn;
@@ 515,21 573,21 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih)
*/
if(bp->next){
bp = pullupblock(bp, blocklen(bp));
- ih = (Iphdr *)(bp->rp);
+ ih = (Ip4hdr*)(bp->rp);
}
- qlock(&ip->fraglock);
+ qlock(&ip->fraglock4);
/*
* find a reassembly queue for this fragment
*/
- for(f = ip->flisthead; f; f = fnext){
- fnext = f->next; /* because ipfragfree changes the list */
+ for(f = ip->flisthead4; f; f = fnext){
+ fnext = f->next; /* because ipfragfree4 changes the list */
if(f->src == src && f->dst == dst && f->id == id)
break;
if(f->age < msec){
ip->stats[ReasmTimeout]++;
- ipfragfree(ip, f);
+ ipfragfree4(ip, f);
}
}
@@ 540,10 598,10 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih)
*/
if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) {
if(f != nil) {
- ipfragfree(ip, f);
+ ipfragfree4(ip, f);
ip->stats[ReasmFails]++;
}
- qunlock(&ip->fraglock);
+ qunlock(&ip->fraglock4);
return bp;
}
@@ 553,18 611,18 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih)
}
BKFG(bp)->foff = offset<<3;
- BKFG(bp)->flen = nhgets(ih->length)-IPHDR;
+ BKFG(bp)->flen = nhgets(ih->length)-IP4HDR;
/* First fragment allocates a reassembly queue */
if(f == nil) {
- f = ipfragallo(ip);
+ f = ipfragallo4(ip);
f->id = id;
f->src = src;
f->dst = dst;
f->blist = bp;
- qunlock(&ip->fraglock);
+ qunlock(&ip->fraglock4);
ip->stats[ReasmReqds]++;
return nil;
}
@@ 587,7 645,7 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih)
if(ovlap > 0) {
if(ovlap >= BKFG(bp)->flen) {
freeblist(bp);
- qunlock(&ip->fraglock);
+ qunlock(&ip->fraglock4);
return nil;
}
BKFG(prev)->flen -= ovlap;
@@ 611,7 669,7 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih)
BKFG(*l)->flen -= ovlap;
BKFG(*l)->foff += ovlap;
/* move up ih hdrs */
- memmove((*l)->rp + ovlap, (*l)->rp, IPHDR);
+ memmove((*l)->rp + ovlap, (*l)->rp, IP4HDR);
(*l)->rp += ovlap;
break;
}
@@ 641,32 699,32 @@ ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih)
for(bl = bl->next; bl; bl = bl->next) {
fragsize = BKFG(bl)->flen;
len += fragsize;
- bl->rp += IPHDR;
+ bl->rp += IP4HDR;
bl->wp = bl->rp + fragsize;
}
bl = f->blist;
f->blist = nil;
- ipfragfree(ip, f);
+ ipfragfree4(ip, f);
ih = BLKIP(bl);
hnputs(ih->length, len);
- qunlock(&ip->fraglock);
+ qunlock(&ip->fraglock4);
ip->stats[ReasmOKs]++;
return bl;
}
pktposn += BKFG(bl)->flen;
}
- qunlock(&ip->fraglock);
+ qunlock(&ip->fraglock4);
return nil;
}
/*
- * ipfragfree - Free a list of fragments - assume hold fraglock
+ * ipfragfree4 - Free a list of fragments - assume hold fraglock4
*/
void
-ipfragfree(IP *ip, Fragment *frag)
+ipfragfree4(IP *ip, Fragment4 *frag)
{
- Fragment *fl, **l;
+ Fragment4 *fl, **l;
if(frag->blist)
freeblist(frag->blist);
@@ 675,7 733,7 @@ ipfragfree(IP *ip, Fragment *frag)
frag->id = 0;
frag->blist = nil;
- l = &ip->flisthead;
+ l = &ip->flisthead4;
for(fl = *l; fl; fl = fl->next) {
if(fl == frag) {
*l = frag->next;
@@ 684,29 742,29 @@ ipfragfree(IP *ip, Fragment *frag)
l = &fl->next;
}
- frag->next = ip->fragfree;
- ip->fragfree = frag;
+ frag->next = ip->fragfree4;
+ ip->fragfree4 = frag;
}
/*
- * ipfragallo - allocate a reassembly queue - assume hold fraglock
+ * ipfragallo4 - allocate a reassembly queue - assume hold fraglock4
*/
-Fragment *
-ipfragallo(IP *ip)
+Fragment4 *
+ipfragallo4(IP *ip)
{
- Fragment *f;
+ Fragment4 *f;
- while(ip->fragfree == nil) {
+ while(ip->fragfree4 == nil) {
/* free last entry on fraglist */
- for(f = ip->flisthead; f->next; f = f->next)
+ for(f = ip->flisthead4; f->next; f = f->next)
;
- ipfragfree(ip, f);
+ ipfragfree4(ip, f);
}
- f = ip->fragfree;
- ip->fragfree = f->next;
- f->next = ip->flisthead;
- ip->flisthead = f;
+ f = ip->fragfree4;
+ ip->fragfree4 = f->next;
+ f->next = ip->flisthead4;
+ ip->flisthead4 = f;
f->age = msec + 30000;
return f;
@@ 733,70 791,4 @@ ipcsum(uchar *addr)
return (sum^0xffff);
}
-enum
-{
- Nmtucache= 128,
-};
-
-typedef struct MTUcache MTUcache;
-
-struct MTUcache
-{
- uchar ip[IPaddrlen];
- ulong mtu;
- ulong ms;
-};
-
-static struct {
- Lock;
- MTUcache c[Nmtucache];
-} mc;
-
-void
-update_mtucache(uchar *ip, ulong mtu)
-{
- MTUcache *oldest, *p;
-
- if(mtu < 512)
- return;
-
- lock(&mc);
- oldest = mc.c;
- for(p = mc.c; p < &mc.c[Nmtucache]; p++){
- if(ipcmp(ip, p->ip) == 0){
- p->mtu = mtu;
- p->ms = msec;
- break;
- }
- if(p->ms < oldest->ms)
- oldest = p;
- }
- if(p == &mc.c[Nmtucache]){
- ipmove(oldest->ip, ip);
- oldest->mtu = mtu;
- oldest->ms = msec;
- }
- unlock(&mc);
-}
-
-ulong
-restrict_mtu(uchar *ip, ulong mtu)
-{
- MTUcache *p;
- lock(&mc);
- for(p = mc.c; p < &mc.c[Nmtucache]; p++){
- if(p->ms + 1000*10*60 < msec){
- memset(p->ip, 0, sizeof(p->ip));
- p->ms = 0;
- }
- if(ipcmp(ip, p->ip) == 0){
- if(p->mtu < mtu)
- mtu = p->mtu;
- break;
- }
- }
- unlock(&mc);
-
- return mtu;
-}
M ip/ip.h => ip/ip.h +84 -14
@@ 24,6 24,11 @@ typedef struct Arpent Arpent;
typedef struct Arp Arp;
typedef struct Route Route;
+typedef struct Routerparams Routerparams;
+typedef struct Hostparams Hostparams;
+typedef struct v6router v6router;
+typedef struct v6params v6params;
+
enum
{
Addrlen= 64,
@@ 44,9 49,11 @@ enum
/* ip versions */
V4= 4,
V6= 6,
+ IP_VER4= 0x40,
+ IP_VER6= 0x60,
/* 2^Lroot trees in the root table */
- Lroot = 10,
+ Lroot= 10,
Maxpath = 64,
};
@@ 78,7 85,7 @@ struct Conv
uint ttl; /* max time to live */
uint tos; /* type of service */
- char *owner ; /* protections */
+ char *owner; /* protections */
int perm;
int inuse; /* opens of listen/data/ctl */
int length;
@@ 138,6 145,9 @@ struct Medium
void (*ares)(Fs*, int, uchar*, uchar*, int, int); /* resolve */
void (*areg)(Ipifc*, uchar*); /* register */
+ /* v6 address generation */
+ void (*pref2addr)(uchar *pref, uchar *ea);
+
int unbindonclose; /* if non-zero, unbind on last close */
};
@@ 148,6 158,12 @@ struct Iplifc
uchar mask[IPaddrlen];
uchar remote[IPaddrlen];
uchar net[IPaddrlen];
+ uchar tentative; /* =1 => v6 dup disc on, =0 => confirmed unique */
+ uchar onlink; /* =1 => onlink, =0 offlink. */
+ uchar autoflag; /* v6 autonomous flag */
+ long validlt; /* v6 valid lifetime */
+ long preflt; /* v6 preferred lifetime */
+ long origint; /* time when addr was added */
Iplink *link; /* addresses linked to this lifc */
Iplifc *next;
};
@@ 164,6 180,25 @@ struct Iplink
int ref;
};
+/* rfc 2461, pp.40--43. */
+
+/* default values, one per stack */
+struct Routerparams {
+ int mflag;
+ int oflag;
+ int maxraint;
+ int minraint;
+ int linkmtu;
+ int reachtime;
+ int rxmitra;
+ int ttl;
+ int routerlt;
+};
+
+struct Hostparams {
+ int rxmithost;
+};
+
struct Ipifc
{
RWlock;
@@ 189,6 224,11 @@ struct Ipifc
ulong in, out; /* message statistics */
ulong inerr, outerr; /* ... */
+
+ uchar sendra6; /* == 1 => send router advs on this ifc */
+ uchar recvra6; /* == 1 => recv router advs on this ifc */
+ Routerparams rp; /* router parameters as in RFC 2461, pp.40--43.
+ used only if node is router */
};
/*
@@ 267,6 307,7 @@ struct Proto
void *priv;
};
+
/*
* one per IP protocol stack
*/
@@ 284,6 325,7 @@ struct Fs
IP *ip;
Ipselftab *self;
Arp *arp;
+ v6params *v6p;
Route *v4root[1<<Lroot]; /* v4 routing forest */
Route *v6root[1<<Lroot]; /* v6 routing forest */
@@ 293,10 335,28 @@ struct Fs
Ifclog *ilog;
char ndb[1024]; /* an ndb entry for this interface */
- int ndbvers;
- long ndbmtime;
};
+/* one per default router known to host */
+struct v6router {
+ uchar inuse;
+ Ipifc *ifc;
+ int ifcid;
+ uchar routeraddr[IPaddrlen];
+ long ltorigin;
+ Routerparams rp;
+};
+
+struct v6params
+{
+ Routerparams rp; /* v6 params, one copy per node now */
+ Hostparams hp;
+ v6router v6rlist[3]; /* max 3 default routers, currently */
+ int cdrouter; /* uses only v6rlist[cdrouter] if */
+ /* cdrouter >= 0. */
+};
+
+
int Fsconnected(Conv*, char*);
Conv* Fsnewcall(Conv*, uchar*, ushort, uchar*, ushort);
int Fspcolstats(char*, int);
@@ 310,7 370,6 @@ char* Fsstdannounce(Conv*, char**, int);
char* Fsstdbind(Conv*, char**, int);
ulong scalednconv(void);
void closeconv(Conv*);
-
/*
* logging
*/
@@ 449,19 508,24 @@ struct Arpent
{
uchar ip[IPaddrlen];
uchar mac[MAClen];
- Medium *type; /* media type */
+ Medium *type; /* media type */
Arpent* hash;
Block* hold;
Block* last;
uint time;
uint used;
uchar state;
+ Arpent *nextrxt; /* re-transmit chain */
+ uint rxtat;
+ uchar rxtsrem;
+ Ipifc *ifc;
+ uchar ifcid; /* must match ifc->id */
};
extern void arpinit(Fs*);
extern int arpread(Arp*, char*, ulong, int);
extern int arpwrite(Fs*, char*, int);
-extern Arpent* arpget(Arp*, Block *bp, int version, Medium *type, uchar *ip, uchar *h);
+extern Arpent* arpget(Arp*, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *h);
extern void arprelease(Arp*, Arpent *a);
extern Block* arpresolve(Arp*, Arpent *a, Medium *type, uchar *mac);
extern void arpenter(Fs*, int version, uchar *ip, uchar *mac, int len, int norefresh);
@@ 509,6 573,7 @@ extern Medium tripmedium;
extern Medium* ipfindmedium(char *name);
extern void addipmedium(Medium *med);
extern int ipforme(Fs*, uchar *addr);
+extern int iptentative(Fs*, uchar *addr);
extern int ipisbm(uchar *);
extern int ipismulticast(uchar *);
extern Ipifc* findipifc(Fs*, uchar *remote, int type);
@@ 516,6 581,7 @@ extern void findprimaryip(Fs*, uchar*);
extern void findlocalip(Fs*, uchar *local, uchar *remote);
extern int ipv4local(Ipifc *ifc, uchar *addr);
extern int ipv6local(Ipifc *ifc, uchar *addr);
+extern int ipv6anylocal(Ipifc *ifc, uchar *addr);
extern Iplifc* iplocalonifc(Ipifc *ifc, uchar *ip);
extern int ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip);
extern int ipismulticast(uchar *ip);
@@ 528,27 594,30 @@ extern void ipifcremroute(Fs*, int, uchar*, uchar*);
extern void ipifcremmulti(Conv *c, uchar *ma, uchar *ia);
extern void ipifcaddmulti(Conv *c, uchar *ma, uchar *ia);
extern char* ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock);
-extern char* ipifcadd(Ipifc *ifc, char **argv, int argc);
+extern char* ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp);
extern long ipselftabread(Fs*, char *a, ulong offset, int n);
-
+extern char* ipifcaddgate6(Fs *f, Ipifc *ifc, char**argv, int argc);
+extern char* ipifcaddpref6(Ipifc *ifc, char**argv, int argc);
+extern void ipsendra6(Fs *f, int on);
+extern long ipgateread6(Fs *f, char *cp, ulong offset, int n);
/*
* ip.c
*/
extern void iprouting(Fs*, int);
extern void closeifcconv(Ifcconv*);
extern void icmpnoconv(Fs*, Block*);
-extern void icmpttlexceeded(Fs*, Ipifc*, Block*);
-extern void initfrag(IP*, int);
+extern void icmpttlexceeded(Fs*, uchar*, Block*);
extern ushort ipcsum(uchar*);
-extern void ipiput(Fs*, Ipifc*, Block*);
-extern void ipoput(Fs*, Block*, int, int, int);
+extern void ipiput4(Fs*, Ipifc*, Block*);
+extern void ipiput6(Fs*, Ipifc*, Block*);
+extern void ipoput4(Fs*, Block*, int, int, int);
+extern void ipoput6(Fs*, Block*, int, int, int);
extern int ipstats(Fs*, char*, int);
extern ushort ptclbsum(uchar*, int);
extern ushort ptclcsum(Block*, int, int);
extern void ip_init(Fs*);
extern void update_mtucache(uchar*, ulong);
extern ulong restrict_mtu(uchar*, ulong);
-
/*
* bootp.c
*/
@@ 573,3 642,4 @@ extern Chan* chandial(char*, char*, char*, Chan**);
extern int debug;
extern Fs fs;
extern void (*igmpreportfn)(Ipifc*, uchar*);
+
M ip/ipaux.c => ip/ipaux.c +181 -13
@@ 5,6 5,7 @@
#include "fns.h"
#include "../port/error.h"
#include "ip.h"
+#include "ipv6.h"
/*
* well known IP addresses
@@ 33,6 34,7 @@ uchar IPallbits[IPaddrlen] = {
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff
};
+
uchar IPnoaddr[IPaddrlen];
/*
@@ 46,6 48,151 @@ uchar v4prefix[IPaddrlen] = {
};
+char *v6hdrtypes[Maxhdrtype] =
+{
+ [HBH] "HopbyHop",
+ [ICMP] "ICMP",
+ [IGMP] "IGMP",
+ [GGP] "GGP",
+ [IPINIP] "IP",
+ [ST] "ST",
+ [TCP] "TCP",
+ [UDP] "UDP",
+ [ISO_TP4] "ISO_TP4",
+ [RH] "Routinghdr",
+ [FH] "Fraghdr",
+ [IDRP] "IDRP",
+ [RSVP] "RSVP",
+ [AH] "Authhdr",
+ [ESP] "ESP",
+ [ICMPv6] "ICMPv6",
+ [NNH] "Nonexthdr",
+ [ISO_IP] "ISO_IP",
+ [IGRP] "IGRP",
+ [OSPF] "OSPF",
+};
+
+/*
+ * well known IPv6 addresses
+ */
+uchar v6Unspecified[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+uchar v6loopback[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x01
+};
+uchar v6linklocal[IPaddrlen] = {
+ 0xfe, 0x80, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+uchar v6linklocalmask[IPaddrlen] = {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+int v6linklocalprefix = 8;
+uchar v6sitelocal[IPaddrlen] = {
+ 0xfe, 0xc0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+uchar v6sitelocalmask[IPaddrlen] = {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+int v6sitelocalprefix = 6;
+uchar v6glunicast[IPaddrlen] = {
+ 0x08, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+uchar v6multicast[IPaddrlen] = {
+ 0xff, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+uchar v6multicastmask[IPaddrlen] = {
+ 0xff, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+int v6multicastprefix = 1;
+uchar v6allnodesN[IPaddrlen] = {
+ 0xff, 0x01, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x01
+};
+uchar v6allnodesNmask[IPaddrlen] = {
+ 0xff, 0xff, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+int v6allnodesprefix = 2;
+uchar v6allnodesL[IPaddrlen] = {
+ 0xff, 0x02, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x01
+};
+uchar v6allnodesLmask[IPaddrlen] = {
+ 0xff, 0xff, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+int v6allnodesLprefix = 2;
+uchar v6allroutersN[IPaddrlen] = {
+ 0xff, 0x01, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x02
+};
+uchar v6allroutersL[IPaddrlen] = {
+ 0xff, 0x02, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x02
+};
+uchar v6allroutersS[IPaddrlen] = {
+ 0xff, 0x05, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x02
+};
+uchar v6solicitednode[IPaddrlen] = {
+ 0xff, 0x02, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0x01,
+ 0xff, 0, 0, 0
+};
+uchar v6solicitednodemask[IPaddrlen] = {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0, 0x0, 0x0
+};
+int v6solicitednodeprefix = 13;
+
+
+
+
ushort
ptclcsum(Block *bp, int offset, int len)
{
@@ 135,16 282,13 @@ eipfmt(Fmt *f)
switch(f->r) {
case 'E': /* Ethernet address */
p = va_arg(f->args, uchar*);
- snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
- return fmtstrcpy(f, buf);
+ return fmtprint(f, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
case 'I': /* Ip address */
p = va_arg(f->args, uchar*);
common:
- if(memcmp(p, v4prefix, 12) == 0){
- snprint(buf, sizeof buf, ifmt, p[12], p[13], p[14], p[15]);
- return fmtstrcpy(f, buf);
- }
+ if(memcmp(p, v4prefix, 12) == 0)
+ return fmtprint(f, ifmt, p[12], p[13], p[14], p[15]);
/* find longest elision */
eln = eli = -1;
@@ 182,8 326,7 @@ common:
case 'V': /* v4 ip address */
p = va_arg(f->args, uchar*);
- snprint(buf, sizeof buf, ifmt, p[0], p[1], p[2], p[3]);
- return fmtstrcpy(f, buf);
+ return fmtprint(f, ifmt, p[0], p[1], p[2], p[3]);
case 'M': /* ip mask */
p = va_arg(f->args, uchar*);
@@ 203,10 346,10 @@ common:
n = 8*16;
/* got one, use /xx format */
- snprint(buf, sizeof buf, "/%d", n);
- return fmtstrcpy(f, buf);
+ return fmtprint(f, "/%d", n);
+
}
- return fmtstrcpy(f, "(eipfmt)");
+ return fmtprint(f, "(eipfmt)");
}
#define CLASS(p) ((*(uchar*)(p))>>6)
@@ 230,7 373,7 @@ v4parseip(uchar *to, char *from)
to[3] = to[2];
to[2] = to[1];
to[1] = 0;
- } else if (i == 2){
+ } else if(i == 2){
to[3] = to[1];
to[1] = 0;
}
@@ 395,9 538,34 @@ uchar classmask[4][16] = {
uchar*
defmask(uchar *ip)
{
- return classmask[ip[IPv4off]>>6];
+ if(isv4(ip))
+ return classmask[ip[IPv4off]>>6];
+ else {
+ if(ipcmp(ip, v6loopback) == 0)
+ return IPallbits;
+ else if(memcmp(ip, v6linklocal, v6linklocalprefix) == 0)
+ return v6linklocalmask;
+ else if(memcmp(ip, v6sitelocal, v6sitelocalprefix) == 0)
+ return v6sitelocalmask;
+ else if(memcmp(ip, v6solicitednode, v6solicitednodeprefix) == 0)
+ return v6solicitednodemask;
+ else if(memcmp(ip, v6multicast, v6multicastprefix) == 0)
+ return v6multicastmask;
+ return IPallbits;
+ }
}
+void
+ipv62smcast(uchar *smcast, uchar *a)
+{
+ assert(IPaddrlen == 16);
+ memmove(smcast, v6solicitednode, IPaddrlen);
+ smcast[13] = a[13];
+ smcast[14] = a[14];
+ smcast[15] = a[15];
+}
+
+
/*
* parse a hex mac address
*/
M ip/ipifc.c => ip/ipifc.c +634 -63
@@ 6,6 6,7 @@
#include "../port/error.h"
#include "ip.h"
+#include "ipv6.h"
#define DPRINT if(0)print
@@ 138,6 139,17 @@ ipifcbind(Conv *c, char **argv, int argc)
ifc->maxmtu = ifc->m->maxmtu;
if(ifc->m->unbindonclose == 0)
ifc->conv->inuse++;
+
+ ifc->rp.mflag = 0; // default not managed
+ ifc->rp.oflag = 0;
+ ifc->rp.maxraint = 600000; // millisecs
+ ifc->rp.minraint = 200000;
+ ifc->rp.linkmtu = 0; // no mtu sent
+ ifc->rp.reachtime = 0;
+ ifc->rp.rxmitra = 0;
+ ifc->rp.ttl = MAXTTL;
+ ifc->rp.routerlt = 3*(ifc->rp.maxraint);
+
ifc->ifcid++;
wunlock(ifc);
@@ 199,6 211,13 @@ ipifcunbind(Ipifc *ifc)
return nil;
}
+
+
+char *sfixedformat = "device %-12s maxmtu %-5d sendra %-1d recvra %-1d mflag %-1d oflag %-1d maxraint %-10d minraint %-10d linkmtu %-10d reachtime %-10d rxmitra %-10d ttl %-10d routerlt %-10d pktin %-7lud pktout %-7lud errin %-7lud errout %-7lud\n";
+
+char *slineformat = " %-40.40I %-10.10M %-40.40I %-12lud %-12lud\n";
+
+
static int
ipifcstate(Conv *c, char *state, int n)
{
@@ 208,14 227,18 @@ ipifcstate(Conv *c, char *state, int n)
ifc = (Ipifc*)c->ptcl;
- m = snprint(state, n, "%-12s %-5d", ifc->dev, ifc->maxmtu);
+ m = snprint(state, n, sfixedformat,
+ ifc->dev, ifc->maxmtu, ifc->sendra6, ifc->recvra6,
+ ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
+ ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
+ ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
+ ifc->in, ifc->out, ifc->inerr, ifc->outerr);
rlock(ifc);
for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
- m += snprint(state+m, n - m,
- " %-20.20I %-20.20M %-20.20I %-7lud %-7lud %-7lud %-7lud\n",
- lifc->local, lifc->mask, lifc->remote,
- ifc->in, ifc->out, ifc->inerr, ifc->outerr);
+ m += snprint(state+m, n - m, slineformat,
+ lifc->local, lifc->mask, lifc->remote,
+ lifc->validlt, lifc->preflt);
if(ifc->lifc == nil)
m += snprint(state+m, n - m, "\n");
runlock(ifc);
@@ 236,9 259,9 @@ ipifclocal(Conv *c, char *state, int n)
rlock(ifc);
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
- m += snprint(state+m, n - m, "%-20.20I ->", lifc->local);
+ m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
for(link = lifc->link; link; link = link->lifclink)
- m += snprint(state+m, n - m, " %-20.20I", link->self->a);
+ m += snprint(state+m, n - m, " %-40.40I", link->self->a);
m += snprint(state+m, n - m, "\n");
}
runlock(ifc);
@@ 331,13 354,14 @@ ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
* add an address to an interface.
*/
char*
-ipifcadd(Ipifc *ifc, char **argv, int argc)
+ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
{
uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
uchar bcast[IPaddrlen], net[IPaddrlen];
Iplifc *lifc, **l;
int i, type, mtu;
Fs *f;
+ int sendnbrdisc = 0;
if(ifc->m == nil)
return "ipifc not yet bound to device";
@@ 380,13 404,25 @@ ipifcadd(Ipifc *ifc, char **argv, int argc)
return Ebadarg;
break;
}
-
+ if(isv4(ip))
+ tentative = 0;
wlock(ifc);
/* ignore if this is already a local address for this ifc */
- for(lifc = ifc->lifc; lifc; lifc = lifc->next)
- if(ipcmp(lifc->local, ip) == 0)
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
+ if(ipcmp(lifc->local, ip) == 0) {
+ if(lifc->tentative != tentative)
+ lifc->tentative = tentative;
+ if(lifcp != nil) {
+ lifc->onlink = lifcp->onlink;
+ lifc->autoflag = lifcp->autoflag;
+ lifc->validlt = lifcp->validlt;
+ lifc->preflt = lifcp->preflt;
+ lifc->origint = lifcp->origint;
+ }
goto out;
+ }
+ }
/* add the address to the list of logical ifc's for this ifc */
lifc = smalloc(sizeof(Iplifc));
@@ 394,18 430,37 @@ ipifcadd(Ipifc *ifc, char **argv, int argc)
ipmove(lifc->mask, mask);
ipmove(lifc->remote, rem);
ipmove(lifc->net, net);
+ lifc->tentative = tentative;
+ if(lifcp != nil) {
+ lifc->onlink = lifcp->onlink;
+ lifc->autoflag = lifcp->autoflag;
+ lifc->validlt = lifcp->validlt;
+ lifc->preflt = lifcp->preflt;
+ lifc->origint = lifcp->origint;
+ }
+ else { // default values
+ lifc->onlink = 1;
+ lifc->autoflag = 1;
+ lifc->validlt = 0xffffffff;
+ lifc->preflt = 0xffffffff;
+ lifc->origint = msec / 10^3;
+ }
lifc->next = nil;
+
for(l = &ifc->lifc; *l; l = &(*l)->next)
;
*l = lifc;
- /* add a route for the local network */
+ /* check for point-to-point interface */
+ if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
if(ipcmp(mask, IPallbits) == 0){
/* point to point networks are a hack */
if(ipcmp(ip, rem) == 0)
findprimaryip(f, lifc->local);
type |= Rptpt;
}
+
+ /* add local routes */
if(isv4(ip))
v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
else
@@ 418,36 473,63 @@ ipifcadd(Ipifc *ifc, char **argv, int argc)
goto out;
}
- /* add subnet directed broadcast addresses to the self cache */
- for(i = 0; i < IPaddrlen; i++)
- bcast[i] = (ip[i] & mask[i]) | ~mask[i];
- addselfcache(f, ifc, lifc, bcast, Rbcast);
+ if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
+ /* add subnet directed broadcast address to the self cache */
+ for(i = 0; i < IPaddrlen; i++)
+ bcast[i] = (ip[i] & mask[i]) | ~mask[i];
+ addselfcache(f, ifc, lifc, bcast, Rbcast);
+
+ /* add subnet directed network address to the self cache */
+ for(i = 0; i < IPaddrlen; i++)
+ bcast[i] = (ip[i] & mask[i]) & mask[i];
+ addselfcache(f, ifc, lifc, bcast, Rbcast);
- /* add old subnet directed broadcast addresses to the self cache */
- for(i = 0; i < IPaddrlen; i++)
- bcast[i] = (ip[i] & mask[i]) & mask[i];
- addselfcache(f, ifc, lifc, bcast, Rbcast);
+ /* add network directed broadcast address to the self cache */
+ memmove(mask, defmask(ip), IPaddrlen);
+ for(i = 0; i < IPaddrlen; i++)
+ bcast[i] = (ip[i] & mask[i]) | ~mask[i];
+ addselfcache(f, ifc, lifc, bcast, Rbcast);
- /* add network directed broadcast addresses to the self cache */
- memmove(mask, defmask(ip), IPaddrlen);
- for(i = 0; i < IPaddrlen; i++)
- bcast[i] = (ip[i] & mask[i]) | ~mask[i];
- addselfcache(f, ifc, lifc, bcast, Rbcast);
+ /* add network directed network address to the self cache */
+ memmove(mask, defmask(ip), IPaddrlen);
+ for(i = 0; i < IPaddrlen; i++)
+ bcast[i] = (ip[i] & mask[i]) & mask[i];
+ addselfcache(f, ifc, lifc, bcast, Rbcast);
+
+ addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
+ }
+ else {
+ if(ipcmp(ip, v6loopback) == 0) {
+ /* add node-local mcast address */
+ addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
+
+ /* add route for all node multicast */
+ v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, v6allnodesN, Rmulti);
+ }
- /* add old network directed broadcast addresses to the self cache */
- memmove(mask, defmask(ip), IPaddrlen);
- for(i = 0; i < IPaddrlen; i++)
- bcast[i] = (ip[i] & mask[i]) & mask[i];
- addselfcache(f, ifc, lifc, bcast, Rbcast);
+ else if(memcmp(ip, v6linklocal, v6linklocalprefix) == 0) {
+ /* add link-local mcast address */
+ addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
+
+ /* add route for all link multicast */
+ v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, Rmulti);
+
+ /* add solicited-node multicast address */
+ ipv62smcast(bcast, ip);
+ addselfcache(f, ifc, lifc, bcast, Rmulti);
+ }
- addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
+ sendnbrdisc = 1;
+ }
/* register the address on this network for address resolution */
- if(ifc->m->areg != nil)
+ if(isv4(ip) && ifc->m->areg != nil)
(*ifc->m->areg)(ifc, ip);
out:
wunlock(ifc);
+ if(tentative && sendnbrdisc)
+ icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
return nil;
}
@@ 505,8 587,6 @@ ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock)
return "address not on this interface";
}
- ifc->ifcid++;
-
/* disassociate any addresses */
while(lifc->link)
remselfcache(f, ifc, lifc, lifc->link->self->a);
@@ 514,8 594,15 @@ ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock)
/* remove the route for this logical interface */
if(isv4(ip))
v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
- else
+ else {
v6delroute(f, lifc->remote, lifc->mask, 1);
+ if(ipcmp(ip, v6loopback) == 0)
+ /* remove route for all node multicast */
+ v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
+ else if(memcmp(ip, v6linklocal, v6linklocalprefix) == 0)
+ /* remove route for all link multicast */
+ v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
+ }
free(lifc);
@@ 525,7 612,7 @@ ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock)
}
/*
- * distrbute routes to active interfaces like the
+ * distribute routes to active interfaces like the
* TRIP linecards
*/
void
@@ 606,7 693,7 @@ ipifcconnect(Conv* c, char **argv, int argc)
wunlock(ifc);
poperror();
- err = ipifcadd(ifc, argv, argc);
+ err = ipifcadd(ifc, argv, argc, 0, nil);
if(err)
return err;
@@ 615,6 702,81 @@ ipifcconnect(Conv* c, char **argv, int argc)
return nil;
}
+char*
+ipifcsetpar6(Ipifc *ifc, char **argv, int argc)
+{
+ int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
+
+ argsleft = argc - 1;
+ i = 1;
+
+ if(argsleft % 2 != 0)
+ return Ebadarg;
+
+ while (argsleft > 1) {
+ if(strcmp(argv[i],"recvra")==0)
+ ifc->recvra6 = (atoi(argv[i+1]) != 0);
+ else if(strcmp(argv[i],"sendra")==0)
+ ifc->sendra6 = (atoi(argv[i+1]) != 0);
+ else if(strcmp(argv[i],"mflag")==0)
+ ifc->rp.mflag = (atoi(argv[i+1]) != 0);
+ else if(strcmp(argv[i],"oflag")==0)
+ ifc->rp.oflag = (atoi(argv[i+1]) != 0);
+ else if(strcmp(argv[i],"maxraint")==0)
+ ifc->rp.maxraint = atoi(argv[i+1]);
+ else if(strcmp(argv[i],"minraint")==0)
+ ifc->rp.minraint = atoi(argv[i+1]);
+ else if(strcmp(argv[i],"linkmtu")==0)
+ ifc->rp.linkmtu = atoi(argv[i+1]);
+ else if(strcmp(argv[i],"reachtime")==0)
+ ifc->rp.reachtime = atoi(argv[i+1]);
+ else if(strcmp(argv[i],"rxmitra")==0)
+ ifc->rp.rxmitra = atoi(argv[i+1]);
+ else if(strcmp(argv[i],"ttl")==0)
+ ifc->rp.ttl = atoi(argv[i+1]);
+ else if(strcmp(argv[i],"routerlt")==0)
+ ifc->rp.routerlt = atoi(argv[i+1]);
+ else
+ return Ebadarg;
+
+ argsleft -= 2;
+ i += 2;
+ }
+
+ // consistency check
+ if(ifc->rp.maxraint < ifc->rp.minraint) {
+ ifc->rp.maxraint = vmax;
+ ifc->rp.minraint = vmin;
+ return Ebadarg;
+ }
+
+ return nil;
+}
+
+char*
+ipifcsendra6(Ipifc *ifc, char **argv, int argc)
+{
+ int i;
+
+ i = 0;
+ if(argc > 1)
+ i = atoi(argv[1]);
+ ifc->sendra6 = (i!=0);
+ return nil;
+}
+
+char*
+ipifcrecvra6(Ipifc *ifc, char **argv, int argc)
+{
+ int i;
+
+ i = 0;
+ if(argc > 1)
+ i = atoi(argv[1]);
+ ifc->recvra6 = (i!=0);
+ return nil;
+}
+
/*
* non-standard control messages.
* called with c->car locked.
@@ 627,7 789,9 @@ ipifcctl(Conv* c, char**argv, int argc)
ifc = (Ipifc*)c->ptcl;
if(strcmp(argv[0], "add") == 0)
- return ipifcadd(ifc, argv, argc);
+ return ipifcadd(ifc, argv, argc, 0, nil);
+ else if(strcmp(argv[0], "try") == 0)
+ return ipifcadd(ifc, argv, argc, 1, nil);
else if(strcmp(argv[0], "remove") == 0)
return ipifcrem(ifc, argv, argc, 1);
else if(strcmp(argv[0], "unbind") == 0)
@@ 641,13 805,24 @@ ipifcctl(Conv* c, char**argv, int argc)
else if(strcmp(argv[0], "reassemble") == 0){
ifc->reassemble = 1;
return nil;
- } else if(strcmp(argv[0], "iprouting") == 0){
+ }
+ else if(strcmp(argv[0], "iprouting") == 0){
i = 1;
if(argc > 1)
i = atoi(argv[1]);
iprouting(c->p->f, i);
return nil;
}
+ else if(strcmp(argv[0], "gate6") == 0)
+ return ipifcaddgate6(c->p->f, ifc, argv, argc);
+ else if(strcmp(argv[0], "addpref6") == 0)
+ return ipifcaddpref6(ifc, argv, argc);
+ else if(strcmp(argv[0], "setpar6") == 0)
+ return ipifcsetpar6(ifc, argv, argc);
+ else if(strcmp(argv[0], "sendra6") == 0)
+ return ipifcsendra6(ifc, argv, argc);
+ else if(strcmp(argv[0], "recvra6") == 0)
+ return ipifcrecvra6(ifc, argv, argc);
return "unsupported ctl";
}
@@ 882,6 1057,10 @@ out:
}
static char *stformat = "%-32.32I %2.2d %4.4s\n";
+enum
+{
+ Nstformat= 41,
+};
long
ipselftabread(Fs *f, char *cp, ulong offset, int n)
@@ 911,6 1090,19 @@ ipselftabread(Fs *f, char *cp, ulong offset, int n)
return m;
}
+int
+iptentative(Fs *f, uchar *addr)
+{
+ Ipself *p;
+
+ p = f->self->hash[hashipa(addr)];
+ for(; p; p = p->next){
+ if(ipcmp(addr, p->a) == 0) {
+ return p->link->lifc->tentative;
+ }
+ }
+ return 0;
+}
/*
* returns
@@ 950,14 1142,16 @@ findipifc(Fs *f, uchar *remote, int type)
uchar gnet[IPaddrlen];
uchar xmask[IPaddrlen];
- x = nil;
+ x = nil; memset(xmask, 0, IPaddrlen);
/* find most specific match */
e = &f->ipifc->conv[f->ipifc->nc];
for(cp = f->ipifc->conv; cp < e; cp++){
if(*cp == 0)
continue;
+
ifc = (Ipifc*)(*cp)->ptcl;
+
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
maskip(remote, lifc->mask, gnet);
if(ipcmp(gnet, lifc->net) == 0){
@@ 985,8 1179,65 @@ findipifc(Fs *f, uchar *remote, int type)
return nil;
}
+enum {
+ unknownv6,
+ multicastv6,
+ unspecifiedv6,
+ linklocalv6,
+ sitelocalv6,
+ globalv6,
+};
+
+int
+v6addrtype(uchar *addr)
+{
+ if(isv6global(addr))
+ return globalv6;
+ if(islinklocal(addr))
+ return linklocalv6;
+ if(isv6mcast(addr))
+ return multicastv6;
+ if(issitelocal(addr))
+ return sitelocalv6;
+ return unknownv6;
+}
+
+#define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (msec/10^3) ) || ( (lifc)->preflt == 0xffffffff ))
+
+void
+findprimaryip6(Fs *f, uchar *local)
+{
+ Conv **cp, **e;
+ Ipifc *ifc;
+ Iplifc *lifc;
+ int atype, atypel;
+
+ ipmove(local, v6Unspecified);
+ atype = unspecifiedv6;
+
+ /* find "best" (global > sitelocal > link local > unspecified)
+ * local address; address must be current */
+
+ e = &f->ipifc->conv[f->ipifc->nc];
+ for(cp = f->ipifc->conv; cp < e; cp++){
+ if(*cp == 0)
+ continue;
+ ifc = (Ipifc*)(*cp)->ptcl;
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ atypel = v6addrtype(lifc->local);
+ if(atypel > atype)
+ if(v6addrcurr(lifc)) {
+ ipmove(local, lifc->local);
+ atype = atypel;
+ if(atype == globalv6)
+ return;
+ }
+ }
+ }
+}
+
/*
- * returns first ip address configured
+ * returns first ip address configured
*/
void
findprimaryip(Fs *f, uchar *local)
@@ 1020,28 1271,57 @@ findlocalip(Fs *f, uchar *local, uchar *remote)
Route *r;
uchar gate[IPaddrlen];
uchar gnet[IPaddrlen];
+ int version;
+ int atype = unspecifiedv6, atypel = unknownv6;
+ USED(atype);
+ USED(atypel);
qlock(f->ipifc);
r = v6lookup(f, remote);
+ version = (memcmp(remote, v4prefix, IPv4off) == 0) ? 4 : 6;
if(r != nil){
ifc = r->ifc;
if(r->type & Rv4)
v4tov6(gate, r->v4.gate);
- else
+ else {
ipmove(gate, r->v6.gate);
+ ipmove(local, v6Unspecified);
+ }
/* find ifc address closest to the gateway to use */
- for(lifc = ifc->lifc; lifc; lifc = lifc->next){
- maskip(gate, lifc->mask, gnet);
- if(ipcmp(gnet, lifc->net) == 0){
- ipmove(local, lifc->local);
- goto out;
+ if(version == 4) {
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ maskip(gate, lifc->mask, gnet);
+ if(ipcmp(gnet, lifc->net) == 0){
+ ipmove(local, lifc->local);
+ goto out;
+ }
+ }
+ }
+ else {
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ atypel = v6addrtype(lifc->local);
+ maskip(gate, lifc->mask, gnet);
+ if(ipcmp(gnet, lifc->net) == 0)
+ if(atypel > atype)
+ if(v6addrcurr(lifc)) {
+ ipmove(local, lifc->local);
+ atype = atypel;
+ if(atype == globalv6)
+ break;
+ }
}
+ if(atype > unspecifiedv6)
+ goto out;
}
}
- findprimaryip(f, local);
+ if(version == 4)
+ findprimaryip(f, local);
+ else
+ findprimaryip6(f, local);
+
out:
qunlock(f->ipifc);
@@ 1073,6 1353,20 @@ ipv6local(Ipifc *ifc, uchar *addr)
Iplifc *lifc;
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ if(!isv4(lifc->local) && !(lifc->tentative)){
+ ipmove(addr, lifc->local);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+ipv6anylocal(Ipifc *ifc, uchar *addr)
+{
+ Iplifc *lifc;
+
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next){
if(!isv4(lifc->local)){
ipmove(addr, lifc->local);
return 1;
@@ 1269,26 1563,303 @@ ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
/* register the address on any network that will proxy for us */
e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == nil)
- continue;
- nifc = (Ipifc*)(*cp)->ptcl;
- if(nifc == ifc)
- continue;
- rlock(nifc);
- m = nifc->m;
- if(m == nil || m->areg == nil){
+ if(!isv4(ip)) { // V6
+ for(cp = f->ipifc->conv; cp < e; cp++){
+ if(*cp == nil)
+ continue;
+ nifc = (Ipifc*)(*cp)->ptcl;
+ if(nifc == ifc)
+ continue;
+
+ rlock(nifc);
+ m = nifc->m;
+ if(m == nil || m->addmulti == nil) {
+ runlock(nifc);
+ continue;
+ }
+ for(lifc = nifc->lifc; lifc; lifc = lifc->next){
+ maskip(ip, lifc->mask, net);
+ if(ipcmp(net, lifc->remote) == 0) { /* add solicited-node multicast address */
+ ipv62smcast(net, ip);
+ addselfcache(f, nifc, lifc, net, Rmulti);
+ arpenter(f, V6, ip, nifc->mac, 6, 0);
+ //(*m->addmulti)(nifc, net, ip);
+ break;
+ }
+ }
+ runlock(nifc);
+ }
+ return;
+ }
+ else { // V4
+ for(cp = f->ipifc->conv; cp < e; cp++){
+ if(*cp == nil)
+ continue;
+ nifc = (Ipifc*)(*cp)->ptcl;
+ if(nifc == ifc)
+ continue;
+
+ rlock(nifc);
+ m = nifc->m;
+ if(m == nil || m->areg == nil){
+ runlock(nifc);
+ continue;
+ }
+ for(lifc = nifc->lifc; lifc; lifc = lifc->next){
+ maskip(ip, lifc->mask, net);
+ if(ipcmp(net, lifc->remote) == 0){
+ (*m->areg)(nifc, ip);
+ break;
+ }
+ }
runlock(nifc);
- continue;
}
- for(lifc = nifc->lifc; lifc; lifc = lifc->next){
- maskip(ip, lifc->mask, net);
- if(ipcmp(net, lifc->remote) == 0){
- (*m->areg)(nifc, ip);
+ }
+}
+
+
+// added for new v6 mesg types
+static void
+adddefroute6(Fs *f, uchar *gate, int force)
+{
+ Route *r;
+
+ r = v6lookup(f, v6Unspecified);
+ if(r!=nil)
+ if(!(force) && (strcmp(r->tag,"ra")!=0)) // route entries generated
+ return; // by all other means take
+ // precedence over router annc
+
+ v6delroute(f, v6Unspecified, v6Unspecified, 1);
+ v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
+}
+
+enum
+{
+ Ngates = 3,
+};
+
+char*
+ipifcaddgate6(Fs *f, Ipifc *ifc, char**argv, int argc)
+{
+ v6router *r = f->v6p->v6rlist;
+ uchar routeraddr[IPaddrlen];
+ int mflag = f->v6p->rp.mflag;
+ int oflag = f->v6p->rp.oflag;
+ int reachtime = f->v6p->rp.reachtime;
+ int rxmitra = f->v6p->rp.rxmitra;
+ int ttl = MAXTTL;
+ int routerlt = f->v6p->rp.routerlt;
+ int force; // force == 1 forces argv[1] to
+ // be the default router.
+ int i, j;
+ int found = 0;
+
+ if((argc<3)||(argc>9))
+ return Ebadarg;
+ if( (parseip(routeraddr, argv[1])!=6) || !(islinklocal(routeraddr)) )
+ return Ebadarg;
+
+ force = (atoi(argv[2])!=0);
+
+ switch(argc){
+ case 9:
+ rxmitra = atoi(argv[8]);
+ /* fall through */
+ case 8:
+ reachtime = atoi(argv[7]);
+ /* fall through */
+ case 7:
+ routerlt = atoi(argv[6]);
+ /* fall through */
+ case 6:
+ oflag = atoi(argv[5]);
+ /* fall through */
+ case 5:
+ mflag = atoi(argv[4]);
+ /* fall through */
+ case 4:
+ ttl = atoi(argv[3]);
+ /* fall through */
+ }
+
+ if((force) && (routerlt < 0))
+ return Ebadarg;
+ if((ttl < 0) || (255 < ttl))
+ return Ebadarg;
+
+ j = -1;
+ for(i=0; i<Ngates; i++) {
+ if(r[i].inuse) {
+ if((ipcmp(routeraddr, r[i].routeraddr)==0) &&
+ (r[i].ifc==ifc)) {
+ j = i;
+ found = 1;
break;
}
}
- runlock(nifc);
+ else {
+ j = i;
+ }
+ }
+
+ if(found==0) {
+ if(routerlt <= 0)
+ return nil;
+ else if((force) && (j<0)) {
+ j = f->v6p->cdrouter;
+ f->v6p->cdrouter = -1;
+ }
+ }
+
+ // assert((found && (j>=0))||(!found && routerlt>0));
+ if(routerlt > 0) {
+ memset(&r[j], 0, sizeof(v6router));
+ r[j].inuse = 1;
+ r[j].ifc = ifc;
+ r[j].ifcid = ifc->ifcid;
+ ipmove(r[j].routeraddr, routeraddr);
+ r[j].ltorigin = msec / 10^3;
+ r[j].rp.mflag = (mflag!=0);
+ r[j].rp.oflag = (oflag!=0);
+ r[j].rp.rxmitra = rxmitra;
+ r[j].rp.reachtime = reachtime;
+ r[j].rp.routerlt = routerlt;
+ r[j].rp.ttl = ttl;
+
+ if((f->v6p->cdrouter < 0) || (force==1)) {
+ f->v6p->cdrouter = j;
+ adddefroute6(f, routeraddr, force);
+ }
+ }
+ else if(j >= 0) { // remove router
+ r[j].inuse = 0;
+ if(f->v6p->cdrouter==j) {
+ f->v6p->cdrouter = -1;
+ v6delroute(f, v6Unspecified, v6Unspecified, 1);
+ for(i=0; i<Ngates; i++) {
+ if(r[i].inuse) {
+ f->v6p->cdrouter = i;
+ adddefroute6(f, r[i].routeraddr, 1);
+ break;
+ }
+ }
+ }
+ }
+ return nil;
+}
+
+char*
+ipifcaddpref6(Ipifc *ifc, char**argv, int argc)
+{
+ uchar onlink = 1;
+ uchar autoflag = 1;
+ long validlt = 0xffffffff;
+ long preflt = 0xffffffff;
+ long origint = msec / 10^3;
+ uchar prefix[IPaddrlen];
+ int plen = 64;
+ Iplifc *lifc;
+ char addr[40];
+ char *params[3];
+
+ switch(argc) {
+ case 7:
+ preflt = atoi(argv[6]);
+ /* fall through */
+ case 6:
+ validlt = atoi(argv[5]);
+ /* fall through */
+ case 5:
+ autoflag = atoi(argv[4]);
+ /* fall through */
+ case 4:
+ onlink = atoi(argv[3]);
+ /* fall through */
+ case 3:
+ plen = atoi(argv[2]);
+ case 2:
+ break;
+ default:
+ return Ebadarg;
+ }
+
+ if((parseip(prefix, argv[1])!=6) ||
+ (validlt < preflt) ||
+ (plen > 64) ||
+ (islinklocal(prefix))
+ )
+ return Ebadarg;
+
+ lifc = smalloc(sizeof(Iplifc));
+ lifc->onlink = (onlink!=0);
+ lifc->autoflag = (autoflag!=0);
+ lifc->validlt = validlt;
+ lifc->preflt = preflt;
+ lifc->origint = origint;
+
+ if(ifc->m->pref2addr!=nil)
+ ifc->m->pref2addr(prefix, ifc->mac);
+ else
+ return Ebadarg;
+
+ sprint(addr, "%I", prefix);
+ params[0] = "add";
+ params[1] = addr;
+ params[2] = "/64";
+
+ return ipifcadd(ifc, params, 3, 0, lifc);
+}
+
+static char *gateformat = "%-1.1s %-40.40I %20ld %10d %-40.40s\n";
+enum
+{
+ Ngateformat= 116,
+};
+
+static char *rtrstat[] =
+{
+[0] "*",
+[1] "-",
+};
+
+/* line corresponding to current default router, if in f->v6p->v6rlist,
+ starts with a "*", others with a "-". */
+
+long
+ipgateread6(Fs *f, char *cp, ulong offset, int n)
+{
+ v6router *r = f->v6p->v6rlist;
+ int i, j, k, l;
+ long m;
+
+
+ if(offset % Ngateformat)
+ return 0;
+
+ offset = offset/Ngateformat;
+ n = n/Ngateformat;
+
+ i = f->v6p->cdrouter;
+ k = i;
+ if((i<0)||(i>2))
+ i = 0;
+ m = 0;
+ for(j = 0; (n > 0) && (j < Ngates) ; j++){
+ if(offset > 0){
+ offset--;
+ i = (i+1) % Ngates;
+ continue;
+ }
+ n--;
+ if(r[i].inuse) {
+ l = (i==k) ? 0 : 1;
+ m += sprint(cp + m, gateformat,
+ rtrstat[l], r[i].routeraddr, r[i].ltorigin,
+ r[i].rp.routerlt, r[i].ifc->dev);
+ }
+ i = (i+1) % Ngates;
}
+ return m;
}
M ip/ipmux.c => ip/ipmux.c +76 -37
@@ 6,19 6,19 @@
#include "../port/error.h"
#include "ip.h"
-
#define DPRINT if(0)print
-typedef struct Iphdr Iphdr;
-typedef struct Ipmuxrock Ipmuxrock;
-typedef struct Ipmux Ipmux;
+typedef struct Ipmuxrock Ipmuxrock;
+typedef struct Ipmux Ipmux;
+typedef struct Ip4hdr Ip4hdr;
+typedef struct Ip6hdr Ip6hdr;
enum
{
- IPHDR = 20, /* sizeof(Iphdr) */
+ IPHDR = 20, /* sizeof(Ip4hdr) */
};
-struct Iphdr
+struct Ip4hdr
{
uchar vihl; /* Version and header length */
uchar tos; /* Type of service */
@@ 32,12 32,24 @@ struct Iphdr
uchar dst[4]; /* IP destination */
uchar data[1]; /* start of data */
};
-Iphdr *ipoff = 0;
+Ip4hdr *ipoff = 0;
+
+struct Ip6hdr
+{
+ uchar vcf[4]; /* version, class label, and flow label */
+ uchar ploadlen[2]; /* payload length */
+ uchar proto; /* next header, i.e. proto */
+ uchar ttl; /* hop limit, i.e. ttl */
+ uchar src[16]; /* IP source */
+ uchar dst[16]; /* IP destination */
+};
+
enum
{
Tproto,
Tdata,
+ Tiph,
Tdst,
Tsrc,
Tifc,
@@ 57,6 69,7 @@ char *ftname[] =
{
[Tproto] "proto",
[Tdata] "data",
+[Tiph] "iph",
[Tdst] "dst",
[Tsrc] "src",
[Tifc] "ifc",
@@ 69,12 82,13 @@ struct Ipmux
{
Ipmux *yes;
Ipmux *no;
- uchar type; /* type of field (Txxxx) */
- uchar ctype; /* tupe of comparison (Cxxxx) */
- uchar len; /* length in bytes of item to compare */
- uchar n; /* number of items val points to */
- short off; /* offset of comparison */
- short eoff; /* end offset of comparison */
+ uchar type; /* type of field (Txxxx) */
+ uchar ctype; /* tupe of comparison (Cxxxx) */
+ uchar len; /* length in bytes of item to compare */
+ uchar n; /* number of items val points to */
+ short off; /* offset of comparison */
+ short eoff; /* end offset of comparison */
+ uchar skiphdr; /* should offset start after ip header */
uchar *val;
uchar *mask;
uchar *e; /* val + n*len */
@@ 148,9 162,15 @@ parseop(char **pp)
len = 1;
p += 5;
}
- else if(strncmp(p, "data", 4) == 0){
- type = Tdata;
- p += 4;
+ else if(strncmp(p, "data", 4) == 0 || strncmp(p, "iph", 3) == 0){
+ if(strncmp(p, "data", 4) == 0) {
+ type = Tdata;
+ p += 4;
+ }
+ else {
+ type = Tiph;
+ p += 3;
+ }
p = skipwhite(p);
if(*p != '[')
return nil;
@@ 173,9 193,8 @@ parseop(char **pp)
return nil;
p++;
len = end - off + 1;
- off += (ulong)(ipoff->data);
}
- else
+ else
return nil;
f = smalloc(sizeof(*f));
@@ 186,6 205,10 @@ parseop(char **pp)
f->mask = nil;
f->n = 1;
f->ref = 1;
+ if(type == Tdata)
+ f->skiphdr = 1;
+ else
+ f->skiphdr = 0;
return f;
}
@@ 250,6 273,7 @@ parsemux(char *p)
v4parseip(f->mask, mask);
break;
case Tdata:
+ case Tiph:
f->mask = smalloc(f->len);
parseval(f->mask, mask, f->len);
break;
@@ 278,6 302,7 @@ parsemux(char *p)
break;
case Tproto:
case Tdata:
+ case Tiph:
parseval(v, vals[n], f->len);
break;
}
@@ 333,7 358,8 @@ ipmuxcmp(Ipmux *a, Ipmux *b)
return n;
/* compare offsets, call earlier ones more specific */
- n = a->off - b->off;
+ n = (a->off+((int)a->skiphdr)*(ulong)ipoff->data) -
+ (b->off+((int)b->skiphdr)*(ulong)ipoff->data);
if(n != 0)
return n;
@@ 629,29 655,35 @@ static void
ipmuxkick(Conv *c)
{
Block *bp;
- Iphdr *ih;
+ struct Ip6hdr *ih6;
bp = qget(c->wq);
if(bp == nil)
return;
-
- ih = (Iphdr*)(bp->rp);
-
- ipoput(c->p->f, bp, 0, ih->ttl, ih->tos);
+ else {
+ Ip4hdr *ih4 = (Ip4hdr*)(bp->rp);
+ if((ih4->vihl)&0xF0 != 0x60)
+ ipoput4(c->p->f, bp, 0, ih4->ttl, ih4->tos);
+ else {
+ ih6 = (struct Ip6hdr*)ih4;
+ ipoput6(c->p->f, bp, 0, ih6->ttl, 0);
+ }
+ }
}
static void
ipmuxiput(Proto *p, Ipifc *ifc, Block *bp)
{
- int len;
+ int len, hl;
Fs *f = p->f;
uchar *m, *h, *v, *e, *ve, *hp;
Conv *c;
Ipmux *mux;
- Iphdr *ip;
- uchar *ia;
+ Ip4hdr *ip;
+ Ip6hdr *ip6;
- ia = ifc->lifc->local;
+ ip = (Ip4hdr*)bp->rp;
+ hl = (ip->vihl&0x0F)<<2;
if(p->priv == nil)
goto nomatch;
@@ 668,7 700,7 @@ ipmuxiput(Proto *p, Ipifc *ifc, Block *bp)
mux = mux->no;
continue;
}
- hp = h + mux->off;
+ hp = h + mux->off + ((int)mux->skiphdr)*hl;
switch(mux->ctype){
case Cbyte:
if(*mux->val == *hp)
@@ 695,11 727,11 @@ ipmuxiput(Proto *p, Ipifc *ifc, Block *bp)
goto yes;
break;
case Cifc:
- if(*((ulong*)mux->val) == *(ulong*)(ia + IPv4off))
+ if(*((ulong*)mux->val) == *(ulong*)(ifc->lifc->local + IPv4off))
goto yes;
break;
case Cmifc:
- if((*(ulong*)(ia + IPv4off) & (*((ulong*)mux->mask))) == *((ulong*)mux->val))
+ if((*(ulong*)(ifc->lifc->local + IPv4off) & (*((ulong*)mux->mask))) == *((ulong*)mux->val))
goto yes;
break;
default:
@@ 727,19 759,24 @@ yes:
if(c != nil){
/* tack on interface address */
bp = padblock(bp, IPaddrlen);
- ipmove(bp->rp, ia);
+ ipmove(bp->rp, ifc->lifc->local);
bp = concatblock(bp);
if(bp != nil)
- if (qpass(c->rq, bp) < 0)
+ if(qpass(c->rq, bp) < 0)
print("Q");
return;
}
nomatch:
/* doesn't match any filter, hand it to the specific protocol handler */
- ip = (Iphdr*)bp->rp;
- p = f->t2p[ip->proto];
- if(p)
+ ip = (Ip4hdr*)bp->rp;
+ if((ip->vihl&0xF0)==0x40) {
+ p = f->t2p[ip->proto];
+ } else {
+ ip6 = (Ip6hdr*)bp->rp;
+ p = f->t2p[ip6->proto];
+ }
+ if(p && p->rcv)
(*p->rcv)(p, ifc, bp);
else
freeblist(bp);
@@ 759,7 796,9 @@ ipmuxsprint(Ipmux *mux, int level, char *buf, int len)
n += snprint(buf+n, len-n, "\n");
return n;
}
- n += snprint(buf+n, len-n, "h[%d:%d]&", mux->off, mux->off+mux->len-1);
+ n += snprint(buf+n, len-n, "h[%d:%d]&",
+ mux->off+((int)mux->skiphdr)*((int)ipoff->data),
+ mux->off+(((int)mux->skiphdr)*((int)ipoff->data))+mux->len-1);
for(i = 0; i < mux->len; i++)
n += snprint(buf+n, len - n, "%2.2ux", mux->mask[i]);
n += snprint(buf+n, len-n, "=");
M ip/iproute.c => ip/iproute.c +35 -49
@@ 16,22 16,6 @@ Route* v4freelist;
Route* v6freelist;
RWlock routelock;
-enum
-{
- RWadd,
- RWflush,
- RWremove,
- RWtag,
-};
-
-static
-Cmdtab routecmd[] = {
- RWadd, "add", 4,
- RWflush, "flush", 2,
- RWremove, "remove", 3,
- RWtag, "tag", 2,
-};
-
static void
freeroute(Route *r)
{
@@ 337,6 321,7 @@ v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
}
#define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
+#define ISDFLT(a, mask, tag) ((ipcmp((a),v6Unspecified)==0) && (ipcmp((mask),v6Unspecified)==0) && (strcmp((tag), "ra")!=0))
void
v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
@@ 346,6 331,12 @@ v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
ulong x, y;
int h, eh;
+ /*
+ if(ISDFLT(a, mask, tag))
+ f->v6p->cdrouter = -1;
+ */
+
+
for(h = 0; h < IPllen; h++){
x = nhgetl(a+4*h);
y = nhgetl(mask+4*h);
@@ 528,8 519,8 @@ v6lookup(Fs *f, uchar *a)
ulong x, y;
uchar gate[IPaddrlen];
- if(memcmp(a, v4prefix, 12) == 0){
- q = v4lookup(f, a+12);
+ if(memcmp(a, v4prefix, IPv4off) == 0){
+ q = v4lookup(f, a+IPv4off);
if(q != nil)
return q;
}
@@ 568,10 559,8 @@ next: ;
if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
if(q->type & Rifc) {
- hnputl(gate, q->v6.gate[0]);
- hnputl(gate+4, q->v6.gate[1]);
- hnputl(gate+8, q->v6.gate[2]);
- hnputl(gate+12, q->v6.gate[3]);
+ for(h = 0; h < IPllen; h++)
+ hnputl(gate+4*h, q->v6.address[h]);
q->ifc = findipifc(f, gate, q->type);
} else
q->ifc = findipifc(f, q->v6.gate, q->type);
@@ 606,10 595,10 @@ routetype(int type, char *p)
enum
{
- Rlinelen= 89,
+ Rlinelen= 137,
};
-char *rformat = "%-24.24I %-24.24M %-24.24I %4.4s %4.4s %3s\n";
+char *rformat = "%-40.40I %-40.40M %-40.40I %4.4s %4.4s %3s\n";
void
convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc)
@@ 779,7 768,6 @@ routewrite(Fs *f, Chan *c, char *p, int n)
int h, changed;
char *tag;
Cmdbuf *cb;
- Cmdtab *ct;
uchar addr[IPaddrlen];
uchar mask[IPaddrlen];
uchar gate[IPaddrlen];
@@ 791,25 779,7 @@ routewrite(Fs *f, Chan *c, char *p, int n)
nexterror();
}
- ct = lookupcmd(cb, routecmd, nelem(routecmd));
-
- switch(ct->index){
- case RWadd:
- parseip(addr, cb->f[1]);
- parseipmask(mask, cb->f[2]);
- parseip(gate, cb->f[3]);
- tag = "none";
- if(c != nil){
- a = c->aux;
- tag = a->tag;
- }
- if(memcmp(addr, v4prefix, IPv4off) == 0)
- v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
- else
- v6addroute(f, tag, addr, mask, gate, 0);
- break;
-
- case RWflush:
+ if(strcmp(cb->f[0], "flush") == 0){
tag = cb->f[1];
for(h = 0; h < nelem(f->v4root); h++)
for(changed = 1; changed;){
@@ 823,18 793,34 @@ routewrite(Fs *f, Chan *c, char *p, int n)
changed = routeflush(f, f->v6root[h], tag);
wunlock(&routelock);
}
- break;
-
- case RWremove:
+ } else if(strcmp(cb->f[0], "remove") == 0){
+ if(cb->nf < 3)
+ error(Ebadarg);
parseip(addr, cb->f[1]);
parseipmask(mask, cb->f[2]);
if(memcmp(addr, v4prefix, IPv4off) == 0)
v4delroute(f, addr+IPv4off, mask+IPv4off, 1);
else
v6delroute(f, addr, mask, 1);
- break;
+ } else if(strcmp(cb->f[0], "add") == 0){
+ if(cb->nf < 4)
+ error(Ebadarg);
+ parseip(addr, cb->f[1]);
+ parseipmask(mask, cb->f[2]);
+ parseip(gate, cb->f[3]);
+ tag = "none";
+ if(c != nil){
+ a = c->aux;
+ tag = a->tag;
+ }
+ if(memcmp(addr, v4prefix, IPv4off) == 0)
+ v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
+ else
+ v6addroute(f, tag, addr, mask, gate, 0);
+ } else if(strcmp(cb->f[0], "tag") == 0) {
+ if(cb->nf < 2)
+ error(Ebadarg);
- case RWtag:
a = c->aux;
na = newipaux(a->owner, cb->f[1]);
c->aux = na;
A ip/ipv6.c => ip/ipv6.c +746 -0
@@ 0,0 1,746 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "ip.h"
+#include "ipv6.h"
+
+enum
+{
+ IP4HDR = 20, /* sizeof(Ip4hdr) */
+ IP6HDR = 40, /* sizeof(Ip6hdr) */
+ IP_HLEN4 = 0x05, /* Header length in words */
+ IP_DF = 0x4000, /* Don't fragment */
+ IP_MF = 0x2000, /* More fragments */
+ IP6FHDR = 8, /* sizeof(Fraghdr6) */
+ IP_MAX = (32*1024), /* Maximum Internet packet size */
+};
+
+#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))
+
+typedef struct IP IP;
+typedef struct Fragment4 Fragment4;
+typedef struct Fragment6 Fragment6;
+typedef struct Ipfrag Ipfrag;
+
+Block* ip6reassemble(IP*, int, Block*, Ip6hdr*);
+void ipfragfree6(IP*, Fragment6*);
+Fragment6* ipfragallo6(IP*);
+static Block* procxtns(IP *ip, Block *bp, int doreasm);
+int unfraglen(Block *bp, uchar *nexthdr, int setfh);
+Block* procopts(Block *bp);
+
+/* MIB II counters */
+enum
+{
+ Forwarding,
+ DefaultTTL,
+ InReceives,
+ InHdrErrors,
+ InAddrErrors,
+ ForwDatagrams,
+ InUnknownProtos,
+ InDiscards,
+ InDelivers,
+ OutRequests,
+ OutDiscards,
+ OutNoRoutes,
+ ReasmTimeout,
+ ReasmReqds,
+ ReasmOKs,
+ ReasmFails,
+ FragOKs,
+ FragFails,
+ FragCreates,
+
+ Nstats,
+};
+
+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",
+};
+
+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 */
+};
+
+void
+ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos)
+{
+ int tentative;
+ Ipifc *ifc;
+ uchar *gate, nexthdr;
+ Ip6hdr *eh;
+ int medialen, len, chunk, uflen, flen, seglen, lid, offset, fragoff, morefrags, blklen;
+ Route *r, *sr;
+ Fraghdr6 fraghdr;
+ Block *xp, *nb;
+ IP *ip;
+
+
+ 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 */
+ len = blocklen(bp);
+
+ tentative = iptentative(f, eh->src);
+ if(tentative){
+ netlog(f, Logip, "reject tx of packet with tentative src address\n");
+ goto free;
+ }
+
+ if(gating){
+ chunk = nhgets(eh->ploadlen);
+ if(chunk > len){
+ ip->stats[OutDiscards]++;
+ netlog(f, Logip, "short gated packet\n");
+ goto free;
+ }
+ if(chunk + IPV6HDR_LEN < len)
+ len = chunk + IPV6HDR_LEN;
+ }
+
+ if(len >= IP_MAX){
+ print("len > IP_MAX, free\n");
+ ip->stats[OutDiscards]++;
+ netlog(f, Logip, "exceeded ip max size %I\n", eh->dst);
+ goto free;
+ }
+
+ r = v6lookup(f, eh->dst);
+ if(r == nil){
+ print("no route for %I, src %I free\n", eh->dst, eh->src);
+ ip->stats[OutNoRoutes]++;
+ netlog(f, Logip, "no interface %I\n", eh->dst);
+ goto free;
+ }
+
+ ifc = r->ifc;
+ if(r->type & (Rifc|Runi))
+ gate = eh->dst;
+ else
+ if(r->type & (Rbcast|Rmulti)) {
+ gate = eh->dst;
+ sr = v6lookup(f, eh->src);
+ if(sr != nil && (sr->type & Runi))
+ ifc = sr->ifc;
+ }
+ 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;
+ }
+
+ if(waserror()){
+ runlock(ifc);
+ nexterror();
+ }
+
+ if(ifc->m == nil) {
+ goto raise;
+ }
+
+ /* If we dont need to fragment just send it */
+ medialen = ifc->maxmtu - ifc->m->hsize;
+ if(len <= medialen) {
+ hnputs(eh->ploadlen, len-IPV6HDR_LEN);
+ ifc->m->bwrite(ifc, bp, V6, gate);
+ runlock(ifc);
+ poperror();
+ return;
+ }
+
+ if(gating)
+ if(ifc->reassemble <= 0) {
+
+ /* v6 intermediate nodes are not supposed to fragment pkts;
+ we fragment if ifc->reassemble is turned on; an exception
+ needed for nat.
+ */
+
+ ip->stats[OutDiscards]++;
+ icmppkttoobig6(f, ifc, bp);
+ netlog(f, Logip, "%I: gated pkts not fragmented\n", eh->dst);
+ goto raise;
+ }
+
+ /* start v6 fragmentation */
+ uflen = unfraglen(bp, &nexthdr, 1);
+ if(uflen > medialen) {
+ ip->stats[FragFails]++;
+ ip->stats[OutDiscards]++;
+ netlog(f, Logip, "%I: unfragmentable part too big\n", eh->dst);
+ goto raise;
+ }
+
+ flen = len - uflen;
+ seglen = (medialen - (uflen + IP6FHDR)) & ~7;
+ if(seglen < 8) {
+ ip->stats[FragFails]++;
+ ip->stats[OutDiscards]++;
+ netlog(f, Logip, "%I: seglen < 8\n", eh->dst);
+ goto raise;
+ }
+
+ lid = incref(&ip->id6);
+ fraghdr.nexthdr = nexthdr;
+ fraghdr.res = 0;
+ hnputl(fraghdr.id, lid);
+
+ xp = bp;
+ offset = uflen;
+ while (xp != nil && offset && offset >= BLEN(xp)) {
+ offset -= BLEN(xp);
+ xp = xp->next;
+ }
+ xp->rp += offset;
+
+ fragoff = 0;
+ morefrags = 1;
+
+ for(; fragoff < flen; fragoff += seglen) {
+ nb = allocb(uflen + IP6FHDR + seglen);
+
+ if(fragoff + seglen >= flen) {
+ seglen = flen - fragoff;
+ morefrags = 0;
+ }
+
+ hnputs(eh->ploadlen, seglen+IP6FHDR);
+ memmove(nb->wp, eh, uflen);
+ nb->wp += uflen;
+
+ hnputs(fraghdr.offsetRM, fragoff); // last 3 bits must be 0
+ fraghdr.offsetRM[1] |= morefrags;
+ memmove(nb->wp, &fraghdr, IP6FHDR);
+ nb->wp += IP6FHDR;
+
+ /* Copy data */
+ chunk = seglen;
+ while (chunk) {
+ if(!xp) {
+ ip->stats[OutDiscards]++;
+ ip->stats[FragFails]++;
+ freeblist(nb);
+ netlog(f, Logip, "!xp: chunk in v6%d\n", chunk);
+ 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;
+ }
+
+ ifc->m->bwrite(ifc, nb, V6, gate);
+ ip->stats[FragCreates]++;
+ }
+ ip->stats[FragOKs]++;
+
+raise:
+ runlock(ifc);
+ poperror();
+free:
+ freeblist(bp);
+
+}
+
+void
+ipiput6(Fs *f, Ipifc *ifc, Block *bp)
+{
+ int hl;
+ int hop, tos;
+ uchar proto;
+ Ip6hdr *h;
+ Proto *p;
+ int notforme;
+ int tentative;
+ uchar v6dst[IPaddrlen];
+ IP *ip;
+ Route *r, *sr;
+
+ ip = f->ip;
+ ip->stats[InReceives]++;
+
+ /*
+ * Ensure we have all the header info in the first
+ * 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);
+ if(hl < IP6HDR)
+ hl = IP6HDR;
+ if(hl > 64)
+ hl = 64;
+ bp = pullupblock(bp, hl);
+ if(bp == nil)
+ return;
+ }
+
+ h = (Ip6hdr *)(bp->rp);
+
+ memmove(&v6dst[0], &(h->dst)[0], IPaddrlen);
+ notforme = ipforme(f, v6dst) == 0;
+ tentative = iptentative(f, v6dst);
+
+ if(tentative && (h->proto != ICMPv6)) {
+ print("tentative addr, drop\n");
+ freeblist(bp);
+ return;
+ }
+
+ /* Check header version */
+ if(BLKIPVER(bp) != IP_VER6) {
+ ip->stats[InHdrErrors]++;
+ netlog(f, Logip, "ip: bad version %ux\n", (h->vcf[0]&0xF0)>>2);
+ freeblist(bp);
+ return;
+ }
+
+ /* route */
+ if(notforme) {
+ if(!ip->iprouting){
+ freeb(bp);
+ return;
+ }
+ /* don't forward to source's network */
+ sr = v6lookup(f, h->src);
+ r = v6lookup(f, h->dst);
+
+ if(r == nil || sr == r){
+ ip->stats[OutDiscards]++;
+ freeblist(bp);
+ return;
+ }
+
+ /* don't forward if packet has timed out */
+ hop = h->ttl;
+ if(hop < 1) {
+ ip->stats[InHdrErrors]++;
+ icmpttlexceeded6(f, ifc, bp);
+ freeblist(bp);
+ return;
+ }
+
+ /* process headers & reassemble if the interface expects it */
+ bp = procxtns(ip, bp, r->ifc->reassemble);
+
+ if(bp == nil)
+ return;
+
+ ip->stats[ForwDatagrams]++;
+ h = (Ip6hdr *) (bp->rp);
+ tos = IPV6CLASS(h);
+ hop = h->ttl;
+ ipoput6(f, bp, 1, hop-1, tos);
+ return;
+ }
+
+ /* reassemble & process headers if needed */
+ bp = procxtns(ip, bp, 1);
+
+ if(bp == nil)
+ return;
+
+ h = (Ip6hdr *) (bp->rp);
+ proto = h->proto;
+ p = Fsrcvpcol(f, proto);
+ if(p != nil && p->rcv != nil) {
+ ip->stats[InDelivers]++;
+ (*p->rcv)(p, ifc, bp);
+ return;
+ }
+
+ ip->stats[InDiscards]++;
+ ip->stats[InUnknownProtos]++;
+ freeblist(bp);
+}
+
+/*
+ * ipfragfree6 - copied from ipfragfree4 - assume hold fraglock6
+ */
+void
+ipfragfree6(IP *ip, Fragment6 *frag)
+{
+ Fragment6 *fl, **l;
+
+ if(frag->blist)
+ freeblist(frag->blist);
+
+ memset(frag->src, 0, IPaddrlen);
+ frag->id = 0;
+ frag->blist = nil;
+
+ l = &ip->flisthead6;
+ for(fl = *l; fl; fl = fl->next) {
+ if(fl == frag) {
+ *l = frag->next;
+ break;
+ }
+ l = &fl->next;
+ }
+
+ frag->next = ip->fragfree6;
+ ip->fragfree6 = frag;
+
+}
+
+/*
+ * ipfragallo6 - copied from ipfragalloc4
+ */
+Fragment6*
+ipfragallo6(IP *ip)
+{
+ Fragment6 *f;
+
+ while(ip->fragfree6 == nil) {
+ /* free last entry on fraglist */
+ for(f = ip->flisthead6; f->next; f = f->next)
+ ;
+ ipfragfree6(ip, f);
+ }
+ f = ip->fragfree6;
+ ip->fragfree6 = f->next;
+ f->next = ip->flisthead6;
+ ip->flisthead6 = f;
+ f->age = msec + 30000;
+
+ return f;
+}
+
+static Block*
+procxtns(IP *ip, Block *bp, int doreasm) {
+
+ int offset;
+ uchar proto;
+ Ip6hdr *h;
+
+ h = (Ip6hdr *) (bp->rp);
+ offset = unfraglen(bp, &proto, 0);
+
+ if((proto == FH) && (doreasm != 0)) {
+ bp = ip6reassemble(ip, offset, bp, h);
+ if(bp == nil)
+ return nil;
+ offset = unfraglen(bp, &proto, 0);
+ }
+
+ if(proto == DOH || offset > IP6HDR)
+ bp = procopts(bp);
+
+ return bp;
+}
+
+
+/* returns length of "Unfragmentable part", i.e., sum of lengths of ipv6 hdr,
+ * 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.
+ */
+int
+unfraglen(Block *bp, uchar *nexthdr, int setfh)
+{
+ uchar *p, *q;
+ int ufl, hs;
+
+ p = bp->rp;
+ q = p+6; /* proto, = p+sizeof(Ip6hdr.vcf)+sizeof(Ip6hdr.ploadlen) */
+ *nexthdr = *q;
+ ufl = IP6HDR;
+ p += ufl;
+
+ for(;;) {
+ if(*nexthdr == HBH || *nexthdr == RH) {
+ *nexthdr = *p;
+ hs = ((int)*(p+1) + 1) * 8;
+ ufl += hs;
+ q = p;
+ p += hs;
+ }
+ else
+ break;
+ }
+
+ if(*nexthdr == FH)
+ *q = *p;
+
+ if(setfh)
+ *q = FH;
+
+ return ufl;
+}
+
+Block*
+procopts(Block *bp)
+{
+ return bp;
+}
+
+Block*
+ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
+{
+
+ int fend, offset;
+ uint id;
+ Fragment6 *f, *fnext;
+ Fraghdr6 *fraghdr;
+ uchar src[IPaddrlen], dst[IPaddrlen];
+ Block *bl, **l, *last, *prev;
+ int ovlap, len, fragsize, pktposn;
+
+ fraghdr = (Fraghdr6 *) (bp->rp + uflen);
+ memmove(src, ih->src, IPaddrlen);
+ memmove(dst, ih->dst, IPaddrlen);
+ id = nhgetl(fraghdr->id);
+ offset = nhgets(fraghdr->offsetRM) & ~7;
+
+ /*
+ * block lists are too hard, pullupblock into a single block
+ */
+ if(bp->next){
+ bp = pullupblock(bp, blocklen(bp));
+ ih = (Ip6hdr *)(bp->rp);
+ }
+
+
+ qlock(&ip->fraglock6);
+
+ /*
+ * find a reassembly queue for this fragment
+ */
+ for(f = ip->flisthead6; f; f = fnext){
+ fnext = f->next;
+ if(ipcmp(f->src, src)==0 && ipcmp(f->dst, dst)==0 && f->id == id)
+ break;
+ if(f->age < msec){
+ ip->stats[ReasmTimeout]++;
+ ipfragfree6(ip, f);
+ }
+ }
+
+
+ /*
+ * if this isn't a fragmented packet, accept it
+ * and get rid of any fragments that might go
+ * with it.
+ */
+ if(nhgets(fraghdr->offsetRM)==0) { // first frag is also the last
+ if(f != nil) {
+ ipfragfree6(ip, f);
+ ip->stats[ReasmFails]++;
+ }
+ qunlock(&ip->fraglock6);
+ return bp;
+ }
+
+ if(bp->base+sizeof(Ipfrag) >= bp->rp){
+ bp = padblock(bp, sizeof(Ipfrag));
+ bp->rp += sizeof(Ipfrag);
+ }
+
+ BKFG(bp)->foff = offset;
+ BKFG(bp)->flen = nhgets(ih->ploadlen) + IP6HDR - uflen - IP6FHDR;
+
+ /* First fragment allocates a reassembly queue */
+ if(f == nil) {
+ f = ipfragallo6(ip);
+ f->id = id;
+ memmove(f->src, src, IPaddrlen);
+ memmove(f->dst, dst, IPaddrlen);
+
+ f->blist = bp;
+
+ qunlock(&ip->fraglock6);
+ ip->stats[ReasmReqds]++;
+ 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);
+ qunlock(&ip->fraglock6);
+ 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;
+ /* move up ih hdrs */
+ memmove((*l)->rp + ovlap, (*l)->rp, uflen);
+ (*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
+ * with the trailing bit of fraghdr->offsetRM[1] set, we're done.
+ */
+ pktposn = 0;
+ for(bl = f->blist; bl; bl = bl->next) {
+ if(BKFG(bl)->foff != pktposn)
+ break;
+
+ 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; bl = bl->next) {
+ fragsize = BKFG(bl)->flen;
+ len += fragsize;
+ bl->rp += uflen + IP6FHDR;
+ bl->wp = bl->rp + fragsize;
+ }
+
+ bl = f->blist;
+ f->blist = nil;
+ ipfragfree6(ip, f);
+ ih = (Ip6hdr*)(bl->rp);
+ hnputs(ih->ploadlen, len);
+ qunlock(&ip->fraglock6);
+ ip->stats[ReasmOKs]++;
+ return bl;
+ }
+ pktposn += BKFG(bl)->flen;
+ }
+ qunlock(&ip->fraglock6);
+ return nil;
+}
+
A ip/ipv6.h => ip/ipv6.h +182 -0
@@ 0,0 1,182 @@
+#define MIN(a, b) ((a) <= (b) ? (a) : (b))
+#define isv6mcast(addr) ((addr)[0] == 0xff)
+#define islinklocal(addr) ( ((addr)[0] == 0xfe) && ((addr)[1] == 0x80) )
+#define issitelocal(addr) ( ((addr)[0] == 0xfe) && ((addr)[1] == 0xc0) )
+#define isv6global(addr) ( (addr)[0] == 0x2 )
+#define optexsts(np) (nhgets((np)->ploadlen) > 24)
+#define issmcast(addr) (memcmp((addr), v6solicitednode, 13) == 0)
+
+/* from RFC 2460 */
+
+typedef struct Ip6hdr Ip6hdr;
+typedef struct Opthdr Opthdr;
+typedef struct Routinghdr Routinghdr;
+typedef struct Fraghdr6 Fraghdr6;
+
+struct Ip6hdr {
+ uchar vcf[4]; // version:4, traffic class:8, flow label:20
+ uchar ploadlen[2]; // payload length: packet length - 40
+ uchar proto; // next header type
+ uchar ttl; // hop limit
+ uchar src[IPaddrlen];
+ uchar dst[IPaddrlen];
+};
+
+struct Opthdr {
+ uchar nexthdr;
+ uchar len;
+};
+
+struct Routinghdr {
+ uchar nexthdr;
+ uchar len;
+ uchar rtetype;
+ uchar segrem;
+};
+
+struct Fraghdr6 {
+ uchar nexthdr;
+ uchar res;
+ uchar offsetRM[2]; // Offset, Res, M flag
+ uchar id[4];
+};
+
+
+enum { /* Header Types */
+ HBH = 0, //?
+ ICMP = 1,
+ IGMP = 2,
+ GGP = 3,
+ IPINIP = 4,
+ ST = 5,
+ TCP = 6,
+ UDP = 17,
+ ISO_TP4 = 29,
+ RH = 43,
+ FH = 44,
+ IDRP = 45,
+ RSVP = 46,
+ AH = 51,
+ ESP = 52,
+ ICMPv6 = 58,
+ NNH = 59,
+ DOH = 60,
+ ISO_IP = 80,
+ IGRP = 88,
+ OSPF = 89,
+
+ Maxhdrtype = 256,
+};
+
+
+enum {
+ // multicast flgs and scop
+
+ well_known_flg = 0,
+ transient_flg = 1,
+
+ node_local_scop = 1,
+ link_local_scop = 2,
+ site_local_scop = 5,
+ org_local_scop = 8,
+ global_scop = 14,
+
+ // various prefix lengths
+
+ SOLN_PREF_LEN = 13,
+
+ // icmpv6 unreach codes
+ icmp6_no_route = 0,
+ icmp6_ad_prohib = 1,
+ icmp6_unassigned = 2,
+ icmp6_adr_unreach = 3,
+ icmp6_port_unreach = 4,
+ icmp6_unkn_code = 5,
+
+ // various flags & constants
+
+ v6MINTU = 1280,
+ HOP_LIMIT = 255,
+ ETHERHDR_LEN = 14,
+ IPV6HDR_LEN = 40,
+ IPV4HDR_LEN = 20,
+
+ // option types
+
+ SRC_LLADDRESS = 1,
+ TARGET_LLADDRESS = 2,
+ PREFIX_INFO = 3,
+ REDIR_HEADER = 4,
+ MTU_OPTION = 5,
+
+ SRC_UNSPEC = 0,
+ SRC_UNI = 1,
+ TARG_UNI = 2,
+ TARG_MULTI = 3,
+
+ t_unitent = 1,
+ t_uniproxy = 2,
+ t_unirany = 3,
+
+ // Router constants (all times in milliseconds)
+
+ MAX_INITIAL_RTR_ADVERT_INTERVAL = 16000,
+ MAX_INITIAL_RTR_ADVERTISEMENTS = 3,
+ MAX_FINAL_RTR_ADVERTISEMENTS = 3,
+ MIN_DELAY_BETWEEN_RAS = 3000,
+ MAX_RA_DELAY_TIME = 500,
+
+ // Host constants
+
+ MAX_RTR_SOLICITATION_DELAY = 1000,
+ RTR_SOLICITATION_INTERVAL = 4000,
+ MAX_RTR_SOLICITATIONS = 3,
+
+ // Node constants
+
+ MAX_MULTICAST_SOLICIT = 3,
+ MAX_UNICAST_SOLICIT = 3,
+ MAX_ANYCAST_DELAY_TIME = 1000,
+ MAX_NEIGHBOR_ADVERTISEMENT = 3,
+ REACHABLE_TIME = 30000,
+ RETRANS_TIMER = 1000,
+ DELAY_FIRST_PROBE_TIME = 5000,
+
+};
+
+extern void ipv62smcast(uchar *, uchar *);
+extern void icmpns(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac);
+extern void icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags);
+extern void icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp);
+extern void icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp);
+extern void icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free);
+
+extern uchar v6allnodesN[IPaddrlen];
+extern uchar v6allnodesL[IPaddrlen];
+extern uchar v6allroutersN[IPaddrlen];
+extern uchar v6allroutersL[IPaddrlen];
+extern uchar v6allnodesNmask[IPaddrlen];
+extern uchar v6allnodesLmask[IPaddrlen];
+extern uchar v6allroutersS[IPaddrlen];
+extern uchar v6solicitednode[IPaddrlen];
+extern uchar v6solicitednodemask[IPaddrlen];
+extern uchar v6Unspecified[IPaddrlen];
+extern uchar v6loopback[IPaddrlen];
+extern uchar v6loopbackmask[IPaddrlen];
+extern uchar v6linklocal[IPaddrlen];
+extern uchar v6linklocalmask[IPaddrlen];
+extern uchar v6sitelocal[IPaddrlen];
+extern uchar v6sitelocalmask[IPaddrlen];
+extern uchar v6glunicast[IPaddrlen];
+extern uchar v6multicast[IPaddrlen];
+extern uchar v6multicastmask[IPaddrlen];
+
+extern int v6linklocalprefix;
+extern int v6sitelocalprefix;
+extern int v6loopbackprefix;
+extern int v6multicastprefix;
+extern int v6solicitednodeprefix;
+extern int v6allnodesNprefix;
+extern int v6allnodesLprefix;
+
+extern int ReTransTimer;
M ip/loopbackmedium.c => ip/loopbackmedium.c +1 -1
@@ 94,7 94,7 @@ loopbackread(void *a)
if(ifc->lifc == nil)
freeb(bp);
else
- ipiput(lb->f, ifc, bp);
+ ipiput4(lb->f, ifc, bp);
runlock(ifc);
poperror();
}
M ip/netdevmedium.c => ip/netdevmedium.c +1 -1
@@ 140,7 140,7 @@ ZZZ is this a good idea?
if(ifc->lifc == nil)
freeb(bp);
else
- ipiput(er->f, ifc, bp);
+ ipiput4(er->f, ifc, bp);
runlock(ifc);
poperror();
}
M ip/netlog.c => ip/netlog.c +1 -1
@@ 207,7 207,7 @@ netlogctl(Fs *f, char* s, int n)
cmderror(cb, "unknown ip control message");
}
- for(i = 1; i < cb->nf; i++){
+ for(i = 1; i < n; i++){
for(fp = flags; fp->name; fp++)
if(strcmp(fp->name, cb->f[i]) == 0)
break;
M ip/pktmedium.c => ip/pktmedium.c +1 -1
@@ 64,7 64,7 @@ pktin(Fs *f, Ipifc *ifc, Block *bp)
if(ifc->lifc == nil)
freeb(bp);
else
- ipiput(f, ifc, bp);
+ ipiput4(f, ifc, bp);
}
void
M ip/rudp.c => ip/rudp.c +3 -1
@@ 321,7 321,7 @@ doipoput(Conv *c, Fs *f, Block *bp, int x, int ttl, int tos)
if(ucb->randdrop && nrand(100) < ucb->randdrop)
freeblist(bp);
else
- ipoput(f, bp, x, ttl, tos);
+ ipoput4(f, bp, x, ttl, tos);
}
int
@@ 402,6 402,7 @@ rudpkick(Conv *c)
return;
uh = (Udphdr *)(bp->rp);
+ uh->vihl = IP_VER4;
rh = (Rudphdr*)uh;
@@ 987,6 988,7 @@ relsendack(Conv *c, Reliable *r, int hangup)
bp->wp += UDP_IPHDR + UDP_RHDRSIZE;
f = c->p->f;
uh = (Udphdr *)(bp->rp);
+ uh->vihl = IP_VER4;
rh = (Rudphdr*)uh;
ptcllen = (UDP_RHDRSIZE-UDP_PHDRSIZE);
M ip/tcp.c => ip/tcp.c +454 -189
@@ 11,13 11,21 @@ enum
{
QMAX = 64*1024-1,
IP_TCPPROTO = 6,
- TCP_IPLEN = 8,
- TCP_PHDRSIZE = 12,
- TCP_HDRSIZE = 20,
- TCP_TCBPHDRSZ = 40,
- TCP_PKT = TCP_IPLEN+TCP_PHDRSIZE,
+
+ TCP4_IPLEN = 8,
+ TCP4_PHDRSIZE = 12,
+ TCP4_HDRSIZE = 20,
+ TCP4_TCBPHDRSZ = 40,
+ TCP4_PKT = TCP4_IPLEN+TCP4_PHDRSIZE,
+
+ TCP6_IPLEN = 0,
+ TCP6_PHDRSIZE = 40,
+ TCP6_HDRSIZE = 20,
+ TCP6_TCBPHDRSZ = 60,
+ TCP6_PKT = TCP6_IPLEN+TCP6_PHDRSIZE,
+
TcptimerOFF = 0,
- TcptimerON = 1,
+ TcptimerON = 1,
TcptimerDONE = 2,
MAX_TIME = (1<<20), /* Forever */
TCP_ACK = 200, /* Timed ack sequence in ms */
@@ 37,6 45,7 @@ enum
MSL2 = 10,
MSPTICK = 50, /* Milliseconds per timer tick */
DEF_MSS = 1460, /* Default mean segment */
+ DEF_MSS6 = 1280, /* Default mean segment (min) for v6 */
DEF_RTT = 500, /* Default round trip */
DEF_KAT = 30000, /* Default time ms) between keep alives */
TCP_LISTEN = 0, /* Listen connection */
@@ 86,8 95,8 @@ struct Tcptimer
void *arg;
};
-typedef struct Tcphdr Tcphdr;
-struct Tcphdr
+typedef struct Tcp4hdr Tcp4hdr;
+struct Tcp4hdr
{
uchar vihl; /* Version and header length */
uchar tos; /* Type of service */
@@ 112,6 121,29 @@ struct Tcphdr
uchar tcpmss[2];
};
+typedef struct Tcp6hdr Tcp6hdr;
+struct Tcp6hdr
+{
+ uchar vcf[4];
+ uchar ploadlen[2];
+ uchar proto;
+ uchar ttl;
+ uchar tcpsrc[IPaddrlen];
+ uchar tcpdst[IPaddrlen];
+ uchar tcpsport[2];
+ uchar tcpdport[2];
+ uchar tcpseq[4];
+ uchar tcpack[4];
+ uchar tcpflag[2];
+ uchar tcpwin[2];
+ uchar tcpcksum[2];
+ uchar tcpurg[2];
+ /* Options segment */
+ uchar tcpopt[2];
+ uchar tcpmss[2];
+};
+
+
typedef struct Tcp Tcp;
struct Tcp
{
@@ 123,13 155,13 @@ struct Tcp
ushort wnd;
ushort urg;
ushort mss;
- ushort len; /* size of data */
+ ushort len; /* size of data */
};
typedef struct Reseq Reseq;
struct Reseq
{
- Reseq *next;
+ Reseq *next;
Tcp seg;
Block *bp;
ushort length;
@@ 148,14 180,13 @@ struct Tcpctl
ulong una; /* Unacked data pointer */
ulong nxt; /* Next sequence expected */
ulong ptr; /* Data pointer */
- ushort wnd; /* Tcp send window */
+ ushort wnd; /* Tcp send window */
ulong urg; /* Urgent data pointer */
ulong wl2;
-
- /* to implement tahoe and reno TCP */
- ulong dupacks; /* number of duplicate acks rcvd */
- int recovery; /* loss recovery flag */
- ulong rxt; /* right window marker for recovery */
+ /* to implement tahoe and reno TCP */
+ ulong dupacks; /* number of duplicate acks rcvd */
+ int recovery; /* loss recovery flag */
+ ulong rxt; /* right window marker for recovery */
} snd;
struct {
ulong nxt; /* Receive pointer to next uchar slot */
@@ 190,7 221,10 @@ struct Tcpctl
int nochecksum; /* non-zero means don't send checksums */
int flgcnt; /* 1 when we're waiting for a SYN/FIN ACK */
- Tcphdr protohdr; /* prototype header */
+ union {
+ Tcp4hdr tcp4hdr;
+ Tcp6hdr tcp6hdr;
+ } protohdr; /* prototype header */
};
int tcp_irtt = DEF_RTT; /* Initial guess at round trip time */
@@ 241,7 275,7 @@ static char *statnames[] =
typedef struct Tcppriv Tcppriv;
struct Tcppriv
{
- Tcptimer *timers; /* List of active timers */
+ Tcptimer *timers; /* List of active timers */
QLock tl; /* Protect timer list */
Rendez tcpr; /* used by tcpackproc */
@@ 642,22 676,28 @@ tcpmtu(Conv *s)
{
Ipifc *ifc;
int mtu;
+ int version = (isv4(s->raddr) && isv4(s->laddr)) ? 4 : 6;
mtu = 0;
ifc = findipifc(s->p->f, s->raddr, 0);
- if(ifc != nil)
- mtu = ifc->maxmtu - ifc->m->hsize - (TCP_PKT + TCP_HDRSIZE);
- if(mtu < 4)
- mtu = DEF_MSS;
- return restrict_mtu(s->raddr, mtu);
+ if(ifc != nil) {
+ if(version == 4)
+ mtu = ifc->maxmtu - ifc->m->hsize - (TCP4_PKT + TCP4_HDRSIZE);
+ else
+ mtu = ifc->maxmtu - ifc->m->hsize - (TCP6_PKT + TCP6_HDRSIZE);
+ }
+
+ if(mtu < 32) {
+ mtu = 1280;
+ }
+
+ return mtu;
}
void
inittcpctl(Conv *s, int mode)
{
Tcpctl *tcb;
- Tcphdr *h;
-
tcb = (Tcpctl*)s->ptcl;
memset(tcb, 0, sizeof(Tcpctl));
@@ 682,13 722,26 @@ inittcpctl(Conv *s, int mode)
if(mode != TCP_LISTEN)
if(ipcmp(s->laddr, IPnoaddr) == 0)
findlocalip(s->p->f, s->laddr, s->raddr);
- h = &tcb->protohdr;
- memset(h, 0, sizeof(*h));
- h->proto = IP_TCPPROTO;
- hnputs(h->tcpsport, s->lport);
- hnputs(h->tcpdport, s->rport);
- v6tov4(h->tcpsrc, s->laddr);
- v6tov4(h->tcpdst, s->raddr);
+
+// if(isv4(s->raddr)) {
+ if(memcmp(s->raddr, v4prefix, IPv4off) == 0 &&
+ memcmp(s->laddr, v4prefix, IPv4off) == 0) {
+ Tcp4hdr* h4 = &tcb->protohdr.tcp4hdr;
+ memset(h4, 0, sizeof(*h4));
+ h4->proto = IP_TCPPROTO;
+ hnputs(h4->tcpsport, s->lport);
+ hnputs(h4->tcpdport, s->rport);
+ v6tov4(h4->tcpsrc, s->laddr);
+ v6tov4(h4->tcpdst, s->raddr);
+ } else {
+ Tcp6hdr* h6 = &tcb->protohdr.tcp6hdr;
+ memset(h6, 0, sizeof(*h6));
+ h6->proto = IP_TCPPROTO;
+ hnputs(h6->tcpsport, s->lport);
+ hnputs(h6->tcpdport, s->rport);
+ ipmove(h6->tcpsrc, s->laddr);
+ ipmove(h6->tcpdst, s->raddr);
+ }
tcb->mss = tcb->cwind = tcpmtu(s);
}
@@ 763,37 816,41 @@ tcpflag(ushort flag)
}
Block *
-htontcp(Tcp *tcph, Block *data, Tcphdr *ph, Tcpctl *tcb)
+htontcp6(Tcp *tcph, Block *data, Tcp6hdr *ph, Tcpctl *tcb)
{
int dlen;
- Tcphdr *h;
+ Tcp6hdr *h;
ushort csum;
ushort hdrlen;
- hdrlen = TCP_HDRSIZE;
+ hdrlen = TCP6_HDRSIZE;
if(tcph->mss)
hdrlen += MSS_LENGTH;
if(data) {
dlen = blocklen(data);
- data = padblock(data, hdrlen + TCP_PKT);
+ data = padblock(data, hdrlen + TCP6_PKT);
if(data == nil)
return nil;
}
else {
dlen = 0;
- data = allocb(hdrlen + TCP_PKT + 64); /* the 64 pad is to meet mintu's */
+ data = allocb(hdrlen + TCP6_PKT + 64); /* the 64 pad is to meet mintu's */
if(data == nil)
return nil;
- data->wp += hdrlen + TCP_PKT;
+ data->wp += hdrlen + TCP6_PKT;
}
/* copy in pseudo ip header plus port numbers */
- h = (Tcphdr *)(data->rp);
- memmove(h, ph, TCP_TCBPHDRSZ);
+ h = (Tcp6hdr *)(data->rp);
+ memmove(h, ph, TCP6_TCBPHDRSZ);
+
+ /* compose pseudo tcp header, do cksum calculation */
+ hnputl(h->vcf, hdrlen + dlen);
+ h->ploadlen[0] = h->ploadlen[1] = h->proto = 0;
+ h->ttl = ph->proto;
/* copy in variable bits */
- hnputs(h->tcplen, hdrlen + dlen);
hnputl(h->tcpseq, tcph->seq);
hnputl(h->tcpack, tcph->ack);
hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags);
@@ 808,39 865,92 @@ htontcp(Tcp *tcph, Block *data, Tcphdr *ph, Tcpctl *tcb)
if(tcb != nil && tcb->nochecksum){
h->tcpcksum[0] = h->tcpcksum[1] = 0;
} else {
- csum = ptclcsum(data, TCP_IPLEN, hdrlen+dlen+TCP_PHDRSIZE);
+ csum = ptclcsum(data, TCP6_IPLEN, hdrlen+dlen+TCP6_PHDRSIZE);
hnputs(h->tcpcksum, csum);
}
-/* netlog(f, Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n",
- tcph->source, tcph->dest,
- tcph->seq, tcph->ack, tcpflag((hdrlen<<10)|tcph->flags),
- tcph->wnd, dlen); */
+ /* move from pseudo header back to normal ip header */
+ memset(h->vcf, 0, 4);
+ h->vcf[0] = IP_VER6;
+ hnputs(h->ploadlen, hdrlen+dlen);
+ h->proto = ph->proto;
+
+ return data;
+}
+
+Block *
+htontcp4(Tcp *tcph, Block *data, Tcp4hdr *ph, Tcpctl *tcb)
+{
+ int dlen;
+ Tcp4hdr *h;
+ ushort csum;
+ ushort hdrlen;
+
+ hdrlen = TCP4_HDRSIZE;
+ if(tcph->mss)
+ hdrlen += MSS_LENGTH;
+
+ if(data) {
+ dlen = blocklen(data);
+ data = padblock(data, hdrlen + TCP4_PKT);
+ if(data == nil)
+ return nil;
+ }
+ else {
+ dlen = 0;
+ data = allocb(hdrlen + TCP4_PKT + 64); /* the 64 pad is to meet mintu's */
+ if(data == nil)
+ return nil;
+ data->wp += hdrlen + TCP4_PKT;
+ }
+
+ /* copy in pseudo ip header plus port numbers */
+ h = (Tcp4hdr *)(data->rp);
+ memmove(h, ph, TCP4_TCBPHDRSZ);
+
+ /* copy in variable bits */
+ hnputs(h->tcplen, hdrlen + dlen);
+ hnputl(h->tcpseq, tcph->seq);
+ hnputl(h->tcpack, tcph->ack);
+ hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags);
+ hnputs(h->tcpwin, tcph->wnd);
+ hnputs(h->tcpurg, tcph->urg);
+
+ if(tcph->mss != 0){
+ h->tcpopt[0] = MSSOPT;
+ h->tcpopt[1] = MSS_LENGTH;
+ hnputs(h->tcpmss, tcph->mss);
+ }
+ if(tcb != nil && tcb->nochecksum){
+ h->tcpcksum[0] = h->tcpcksum[1] = 0;
+ } else {
+ csum = ptclcsum(data, TCP4_IPLEN, hdrlen+dlen+TCP4_PHDRSIZE);
+ hnputs(h->tcpcksum, csum);
+ }
return data;
}
int
-ntohtcp(Tcp *tcph, Block **bpp)
+ntohtcp6(Tcp *tcph, Block **bpp)
{
- Tcphdr *h;
+ Tcp6hdr *h;
uchar *optr;
ushort hdrlen;
ushort optlen;
int n;
- *bpp = pullupblock(*bpp, TCP_PKT+TCP_HDRSIZE);
+ *bpp = pullupblock(*bpp, TCP6_PKT+TCP6_HDRSIZE);
if(*bpp == nil)
return -1;
- h = (Tcphdr *)((*bpp)->rp);
+ h = (Tcp6hdr *)((*bpp)->rp);
tcph->source = nhgets(h->tcpsport);
tcph->dest = nhgets(h->tcpdport);
tcph->seq = nhgetl(h->tcpseq);
tcph->ack = nhgetl(h->tcpack);
-
hdrlen = (h->tcpflag[0] & 0xf0)>>2;
- if(hdrlen < TCP_HDRSIZE) {
+ if(hdrlen < TCP6_HDRSIZE) {
freeblist(*bpp);
return -1;
}
@@ 849,19 959,72 @@ ntohtcp(Tcp *tcph, Block **bpp)
tcph->wnd = nhgets(h->tcpwin);
tcph->urg = nhgets(h->tcpurg);
tcph->mss = 0;
- tcph->len = nhgets(h->length) - (hdrlen + TCP_PKT);
+ tcph->len = nhgets(h->ploadlen) - hdrlen;
- *bpp = pullupblock(*bpp, hdrlen+TCP_PKT);
+ *bpp = pullupblock(*bpp, hdrlen+TCP6_PKT);
if(*bpp == nil)
return -1;
-/* netlog(Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n",
- tcph->source, tcph->dest,
- tcph->seq, tcph->ack, tcpflag((hdrlen<<10)|tcph->flags),
- tcph->wnd, nhgets(h->length)-hdrlen-TCP_PKT); */
+ optr = h->tcpopt;
+ n = hdrlen - TCP6_HDRSIZE;
+ while(n > 0 && *optr != EOLOPT) {
+ if(*optr == NOOPOPT) {
+ n--;
+ optr++;
+ continue;
+ }
+ optlen = optr[1];
+ if(optlen < 2 || optlen > n)
+ break;
+ switch(*optr) {
+ case MSSOPT:
+ if(optlen == MSS_LENGTH)
+ tcph->mss = nhgets(optr+2);
+ break;
+ }
+ n -= optlen;
+ optr += optlen;
+ }
+ return hdrlen;
+}
+
+int
+ntohtcp4(Tcp *tcph, Block **bpp)
+{
+ Tcp4hdr *h;
+ uchar *optr;
+ ushort hdrlen;
+ ushort optlen;
+ int n;
+
+ *bpp = pullupblock(*bpp, TCP4_PKT+TCP4_HDRSIZE);
+ if(*bpp == nil)
+ return -1;
+
+ h = (Tcp4hdr *)((*bpp)->rp);
+ tcph->source = nhgets(h->tcpsport);
+ tcph->dest = nhgets(h->tcpdport);
+ tcph->seq = nhgetl(h->tcpseq);
+ tcph->ack = nhgetl(h->tcpack);
+
+ hdrlen = (h->tcpflag[0] & 0xf0)>>2;
+ if(hdrlen < TCP4_HDRSIZE) {
+ freeblist(*bpp);
+ return -1;
+ }
+
+ tcph->flags = h->tcpflag[1];
+ tcph->wnd = nhgets(h->tcpwin);
+ tcph->urg = nhgets(h->tcpurg);
+ tcph->mss = 0;
+ tcph->len = nhgets(h->length) - (hdrlen + TCP4_PKT);
+
+ *bpp = pullupblock(*bpp, hdrlen+TCP4_PKT);
+ if(*bpp == nil)
+ return -1;
optr = h->tcpopt;
- n = hdrlen - TCP_HDRSIZE;
+ n = hdrlen - TCP4_HDRSIZE;
while(n > 0 && *optr != EOLOPT) {
if(*optr == NOOPOPT) {
n--;
@@ 871,7 1034,6 @@ ntohtcp(Tcp *tcph, Block **bpp)
optlen = optr[1];
if(optlen < 2 || optlen > n)
break;
-if(0) print("tcpopt %d %d\n", *optr, optlen);
switch(*optr) {
case MSSOPT:
if(optlen == MSS_LENGTH)
@@ 899,17 1061,14 @@ tcpsndsyn(Tcpctl *tcb)
tcb->sndsyntime = msec;
}
-
-/*
- * called with v4 (4 byte) addresses
- */
void
-sndrst(Proto *tcp, uchar *source, uchar *dest, ushort length, Tcp *seg)
+sndrst(Proto *tcp, uchar *source, uchar *dest, ushort length, Tcp *seg, int version)
{
- Tcphdr ph;
Block *hbp;
uchar rflags;
Tcppriv *tpriv;
+ Tcp4hdr ph4;
+ Tcp6hdr ph6;
tpriv = tcp->priv;
@@ 917,13 1076,26 @@ sndrst(Proto *tcp, uchar *source, uchar *dest, ushort length, Tcp *seg)
return;
/* make pseudo header */
- memset(&ph, 0, sizeof(ph));
- v6tov4(ph.tcpsrc, dest);
- v6tov4(ph.tcpdst, source);
- ph.proto = IP_TCPPROTO;
- hnputs(ph.tcplen, TCP_HDRSIZE);
- hnputs(ph.tcpsport, seg->dest);
- hnputs(ph.tcpdport, seg->source);
+ if(version == 4) {
+ memset(&ph4, 0, sizeof(ph4));
+ ph4.vihl = IP_VER4;
+ v6tov4(ph4.tcpsrc, dest);
+ v6tov4(ph4.tcpdst, source);
+ ph4.proto = IP_TCPPROTO;
+ hnputs(ph4.tcplen, TCP4_HDRSIZE);
+ hnputs(ph4.tcpsport, seg->dest);
+ hnputs(ph4.tcpdport, seg->source);
+ }
+ else {
+ memset(&ph6, 0, sizeof(ph6));
+ ph6.vcf[0] = IP_VER6;
+ ipmove(ph6.tcpsrc, dest);
+ ipmove(ph6.tcpdst, source);
+ ph6.proto = IP_TCPPROTO;
+ hnputs(ph6.ploadlen, TCP6_HDRSIZE);
+ hnputs(ph6.tcpsport, seg->dest);
+ hnputs(ph6.tcpdport, seg->source);
+ }
tpriv->stats[OutRsts]++;
rflags = RST;
@@ 947,11 1119,18 @@ sndrst(Proto *tcp, uchar *source, uchar *dest, ushort length, Tcp *seg)
seg->wnd = 0;
seg->urg = 0;
seg->mss = 0;
- hbp = htontcp(seg, nil, &ph, nil);
- if(hbp == nil)
- return;
-
- ipoput(tcp->f, hbp, 0, MAXTTL, DFLTTOS);
+ if(version == 4) {
+ hbp = htontcp4(seg, nil, &ph4, nil);
+ if(hbp == nil)
+ return;
+ ipoput4(tcp->f, hbp, 0, MAXTTL, DFLTTOS);
+ }
+ else {
+ hbp = htontcp6(seg, nil, &ph6, nil);
+ if(hbp == nil)
+ return;
+ ipoput6(tcp->f, hbp, 0, MAXTTL, DFLTTOS);
+ }
}
/*
@@ 963,13 1142,13 @@ tcphangup(Conv *s)
{
Tcp seg;
Tcpctl *tcb;
- Tcphdr ph;
Block *hbp;
tcb = (Tcpctl*)s->ptcl;
if(waserror())
return commonerror();
if(s->raddr != 0) {
+ int version = isv4(s->raddr) ? 4 : 6;
seg.flags = RST | ACK;
seg.ack = tcb->rcv.nxt;
seg.seq = tcb->snd.ptr;
@@ 977,9 1156,16 @@ tcphangup(Conv *s)
seg.urg = 0;
seg.mss = 0;
tcb->last_ack = tcb->rcv.nxt;
- hnputs(ph.tcplen, TCP_HDRSIZE);
- hbp = htontcp(&seg, nil, &tcb->protohdr, tcb);
- ipoput(s->p->f, hbp, 0, s->ttl, s->tos);
+ if(version == 4) {
+ tcb->protohdr.tcp4hdr.vihl = IP_VER4;
+ hbp = htontcp4(&seg, nil, &tcb->protohdr.tcp4hdr, tcb);
+ ipoput4(s->p->f, hbp, 0, s->ttl, s->tos);
+ }
+ else {
+ tcb->protohdr.tcp6hdr.vcf[0] = IP_VER6;
+ hbp = htontcp6(&seg, nil, &tcb->protohdr.tcp6hdr, tcb);
+ ipoput6(s->p->f, hbp, 0, s->ttl, s->tos);
+ }
}
localclose(s, nil);
poperror();
@@ 991,7 1177,6 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst)
{
Conv *new;
Tcpctl *tcb;
- Tcphdr *h;
Tcppriv *tpriv;
new = Fsnewcall(s, src, segp->source, dst, segp->dest);
@@ 1010,13 1195,24 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst)
tcb->rtt_timer.arg = new;
tcb->rtt_timer.state = TcptimerOFF;
- h = &tcb->protohdr;
- memset(h, 0, sizeof(*h));
- h->proto = IP_TCPPROTO;
- hnputs(h->tcpsport, new->lport);
- hnputs(h->tcpdport, new->rport);
- v6tov4(h->tcpsrc, dst);
- v6tov4(h->tcpdst, src);
+ if(isv4(src)) {
+ Tcp4hdr *h = &tcb->protohdr.tcp4hdr;
+ memset(h, 0, sizeof(*h));
+ h->proto = IP_TCPPROTO;
+ hnputs(h->tcpsport, new->lport);
+ hnputs(h->tcpdport, new->rport);
+ v6tov4(h->tcpsrc, dst);
+ v6tov4(h->tcpdst, src);
+ }
+ else {
+ Tcp6hdr *h = &tcb->protohdr.tcp6hdr;
+ memset(h, 0, sizeof(*h));
+ h->proto = IP_TCPPROTO;
+ hnputs(h->tcpsport, new->lport);
+ hnputs(h->tcpdport, new->rport);
+ ipmove(h->tcpsrc, dst);
+ ipmove(h->tcpdst, src);
+ }
tpriv = new->p->priv;
iphtadd(&tpriv->ht, new);
@@ 1195,7 1391,7 @@ update(Conv *s, Tcp *seg)
if(rtt == 0)
rtt = 1; /* otherwise all close systems will rexmit in 0 time */
rtt *= MSPTICK;
- if (tcb->srtt == 0) {
+ if(tcb->srtt == 0) {
tcb->srtt = rtt << LOGAGAIN;
tcb->mdev = rtt << LOGDGAIN;
} else {
@@ 1237,7 1433,8 @@ void
tcpiput(Proto *tcp, Ipifc*, Block *bp)
{
Tcp seg;
- Tcphdr *h;
+ Tcp4hdr *h4;
+ Tcp6hdr *h6;
int hdrlen;
Tcpctl *tcb;
ushort length;
@@ 1245,45 1442,92 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
Conv *s;
Fs *f;
Tcppriv *tpriv;
+ int version;
f = tcp->f;
tpriv = tcp->priv;
tpriv->stats[InSegs]++;
- h = (Tcphdr*)(bp->rp);
-
- length = nhgets(h->length);
- v4tov6(dest, h->tcpdst);
- v4tov6(source, h->tcpsrc);
+ h4 = (Tcp4hdr*)(bp->rp);
+ h6 = (Tcp6hdr*)(bp->rp);
+
+ if((h4->vihl&0xF0)==IP_VER4) {
+ version = 4;
+ length = nhgets(h4->length);
+ v4tov6(dest, h4->tcpdst);
+ v4tov6(source, h4->tcpsrc);
+
+ h4->Unused = 0;
+ hnputs(h4->tcplen, length-TCP4_PKT);
+ if((h4->tcpcksum[0] || h4->tcpcksum[1]) &&
+ ptclcsum(bp, TCP4_IPLEN, length-TCP4_IPLEN)) {
+ tpriv->stats[CsumErrs]++;
+ tpriv->stats[InErrs]++;
+ netlog(f, Logtcp, "bad tcp proto cksum\n");
+ freeblist(bp);
+ return;
+ }
- h->Unused = 0;
- hnputs(h->tcplen, length-TCP_PKT);
- if((h->tcpcksum[0] || h->tcpcksum[1]) &&
- ptclcsum(bp, TCP_IPLEN, length-TCP_IPLEN)) {
- tpriv->stats[CsumErrs]++;
- tpriv->stats[InErrs]++;
- netlog(f, Logtcp, "bad tcp proto cksum\n");
- freeblist(bp);
- return;
- }
+ hdrlen = ntohtcp4(&seg, &bp);
+ if(hdrlen < 0){
+ tpriv->stats[HlenErrs]++;
+ tpriv->stats[InErrs]++;
+ netlog(f, Logtcp, "bad tcp hdr len\n");
+ return;
+ }
- hdrlen = ntohtcp(&seg, &bp);
- if(hdrlen < 0){
- tpriv->stats[HlenErrs]++;
- tpriv->stats[InErrs]++;
- netlog(f, Logtcp, "bad tcp hdr len\n");
- return;
+ /* trim the packet to the size claimed by the datagram */
+ length -= hdrlen+TCP4_PKT;
+ bp = trimblock(bp, hdrlen+TCP4_PKT, length);
+ if(bp == nil){
+ tpriv->stats[LenErrs]++;
+ tpriv->stats[InErrs]++;
+ netlog(f, Logtcp, "tcp len < 0 after trim\n");
+ return;
+ }
}
+ else {
+ int ttl = h6->ttl;
+ int proto = h6->proto;
+
+ version = 6;
+ length = nhgets(h6->ploadlen);
+ ipmove(dest, h6->tcpdst);
+ ipmove(source, h6->tcpsrc);
+
+ h6->ploadlen[0] = h6->ploadlen[1] = h6->proto = 0;
+ h6->ttl = proto;
+ hnputl(h6->vcf, length);
+ if((h6->tcpcksum[0] || h6->tcpcksum[1]) &&
+ ptclcsum(bp, TCP6_IPLEN, length+TCP6_PHDRSIZE)) {
+ tpriv->stats[CsumErrs]++;
+ tpriv->stats[InErrs]++;
+ netlog(f, Logtcp, "bad tcp proto cksum\n");
+ freeblist(bp);
+ return;
+ }
+ h6->ttl = ttl;
+ h6->proto = proto;
+ hnputs(h6->ploadlen, length);
+
+ hdrlen = ntohtcp6(&seg, &bp);
+ if(hdrlen < 0){
+ tpriv->stats[HlenErrs]++;
+ tpriv->stats[InErrs]++;
+ netlog(f, Logtcp, "bad tcp hdr len\n");
+ return;
+ }
- /* trim the packet to the size claimed by the datagram */
- length -= hdrlen+TCP_PKT;
- bp = trimblock(bp, hdrlen+TCP_PKT, length);
- if(bp == nil){
- tpriv->stats[LenErrs]++;
- tpriv->stats[InErrs]++;
- netlog(f, Logtcp, "tcp len < 0 after trim\n");
- return;
+ /* trim the packet to the size claimed by the datagram */
+ length -= hdrlen;
+ bp = trimblock(bp, hdrlen+TCP6_PKT, length);
+ if(bp == nil){
+ tpriv->stats[LenErrs]++;
+ tpriv->stats[InErrs]++;
+ netlog(f, Logtcp, "tcp len < 0 after trim\n");
+ return;
+ }
}
/* lock protocol while searching for a conversation */
@@ 1294,7 1538,7 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
if(s == nil){
reset:
qunlock(tcp);
- sndrst(tcp, source, dest, length, &seg);
+ sndrst(tcp, source, dest, length, &seg, version);
freeblist(bp);
return;
}
@@ 1334,7 1578,7 @@ reset:
switch(tcb->state) {
case Closed:
- sndrst(tcp, source, dest, length, &seg);
+ sndrst(tcp, source, dest, length, &seg, version);
goto raise;
case Listen:
if(seg.flags & SYN) {
@@ 1349,7 1593,7 @@ reset:
case Syn_sent:
if(seg.flags & ACK) {
if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) {
- sndrst(tcp, source, dest, length, &seg);
+ sndrst(tcp, source, dest, length, &seg, version);
goto raise;
}
}
@@ 1413,7 1657,7 @@ reset:
/* Cannot accept so answer with a rst */
if(length && tcb->state == Closed) {
- sndrst(tcp, source, dest, length, &seg);
+ sndrst(tcp, source, dest, length, &seg, version);
goto raise;
}
@@ 1448,7 1692,7 @@ reset:
switch(tcb->state) {
case Syn_received:
if(!seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){
- sndrst(tcp, source, dest, length, &seg);
+ sndrst(tcp, source, dest, length, &seg, version);
goto raise;
}
update(s, &seg);
@@ 1556,7 1800,7 @@ reset:
/* no process to read the data, send a reset */
if(bp != nil)
freeblist(bp);
- sndrst(tcp, source, dest, length, &seg);
+ sndrst(tcp, source, dest, length, &seg, version);
qunlock(s);
poperror();
return;
@@ 1649,6 1893,15 @@ tcpoutput(Conv *s)
ulong ssize, dsize, usable, sent;
Fs *f;
Tcppriv *tpriv;
+ //int version = isv4(s->raddr) ? 4 : 6;
+ int version;
+
+ if( (memcmp(s->raddr, v4prefix, IPv4off) == 0 &&
+ memcmp(s->laddr, v4prefix, IPv4off) == 0)
+ || ipcmp(s->raddr, IPnoaddr) == 0)
+ version = 4;
+ else
+ version = 6;
f = s->p->f;
tpriv = s->p->priv;
@@ 1681,7 1934,7 @@ tcpoutput(Conv *s)
*/
if(tcb->snd.wnd == 0){
if(sent != 0) {
- if ((tcb->flags&FORCE) == 0)
+ if((tcb->flags&FORCE) == 0)
break;
tcb->snd.ptr = tcb->snd.una;
}
@@ 1755,8 2008,6 @@ tcpoutput(Conv *s)
seg.flags |= FIN;
dsize--;
}
-/* netlog(f, Logtcp, "qcopy: dlen %d blen %d sndcnt %d qlen %d sent %d rp[0] %d\n",
- dsize, BLEN(bp), sndcnt, qlen(s->wq), sent, bp->rp[0]); */
}
if(sent+dsize == sndcnt)
@@ 1782,10 2033,21 @@ tcpoutput(Conv *s)
tcb->snd.nxt = tcb->snd.ptr;
/* Build header, link data and compute cksum */
- hbp = htontcp(&seg, bp, &tcb->protohdr, tcb);
- if(hbp == nil) {
- freeblist(bp);
- return;
+ if(version == 4) {
+ tcb->protohdr.tcp4hdr.vihl = IP_VER4;
+ hbp = htontcp4(&seg, bp, &tcb->protohdr.tcp4hdr, tcb);
+ if(hbp == nil) {
+ freeblist(bp);
+ return;
+ }
+ }
+ else {
+ tcb->protohdr.tcp6hdr.vcf[0] = IP_VER6;
+ hbp = htontcp6(&seg, bp, &tcb->protohdr.tcp6hdr, tcb);
+ if(hbp == nil) {
+ freeblist(bp);
+ return;
+ }
}
/* Start the transmission timers if there is new data and we
@@ 1814,7 2076,10 @@ tcpoutput(Conv *s)
qlock(s);
nexterror();
}
- ipoput(f, hbp, 0, s->ttl, s->tos);
+ if(version == 4)
+ ipoput4(f, hbp, 0, s->ttl, s->tos);
+ else
+ ipoput6(f, hbp, 0, s->ttl, s->tos);
qlock(s);
poperror();
}
@@ 1832,7 2097,6 @@ tcpsendka(Conv *s)
tcb = (Tcpctl*)s->ptcl;
-
dbp = nil;
seg.urg = 0;
seg.source = s->lport;
@@ 1850,14 2114,26 @@ tcpsendka(Conv *s)
dbp->wp++;
}
- /* Build header, link data and compute cksum */
- hbp = htontcp(&seg, dbp, &tcb->protohdr, tcb);
- if(hbp == nil) {
- freeblist(dbp);
- return;
+ if(isv4(s->raddr)) {
+ /* Build header, link data and compute cksum */
+ tcb->protohdr.tcp4hdr.vihl = IP_VER4;
+ hbp = htontcp4(&seg, dbp, &tcb->protohdr.tcp4hdr, tcb);
+ if(hbp == nil) {
+ freeblist(dbp);
+ return;
+ }
+ ipoput4(s->p->f, hbp, 0, s->ttl, s->tos);
+ }
+ else {
+ /* Build header, link data and compute cksum */
+ tcb->protohdr.tcp6hdr.vcf[0] = IP_VER6;
+ hbp = htontcp6(&seg, dbp, &tcb->protohdr.tcp6hdr, tcb);
+ if(hbp == nil) {
+ freeblist(dbp);
+ return;
+ }
+ ipoput6(s->p->f, hbp, 0, s->ttl, s->tos);
}
-
- ipoput(s->p->f, hbp, 0, s->ttl, s->tos);
}
/*
@@ 2133,7 2409,7 @@ tcptrim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
seg->flags &= ~SYN;
seg->seq++;
- if (seg->urg > 1)
+ if(seg->urg > 1)
seg->urg--;
else
seg->flags &= ~URG;
@@ 2144,7 2420,7 @@ tcptrim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
seg->seq += dupcnt;
*length -= dupcnt;
- if (seg->urg > dupcnt)
+ if(seg->urg > dupcnt)
seg->urg -= dupcnt;
else {
seg->flags &= ~URG;
@@ 2167,61 2443,50 @@ tcptrim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
void
tcpadvise(Proto *tcp, Block *bp, char *msg)
{
- Tcphdr *h;
+ Tcp4hdr *h4;
+ Tcp6hdr *h6;
Tcpctl *tcb;
uchar source[IPaddrlen];
uchar dest[IPaddrlen];
ushort psource, pdest;
Conv *s, **p;
- h = (Tcphdr*)(bp->rp);
+ h4 = (Tcp4hdr*)(bp->rp);
+ h6 = (Tcp6hdr*)(bp->rp);
- v4tov6(dest, h->tcpdst);
- v4tov6(source, h->tcpsrc);
- psource = nhgets(h->tcpsport);
- pdest = nhgets(h->tcpdport);
+ if((h4->vihl&0xF0)==IP_VER4) {
+ v4tov6(dest, h4->tcpdst);
+ v4tov6(source, h4->tcpsrc);
+ psource = nhgets(h4->tcpsport);
+ pdest = nhgets(h4->tcpdport);
+ }
+ else {
+ ipmove(dest, h6->tcpdst);
+ ipmove(source, h6->tcpsrc);
+ psource = nhgets(h6->tcpsport);
+ pdest = nhgets(h6->tcpdport);
+ }
/* Look for a connection */
qlock(tcp);
- if(strcmp(msg, "unfragmentable") == 0){
- for(p = tcp->conv; *p; p++) {
- s = *p;
- tcb = (Tcpctl*)s->ptcl;
- if(tcb->state != Closed)
- if(ipcmp(s->raddr, dest) == 0)
- if(ipcmp(s->laddr, source) == 0){
- qlock(s);
- qunlock(tcp);
- switch(tcb->state){
- case Syn_sent:
- localclose(s, msg);
- break;
- }
- qunlock(s);
- freeblist(bp);
- return;
- }
- }
- } else {
- for(p = tcp->conv; *p; p++) {
- s = *p;
- tcb = (Tcpctl*)s->ptcl;
- if(s->rport == pdest)
- if(s->lport == psource)
- if(tcb->state != Closed)
- if(ipcmp(s->raddr, dest) == 0)
- if(ipcmp(s->laddr, source) == 0){
- qlock(s);
- qunlock(tcp);
- switch(tcb->state){
- case Syn_sent:
- localclose(s, msg);
- break;
- }
- qunlock(s);
- freeblist(bp);
- return;
+ for(p = tcp->conv; *p; p++) {
+ s = *p;
+ tcb = (Tcpctl*)s->ptcl;
+ if(s->rport == pdest)
+ if(s->lport == psource)
+ if(tcb->state != Closed)
+ if(ipcmp(s->raddr, dest) == 0)
+ if(ipcmp(s->laddr, source) == 0){
+ qlock(s);
+ qunlock(tcp);
+ switch(tcb->state){
+ case Syn_sent:
+ localclose(s, msg);
+ break;
}
+ qunlock(s);
+ freeblist(bp);
+ return;
}
}
qunlock(tcp);
M ip/tripmedium.c => ip/tripmedium.c +1 -1
@@ 142,7 142,7 @@ tripread(void *a)
for(;;) {
bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxmtu, 0);
ifc->in++;
- ipiput(er->fs, ifc, bp);
+ ipiput4(er->fs, ifc, bp);
}
pexit("hangup", 1);
M ip/udp.c => ip/udp.c +220 -78
@@ 6,14 6,22 @@
#include "../port/error.h"
#include "ip.h"
+#include "ipv6.h"
+
#define DPRINT if(0)print
enum
{
- UDP_PHDRSIZE = 12,
- UDP_HDRSIZE = 20,
- UDP_IPHDR = 8,
+ UDP_UDPHDR_SZ = 8,
+
+ UDP4_PHDR_OFF = 8,
+ UDP4_PHDR_SZ = 12,
+ UDP4_IPHDR_SZ = 20,
+ UDP6_IPHDR_SZ = 40,
+ UDP6_PHDR_SZ = 40,
+ UDP6_PHDR_OFF = 0,
+
IP_UDPPROTO = 17,
UDP_USEAD6 = 36,
UDP_USEAD4 = 12,
@@ 23,8 31,8 @@ enum
Udpmaxxmit = 10,
};
-typedef struct Udphdr Udphdr;
-struct Udphdr
+typedef struct Udp4hdr Udp4hdr;
+struct Udp4hdr
{
/* ip header */
uchar vihl; /* Version and header length */
@@ 35,8 43,24 @@ struct Udphdr
uchar Unused;
uchar udpproto; /* Protocol */
uchar udpplen[2]; /* Header plus data length */
- uchar udpsrc[4]; /* Ip source */
- uchar udpdst[4]; /* Ip destination */
+ uchar udpsrc[IPv4addrlen]; /* Ip source */
+ uchar udpdst[IPv4addrlen]; /* Ip destination */
+
+ /* udp header */
+ uchar udpsport[2]; /* Source port */
+ uchar udpdport[2]; /* Destination port */
+ uchar udplen[2]; /* data length */
+ uchar udpcksum[2]; /* Checksum */
+};
+
+typedef struct Udp6hdr Udp6hdr;
+struct Udp6hdr {
+ uchar viclfl[4];
+ uchar len[2];
+ uchar nextheader;
+ uchar hoplimit;
+ uchar udpsrc[IPaddrlen];
+ uchar udpdst[IPaddrlen];
/* udp header */
uchar udpsport[2]; /* Source port */
@@ 68,6 92,8 @@ struct Udppriv
ulong lenerr; /* short packet */
};
+void (*etherprofiler)(char *name, int qlen);
+
/*
* protocol specific part of Conv
*/
@@ 142,12 168,15 @@ udpclose(Conv *c)
ucb = (Udpcb*)c->ptcl;
ucb->headers = 0;
+
+ qunlock(c);
}
void
udpkick(Conv *c)
{
- Udphdr *uh;
+ Udp4hdr *uh4;
+ Udp6hdr *uh6;
ushort rport;
uchar laddr[IPaddrlen], raddr[IPaddrlen];
Block *bp;
@@ 155,6 184,7 @@ udpkick(Conv *c)
int dlen, ptcllen;
Udppriv *upriv;
Fs *f;
+ int version;
upriv = c->p->priv;
f = c->p->f;
@@ 179,7 209,7 @@ udpkick(Conv *c)
if(ipforme(f, laddr) != Runi)
findlocalip(f, laddr, raddr);
rport = nhgets(bp->rp);
- bp->rp += 2+2; /* Igonore local port */
+ bp->rp += 2+2; /* Ignore local port */
break;
case 4:
bp = pullupblock(bp, UDP_USEAD4);
@@ 199,45 229,97 @@ udpkick(Conv *c)
break;
}
- dlen = blocklen(bp);
+ if(ucb->headers == 6) {
+ if(memcmp(laddr, v4prefix, IPv4off) == 0 ||
+ ipcmp(laddr, IPnoaddr) == 0)
+ version = 4;
+ else
+ version = 6;
+ }
+ else if(ucb->headers == 4)
+ version = 4;
+ else {
+ if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
+ memcmp(c->laddr, v4prefix, IPv4off) == 0)
+ || ipcmp(c->raddr, IPnoaddr) == 0)
+ version = 4;
+ else
+ version = 6;
+ }
+ dlen = blocklen(bp);
/* Make space to fit udp & ip header */
- bp = padblock(bp, UDP_IPHDR+UDP_HDRSIZE);
+ if(version == 4)
+ bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);
+ else
+ bp = padblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ);
+
if(bp == nil)
return;
- uh = (Udphdr *)(bp->rp);
-
- ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE);
- uh->Unused = 0;
- uh->udpproto = IP_UDPPROTO;
- uh->frag[0] = 0;
- uh->frag[1] = 0;
- hnputs(uh->udpplen, ptcllen);
- switch(ucb->headers){
- case 4:
- case 6:
- v6tov4(uh->udpdst, raddr);
- hnputs(uh->udpdport, rport);
- v6tov4(uh->udpsrc, laddr);
- break;
- default:
- v6tov4(uh->udpdst, c->raddr);
- hnputs(uh->udpdport, c->rport);
- if(ipcmp(c->laddr, IPnoaddr) == 0)
- findlocalip(f, c->laddr, c->raddr);
- v6tov4(uh->udpsrc, c->laddr);
- break;
+ /* fill in pseudo header and compute checksum */
+ if(version == 4)
+ {
+ uh4 = (Udp4hdr *)(bp->rp);
+ ptcllen = dlen + UDP_UDPHDR_SZ;
+ uh4->Unused = 0;
+ uh4->udpproto = IP_UDPPROTO;
+ uh4->frag[0] = 0;
+ uh4->frag[1] = 0;
+ hnputs(uh4->udpplen, ptcllen);
+ if(ucb->headers == 4 || ucb->headers == 6) {
+ v6tov4(uh4->udpdst, raddr);
+ hnputs(uh4->udpdport, rport);
+ v6tov4(uh4->udpsrc, laddr);
+ } else {
+ v6tov4(uh4->udpdst, c->raddr);
+ hnputs(uh4->udpdport, c->rport);
+ if(ipcmp(c->laddr, IPnoaddr) == 0)
+ findlocalip(f, c->laddr, c->raddr);
+ v6tov4(uh4->udpsrc, c->laddr);
+ }
+ hnputs(uh4->udpsport, c->lport);
+ hnputs(uh4->udplen, ptcllen);
+ uh4->udpcksum[0] = 0;
+ uh4->udpcksum[1] = 0;
+ hnputs(uh4->udpcksum,
+ ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));
+ uh4->vihl = IP_VER4;
+ ipoput4(f, bp, 0, c->ttl, c->tos);
+ }
+ else {
+ // using the v6 ip header to create pseudo header
+ // first then reset it to the normal ip header
+ uh6 = (Udp6hdr *)(bp->rp);
+ memset(uh6, 0, 8);
+ ptcllen = dlen + UDP_UDPHDR_SZ;
+ hnputl(uh6->viclfl, ptcllen);
+ uh6->hoplimit = IP_UDPPROTO;
+ if(ucb->headers == 6) {
+ ipmove(uh6->udpdst, raddr);
+ hnputs(uh6->udpdport, rport);
+ ipmove(uh6->udpsrc, laddr);
+ } else {
+ ipmove(uh6->udpdst, c->raddr);
+ hnputs(uh6->udpdport, c->rport);
+ if(ipcmp(c->laddr, IPnoaddr) == 0)
+ findlocalip(f, c->laddr, c->raddr);
+ ipmove(uh6->udpsrc, c->laddr);
+ }
+ hnputs(uh6->udpsport, c->lport);
+ hnputs(uh6->udplen, ptcllen);
+ uh6->udpcksum[0] = 0;
+ uh6->udpcksum[1] = 0;
+ hnputs(uh6->udpcksum,
+ ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ));
+ memset(uh6, 0, 8);
+ uh6->viclfl[0] = IP_VER6;
+ hnputs(uh6->len, ptcllen);
+ uh6->nextheader = IP_UDPPROTO;
+
+ ipoput6(f, bp, 0, c->ttl, c->tos);
}
- hnputs(uh->udpsport, c->lport);
- hnputs(uh->udplen, ptcllen);
- uh->udpcksum[0] = 0;
- uh->udpcksum[1] = 0;
-
- hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_HDRSIZE));
-
upriv->ustats.udpOutDatagrams++;
- ipoput(f, bp, 0, c->ttl, c->tos);
}
Conv*
@@ 253,42 335,76 @@ udpincoming(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport)
void
udpiput(Proto *udp, Ipifc *ifc, Block *bp)
{
- int len, olen, ottl;
- Udphdr *uh;
+ int len;
+ Udp4hdr *uh4;
+ Udp6hdr *uh6;
Conv *c;
Udpcb *ucb;
uchar raddr[IPaddrlen], laddr[IPaddrlen];
ushort rport, lport;
Udppriv *upriv;
Fs *f;
+ int version;
upriv = udp->priv;
f = udp->f;
-
upriv->ustats.udpInDatagrams++;
- uh = (Udphdr*)(bp->rp);
-
- /* Put back pseudo header for checksum (remember old values for icmpnoconv()) */
- ottl = uh->Unused;
- uh->Unused = 0;
- len = nhgets(uh->udplen);
- olen = nhgets(uh->udpplen);
- hnputs(uh->udpplen, len);
-
- v4tov6(raddr, uh->udpsrc);
- v4tov6(laddr, uh->udpdst);
- lport = nhgets(uh->udpdport);
- rport = nhgets(uh->udpsport);
-
- if(nhgets(uh->udpcksum)) {
- if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) {
+ uh4 = (Udp4hdr*)(bp->rp);
+ version = ((uh4->vihl&0xF0)==IP_VER6) ? 6 : 4;
+
+ /* Put back pseudo header for checksum
+ * (remember old values for icmpnoconv()) */
+ if(version == 4) {
+ int ottl, olen;
+ ottl = uh4->Unused;
+ uh4->Unused = 0;
+ len = nhgets(uh4->udplen);
+ olen = nhgets(uh4->udpplen);
+ hnputs(uh4->udpplen, len);
+
+ v4tov6(raddr, uh4->udpsrc);
+ v4tov6(laddr, uh4->udpdst);
+ lport = nhgets(uh4->udpdport);
+ rport = nhgets(uh4->udpsport);
+
+ if(nhgets(uh4->udpcksum)) {
+ if(ptclcsum(bp, UDP4_PHDR_OFF, len+UDP4_PHDR_SZ)) {
+ upriv->ustats.udpInErrors++;
+ netlog(f, Logudp, "udp: checksum error %I\n", raddr);
+ DPRINT("udp: checksum error %I\n", raddr);
+ freeblist(bp);
+ return;
+ }
+ }
+ uh4->Unused = ottl;
+ hnputs(uh4->udpplen, olen);
+ }
+ else {
+ int ottl, oviclfl, olen;
+ uh6 = (Udp6hdr*)(bp->rp);
+ len = nhgets(uh6->udplen);
+ oviclfl = nhgetl(uh6->viclfl);
+ olen = nhgets(uh6->len);
+ ottl = uh6->hoplimit;
+ ipmove(raddr, uh6->udpsrc);
+ ipmove(laddr, uh6->udpdst);
+ lport = nhgets(uh6->udpdport);
+ rport = nhgets(uh6->udpsport);
+ memset(uh6, 0, 8);
+ hnputl(uh6->viclfl, len);
+ uh6->hoplimit = IP_UDPPROTO;
+ if(ptclcsum(bp, UDP6_PHDR_OFF, len+UDP6_PHDR_SZ)) {
upriv->ustats.udpInErrors++;
netlog(f, Logudp, "udp: checksum error %I\n", raddr);
DPRINT("udp: checksum error %I\n", raddr);
freeblist(bp);
return;
}
+ hnputl(uh6->viclfl, oviclfl);
+ hnputs(uh6->len, olen);
+ uh6->nextheader = IP_UDPPROTO;
+ uh6->hoplimit = ottl;
}
qlock(udp);
@@ 299,10 415,15 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
upriv->ustats.udpNoPorts++;
qunlock(udp);
netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
- laddr, lport);
- uh->Unused = ottl;
- hnputs(uh->udpplen, olen);
- icmpnoconv(f, bp);
+ laddr, lport);
+
+ if(version == 4)
+ icmpnoconv(f, bp);
+ else {
+print("udpiput: no conv %I!%d -> %I!%d\n", raddr, rport, laddr, lport);
+ icmphostunr(f, ifc, bp, icmp6_port_unreach, 0);
+ }
+
freeblist(bp);
return;
}
@@ 311,8 432,12 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
if(c->state == Announced){
if(ucb->headers == 0){
/* create a new conversation */
- if(ipforme(f, laddr) != Runi)
- v4tov6(laddr, ifc->lifc->local);
+ if(ipforme(f, laddr) != Runi) {
+ if(version == 4)
+ v4tov6(laddr, ifc->lifc->local);
+ else
+ ipmove(laddr, ifc->lifc->local);
+ }
c = Fsnewcall(c, raddr, rport, laddr, lport);
if(c == nil){
qunlock(udp);
@@ 330,18 455,21 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
/*
* Trim the packet down to data size
*/
- len -= (UDP_HDRSIZE-UDP_PHDRSIZE);
- bp = trimblock(bp, UDP_IPHDR+UDP_HDRSIZE, len);
+ len -= UDP_UDPHDR_SZ;
+ if(version == 4)
+ bp = trimblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ, len);
+ else
+ bp = trimblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ, len);
if(bp == nil){
qunlock(c);
netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
- laddr, lport);
+ laddr, lport);
upriv->lenerr++;
return;
}
netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
- laddr, lport, len);
+ laddr, lport, len);
switch(ucb->headers){
case 6:
@@ 374,7 502,7 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
if(qfull(c->rq)){
qunlock(c);
netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
- laddr, lport);
+ laddr, lport);
freeblist(bp);
return;
}
@@ 405,17 533,30 @@ udpctl(Conv *c, char **f, int n)
void
udpadvise(Proto *udp, Block *bp, char *msg)
{
- Udphdr *h;
+ Udp4hdr *h4;
+ Udp6hdr *h6;
uchar source[IPaddrlen], dest[IPaddrlen];
ushort psource, pdest;
Conv *s, **p;
+ int version;
+
+ h4 = (Udp4hdr*)(bp->rp);
+ version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4;
+
+ if(version == 4) {
+ v4tov6(dest, h4->udpdst);
+ v4tov6(source, h4->udpsrc);
+ psource = nhgets(h4->udpsport);
+ pdest = nhgets(h4->udpdport);
+ } else {
+ h6 = (Udp6hdr*)(bp->rp);
+ ipmove(dest, h6->udpdst);
+ ipmove(source, h6->udpsrc);
+ psource = nhgets(h6->udpsport);
+ pdest = nhgets(h6->udpdport);
+ }
- h = (Udphdr*)(bp->rp);
-
- v4tov6(dest, h->udpdst);
- v4tov6(source, h->udpsrc);
- psource = nhgets(h->udpsport);
- pdest = nhgets(h->udpdport);
+print("udpadvise: looking for s %I sp %d d %I dp %d\n", source, (int)psource, dest, (int)pdest);
/* Look for a connection */
qlock(udp);
@@ 427,6 568,7 @@ udpadvise(Proto *udp, Block *bp, char *msg)
if(ipcmp(s->laddr, source) == 0){
qlock(s);
qunlock(udp);
+print("udpadvise: found, hanging up\n");
qhangup(s->rq, msg);
qhangup(s->wq, msg);
qunlock(s);
M port/devnmouse.c => port/devnmouse.c +0 -2
@@ 32,8 32,6 @@ enum{
Qdir,
Qcursor,
Qmousepoint,
- Qmousein,
- Qmousectl,
};
static Dirtab mousedir[]={