A ip/arp.c => ip/arp.c +314 -0
@@ 0,0 1,314 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "ip.h"
+
+/*
+ * address resolution tables
+ */
+
+enum
+{
+ NHASH = (1<<6),
+ NCACHE = 256,
+
+ AOK = 1,
+ AWAIT = 2,
+};
+
+char *arpstate[] =
+{
+ "UNUSED",
+ "OK",
+ "WAIT",
+};
+
+typedef struct Arpcache Arpcache;
+struct Arpcache
+{
+ QLock;
+ Arpent* hash[NHASH];
+ Arpent cache[NCACHE];
+};
+
+Arpcache arp;
+
+char *Ebadarp = "bad arp";
+
+#define haship(s) ((s)[IPaddrlen-1]%NHASH)
+
+static Arpent*
+newarp(uchar *ip, Medium *m)
+{
+ uint t;
+ Block *next, *xp;
+ Arpent *a, *e, *f, **l;
+
+ /* 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;
+ while(xp){
+ next = xp->list;
+ freeblist(xp);
+ xp = next;
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+}
+
+Arpent*
+arpget(Block *bp, int version, Medium *type, uchar *ip, uchar *mac)
+{
+ int hash;
+ Arpent *a;
+ uchar v6ip[IPaddrlen];
+
+ if(version == V4) {
+ v4tov6(v6ip, ip);
+ ip = v6ip;
+ }
+
+ qlock(&arp);
+ hash = haship(ip);
+ 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(ip, type);
+ a->state = AWAIT;
+ }
+ a->used = msec;
+ if(a->state == AWAIT){
+ if(a->hold)
+ a->last->list = bp;
+ else
+ a->hold = bp;
+ a->last = bp;
+ bp->list = nil;
+ return a; /* return with arp qlocked */
+ }
+
+ memmove(mac, a->mac, a->type->maclen);
+ qunlock(&arp);
+ return nil;
+}
+
+/*
+ * called with arp locked
+ */
+void
+arprelease(Arpent*)
+{
+ qunlock(&arp);
+}
+
+/*
+ * called with arp locked
+ */
+Block*
+arpresolve(Arpent *a, Medium *type, uchar *mac)
+{
+ Block *bp;
+
+ memmove(a->mac, mac, type->maclen);
+ a->type = type;
+ a->state = AOK;
+ a->used = msec;
+ bp = a->hold;
+ a->hold = nil;
+ qunlock(&arp);
+
+ return bp;
+}
+
+void
+arpenter(Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int refresh)
+{
+ Arpent *a;
+ Block *bp, *next;
+ uchar v6ip[IPaddrlen];
+
+ if(version == V4){
+ v4tov6(v6ip, ip);
+ ip = v6ip;
+ }
+
+ qlock(&arp);
+ 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) {
+ a->state = AOK;
+ memmove(a->mac, mac, type->maclen);
+ bp = a->hold;
+ a->hold = nil;
+ if(version == V4)
+ ip += IPv4off;
+ qunlock(&arp);
+ while(bp) {
+ next = bp->list;
+ if(ifc != nil){
+ if(waserror()){
+ runlock(ifc);
+ nexterror();
+ }
+ rlock(ifc);
+ if(ifc->m != nil)
+ ifc->m->bwrite(ifc, bp, version, ip);
+ else
+ freeb(bp);
+ runlock(ifc);
+ poperror();
+ } else
+ freeb(bp);
+ bp = next;
+ }
+ a->used = msec;
+ return;
+ }
+ }
+
+ /* if nil, we're adding a new entry */
+ if(refresh == 0){
+ a = newarp(ip, type);
+ a->state = AOK;
+ a->type = type;
+ memmove(a->mac, mac, type->maclen);
+ }
+
+ qunlock(&arp);
+}
+
+int
+arpwrite(char *s, int len)
+{
+ int n;
+ Block *bp;
+ Arpent *a;
+ char *f[4], buf[256];
+ uchar ip[], mac[MAClen];
+ Medium *m;
+
+ 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 = parsefields(buf, f, 4, " ");
+ 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));
+ qunlock(&arp);
+ } else if(strcmp(f[0], "add") == 0){
+ if(n != 4)
+ error(Ebadarp);
+ m = ipfindmedium(f[1]);
+ if(m == nil)
+ error(Ebadarp);
+ parseip(ip, f[2]);
+ parsemac(mac, f[3], m->maclen);
+ arpenter(nil, V6, ip, mac, m, 0);
+ } else
+ error(Ebadarp);
+
+ return len;
+}
+
+enum
+{
+ Alinelen= 66,
+};
+
+char *aformat = "%-6.6s %-8.8s %-16.16I %-32.32s\n";
+
+static void
+convmac(char *p, uchar *mac, int n)
+{
+ while(n-- > 0)
+ p += sprint(p, "%2.2ux", *mac++);
+}
+
+int
+arpread(char *p, ulong offset, int len)
+{
+ Arpent *a;
+ int n;
+ char mac[2*MAClen+1];
+
+ if(offset % Alinelen)
+ return 0;
+
+ offset = offset/Alinelen;
+ len = len/Alinelen;
+
+ n = 0;
+ for(a = arp.cache; len > 0 && a < &arp.cache[NCACHE]; a++){
+ if(a->state == 0)
+ continue;
+ if(offset > 0){
+ offset--;
+ continue;
+ }
+ len--;
+ qlock(&arp);
+ convmac(mac, a->mac, a->type->maclen);
+ n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac);
+ qunlock(&arp);
+ }
+
+ return n;
+}
M ip/devip.c => ip/devip.c +311 -244
@@ 14,13 14,14 @@ enum
Qtopdir= 1, /* top level directory */
Qtopbase,
Qarp= Qtopbase,
- Qipifc,
Qiproute,
+ Qiprouter,
Qlog,
Qprotodir, /* directory for a protocol */
Qprotobase,
Qclone= Qprotobase,
+ Qstats,
Qconvdir, /* directory for a conversation */
Qconvbase,
@@ 79,7 80,7 @@ ip3gen(Chan *c, int i, Dir *dp)
q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qstatus), 0};
break;
}
- devdir(c, q, p, 0, cv->owner, 0444, dp);
+ devdir(c, q, p, 0, cv->owner, 0666, dp);
return 1;
}
@@ 91,7 92,11 @@ ip2gen(Chan *c, int i, Dir *dp)
switch(i) {
case Qclone:
q = (Qid){QID(PROTO(c->qid), 0, Qclone), 0};
- devdir(c, q, "clone", 0, network, 0444, dp);
+ devdir(c, q, "clone", 0, network, 0666, dp);
+ return 1;
+ case Qstats:
+ q = (Qid){QID(PROTO(c->qid), 0, Qstats), 0};
+ devdir(c, q, "stats", 0, network, 0444, dp);
return 1;
}
return -1;
@@ 110,20 115,20 @@ ip1gen(Chan *c, int i, Dir *dp)
p = "arp";
q = (Qid){QID(0, 0, Qarp), 0};
break;
- case Qipifc:
- p = "ipifc";
- q = (Qid){QID(0, 0, Qipifc), 0};
- break;
case Qiproute:
p = "iproute";
q = (Qid){QID(0, 0, Qiproute), 0};
break;
+ case Qiprouter:
+ p = "iprouter";
+ q = (Qid){QID(0, 0, Qiprouter), 0};
+ break;
case Qlog:
p = "log";
q = (Qid){QID(0, 0, Qlog), 0};
break;
}
- devdir(c, q, p, 0, network, 0444, dp);
+ devdir(c, q, p, 0, network, 0666, dp);
return 1;
}
@@ 146,9 151,9 @@ ipgen(Chan *c, Dirtab*, int, int s, Dir *dp)
s -= fs.np;
return ip1gen(c, s+Qtopbase, dp);
case Qarp:
- case Qipifc:
case Qlog:
case Qiproute:
+ case Qiprouter:
return ip1gen(c, TYPE(c->qid), dp);
case Qprotodir:
if(s < fs.p[PROTO(c->qid)]->ac) {
@@ 161,6 166,7 @@ ipgen(Chan *c, Dirtab*, int, int s, Dir *dp)
s -= fs.p[PROTO(c->qid)]->ac;
return ip2gen(c, s+Qprotobase, dp);
case Qclone:
+ case Qstats:
return ip2gen(c, TYPE(c->qid), dp);
case Qconvdir:
return ip3gen(c, s+Qconvbase, dp);
@@ 193,6 199,8 @@ ipinit(void)
fmtinstall('i', eipconv);
fmtinstall('I', eipconv);
fmtinstall('E', eipconv);
+ fmtinstall('V', eipconv);
+ fmtinstall('M', eipconv);
}
static Chan*
@@ 217,25 225,24 @@ ipwalk(Chan* c, char* name)
{
Path *op;
- if(strcmp(name, "..") == 0){
- switch(TYPE(c->qid)){
- case Qtopdir:
- case Qprotodir:
- c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
- break;
- case Qconvdir:
- c->qid = (Qid){QID(PROTO(c->qid), 0, Qprotodir)|CHDIR, 0};
- break;
- default:
- panic("ipwalk %lux", c->qid.path);
- }
- op = c->path;
- c->path = ptenter(&syspt, op, name);
- decref(op);
- return 1;
- }
+ if(strcmp(name, "..") != 0)
+ return devwalk(c, name, nil, 0, ipgen);
- return devwalk(c, name, nil, 0, ipgen);
+ switch(TYPE(c->qid)){
+ case Qtopdir:
+ case Qprotodir:
+ c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
+ break;
+ case Qconvdir:
+ c->qid = (Qid){QID(PROTO(c->qid), 0, Qprotodir)|CHDIR, 0};
+ break;
+ default:
+ panic("ipwalk %lux", c->qid.path);
+ }
+ op = c->path;
+ c->path = ptenter(&syspt, op, name);
+ decref(op);
+ return 1;
}
static void
@@ 272,18 279,22 @@ ipopen(Chan* c, int omode)
switch(TYPE(c->qid)) {
default:
break;
- case Qipifc:
- c->aux = newifcconv();
- break;
case Qlog:
netlogopen();
break;
+ case Qiprouter:
+ iprouteropen();
+ break;
+ case Qiproute:
+ memmove(c->tag, "none", sizeof(c->tag));
+ break;
case Qtopdir:
case Qprotodir:
case Qconvdir:
case Qstatus:
case Qremote:
case Qlocal:
+ case Qstats:
if(omode != OREAD)
error(Eperm);
break;
@@ 300,12 311,12 @@ ipopen(Chan* c, int omode)
case Qctl:
case Qerr:
p = fs.p[PROTO(c->qid)];
- lock(p);
+ qlock(p);
cv = p->conv[CONV(c->qid)];
lock(cv);
if(waserror()) {
unlock(cv);
- unlock(p);
+ qunlock(p);
nexterror();
}
if((perm & (cv->perm>>6)) != perm) {
@@ 321,7 332,7 @@ ipopen(Chan* c, int omode)
cv->perm = 0660;
}
unlock(cv);
- unlock(p);
+ qunlock(p);
poperror();
break;
case Qlisten:
@@ 381,8 392,10 @@ static void
closeconv(Conv *cv)
{
Conv *nc;
+ Ipmulti *mp;
lock(cv);
+
if(--cv->inuse > 0) {
unlock(cv);
return;
@@ 397,6 410,9 @@ closeconv(Conv *cv)
strcpy(cv->owner, network);
cv->perm = 0660;
+ while((mp = cv->multi) != nil)
+ ipifcremmulti(cv, mp->ma, mp->ia);
+
/* The close routine will unlock the conv */
cv->p->close(cv);
}
@@ 407,13 423,13 @@ ipclose(Chan* c)
switch(TYPE(c->qid)) {
default:
break;
- case Qipifc:
+ case Qlog:
if(c->flag & COPEN)
- closeifcconv(c->aux);
- c->aux = nil;
+ netlogclose();
break;
- case Qlog:
- netlogclose();
+ case Qiprouter:
+ if(c->flag & COPEN)
+ iprouterclose();
break;
case Qdata:
case Qctl:
@@ 423,13 439,18 @@ ipclose(Chan* c)
}
}
+enum
+{
+ Statelen= 1024,
+};
+
static long
ipread(Chan *ch, void *a, long n, ulong offset)
{
Conv *c;
Proto *x;
- byte ip[4];
- char buf[256], *p, *statename;
+ char *buf, *p;
+ long m, rv;
p = a;
switch(TYPE(ch->qid)) {
@@ 441,41 462,61 @@ ipread(Chan *ch, void *a, long n, ulong offset)
return devdirread(ch, a, n, 0, 0, ipgen);
case Qarp:
return arpread(a, offset, n);
- case Qipifc:
- return Mediaifcread(a, offset, n);
case Qiproute:
return routeread(a, offset, n);
+ case Qiprouter:
+ return iprouterread(a, n);
case Qlog:
return netlogread(a, offset, n);
case Qctl:
+ buf = smalloc(16);
sprint(buf, "%d", CONV(ch->qid));
- return readstr(offset, p, n, buf);
+ rv = readstr(offset, p, n, buf);
+ free(buf);
+ return rv;
case Qremote:
+ buf = smalloc(Statelen);
c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
- hnputl(ip, c->raddr);
- sprint(buf, "%I!%d\n", ip, c->rport);
- return readstr(offset, p, n, buf);
+ sprint(buf, "%I!%d\n", c->raddr, c->rport);
+ rv = readstr(offset, p, n, buf);
+ free(buf);
+ return rv;
case Qlocal:
- c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
- if(media != nil && c->laddr == 0)
- hnputl(ip, Mediagetaddr(media));
- else
- hnputl(ip, c->laddr);
- sprint(buf, "%I!%d\n", ip, c->lport);
- return readstr(offset, p, n, buf);
+ buf = smalloc(Statelen);
+ x = fs.p[PROTO(ch->qid)];
+ c = x->conv[CONV(ch->qid)];
+ if(x->local == nil) {
+ sprint(buf, "%I!%d\n", c->laddr, c->lport);
+ } else {
+ (*x->local)(c, buf, Statelen-2);
+ }
+ rv = readstr(offset, p, n, buf);
+ free(buf);
+ return rv;
case Qstatus:
+ buf = smalloc(Statelen);
x = fs.p[PROTO(ch->qid)];
c = x->conv[CONV(ch->qid)];
- x->state(&statename, c);
- sprint(buf, "%s/%d %d %s \n", c->p->name, c->x, c->inuse, statename);
- return readstr(offset, p, n, buf);
+ m = sprint(buf, "%s/%d %d ", c->p->name, c->x, c->inuse);
+ (*x->state)(c, buf, Statelen-m-2);
+ rv = readstr(offset, p, n, buf);
+ free(buf);
+ return rv;
case Qdata:
c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
return qread(c->rq, a, n);
-
case Qerr:
c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
return qread(c->eq, a, n);
+ case Qstats:
+ x = fs.p[PROTO(ch->qid)];
+ if(x->stats == nil)
+ error("stats not implemented");
+ buf = smalloc(Statelen);
+ (*x->stats)(buf, Statelen);
+ rv = readstr(offset, p, n, buf);
+ free(buf);
+ return rv;
}
}
@@ 485,15 526,18 @@ ipbread(Chan* c, long n, ulong offset)
return devbread(c, n, offset);
}
+/*
+ * set local address to be that of the ifc closest to remote address
+ */
static void
setladdr(Conv* c)
{
- byte rem[4];
-
- hnputl(rem, c->raddr);
- c->laddr = Mediagetsrc(rem);
+ findlocalip(c->laddr, c->raddr);
}
+/*
+ * pick a local port and set it
+ */
static void
setlport(Conv* c)
{
@@ 506,7 550,7 @@ setlport(Conv* c)
pp = &p->nextrport;
else
pp = &p->nextport;
- lock(p);
+ qlock(p);
for(;;(*pp)++){
/*
* Fsproto initialises p->nextport to 0 and the restricted
@@ 536,14 580,21 @@ setlport(Conv* c)
break;
}
c->lport = (*pp)++;
- unlock(p);
+ qunlock(p);
}
+/*
+ * set a local address and port from a string of the form
+ * address!port
+ * if address is missing and not announcing, pick one
+ * if address is missing and announcing, leave address as zero (i.e. matches anything)
+ * if port is 0, pick a free one
+ * if port is '*', leave port as zero (i.e. matches anything)
+ */
static void
-setladdrport(Conv* c, char* str, int nodefault)
+setladdrport(Conv* c, char* str, int announcing)
{
char *p;
- uchar addr[IPaddrlen];
/*
* ignore restricted part if it exists. it's
@@ 552,19 603,16 @@ setladdrport(Conv* c, char* str, int nodefault)
p = strchr(str, '!');
if(p == nil || strcmp(p, "!r") == 0) {
p = str;
- if(nodefault)
+ memset(c->laddr, 0, sizeof(c->laddr));
+ if(!announcing)
setladdr(c);
- else
- c->laddr = 0;
- }
- else {
+ } else {
*p++ = 0;
- parseip(addr, str);
- c->laddr = nhgetl(addr);
+ parseip(c->laddr, str);
}
- if(*p == '*')
- c->lport = 0;
- else {
+
+ c->lport = 0;
+ if(*p != '*'){
c->lport = atoi(p);
if(c->lport == 0)
setlport(c);
@@ 575,14 623,12 @@ static char*
setraddrport(Conv* c, char* str)
{
char *p;
- uchar addr[IPaddrlen];
p = strchr(str, '!');
if(p == nil)
return "malformed address";
*p++ = 0;
- parseip(addr, str);
- c->raddr = nhgetl(addr);
+ parseip(c->raddr, str);
c->rport = atoi(p);
p = strchr(p, '!');
if(p){
@@ 592,44 638,163 @@ setraddrport(Conv* c, char* str)
return nil;
}
+/*
+ * called by protocol connect routine to set addresses
+ */
+char*
+Fsstdconnect(Conv *c, char *argv[], int argc)
+{
+ char *p;
+
+ switch(argc) {
+ default:
+ return "bad args to connect";
+ case 2:
+ p = setraddrport(c, argv[1]);
+ if(p != nil)
+ return p;
+ setladdr(c);
+ setlport(c);
+ break;
+ case 3:
+ p = setraddrport(c, argv[1]);
+ if(p != nil)
+ return p;
+ setladdrport(c, argv[2], 0);
+ break;
+ }
+ return nil;
+}
+/*
+ * initiate connection and sleep till its set up
+ */
static int
connected(void* a)
{
return ((Conv*)a)->state == Connected;
}
+static void
+connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
+{
+ char *p;
+
+ c->state = Connecting;
+ c->cerr[0] = '\0';
+ if(x->connect == nil)
+ error("connect not supported");
+ p = x->connect(c, cb->f, cb->nf);
+ if(p != nil)
+ error(p);
+ sleep(&c->cr, connected, c);
+ if(c->cerr[0] != '\0')
+ error(c->cerr);
+}
+
+/*
+ * called by protocol announce routine to set addresses
+ */
+char*
+Fsstdannounce(Conv* c, char* argv[], int argc)
+{
+ switch(argc){
+ default:
+ return "bad args to announce";
+ case 2:
+ setladdrport(c, argv[1], 1);
+ break;
+ }
+ return nil;
+}
+/*
+ * initiate announcement and sleep till its set up
+ */
static int
announced(void* a)
{
return ((Conv*)a)->state == Announced;
}
+static void
+announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb)
+{
+ char *p;
+
+ c->state = Announcing;
+ c->cerr[0] = '\0';
+ if(x->announce == nil)
+ error("announce not supported");
+ p = x->announce(c, cb->f, cb->nf);
+ if(p != nil)
+ error(p);
+ sleep(&c->cr, announced, c);
+ if(c->cerr[0] != '\0')
+ error(c->cerr);
+}
+
+/*
+ * called by protocol bide routine to set addresses
+ */
+char*
+Fsstdbind(Conv* c, char* argv[], int argc)
+{
+ switch(argc){
+ default:
+ return "bad args to bind";
+ case 2:
+ setladdrport(c, argv[1], 0);
+ break;
+ }
+ return nil;
+}
+
+static void
+bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
+{
+ char *p;
+
+ if(x->bind == nil)
+ p = Fsstdbind(c, cb->f, cb->nf);
+ else
+ p = x->bind(c, cb->f, cb->nf);
+ if(p != nil)
+ error(p);
+}
+
+static void
+ttlctlmsg(Conv *c, Cmdbuf *cb)
+{
+ if(cb->nf < 2)
+ c->ttl = MAXTTL;
+ else
+ c->ttl = atoi(cb->f[1]);
+}
static long
ipwrite(Chan* ch, char* a, long n, ulong)
{
Conv *c;
Proto *x;
- int nfield;
- char *p, *fields[10], buf[128];
+ char *p;
+ Cmdbuf *cb;
+ uchar ia[IPaddrlen];
switch(TYPE(ch->qid)){
default:
error(Eperm);
+ case Qdata:
+ x = fs.p[PROTO(ch->qid)];
+ c = x->conv[CONV(ch->qid)];
+
+ if(c->wq == nil)
+ error(Eperm);
+
+ qwrite(c->wq, a, n);
+ x->kick(c, n);
+ break;
case Qarp:
- p = arpwrite(a, n);
- if(p != nil)
- error(p);
- return n;
- case Qipifc:
- p = Mediaifcwrite(ch->aux, a, n);
- if(p != nil)
- error(p);
- return n;
+ return arpwrite(a, n);
case Qiproute:
- p = routewrite(a, n);
- if(p != nil)
- error(p);
- return n;
+ return routewrite(ch, a, n);
case Qlog:
p = netlogctl(a, n);
if(p != nil)
@@ 638,90 803,48 @@ ipwrite(Chan* ch, char* a, long n, ulong)
case Qctl:
x = fs.p[PROTO(ch->qid)];
c = x->conv[CONV(ch->qid)];
- if(n > sizeof(buf)-1)
- n = sizeof(buf)-1;
- memmove(buf, a, n);
- buf[n] = '\0';
- nfield = parsefields(buf, fields, 10, " ");
- if(strcmp(fields[0], "connect") == 0){
- if(canqlock(&c->car) == 0)
- error("connect/announce in progress");
- if(waserror()) {
- qunlock(&c->car);
- nexterror();
- }
- c->state = Connecting;
- c->cerr[0] = '\0';
- p = x->connect(c, fields, nfield);
- if(p != nil)
- error(p);
- sleep(&c->cr, connected, c);
- if(c->cerr[0] != '\0')
- error(c->cerr);
- qunlock(&c->car);
- poperror();
- return n;
- }
- if(strcmp(fields[0], "announce") == 0){
- if(canqlock(&c->car) == 0)
- error("connect/announce in progress");
- if(waserror()) {
- qunlock(&c->car);
- nexterror();
- }
- c->state = Announcing;
- c->cerr[0] = '\0';
- p = x->announce(c, fields, nfield);
- if(p != nil)
- error(p);
- sleep(&c->cr, announced, c);
- if(c->cerr[0] != '\0')
- error(c->cerr);
- qunlock(&c->car);
- poperror();
- return n;
+ cb = parsecmd(a, n);
+
+ if(canqlock(&c->car) == 0){
+ free(cb);
+ error("connect/announce in progress");
}
- if(strcmp(fields[0], "bind") == 0){
- if(canqlock(&c->car) == 0)
- error("connect/announce in progress");
- if(waserror()) {
- qunlock(&c->car);
- nexterror();
- }
- switch(nfield){
- default:
- error("bad args to bind");
- case 2:
- setladdr(c);
- c->lport = atoi(fields[1]);
- if(c->lport == 0)
- setlport(c);
- break;
- }
+ if(waserror()) {
qunlock(&c->car);
- poperror();
- return n;
- }
- if(strcmp(fields[0], "ttl") == 0){
- if(nfield < 2)
- c->ttl = MAXTTL;
- else
- c->ttl = atoi(fields[1]);
- return n;
+ free(cb);
+ nexterror();
}
- if(x->ctl != nil) {
- p = x->ctl(c, fields, nfield);
+ if(strcmp(cb->f[0], "connect") == 0)
+ connectctlmsg(x, c, cb);
+ else if(strcmp(cb->f[0], "announce") == 0)
+ announcectlmsg(x, c, cb);
+ else if(strcmp(cb->f[0], "bind") == 0)
+ bindctlmsg(x, c, cb);
+ else if(strcmp(cb->f[0], "ttl") == 0)
+ ttlctlmsg(c, cb);
+ else if(strcmp(cb->f[0], "addmulti") == 0){
+ if(cb->nf < 2)
+ error("addmulti needs interface address");
+ if(!ipismulticast(c->raddr))
+ error("addmulti for a non multicast address");
+ parseip(ia, cb->f[1]);
+ ipifcaddmulti(c, c->raddr, ia);
+ } 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);
+ } else if(x->ctl != nil) {
+ p = x->ctl(c, cb->f, cb->nf);
if(p != nil)
error(p);
- return n;
- }
- error("unknown control request");
- case Qdata:
- x = fs.p[PROTO(ch->qid)];
- c = x->conv[CONV(ch->qid)];
-
- qwrite(c->wq, a, n);
- x->kick(c, n);
+ } else
+ error("unknown control request");
+ qunlock(&c->car);
+ free(cb);
+ poperror();
}
return n;
}
@@ 782,7 905,7 @@ Fsproto(Fs *fs, Proto *p)
* built in
*/
int
-Fsbuiltinproto(Fs* fs, byte proto)
+Fsbuiltinproto(Fs* fs, uchar proto)
{
return fs->t2p[proto] != nil;
}
@@ 790,14 913,12 @@ Fsbuiltinproto(Fs* fs, byte proto)
Conv*
Fsprotoclone(Proto *p, char *user)
{
- char *junk;
- int unused;
Conv *c, **pp, **ep;
c = nil;
- lock(p);
+ qlock(p);
if(waserror()) {
- unlock(p);
+ qunlock(p);
nexterror();
}
ep = &p->conv[p->nc];
@@ 812,7 933,6 @@ Fsprotoclone(Proto *p, char *user)
c->x = pp - p->conv;
c->ptcl = malloc(p->ptclsize);
if(c->ptcl == nil) {
- unlock(c);
free(c);
error(Enomem);
}
@@ 823,15 943,18 @@ Fsprotoclone(Proto *p, char *user)
break;
}
if(canlock(c)){
- unused = p->state(&junk, c);
- if(c->inuse == 0 && unused)
+ /*
+ * make sure both processes and protocol
+ * are done with this Conv
+ */
+ if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0))
break;
unlock(c);
}
}
if(pp >= ep) {
- unlock(p);
+ qunlock(p);
poperror();
return nil;
}
@@ 840,8 963,8 @@ Fsprotoclone(Proto *p, char *user)
strcpy(c->owner, user);
c->perm = 0660;
c->state = 0;
- c->laddr = 0;
- c->raddr = 0;
+ ipmove(c->laddr, IPnoaddr);
+ ipmove(c->raddr, IPnoaddr);
c->lport = 0;
c->rport = 0;
c->restricted = 0;
@@ 851,7 974,7 @@ Fsprotoclone(Proto *p, char *user)
qreopen(c->eq);
unlock(c);
- unlock(p);
+ qunlock(p);
poperror();
return c;
}
@@ 878,13 1001,13 @@ Fsconnected(Fs*, Conv* c, char* msg)
}
Proto*
-Fsrcvpcol(Fs* fs, byte proto)
+Fsrcvpcol(Fs* fs, uchar proto)
{
return fs->t2p[proto];
}
Conv*
-Fsnewcall(Fs*, Conv *c, Ipaddr raddr, ushort rport, Ipaddr laddr, ushort lport)
+Fsnewcall(Fs*, Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport)
{
Conv *nc;
Conv **l;
@@ 905,9 1028,9 @@ Fsnewcall(Fs*, Conv *c, Ipaddr raddr, ushort rport, Ipaddr laddr, ushort lport)
unlock(c);
return nil;
}
- nc->raddr = raddr;
+ ipmove(nc->raddr, raddr);
nc->rport = rport;
- nc->laddr = laddr;
+ ipmove(nc->laddr, laddr);
nc->lport = lport;
nc->next = nil;
*l = nc;
@@ 917,59 1040,3 @@ Fsnewcall(Fs*, Conv *c, Ipaddr raddr, ushort rport, Ipaddr laddr, ushort lport)
return nc;
}
-
-int
-Fspcolstats(char *buf, int len)
-{
- Proto **p;
- int n;
-
- n = 0;
- for(p = fs.p; *p; p++){
- n += snprint(buf + n, len - n,
- "%s: csum %d hlen %d len %d order %d rexmit %d\n",
- (*p)->name, (*p)->csumerr, (*p)->hlenerr, (*p)->lenerr,
- (*p)->order, (*p)->rexmit);
- if((*p)->stats)
- n += (*(*p)->stats)(buf + n, len - n);
- }
- return n;
-}
-
-char*
-Fsstdconnect(Conv *c, char *argv[], int argc)
-{
- char *p;
-
- switch(argc) {
- default:
- return "bad args to connect";
- case 2:
- p = setraddrport(c, argv[1]);
- if(p != nil)
- return p;
- setladdr(c);
- setlport(c);
- break;
- case 3:
- p = setraddrport(c, argv[1]);
- if(p != nil)
- return p;
- setladdrport(c, argv[2], 1);
- break;
- }
- return nil;
-}
-
-char*
-Fsstdannounce(Conv* c, char* argv[], int argc)
-{
- switch(argc){
- default:
- return "bad args to announce";
- case 2:
- setladdrport(c, argv[1], 0);
- break;
- }
- return nil;
-}
A ip/eipconvtest.c => ip/eipconvtest.c +152 -0
@@ 0,0 1,152 @@
+#include <u.h>
+#include <libc.h>
+
+enum
+{
+ Isprefix= 16,
+};
+
+uchar prefixvals[256] =
+{
+[0x00] 0 | Isprefix,
+[0x80] 1 | Isprefix,
+[0xC0] 2 | Isprefix,
+[0xE0] 3 | Isprefix,
+[0xF0] 4 | Isprefix,
+[0xF8] 5 | Isprefix,
+[0xFC] 6 | Isprefix,
+[0xFE] 7 | Isprefix,
+[0xFF] 8 | Isprefix,
+};
+
+uchar v4prefix[16] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff,
+ 0, 0, 0, 0
+};
+
+void
+hnputl(void *p, ulong v)
+{
+ uchar *a;
+
+ a = p;
+ a[0] = v>>24;
+ a[1] = v>>16;
+ a[2] = v>>8;
+ a[3] = v;
+}
+
+int
+eipconv(va_list *arg, Fconv *f)
+{
+ char buf[8*5];
+ static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
+ static char *ifmt = "%d.%d.%d.%d";
+ uchar *p, ip[16];
+ ulong *lp;
+ ushort s;
+ int i, j, n, eln, eli;
+
+ switch(f->chr) {
+ case 'E': /* Ethernet address */
+ p = va_arg(*arg, uchar*);
+ sprint(buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
+ break;
+ case 'I': /* Ip address */
+ p = va_arg(*arg, uchar*);
+common:
+ if(memcmp(p, v4prefix, 12) == 0)
+ sprint(buf, ifmt, p[12], p[13], p[14], p[15]);
+ else {
+ /* find longest elision */
+ eln = eli = -1;
+ for(i = 0; i < 16; i += 2){
+ for(j = i; j < 16; j += 2)
+ if(p[j] != 0 || p[j+1] != 0)
+ break;
+ if(j > i && j - i > eln){
+ eli = i;
+ eln = j - i;
+ }
+ }
+
+ /* print with possible elision */
+ n = 0;
+ for(i = 0; i < 16; i += 2){
+ if(i == eli){
+ n += sprint(buf+n, "::");
+ i += eln;
+ if(i >= 16)
+ break;
+ } else if(i != 0)
+ n += sprint(buf+n, ":");
+ s = (p[i]<<8) + p[i+1];
+ n += sprint(buf+n, "%ux", s);
+ }
+ }
+ break;
+ case 'i': /* v6 address as 4 longs */
+ lp = va_arg(*arg, ulong*);
+ for(i = 0; i < 4; i++)
+ hnputl(ip+4*i, *lp++);
+ p = ip;
+ goto common;
+ case 'V': /* v4 ip address */
+ p = va_arg(*arg, uchar*);
+ sprint(buf, ifmt, p[0], p[1], p[2], p[3]);
+ break;
+ case 'M': /* ip mask */
+ p = va_arg(*arg, uchar*);
+
+ /* look for a prefix mask */
+ for(i = 0; i < 16; i++)
+ if(p[i] != 0xff)
+ break;
+ if(i < 16){
+ if((prefixvals[p[i]] & Isprefix) == 0)
+ goto common;
+ for(j = i+1; j < 16; j++)
+ if(p[j] != 0)
+ goto common;
+ n = 8*i + (prefixvals[p[i]] & ~Isprefix);
+ } else
+ n = 8*16;
+
+ /* got one, use /xx format */
+ sprint(buf, "/%d", n);
+ break;
+ default:
+ strcpy(buf, "(eipconv)");
+ }
+ strconv(buf, f);
+ return sizeof(uchar*);
+}
+
+uchar testvec[11][16] =
+{
+ { 0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 1,3,4,5, },
+ { 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, },
+ { 0xff,0xff,0x80,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, },
+ { 0xff,0xff,0xff,0xc0, 0,0,0,0, 0,0,0,0, 0,0,0,0, },
+ { 0xff,0xff,0xff,0xff, 0xe0,0,0,0, 0,0,0,0, 0,0,0,0, },
+ { 0xff,0xff,0xff,0xff, 0xff,0xf0,0,0, 0,0,0,0, 0,0,0,0, },
+ { 0xff,0xff,0xff,0xff, 0xff,0xff,0xf8,0, 0,0,0,0, 0,0,0,0, },
+ { 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, },
+ { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, },
+ { 0,0,0,0, 0,0x11,0,0, 0,0,0,0, 0,0,0,0, },
+ { 0,0,0,0x11, 0,0,0,0, 0,0,0,0, 0,0,0,0x12, },
+};
+
+void
+main(void)
+{
+ int i;
+
+ fmtinstall('I', eipconv);
+ fmtinstall('M', eipconv);
+ for(i = 0; i < 11; i++)
+ print("%I\n%M\n", testvec[i], testvec[i]);
+ exits(0);
+}
A ip/ethermedium.c => ip/ethermedium.c +523 -0
@@ 0,0 1,523 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "ip.h"
+#include "kernel.h"
+
+typedef struct Etherhdr Etherhdr;
+struct Etherhdr
+{
+ uchar d[6];
+ uchar s[6];
+ uchar t[2];
+};
+
+static void etherread(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);
+static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
+static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
+static Block* multicastarp(Arpent *a, uchar *mac);
+static void sendarp(Ipifc *ifc, Arpent *a);
+static int multicastea(uchar *ea, uchar *ip);
+static void recvarpproc(Ipifc *ifc);
+
+Medium ethermedium =
+{
+ "ether",
+ 14,
+ 60,
+ 1514,
+ 6,
+ etherbind,
+ etherunbind,
+ etherbwrite,
+ etheraddmulti,
+ etherremmulti,
+ nil, /* pktin */
+ nil, /* addroute */
+ nil, /* remroute */
+ nil, /* flushroute */
+ nil, /* joinmulti */
+ nil, /* leavemulti */
+};
+
+typedef struct Etherrock Etherrock;
+struct Etherrock
+{
+ Proc *arpp; /* arp process */
+ Proc *readp; /* reading process */
+ Chan *mchan; /* Data channel */
+ Chan *achan; /* Arp channel */
+ Chan *cchan; /* Control channel */
+};
+
+/*
+ * ethernet arp request
+ */
+enum
+{
+ ETARP = 0x0806,
+ ETIP = 0x0800,
+ ARPREQUEST = 1,
+ ARPREPLY = 2,
+};
+typedef struct Etherarp Etherarp;
+struct Etherarp
+{
+ uchar d[6];
+ uchar s[6];
+ uchar type[2];
+ uchar hrd[2];
+ uchar pro[2];
+ uchar hln;
+ uchar pln;
+ uchar op[2];
+ uchar sha[6];
+ uchar spa[4];
+ uchar tha[6];
+ uchar tpa[4];
+};
+
+
+/*
+ * called to bind an IP ifc to an ethernet device
+ * called with ifc wlock'd
+ */
+static void
+etherbind(Ipifc *ifc, int argc, char **argv)
+{
+ Chan *mchan, *cchan, *achan;
+ char addr[2*NAMELEN];
+ char dir[2*NAMELEN];
+ char *buf;
+ int fd, cfd, n;
+ char *ptr;
+ Etherrock *er;
+
+ if(argc < 2)
+ error(Ebadarg);
+
+ mchan = cchan = achan = nil;
+ buf = nil;
+ if(waserror()){
+ if(mchan != nil)
+ cclose(mchan);
+ if(cchan != nil)
+ cclose(cchan);
+ if(achan != nil)
+ cclose(achan);
+ if(buf != nil)
+ free(buf);
+ nexterror();
+ }
+
+ /*
+ * open ip conversation
+ *
+ * the dial will fail if the type is already open on
+ * this device.
+ */
+ snprint(addr, sizeof(addr), "%s!0x800", argv[2]);
+ fd = kdial(addr, nil, dir, &cfd);
+ if(fd < 0)
+ error("dial 0x800 failed");
+ mchan = fdtochan(fd, ORDWR, 0, 1);
+ cchan = fdtochan(cfd, ORDWR, 0, 1);
+ kclose(fd);
+ kclose(cfd);
+
+ /*
+ * get mac address
+ */
+ snprint(addr, sizeof(addr), "%s/stats", dir);
+ fd = kopen(addr, OREAD);
+ if(fd < 0)
+ error("can't read ether stats");
+
+ buf = smalloc(512);
+ n = kread(fd, buf, 511);
+ kclose(fd);
+ if(n <= 0)
+ error(Eio);
+ buf[n] = 0;
+
+ ptr = strstr(buf, "addr: ");
+ if(!ptr)
+ error(Eio);
+ ptr += 6;
+
+ parsemac(ifc->mac, ptr, 6);
+
+ /*
+ * open arp conversation
+ */
+ snprint(addr, sizeof(addr), "%s!0x806", argv[2]);
+ fd = kdial(addr, nil, nil, nil);
+ if(fd < 0)
+ error("dial 0x806 failed");
+ achan = fdtochan(fd, ORDWR, 0, 1);
+ kclose(fd);
+
+ er = smalloc(sizeof(*er));
+ er->mchan = mchan;
+ er->cchan = cchan;
+ er->achan = achan;
+ ifc->arg = er;
+
+ free(buf);
+ poperror();
+
+ kproc("etherread", etherread, ifc);
+ kproc("recvarpproc", recvarpproc, ifc);
+}
+
+/*
+ * called with ifc wlock'd
+ */
+static void
+etherunbind(Ipifc *ifc)
+{
+ Etherrock *er = ifc->arg;
+
+ if(er->readp)
+ postnote(er->readp, 1, "unbind", 0);
+ if(er->arpp)
+ postnote(er->arpp, 1, "unbind", 0);
+
+ /* wait for readers to die */
+ while(er->arpp != 0 || er->readp != 0)
+ tsleep(&up->sleep, return0, 0, 300);
+
+ if(er->mchan != nil)
+ cclose(er->mchan);
+ if(er->achan != nil)
+ cclose(er->achan);
+ if(er->cchan != nil)
+ cclose(er->cchan);
+
+ free(er);
+}
+
+/*
+ * called by ipoput with a single block to write
+ */
+static void
+etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
+{
+ Etherhdr *eh;
+ Arpent *a;
+ uchar mac[6];
+ Etherrock *er = ifc->arg;
+
+ if(waserror()) {
+ print("etherbwrite failed\n");
+ ipifccheckout(ifc);
+ return;
+ }
+ if(ipifccheckin(ifc, ðermedium) < 0){
+ freeb(bp);
+ poperror();
+ return;
+ }
+
+ /* get mac address of destination */
+ a = arpget(bp, version, ðermedium, ip, mac);
+ if(a){
+ /* check for broadcast or multicast */
+ bp = multicastarp(a, mac);
+ if(bp == nil){
+ sendarp(ifc, a);
+ goto out;
+ }
+ }
+
+ /* make it a single block with space for the ether header */
+ bp = padblock(bp, ifc->m->hsize);
+ if(bp->next)
+ bp = concatblock(bp);
+ if(BLEN(bp) < ifc->minmtu)
+ bp = adjustblock(bp, ifc->minmtu);
+ eh = (Etherhdr*)bp->rp;
+
+ /* copy in mac addresses and ether type */
+ memmove(eh->s, ifc->mac, sizeof(eh->s));
+ memmove(eh->d, mac, sizeof(eh->d));
+ switch(version){
+ case V4:
+ eh->t[0] = 0x08;
+ eh->t[1] = 0x00;
+ break;
+ case V6:
+ eh->t[0] = 0x86;
+ eh->t[1] = 0xDD;
+ break;
+ }
+
+ devtab[er->mchan->type]->bwrite(er->mchan, bp, 0);
+ ifc->out++;
+
+out:
+ ipifccheckout(ifc);
+ poperror();
+}
+
+/*
+ * process to read from the ethernet
+ */
+static void
+etherread(void *a)
+{
+ Ipifc *ifc;
+ Block *bp;
+ Etherrock *er;
+
+ ifc = a;
+ er = ifc->arg;
+ er->readp = up; /* hide identity under a rock for unbind */
+ if(waserror()){
+ er->readp = 0;
+ pexit("hangup", 1);
+ }
+ for(;;){
+ bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxmtu, 0);
+ ifc->in++;
+ bp->rp += ifc->m->hsize;
+ if(ifc->lifc == nil)
+ freeb(bp);
+ else
+ ipiput(ifc->lifc->local, bp);
+ }
+}
+
+static void
+etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
+{
+ uchar mac[6];
+ char buf[64];
+ Etherrock *er = ifc->arg;
+
+ multicastea(mac, a);
+ sprint(buf, "addmulti %E", mac);
+ devtab[er->cchan->type]->write(er->cchan, buf, strlen(buf), 0);
+}
+
+static void
+etherremmulti(Ipifc *ifc, uchar *a, uchar *)
+{
+ uchar mac[6];
+ char buf[64];
+ Etherrock *er = ifc->arg;
+
+ multicastea(mac, a);
+ sprint(buf, "remmulti %E", mac);
+ devtab[er->cchan->type]->write(er->cchan, buf, strlen(buf), 0);
+}
+
+/*
+ * send an ethernet arp
+ * (only v4, v6 uses the neighbor discovery, rfc1970)
+ */
+static void
+sendarp(Ipifc *ifc, Arpent *a)
+{
+ int n;
+ Block *bp;
+ Etherarp *e;
+ Etherrock *er = ifc->arg;
+
+ /* don't do anything if it's been less than a second since the last */
+ if(msec - a->time < 1000){
+ arprelease(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;
+ arprelease(a);
+
+ n = sizeof(Etherarp);
+ if(n < a->type->minmtu)
+ n = a->type->minmtu;
+ bp = allocb(n);
+ memset(bp->rp, 0, n);
+ e = (Etherarp*)bp->rp;
+ memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
+ ipv4local(ifc, e->spa);
+ memmove(e->sha, ifc->mac, sizeof(e->sha));
+ memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
+ memmove(e->s, ifc->mac, sizeof(e->s));
+
+ hnputs(e->type, ETARP);
+ hnputs(e->hrd, 1);
+ hnputs(e->pro, ETIP);
+ e->hln = sizeof(e->sha);
+ e->pln = sizeof(e->spa);
+ hnputs(e->op, ARPREQUEST);
+ bp->wp += n;
+
+ n = devtab[er->achan->type]->bwrite(er->achan, bp, 0);
+ if(n < 0)
+ print("arp: send: %r\n");
+}
+
+static void
+recvarp(Ipifc *ifc)
+{
+ int n;
+ Block *ebp, *rbp;
+ Etherarp *e, *r;
+ uchar ip[IPaddrlen];
+ Etherrock *er = ifc->arg;
+
+ ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxmtu, 0);
+ if(ebp == nil) {
+ print("arp: rcv: %r\n");
+ return;
+ }
+
+ e = (Etherarp*)ebp->rp;
+ switch(nhgets(e->op)) {
+ default:
+ break;
+
+ case ARPREPLY:
+ arpenter(ifc, V4, e->spa, e->sha, ðermedium, 0);
+ break;
+
+ case ARPREQUEST:
+ /* don't answer arps till we know who we are */
+ if(ifc->lifc == 0)
+ break;
+
+ /* check for someone that think's they're me */
+ v4tov6(ip, e->spa);
+ if(iplocalonifc(ifc, ip)){
+ 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);
+ break;
+ }
+ }
+
+ /* refresh what we know about sender */
+ arpenter(ifc, V4, e->spa, e->sha, ðermedium, 1);
+
+ /* answer only requests for our address or systems we're proxying for */
+ v4tov6(ip, e->tpa);
+ if(!iplocalonifc(ifc, ip))
+ if(ipproxyifc(ifc, ip) == 0)
+ 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;
+ rbp = allocb(n);
+ r = (Etherarp*)rbp->rp;
+ memset(r, 0, sizeof(Etherarp));
+ hnputs(r->type, ETARP);
+ hnputs(r->hrd, 1);
+ hnputs(r->pro, ETIP);
+ r->hln = sizeof(r->sha);
+ r->pln = sizeof(r->spa);
+ hnputs(r->op, ARPREPLY);
+ memmove(r->tha, e->sha, sizeof(r->tha));
+ memmove(r->tpa, e->spa, sizeof(r->tpa));
+ memmove(r->sha, ifc->mac, sizeof(r->sha));
+ memmove(r->spa, e->tpa, sizeof(r->spa));
+ memmove(r->d, e->sha, sizeof(r->d));
+ memmove(r->s, ifc->mac, sizeof(r->s));
+ rbp->wp += n;
+
+ n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
+ if(n < 0)
+ print("arp: write: %r\n");
+ }
+ freeb(ebp);
+}
+
+static void
+recvarpproc(Ipifc *ifc)
+{
+ Etherrock *er = ifc->arg;
+
+ er->arpp = up;
+ if(waserror()){
+ er->arpp = 0;
+ pexit("hangup", 1);
+ }
+ for(;;)
+ recvarp(ifc);
+}
+
+static int
+multicastea(uchar *ea, uchar *ip)
+{
+ int x;
+
+ switch(x = ipismulticast(ip)){
+ case V4:
+ ea[0] = 0x01;
+ ea[1] = 0x00;
+ ea[2] = 0x5e;
+ ea[3] = ip[13] & 0x7f;
+ ea[4] = ip[14];
+ ea[5] = ip[15];
+ break;
+ 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;
+ }
+ return x;
+}
+
+/*
+ * fill in an arp entry for broadcast or multicast
+ * addresses
+ */
+static Block*
+multicastarp(Arpent *a, uchar *mac)
+{
+ /* is it broadcast? */
+ switch(ipforme(a->ip)){
+ case Runi:
+ return nil;
+ case Rbcast:
+ memset(mac, 0xff, 6);
+ return arpresolve(a, ðermedium, mac);
+ default:
+ break;
+ }
+
+ /* if multicast, fill in mac */
+ switch(multicastea(mac, a->ip)){
+ case V4:
+ case V6:
+ return arpresolve(a, ðermedium, mac);
+ }
+
+ /* let arp take care of it */
+ return nil;
+}
M ip/gre.c => ip/gre.c +43 -35
@@ 23,20 23,20 @@ enum
typedef struct GREhdr
{
/* ip header */
- byte vihl; /* Version and header length */
- byte tos; /* Type of service */
- byte len[2]; /* packet length (including headers) */
- byte id[2]; /* Identification */
- byte frag[2]; /* Fragment information */
- byte Unused;
- byte proto; /* Protocol */
- byte cksum[2]; /* checksum */
- byte src[4]; /* Ip source */
- byte dst[4]; /* Ip destination */
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar len[2]; /* packet length (including headers) */
+ uchar id[2]; /* Identification */
+ uchar frag[2]; /* Fragment information */
+ uchar Unused;
+ uchar proto; /* Protocol */
+ uchar cksum[2]; /* checksum */
+ uchar src[4]; /* Ip source */
+ uchar dst[4]; /* Ip destination */
/* gre header */
- byte flags[2];
- byte eproto[2]; /* encapsulation protocol */
+ uchar flags[2];
+ uchar eproto[2]; /* encapsulation protocol */
} GREhdr;
Proto gre;
@@ 56,7 56,7 @@ greconnect(Conv *c, char **argv, int argc)
/* make sure noone's already connected to this other sys */
p = c->p;
- lock(p);
+ qlock(p);
ecp = &p->conv[p->nc];
for(cp = p->conv; cp < ecp; cp++){
tc = *cp;
@@ 66,12 66,12 @@ greconnect(Conv *c, char **argv, int argc)
continue;
if(tc->rport == c->rport && tc->raddr == c->raddr){
err = "already connected to that addr/proto";
- c->rport = 0;
- c->raddr = 0;
+ ipmove(c->laddr, IPnoaddr);
+ ipmove(c->raddr, IPnoaddr);
break;
}
}
- unlock(p);
+ qunlock(p);
if(err != nil)
return err;
@@ 81,11 81,10 @@ greconnect(Conv *c, char **argv, int argc)
}
static int
-grestate(char **msg, Conv *c)
+grestate(Conv *c, char *state, int n)
{
USED(c);
- *msg = "Datagram";
- return 1;
+ return snprint(state, n, "%s", "Datagram");
}
static void
@@ 107,8 106,8 @@ greclose(Conv *c)
qclose(c->rq);
qclose(c->wq);
qclose(c->eq);
- c->laddr = 0;
- c->raddr = 0;
+ ipmove(c->laddr, IPnoaddr);
+ ipmove(c->raddr, IPnoaddr);
c->lport = 0;
c->rport = 0;
@@ 122,7 121,7 @@ grekick(Conv *c, int l)
{
GREhdr *ghp;
Block *bp;
- ulong raddr, laddr;
+ uchar laddr[IPaddrlen], raddr[IPaddrlen];
USED(l);
@@ 142,16 141,17 @@ grekick(Conv *c, int l)
ghp = (GREhdr *)(bp->rp);
- raddr = nhgetl(ghp->dst);
- laddr = nhgetl(ghp->src);
- if(raddr == 0)
- raddr = c->raddr;
- if(laddr == 0 || Mediaforme(ghp->src) <= 0)
- laddr = c->laddr;
+ v4tov6(raddr, ghp->dst);
+ if(ipcmp(raddr, v4prefix) == 0)
+ memmove(ghp->dst, c->raddr + IPv4off, IPv4addrlen);
+ v4tov6(laddr, ghp->src);
+ if(ipcmp(laddr, v4prefix) == 0){
+ if(ipcmp(c->laddr, IPnoaddr) == 0)
+ findlocalip(c->laddr, raddr); /* pick interface closest to dest */
+ memmove(ghp->src, c->laddr + IPv4off, IPv4addrlen);
+ }
ghp->proto = IP_GREPROTO;
- hnputl(ghp->dst, raddr);
- hnputl(ghp->src, laddr);
hnputs(ghp->eproto, c->rport);
ghp->frag[0] = 0;
ghp->frag[1] = 0;
@@ 160,19 160,18 @@ grekick(Conv *c, int l)
}
static void
-greiput(Media *m, Block *bp)
+greiput(uchar*, Block *bp)
{
int len;
GREhdr *ghp;
- Ipaddr addr;
Conv *c, **p;
ushort eproto;
+ uchar raddr[IPaddrlen];
- USED(m);
ghp = (GREhdr*)(bp->rp);
+ v4tov6(raddr, ghp->src);
eproto = nhgets(ghp->eproto);
- addr = nhgetl(ghp->src);
/* Look for a conversation structure for this port and address */
c = nil;
@@ 180,7 179,7 @@ greiput(Media *m, Block *bp)
c = *p;
if(c->inuse == 0)
continue;
- if(c->raddr == addr && c->rport == eproto)
+ if(c->rport == eproto && ipcmp(c->raddr, raddr) == 0)
break;
}
@@ 216,6 215,14 @@ greiput(Media *m, Block *bp)
}
}
+int
+grestats(char *buf, int len)
+{
+ return snprint(buf, len,
+ "gre: csum %d hlen %d len %d order %d rexmit %d\n",
+ gre.csumerr, gre.hlenerr, gre.lenerr, gre.order, gre.rexmit);
+}
+
void
greinit(Fs *fs)
{
@@ 229,6 236,7 @@ greinit(Fs *fs)
gre.rcv = greiput;
gre.ctl = nil;
gre.advise = nil;
+ gre.stats = grestats;
gre.ipproto = IP_GREPROTO;
gre.nc = 64;
gre.ptclsize = 0;
M ip/icmp.c => ip/icmp.c +44 -42
@@ 8,22 8,22 @@
#include "ip.h"
typedef struct Icmp {
- byte vihl; /* Version and header length */
- byte tos; /* Type of service */
- byte length[2]; /* packet length */
- byte id[2]; /* Identification */
- byte frag[2]; /* Fragment information */
- byte ttl; /* Time to live */
- byte proto; /* Protocol */
- byte ipcksum[2]; /* Header checksum */
- byte src[4]; /* Ip source */
- byte dst[4]; /* Ip destination */
- byte type;
- byte code;
- byte cksum[2];
- byte icmpid[2];
- byte seq[2];
- byte data[1];
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar length[2]; /* packet length */
+ uchar id[2]; /* Identification */
+ uchar frag[2]; /* Fragment information */
+ uchar ttl; /* Time to live */
+ uchar proto; /* Protocol */
+ uchar ipcksum[2]; /* Header checksum */
+ uchar src[4]; /* Ip source */
+ uchar dst[4]; /* Ip destination */
+ uchar type;
+ uchar code;
+ uchar cksum[2];
+ uchar icmpid[2];
+ uchar seq[2];
+ uchar data[1];
} Icmp;
enum { /* Packet Types */
@@ 67,11 67,10 @@ icmpconnect(Conv *c, char **argv, int argc)
}
static int
-icmpstate(char **s, Conv *c)
+icmpstate(Conv *c, char *state, int n)
{
USED(c);
- *s = "Datagram";
- return 1;
+ return snprint(state, n, "%s", "Datagram");
}
static void
@@ 99,7 98,8 @@ icmpclose(Conv *c)
{
qclose(c->rq);
qclose(c->wq);
- c->laddr = 0;
+ ipmove(c->laddr, IPnoaddr);
+ ipmove(c->raddr, IPnoaddr);
c->lport = 0;
unlock(c);
}
@@ 122,8 122,8 @@ icmpkick(Conv *c, int l)
p = (Icmp *)(bp->rp);
if(p->type <= Maxtype)
stats.out[p->type]++;
- hnputl(p->dst, c->raddr);
- hnputl(p->src, c->laddr);
+ v6tov4(p->dst, c->raddr);
+ v6tov4(p->src, c->laddr);
p->proto = IP_ICMPPROTO;
hnputs(p->icmpid, c->lport);
memset(p->cksum, 0, sizeof(p->cksum));
@@ 137,11 137,8 @@ icmpnoconv(Block *bp)
Block *nbp;
Icmp *p, *np;
- /* don't bother if we haven't gotten any links up yet */
- if(Mediabooting())
- return;
-
p = (Icmp *)bp->rp;
+ netlog(Logicmp, "sending icmpnoconv -> %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;
@@ 164,20 161,17 @@ goticmpkt(Block *bp)
{
Conv **c, *s;
Icmp *p;
- Ipaddr dst;
+ uchar dst[IPaddrlen];
ushort recid;
p = (Icmp *) bp->rp;
- dst = nhgetl(p->src);
+ v4tov6(dst, p->src);
recid = nhgets(p->icmpid);
-netlog(Logicmp, "goticmpkt from %i to %d\n", dst, recid);
for(c = icmp.conv; *c; c++) {
s = *c;
-netlog(Logicmp, "conv %i %d %i %d\n", s->laddr, s->lport, s->raddr, s->rport);
- if(s->lport == recid && s->raddr == dst){
- if(bp->next)
- bp = concatblock(bp);
+ if(s->lport == recid)
+ if(ipcmp(s->raddr, dst) == 0){
qpass(s->rq, bp);
return;
}
@@ 189,7 183,7 @@ static Block *
mkechoreply(Block *bp)
{
Icmp *q;
- byte ip[4];
+ uchar ip[4];
q = (Icmp *)bp->rp;
memmove(ip, q->src, sizeof(q->dst));
@@ 198,6 192,7 @@ mkechoreply(Block *bp)
q->type = EchoReply;
memset(q->cksum, 0, sizeof(q->cksum));
hnputs(q->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE));
+
return bp;
}
@@ 212,7 207,7 @@ static char *unreachcode[] =
};
static void
-icmpiput(Media *m, Block *bp)
+icmpiput(uchar*, Block *bp)
{
int n, iplen;
Icmp *p;
@@ 221,21 216,23 @@ icmpiput(Media *m, Block *bp)
char *msg;
char m2[128];
- USED(m);
p = (Icmp *)bp->rp;
netlog(Logicmp, "icmpiput %d %d\n", p->type, p->code);
n = blocklen(bp);
if(n < ICMP_IPSIZE+ICMP_HDRSIZE){
icmp.hlenerr++;
+ netlog(Logicmp, "icmp hlen %d\n", n);
goto raise;
}
iplen = nhgets(p->length);
if(iplen > n || (iplen % 1)){
icmp.lenerr++;
+ netlog(Logicmp, "icmp length %d\n", iplen);
goto raise;
}
if(ptclcsum(bp, ICMP_IPSIZE, iplen - ICMP_IPSIZE)){
icmp.csumerr++;
+ netlog(Logicmp, "icmp checksum error\n");
goto raise;
}
if(p->type <= Maxtype)
@@ 269,7 266,7 @@ icmpiput(Media *m, Block *bp)
break;
case TimeExceed:
if(p->code == 0){
- sprint(m2, "ttl exceeded at %I", p->src);
+ sprint(m2, "ttl exceeded at %V", p->src);
bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
if(blocklen(bp) < 8){
@@ 301,16 298,17 @@ icmpadvise(Block *bp, char *msg)
{
Conv **c, *s;
Icmp *p;
- Ipaddr dst;
+ uchar dst[IPaddrlen];
ushort recid;
p = (Icmp *) bp->rp;
- dst = nhgetl(p->dst);
+ v4tov6(dst, p->dst);
recid = nhgets(p->icmpid);
for(c = icmp.conv; *c; c++) {
s = *c;
- if(s->lport == recid && s->raddr == dst){
+ if(s->lport == recid)
+ if(ipcmp(s->raddr, dst) == 0){
qhangup(s->rq, msg);
qhangup(s->wq, msg);
break;
@@ 324,10 322,14 @@ icmpstats(char *buf, int len)
{
int i, n;
- n = snprint(buf, len, "\trcvd ");
+
+ n = snprint(buf, len,
+ "icmp: csum %d hlen %d len %d order %d rexmit %d\n",
+ icmp.csumerr, icmp.hlenerr, icmp.lenerr, icmp.order, icmp.rexmit);
+ n += snprint(buf+n, len-n, "\trcvd ");
for(i = 0; i < Maxtype && len > n; i++)
n += snprint(buf+n, len-n, " %d", stats.in[i]);
- n += snprint(buf+n, len - n, "\n\tsent ");
+ n += snprint(buf+n, len-n, "\n\tsent ");
for(i = 0; i < Maxtype && len > n; i++)
n += snprint(buf+n, len-n, " %d", stats.out[i]);
if(n < len)
M ip/il.c => ip/il.c +77 -66
@@ 63,7 63,7 @@ struct Ilcb /* Control block */
QLock ackq; /* Unacknowledged queue */
Block *unacked;
Block *unackedtail;
- ulong unackedbytes;
+ ulong unackeduchars;
QLock outo; /* Out of order packet queue */
Block *outoforder;
ulong next; /* Id of next to send */
@@ 77,7 77,7 @@ struct Ilcb /* Control block */
int querytime; /* Query timer */
int deathtime; /* Time to kill connection */
int delay; /* Average of the fixed rtt delay */
- int rate; /* Average byte rate */
+ int rate; /* Average uchar rate */
int mdev; /* Mean deviation of rtt */
int maxrtt; /* largest rtt seen */
ulong rttack; /* The ack we are waiting for */
@@ 87,7 87,6 @@ struct Ilcb /* Control block */
int rexmit; /* number of retransmits */
ulong qt[Nqt+1]; /* state table for query messages */
int qtx; /* ... index into qt */
- char buf[128];
};
enum
@@ 102,24 101,24 @@ enum
typedef struct Ilhdr Ilhdr;
struct Ilhdr
{
- byte vihl; /* Version and header length */
- byte tos; /* Type of service */
- byte length[2]; /* packet length */
- byte id[2]; /* Identification */
- byte frag[2]; /* Fragment information */
- byte ttl; /* Time to live */
- byte proto; /* Protocol */
- byte cksum[2]; /* Header checksum */
- byte src[4]; /* Ip source */
- byte dst[4]; /* Ip destination */
- byte ilsum[2]; /* Checksum including header */
- byte illen[2]; /* Packet length */
- byte iltype; /* Packet type */
- byte ilspec; /* Special */
- byte ilsrc[2]; /* Src port */
- byte ildst[2]; /* Dst port */
- byte ilid[4]; /* Sequence id */
- byte ilack[4]; /* Acked sequence */
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar length[2]; /* packet length */
+ uchar id[2]; /* Identification */
+ uchar frag[2]; /* Fragment information */
+ uchar ttl; /* Time to live */
+ uchar proto; /* Protocol */
+ uchar cksum[2]; /* Header checksum */
+ uchar src[4]; /* Ip source */
+ uchar dst[4]; /* Ip destination */
+ uchar ilsum[2]; /* Checksum including header */
+ uchar illen[2]; /* Packet length */
+ uchar iltype; /* Packet type */
+ uchar ilspec; /* Special */
+ uchar ilsrc[2]; /* Src port */
+ uchar ildst[2]; /* Dst port */
+ uchar ilid[4]; /* Sequence id */
+ uchar ilack[4]; /* Acked sequence */
};
static struct Ilstats
@@ 167,7 166,7 @@ void iltimers(Ilcb*);
char* ilstart(Conv*, int, int);
void ilackproc();
void iloutoforder(Conv*, Ilhdr*, Block*);
-void iliput(Media*, Block*);
+void iliput(uchar*, Block*);
void iladvise(Block*, char*);
int ilnextqt(Ilcb*);
@@ 189,23 188,26 @@ ilconnect(Conv *c, char **argv, int argc)
return ilstart(c, IL_CONNECT, 20);
}
-int
-ilstate(char **msg, Conv *c)
+static int
+ilstate(Conv *c, char *state, int n)
{
Ilcb *ic;
- int isclose;
ic = (Ilcb*)(c->ptcl);
+ return snprint(state, n, "%14.14s del %5.5d Br %5.5d md %5.5d una %5.5d rex %5.5d max %5.5d",
+ ilstates[ic->state],
+ ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain,
+ ic->unackeduchars, ic->rexmit, ic->maxrtt);
+}
- isclose = 0;
- if(ic->state == Ilclosed)
- isclose = 1;
+static int
+ilinuse(Conv *c)
+{
+ Ilcb *ic;
+
+ ic = (Ilcb*)(c->ptcl);
+ return ic->state != Ilclosed;
- sprint(ic->buf, "%s del %d Br %d md %d una %d rex %d max %d", ilstates[ic->state],
- ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain,
- ic->unackedbytes, ic->rexmit, ic->maxrtt);
- *msg = ic->buf;
- return isclose;
}
/* called with c locked */
@@ 248,7 250,7 @@ ilclose(Conv *c)
break;
case Illistening:
ic->state = Ilclosed;
- c->laddr = 0;
+ ipmove(c->laddr, IPnoaddr);
c->lport = 0;
break;
}
@@ 291,8 293,8 @@ ilkick(Conv *c, int l)
/* Ip fields */
ih->frag[0] = 0;
ih->frag[1] = 0;
- hnputl(ih->dst, c->raddr);
- hnputl(ih->src, c->laddr);
+ v6tov4(ih->dst, c->raddr);
+ v6tov4(ih->src, c->laddr);
ih->proto = IP_ILPROTO;
/* Il fields */
@@ 338,7 340,13 @@ ilcreate(Conv *c)
int
ilxstats(char *buf, int len)
{
- return snprint(buf, len, "\tdupp %d dupb %d\n", ilstats.dup, ilstats.dupb);
+ int n;
+
+ n = snprint(buf, len,
+ "il: csum %d hlen %d len %d order %d rexmit %d",
+ il.csumerr, il.hlenerr, il.lenerr, il.order, il.rexmit);
+ n += snprint(buf+n, len-n, " dupp %d dupb %d\n",
+ ilstats.dup, ilstats.dupb);
}
void
@@ 355,6 363,7 @@ ilinit(Fs *fs)
il.ctl = nil;
il.advise = iladvise;
il.stats = ilxstats;
+ il.inuse = ilinuse;
il.ipproto = IP_ILPROTO;
il.nc = Nchans;
il.ptclsize = sizeof(Ilcb);
@@ 383,7 392,7 @@ ilackq(Ilcb *ic, Block *bp)
}
ic->unackedtail = np;
np->list = nil;
- ic->unackedbytes += n;
+ ic->unackeduchars += n;
}
static
@@ 450,24 459,24 @@ ilackto(Ilcb *ic, ulong ackto)
bp = ic->unacked;
ic->unacked = bp->list;
bp->list = nil;
- ic->unackedbytes -= blocklen(bp);
+ ic->unackeduchars -= blocklen(bp);
freeblist(bp);
}
qunlock(&ic->ackq);
}
void
-iliput(Media *m, Block *bp)
+iliput(uchar*, Block *bp)
{
char *st;
Ilcb *ic;
Ilhdr *ih;
- Ipaddr dst;
+ uchar raddr[IPaddrlen];
+ uchar laddr[IPaddrlen];
ushort sp, dp, csum;
int plen, illen;
Conv *s, **p, *new, *spec, *gen;
- USED(m);
ih = (Ilhdr *)bp->rp;
plen = blocklen(bp);
if(plen < IL_IPSIZE+IL_HDRSIZE){
@@ 485,7 494,7 @@ iliput(Media *m, Block *bp)
sp = nhgets(ih->ildst);
dp = nhgets(ih->ilsrc);
- dst = nhgetl(ih->src);
+ v4tov6(raddr, ih->src);
if(ilcksum && (csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) {
if(ih->iltype < 0 || ih->iltype > Ilclose)
@@ 493,14 502,16 @@ iliput(Media *m, Block *bp)
else
st = iltype[ih->iltype];
il.csumerr++;
- netlog(Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %i/%d->%d)\n",
- csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), dst, sp, dp);
+ netlog(Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %I/%d->%d)\n",
+ csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp);
goto raise;
}
for(p = il.conv; *p; p++) {
s = *p;
- if(s->lport == sp && s->rport == dp && s->raddr == dst) {
+ if(s->lport == sp)
+ if(s->rport == dp)
+ if(ipcmp(s->raddr, raddr) == 0) {
ilprocess(s, ih, bp);
return;
}
@@ 511,8 522,8 @@ iliput(Media *m, Block *bp)
st = "?";
else
st = iltype[ih->iltype];
- netlog(Logil, "il: no channel, pkt(%s id %lud ack %lud %i/%ud->%ud)\n",
- st, nhgetl(ih->ilid), nhgetl(ih->ilack), dst, sp, dp);
+ netlog(Logil, "il: no channel, pkt(%s id %lud ack %lud %I/%ud->%ud)\n",
+ st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp);
goto raise;
}
@@ 524,7 535,7 @@ iliput(Media *m, Block *bp)
if(ic->state != Illistening)
continue;
- if(s->rport == 0 && s->raddr == 0) {
+ if(s->rport == 0 && ipcmp(s->raddr, IPnoaddr) == 0) {
if(s->lport == sp) {
spec = s;
break;
@@ 542,9 553,10 @@ iliput(Media *m, Block *bp)
else
goto raise;
- new = Fsnewcall(&fs, s, nhgetl(ih->src), dp, nhgetl(ih->dst), sp);
+ v4tov6(laddr, ih->dst);
+ new = Fsnewcall(&fs, s, raddr, dp, laddr, sp);
if(new == nil){
- netlog(Logil, "il: bad newcall %i/%ud->%ud\n", dst, sp, dp);
+ netlog(Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp);
ilsendctl(nil, ih, Ilclose, 0, nhgetl(ih->ilid), 0);
goto raise;
}
@@ 797,7 809,7 @@ ilhangup(Conv *s, char *msg)
Ilcb *ic;
int callout;
- netlog(Logil, "il: hangup! %i %d/%d: %s\n", s->raddr, s->lport, s->rport, msg?msg:"no reason");
+ netlog(Logil, "il: hangup! %I %d/%d: %s\n", s->raddr, s->lport, s->rport, msg?msg:"no reason");
ic = (Ilcb*)s->ptcl;
callout = ic->state == Ilsyncer;
@@ 859,7 871,7 @@ void
iloutoforder(Conv *s, Ilhdr *h, Block *bp)
{
Ilcb *ic;
- byte *lid;
+ uchar *lid;
Block *f, **l;
ulong id, newid;
@@ 932,8 944,8 @@ ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec)
ttl = MAXTTL;
}
else {
- hnputl(ih->dst, ipc->raddr);
- hnputl(ih->src, ipc->laddr);
+ v6tov4(ih->dst, ipc->raddr);
+ v6tov4(ih->src, ipc->laddr);
hnputs(ih->ilsrc, ipc->lport);
hnputs(ih->ildst, ipc->rport);
hnputl(ih->ilid, id);
@@ 1015,9 1027,7 @@ loop:
break;
}
if(ic->timeout >= ic->fasttime) {
- ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
- ic->querytime = Querytime;
- ic->timeout = 0;
+ ilrexmit(ic);
ilbackoff(ic);
}
if(ic->timeout >= ic->slowtime) {
@@ 1053,7 1063,7 @@ ilstart(Conv *c, int type, int window)
ic->unacked = nil;
ic->outoforder = nil;
- ic->unackedbytes = 0;
+ ic->unackeduchars = 0;
ic->delay = Iltickms<<LogAGain;
ic->mdev = Iltickms<<LogDGain;
ic->rate = DefByteRate<<LogAGain;
@@ 1111,8 1121,8 @@ iltimers(Ilcb *ic)
int pt;
ic->timeout = 0;
- pt = (ic->delay>>LogAGain) + ic->unackedbytes/(ic->rate>>LogAGain) + (ic->mdev>>(LogDGain-1));
- ic->fasttime = pt + Iltickms - 1;
+ pt = (ic->delay>>LogAGain) + ic->unackeduchars/(ic->rate>>LogAGain) + ic->mdev;
+ ic->fasttime = Acktime + pt + Iltickms - 1;
if(ic->fasttime > Fasttime)
ic->fasttime = Fasttime;
ic->slowtime = (Slowtime/Seconds)*pt;
@@ 1125,22 1135,23 @@ iladvise(Block *bp, char *msg)
{
Ilhdr *h;
Ilcb *ic;
- Ipaddr source, dest;
+ uchar source[IPaddrlen], dest[IPaddrlen];
ushort psource;
Conv *s, **p;
h = (Ilhdr*)(bp->rp);
- dest = nhgetl(h->dst);
- source = nhgetl(h->src);
+ v4tov6(dest, h->dst);
+ v4tov6(source, h->src);
psource = nhgets(h->ilsrc);
/* Look for a connection, unfortunately the destination port is missing */
for(p = il.conv; *p; p++) {
s = *p;
- if(s->laddr == source && s->lport == psource)
- if(s->raddr == dest){
+ if(s->lport == psource)
+ if(ipcmp(s->laddr, source) == 0)
+ if(ipcmp(s->raddr, dest) == 0){
ic = (Ilcb*)s->ptcl;
switch(ic->state){
case Ilsyncer:
M ip/ip.c => ip/ip.c +58 -58
@@ 18,29 18,29 @@ enum
IP_HLEN = 0x05, /* Header length in characters */
IP_DF = 0x4000, /* Don't fragment */
IP_MF = 0x2000, /* More fragments */
- IP_MAX = (64*1024), /* Maximum Internet packet size */
+ IP_MAX = (32*1024), /* Maximum Internet packet size */
};
struct Iphdr
{
- byte vihl; /* Version and header length */
- byte tos; /* Type of service */
- byte length[2]; /* packet length */
- byte id[2]; /* Identification */
- byte frag[2]; /* Fragment information */
- byte ttl; /* Time to live */
- byte proto; /* Protocol */
- byte cksum[2]; /* Header checksum */
- byte src[4]; /* Ip source */
- byte dst[4]; /* Ip destination */
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar length[2]; /* packet length */
+ uchar id[2]; /* Identification */
+ uchar frag[2]; /* Fragment information */
+ 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;
- Ipaddr src;
- Ipaddr dst;
+ ulong src;
+ ulong dst;
ushort id;
ulong age;
};
@@ 57,8 57,8 @@ Fragment* fragfree;
ulong Id;
int iprouting; /* true if we route like a gateway */
ulong ipcsumerr;
-ulong ipin, ippin; /* bytes, packets in */
-ulong ipout, ippout; /* bytes, packets out */
+ulong ipin, ippin; /* uchars, packets in */
+ulong ipout, ippout; /* uchars, packets out */
#define BLKIP(xp) ((Iphdr*)((xp)->rp))
/*
@@ 73,7 73,7 @@ static struct Stats
ulong droppedfrag;
} stats;
-ushort ipcsum(byte*);
+ushort ipcsum(uchar*);
Block* ipreassemble(int, Block*, Iphdr*);
void ipfragfree(Fragment*);
Fragment* ipfragallo(void);
@@ 81,17 81,18 @@ Fragment* ipfragallo(void);
void
ipoput(Block *bp, int gating, int ttl)
{
- Media *m;
- byte gate[4];
+ Ipifc *ifc;
+ uchar *gate;
ushort fragoff;
Block *xp, *nb;
Iphdr *eh, *feh;
int lid, len, seglen, chunk, dlen, blklen, offset, medialen;
+ Route *r;
/* Fill out the ip header */
eh = (Iphdr *)(bp->rp);
- /* Number of bytes in data and ip header to write */
+ /* Number of uchars in data and ip header to write */
len = blocklen(bp);
ipout += len;
ippout++;
@@ 104,30 105,30 @@ ipoput(Block *bp, int gating, int ttl)
if(chunk < len)
len = chunk;
}
- if(len >= IP_MAX) {
- netlog(Logip, "exceeded ip max size %I\n", eh->dst);
+ if(len >= IP_MAX){
+ netlog(Logip, "exceeded ip max size %V\n", eh->dst);
goto raise;
}
- if(isbmcast(eh->dst)){
- m = Mediaroute(eh->src, nil);
- memmove(gate, eh->dst, IPaddrlen);
- } else
- m = Mediaroute(eh->dst, gate);
- if(m == nil){
+ r = v4lookup(eh->dst);
+ if(r == nil){
stats.noroute++;
- netlog(Logip, "no interface %I\n", eh->dst);
+ netlog(Logip, "no interface %V\n", eh->dst);
goto raise;
}
-
+ if(r->type & (Rifc|Runi|Rbcast|Rmulti))
+ gate = eh->dst;
+ else
+ gate = r->v4.gate;
if(!gating){
eh->vihl = IP_VER|IP_HLEN;
eh->tos = 0;
eh->ttl = ttl;
}
+ ifc = r->ifc;
/* If we dont need to fragment just send it */
- medialen = m->maxmtu-m->hsize;
+ medialen = ifc->m->maxmtu - ifc->m->hsize;
if(len <= medialen) {
if(!gating)
hnputs(eh->id, Id++);
@@ 138,18 139,19 @@ ipoput(Block *bp, int gating, int ttl)
eh->cksum[1] = 0;
hnputs(eh->cksum, ipcsum(&eh->vihl));
- Mediawrite(m, bp, gate);
+/*print("ipoput %V->%V via %V\n", eh->src, eh->dst, gate);*/
+ ifc->m->bwrite(ifc, bp, V4, gate);
return;
}
if(eh->frag[0] & (IP_DF>>8)){
- netlog(Logip, "%I: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
+ netlog(Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
goto raise;
}
seglen = (medialen - IPHDR) & ~7;
if(seglen < 8){
- netlog(Logip, "%I seglen < 8\n", eh->dst);
+ netlog(Logip, "%V seglen < 8\n", eh->dst);
goto raise;
}
@@ 206,7 208,7 @@ ipoput(Block *bp, int gating, int ttl)
feh->cksum[0] = 0;
feh->cksum[1] = 0;
hnputs(feh->cksum, ipcsum(&feh->vihl));
- Mediawrite(m, nb, gate);
+ ifc->m->bwrite(ifc, nb, V4, gate);
}
raise:
@@ 218,7 220,7 @@ initfrag(int size)
{
Fragment *fq, *eq;
- fragfree = malloc(sizeof(Fragment) * size);
+ fragfree = (Fragment*)malloc(sizeof(Fragment) * size);
if(fragfree == nil)
panic("initfrag");
@@ 234,12 236,13 @@ void (*ipextprotoiput)(Block*);
//#define DBG(x) if((logmask & Logipmsg) && (iponly == 0 || x == iponly))netlog
void
-ipiput(Media *m, Block *bp)
+ipiput(uchar *ia, Block *bp)
{
Iphdr *h;
Proto *p;
ushort frag;
int notforme;
+ uchar v6dst[IPaddrlen];
// h = (Iphdr *)(bp->rp);
// DBG(nhgetl(h->src))(Logipmsg, "ipiput %I %I len %d proto %d\n", h->src, h->dst, BLEN(bp), h->proto);
@@ 252,14 255,7 @@ ipiput(Media *m, Block *bp)
}
h = (Iphdr *)(bp->rp);
- /* Look to see if its for me before we waste time checksumming it */
- notforme = Mediaforme(h->dst) == 0;
- if(notforme && !iprouting) {
- netlog(Logip, "ip: pkt not for me\n");
- freeblist(bp);
- return;
- }
-
+ /* dump anything that whose header doesn't checksum */
if(ipcsum(&h->vihl)) {
ipcsumerr++;
netlog(Logip, "ip: checksum error %I\n", h->src);
@@ 267,6 263,21 @@ ipiput(Media *m, Block *bp)
return;
}
+ /* route */
+ v4tov6(v6dst, h->dst);
+ notforme = ipforme(v6dst) == 0;
+ if(notforme) {
+ if(iprouting) {
+ /* gate */
+ if(h->ttl <= 1)
+ freeblist(bp);
+ else
+ ipoput(bp, 1, h->ttl - 1);
+ } else
+ useriprouter(ia, bp);
+ return;
+ }
+
/* Check header length and version */
if(h->vihl != (IP_VER|IP_HLEN)) {
netlog(Logip, "ip: %I bad hivl %ux\n", h->src, h->vihl);
@@ 287,20 298,9 @@ ipiput(Media *m, Block *bp)
ipin += blocklen(bp);
ippin++;
- if(iprouting) {
- /* gate */
- if(notforme){
- if(h->ttl == 0)
- freeblist(bp);
- else
- ipoput(bp, 1, h->ttl - 1);
- return;
- }
- }
-
p = Fsrcvpcol(&fs, h->proto);
if(p != nil && p->rcv != nil)
- (*p->rcv)(m, bp);
+ (*p->rcv)(ia, bp);
else if(ipextprotoiput != nil)
ipextprotoiput(bp);
else
@@ 325,7 325,7 @@ ipreassemble(int offset, Block *bp, Iphdr *ip)
int fend;
ushort id;
Fragment *f, *fnext;
- Ipaddr src, dst;
+ ulong src, dst;
Block *bl, **l, *last, *prev;
int ovlap, len, fragsize, pktposn;
@@ 532,7 532,7 @@ ipfragallo(void)
}
ushort
-ipcsum(byte *addr)
+ipcsum(uchar *addr)
{
int len;
ulong sum;
M ip/ip.h => ip/ip.h +297 -115
@@ 1,15 1,19 @@
-typedef ulong Ipaddr;
-typedef uchar byte;
typedef struct Conv Conv;
typedef struct Fs Fs;
typedef union Hwaddr Hwaddr;
typedef struct Ifcconv Ifcconv;
+typedef struct Ipself Ipself;
+typedef struct Iplink Iplink;
+typedef struct Iplifc Iplifc;
+typedef struct Ipmulti Ipmulti;
typedef struct Iproute Iproute;
-typedef struct Media Media;
-typedef struct Multicast Multicast;
+typedef struct Ipifc Ipifc;
+typedef struct Medium Medium;
typedef struct Proto Proto;
typedef struct Pstate Pstate;
typedef struct Tcpc Tcpc;
+typedef struct Arpent Arpent;
+typedef struct Route Route;
enum
{
@@ 18,14 22,18 @@ enum
Nhash= 64,
Maxincall= 5,
Nchans= 256,
+ MAClen= 16, /* longest mac address */
MAXTTL= 255,
- IPaddrlen= 4,
- Ipbcast= 0xffffffff, /* ip broadcast address */
- Ipbcastobs= 0, /* obsolete (but still used) ip broadcast addr */
- Ipallsys= 0xe0000001, /* multicast for all systems */
- Ipallrouter= 0xe0000002, /* multicast for all routers */
+ IPaddrlen= 16,
+ IPv4addrlen= 4,
+ IPv4off= 12,
+ IPllen= 4,
+
+ /* ip versions */
+ V4= 4,
+ V6= 6,
};
enum
@@ 46,8 54,8 @@ struct Conv
int x; /* conversation index */
Proto* p;
- Ipaddr laddr; /* local IP address */
- Ipaddr raddr; /* remote IP address */
+ uchar laddr[IPaddrlen]; /* local IP address */
+ uchar raddr[IPaddrlen]; /* remote IP address */
int restricted; /* remote port is restricted */
ushort lport; /* local port number */
ushort rport; /* remote port number */
@@ 77,86 85,104 @@ struct Conv
QLock listenq;
Rendez listenr;
+ Ipmulti *multi; /* multicast bindings for this interface */
+
void* ptcl; /* protocol specific stuff */
};
-union Hwaddr
+struct Medium
{
- byte ether[6];
+ char *name;
+ int hsize; /* medium header size */
+ int minmtu; /* default min mtu */
+ int maxmtu; /* default max mtu */
+ int maclen; /* mac address length */
+ void (*bind)(Ipifc*, int, char**);
+ void (*unbind)(Ipifc*);
+ void (*bwrite)(Ipifc *ifc, Block *b, int version, uchar *ip);
+
+ /* for arming interfaces to receive multicast */
+ void (*addmulti)(Ipifc *ifc, uchar *a, uchar *ia);
+ void (*remmulti)(Ipifc *ifc, uchar *a, uchar *ia);
+
+ /* process packets written to 'data' */
+ void (*pktin)(Ipifc *ifc, Block *bp);
+
+ /* routes for router boards */
+ void (*addroute)(Ipifc *ifc, int, uchar*, uchar*, uchar*, int);
+ void (*remroute)(Ipifc *ifc, int, uchar*, uchar*);
+ void (*flushroutes)(Ipifc *ifc);
+
+ /* for routing multicast groups */
+ void (*joinmulti)(Ipifc *ifc, uchar *a, uchar *ia, uchar **iap);
+ void (*leavemulti)(Ipifc *ifc, uchar *a, uchar *ia);
};
-enum
+/* logical interface associated with a physical one */
+struct Iplifc
{
- METHER, /* Media types */
- MFDDI,
- MPACKET,
+ uchar local[IPaddrlen];
+ uchar mask[IPaddrlen];
+ uchar remote[IPaddrlen];
+ uchar net[IPaddrlen];
+ Iplink *link; /* addresses linked to this lifc */
+ Iplifc *next;
};
-/* one per multicast address per medium */
-struct Multicast
+/* binding twixt Ipself and Ipifc */
+struct Iplink
{
- Ipaddr addr;
+ Ipself *local;
+ Iplifc *lifc;
+ Iplink *locallink; /* next link for this local address */
+ Iplink *lifclink; /* next link for this ifc */
+ ulong expire;
+ Iplink *next; /* free list */
int ref;
- int timeout;
- Multicast *next;
};
-struct Media
+struct Ipifc
{
- int type; /* Media type */
- Chan* mchan; /* Data channel */
- Chan* achan; /* Arp channel */
- Chan* cchan; /* Control channel */
- char* dev; /* device mfd points to */
- Ipaddr myip[5];
- Ipaddr mymask;
- Ipaddr mynetmask;
- Ipaddr remip; /* Address of remote side */
- byte netmyip[4]; /* In Network byte order */
- int arping; /* true if we mus arp */
+ RWlock;
+
+ Conv *conv; /* link to its conversation structure */
+ char dev[64]; /* device we're attached to */
+ Medium *m; /* Media pointer */
int maxmtu; /* Maximum transfer unit */
int minmtu; /* Minumum tranfer unit */
- int hsize; /* Media header size */
- Hwaddr;
+ void *arg; /* medium specific */
+
+ /* these are used so that we can unbind on the fly */
+ Lock idlock;
+ uchar ifcid; /* incremented each 'bind/unbind/add/remove' */
+ int ref; /* number of proc's using this ipifc */
+ Rendez wait; /* where unbinder waits for ref == 0 */
+ int unbinding;
+
+ uchar mac[MAClen]; /* MAC address */
+
+ Iplifc *lifc; /* logical interfaces on this physical one */
+
ulong in, out; /* message statistics */
ulong inerr, outerr; /* ... */
- int inuse;
- Conv *c; /* for packet interface */
-
- QLock mlock; /* lock for changing *multi */
- Multicast *multi; /* list of multicast addresses we're listening to */
- int mactive; /* number of active multicast addresses */
+};
- Media* link;
+/*
+ * one per multicast-lifc pair used by a Conv
+ */
+struct Ipmulti
+{
+ uchar ma[IPaddrlen];
+ uchar ia[IPaddrlen];
+ Ipmulti *next;
};
-int Mediabooting(void);
-int Mediaforme(byte*);
-int Mediaforpt2pt(byte*);
-Ipaddr Mediagetsrc(byte*);
-void Mediaclose(Media*);
-char* Mediaopen(int, char*, Conv*, Ipaddr, Ipaddr, Ipaddr, int, Media**);
-Media* Mediaroute(byte*, byte*);
-void Mediasetaddr(Media*, Ipaddr, Ipaddr);
-void Mediasetraddr(Media*, Ipaddr);
-Ipaddr Mediagetaddr(Media*);
-Ipaddr Mediagetraddr(Media*);
-void Mediawrite(Media*, Block*, byte*);
-int Mediaifcread(char*, ulong, int);
-char* Mediaifcwrite(Ifcconv*, char*, int);
-void Mediaresolver(Media*);
-void Mediaread(Media*);
-int Mediaarp(Media*, Block*, byte*, Hwaddr*);
-Media* Mediafind(Iproute*);
-Multicast* Mediacopymulti(Media*);
-void Mediamulticastadd(Media*, Ifcconv*, Ipaddr);
-void Mediamulticastrem(Media*, Ipaddr);
/*
* one per multiplexed protocol
*/
struct Proto
{
- Lock;
+ QLock;
char* name; /* protocol name */
int x; /* protocol index */
int ipproto; /* ip protocol type */
@@ 164,13 190,16 @@ struct Proto
void (*kick)(Conv*, int);
char* (*connect)(Conv*, char**, int);
char* (*announce)(Conv*, char**, int);
- int (*state)(char**, Conv*);
+ char* (*bind)(Conv*, char**, int);
+ int (*state)(Conv*, char*, int);
void (*create)(Conv*);
void (*close)(Conv*);
- void (*rcv)(Media*, Block*);
+ void (*rcv)(uchar*, Block*);
char* (*ctl)(Conv*, char**, int);
void (*advise)(Block*, char*);
int (*stats)(char*, int);
+ int (*local)(Conv*, char*, int);
+ int (*inuse)(Conv*);
Conv **conv; /* array of conversations */
int ptclsize; /* size of per protocol ctl block */
@@ 196,16 225,19 @@ struct Fs
Proto* t2p[256]; /* vector of all ip protocol handlers */
};
int Fsconnected(Fs*, Conv*, char*);
-Conv* Fsnewcall(Fs*, Conv*, Ipaddr, ushort, Ipaddr, ushort);
+Conv* Fsnewcall(Fs*, Conv*, uchar*, ushort, uchar*, ushort);
int Fspcolstats(char*, int);
int Fsproto(Fs*, Proto*);
-int Fsbuiltinproto(Fs*, byte);
+int Fsbuiltinproto(Fs*, uchar);
Conv* Fsprotoclone(Proto*, char*);
-Proto* Fsrcvpcol(Fs*, byte);
+Proto* Fsrcvpcol(Fs*, uchar);
char* Fsstdconnect(Conv*, char**, int);
char* Fsstdannounce(Conv*, char**, int);
+char* Fsstdbind(Conv*, char**, int);
-/* log flags */
+/*
+ * logging
+ */
enum
{
Logip= 1<<1,
@@ 225,7 257,8 @@ enum
};
extern int logmask; /* mask of things to debug */
-extern Ipaddr iponly; /* ip address to print debugging for */
+extern uchar iponly[IPaddrlen]; /* ip address to print debugging for */
+extern int iponlyset;
void netlogopen(void);
void netlogclose(void);
@@ 233,51 266,200 @@ char* netlogctl(char*, int);
long netlogread(void*, ulong, long);
void netlog(int, char*, ...);
-#define msec TK2MS(MACHP(0)->ticks)
+/*
+ * iproute.c
+ */
+typedef struct RouteTree RouteTree;
+typedef struct Routewalk Routewalk;
+typedef struct V4route V4route;
+typedef struct V6route V6route;
-/* Globals */
-extern int debug;
-extern Fs fs;
-extern Media* media;
-extern int iprouting; /* true if routing turned on */
-extern void (*igmpreportfn)(Media*, byte*);
-
-int arpread(byte*, ulong, int);
-char* arpwrite(char*, int);
-void closeifcconv(Ifcconv*);
-Ipaddr defmask(Ipaddr);
-int eipconv(va_list*, Fconv*);
-int equivip(byte*, byte*);
-void fatal(byte*, ...);
-void hnputl(byte*, ulong);
-void hnputs(byte*, ushort);
-void icmpnoconv(Block*);
-void initfrag(int);
-ushort ipcsum(byte*);
-void (*ipextprotoiput)(Block*);
-Ipaddr ipgetsrc(byte*);
-void ipiput(Media*, Block*);
-void ipoput(Block*, int, int);
-int ipstats(char*, int);
-int ismcast(byte*);
-int isbmcast(byte*);
-byte* logctl(byte*);
-void maskip(byte*, byte*, byte*);
-Ifcconv* newifcconv(void);
-ulong nhgetl(byte*);
-ushort nhgets(byte*);
-void (*pktifcrcv)(Conv*, Block*);
-ushort ptclbsum(byte*, int);
-ushort ptclcsum(Block*, int, int);
-int pullblock(Block**, int);
-Block* pullupblock(Block*, int);
-char* routeadd(Ipaddr, Ipaddr, Ipaddr, Media *m);
-void routedelete(ulong, ulong, Media *m);
-int routeread(byte*, ulong, int);
-char* routewrite(char*, int);
+enum
+{
+
+ /* type bits */
+ Rv4= (1<<0), /* this is a version 4 route */
+ Rifc= (1<<1), /* this route is a directly connected interface */
+ Rptpt= (1<<2), /* this route is a pt to pt interface */
+ Runi= (1<<3), /* a unicast self address */
+ Rbcast= (1<<4), /* a broadcast self address */
+ Rmulti= (1<<5), /* a multicast self address */
+};
+
+struct Routewalk {
+ int n;
+ int o;
+ int h;
+ char* p;
+ void* state;
+ void (*walk)(Route*, Routewalk*);
+};
+
+struct RouteTree
+{
+ Route* right;
+ Route* left;
+ Route* mid;
+ uchar depth;
+ uchar type;
+ uchar ifcid; /* must match ifc->id */
+ Ipifc *ifc;
+ char tag[4];
+};
+
+struct V4route
+{
+ ulong address;
+ ulong endaddress;
+ uchar gate[IPv4addrlen];
+};
+
+struct V6route
+{
+ ulong address[IPllen];
+ ulong endaddress[IPllen];
+ uchar gate[IPaddrlen];
+};
+
+struct Route
+{
+ RouteTree;
+
+ union {
+ V6route v6;
+ V4route v4;
+ };
+};
+extern void v4addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type);
+extern void v6addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type);
+extern void v4delroute(uchar *a, uchar *mask);
+extern void v6delroute(uchar *a, uchar *mask);
+extern Route* v4lookup(uchar *a);
+extern Route* v6lookup(uchar *a);
+extern long routeread(char*, ulong, int);
+extern long routewrite(Chan*, char*, int);
+
+/*
+ * arp.c
+ */
+struct Arpent
+{
+ uchar ip[IPaddrlen];
+ uchar mac[MAClen];
+ Medium *type; /* media type */
+ Arpent* hash;
+ Block* hold;
+ Block* last;
+ uint time;
+ uint used;
+ uchar state;
+};
+
+extern int arpread(char*, ulong, int);
+extern int arpwrite(char*, int);
+extern Arpent* arpget(Block *bp, int version, Medium *type, uchar *ip, uchar *h);
+extern void arprelease(Arpent *a);
+extern Block* arpresolve(Arpent *a, Medium *type, uchar *mac);
+extern void arpenter(Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int norefresh);
/*
* ipaux.c
*/
-int myetheraddr(uchar*, char*);
-ulong parseip(uchar*, char*);
+
+typedef struct Cmdbuf Cmdbuf;
+struct Cmdbuf
+{
+ char buf[64];
+ char *f[16];
+ int nf;
+};
+
+extern int myetheraddr(uchar*, char*);
+extern ulong parseip(uchar*, char*);
+extern ulong parseipmask(uchar*, char*);
+extern void maskip(uchar *from, uchar *mask, uchar *to);
+extern int parsemac(uchar *to, char *from, int len);
+extern uchar* defmask(uchar*);
+extern int isv4(uchar*);
+extern void v4tov6(uchar *v6, uchar *v4);
+extern int v6tov4(uchar *v4, uchar *v6);
+extern Cmdbuf* parsecmd(char *a, int n);
+extern int eipconv(va_list *arg, Fconv *f);
+
+#define ipcmp(x, y) memcmp(x, y, IPaddrlen)
+#define ipmove(x, y) memmove(x, y, IPaddrlen)
+
+extern uchar IPv4bcast[IPaddrlen];
+extern uchar IPv4bcastobs[IPaddrlen];
+extern uchar IPv4allsys[IPaddrlen];
+extern uchar IPv4allrouter[IPaddrlen];
+extern uchar IPnoaddr[IPaddrlen];
+extern uchar v4prefix[IPaddrlen];
+extern uchar IPallbits[IPaddrlen];
+
+#define msec TK2MS(MACHP(0)->ticks)
+
+/*
+ * media
+ */
+extern Medium ethermedium;
+extern Medium nullmedium;
+extern Medium pktmedium;
+extern Proto ipifc;
+
+/*
+ * ipifc.c
+ */
+extern Medium* ipfindmedium(char *name);
+extern int ipforme(uchar *addr);
+extern int ipismulticast(uchar *);
+extern Ipifc* findipifc(uchar *remote, int type);
+extern void findlocalip(uchar *local, uchar *remote);
+extern int ipv4local(Ipifc *ifc, uchar *addr);
+extern int ipv6local(Ipifc *ifc, uchar *addr);
+extern Iplifc* iplocalonifc(Ipifc *ifc, uchar *ip);
+extern int ipproxyifc(Ipifc *ifc, uchar *ip);
+extern int ipismulticast(uchar *ip);
+extern int ipisbooting(void);
+extern int ipifccheckin(Ipifc *ifc, Medium *med);
+extern void ipifccheckout(Ipifc *ifc);
+extern int ipifcgrab(Ipifc *ifc);
+extern void ipifcaddroute(int, uchar*, uchar*, uchar*, int);
+extern void ipifcremroute(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);
+
+/*
+ * ip.c
+ */
+extern void closeifcconv(Ifcconv*);
+extern void icmpnoconv(Block*);
+extern void initfrag(int);
+extern ushort ipcsum(uchar*);
+extern void (*ipextprotoiput)(Block*);
+extern void ipiput(uchar*, Block*);
+extern void ipoput(Block*, int, int);
+extern int ipstats(char*, int);
+extern uchar* logctl(uchar*);
+extern Ifcconv* newifcconv(void);
+extern void (*pktifcrcv)(Conv*, Block*);
+extern ushort ptclbsum(uchar*, int);
+extern ushort ptclcsum(Block*, int, int);
+
+/*
+ * iprouter.c
+ */
+void useriprouter(uchar*, Block*);
+void iprouteropen(void);
+void iprouterclose(void);
+long iprouterread(void*, int);
+
+/*
+ * global to all of the stack
+ */
+extern int debug;
+extern Fs fs;
+extern int iprouting; /* true if routing turned on */
+extern void (*igmpreportfn)(Ipifc*, uchar*);
M ip/ipaux.c => ip/ipaux.c +283 -60
@@ 7,10 7,50 @@
#include "kernel.h"
#include "ip.h"
+/*
+ * well known IP addresses
+ */
+uchar IPv4bcast[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff
+};
+uchar IPv4allsys[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff,
+ 0xe0, 0, 0, 0x01
+};
+uchar IPv4allrouter[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff,
+ 0xe0, 0, 0, 0x02
+};
+uchar IPallbits[IPaddrlen] = {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff
+};
+uchar IPnoaddr[IPaddrlen];
+
+/*
+ * prefix of all v4 addresses
+ */
+uchar v4prefix[IPaddrlen] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0xff, 0xff,
+ 0, 0, 0, 0
+};
+
+
ushort
ptclcsum(Block *bp, int offset, int len)
{
- byte *addr;
+ uchar *addr;
ulong losum, hisum;
ushort csum;
int odd, blocklen, x;
@@ 64,65 104,34 @@ ptclcsum(Block *bp, int offset, int len)
return ~losum & 0xffff;
}
-Ipaddr
-defmask(Ipaddr ip)
+enum
{
- switch(ip>>30){
- default:
- return 0xff000000;
- case 2:
- return 0xffff0000;
- case 3:
- return 0xffffff00;
- }
-}
+ Isprefix= 16,
+};
-int
-myetheraddr(uchar *to, char *dev)
+uchar prefixvals[256] =
{
- int n, fd;
- char buf[256], *ptr;
-
- /* Make one exist */
- if(*dev == '/' || *dev == '#')
- sprint(buf, "%s/clone", dev);
- else
- sprint(buf, "/net/%s/clone", dev);
-
- fd = kopen(buf, ORDWR);
- if(fd >= 0)
- kclose(fd);
-
- if(*dev == '/' || *dev == '#')
- sprint(buf, "%s/0/stats", dev);
- else
- sprint(buf, "/net/%s/0/stats", dev);
- fd = kopen(buf, OREAD);
- if(fd < 0)
- return -1;
-
- n = kread(fd, buf, sizeof(buf)-1);
- kclose(fd);
- if(n <= 0)
- return -1;
- buf[n] = 0;
-
- ptr = strstr(buf, "addr: ");
- if(!ptr)
- return -1;
- ptr += 6;
-
- parseether(to, ptr);
- return 0;
-}
+[0x00] 0 | Isprefix,
+[0x80] 1 | Isprefix,
+[0xC0] 2 | Isprefix,
+[0xE0] 3 | Isprefix,
+[0xF0] 4 | Isprefix,
+[0xF8] 5 | Isprefix,
+[0xFC] 6 | Isprefix,
+[0xFE] 7 | Isprefix,
+[0xFF] 8 | Isprefix,
+};
int
eipconv(va_list *arg, Fconv *f)
{
- char buf[64];
+ char buf[8*5];
static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
static char *ifmt = "%d.%d.%d.%d";
- uchar *p, ip[4];
+ uchar *p, ip[16];
+ ulong *lp;
+ ushort s;
+ int i, j, n, eln, eli;
switch(f->chr) {
case 'E': /* Ethernet address */
@@ 131,11 140,66 @@ eipconv(va_list *arg, Fconv *f)
break;
case 'I': /* Ip address */
p = va_arg(*arg, uchar*);
+common:
+ if(memcmp(p, v4prefix, 12) == 0)
+ sprint(buf, ifmt, p[12], p[13], p[14], p[15]);
+ else {
+ /* find longest elision */
+ eln = eli = -1;
+ for(i = 0; i < 16; i += 2){
+ for(j = i; j < 16; j += 2)
+ if(p[j] != 0 || p[j+1] != 0)
+ break;
+ if(j > i && j - i > eln){
+ eli = i;
+ eln = j - i;
+ }
+ }
+
+ /* print with possible elision */
+ n = 0;
+ for(i = 0; i < 16; i += 2){
+ if(i == eli){
+ n += sprint(buf+n, "::");
+ i += eln;
+ if(i >= 16)
+ break;
+ } else if(i != 0)
+ n += sprint(buf+n, ":");
+ s = (p[i]<<8) + p[i+1];
+ n += sprint(buf+n, "%ux", s);
+ }
+ }
+ break;
+ case 'i': /* v6 address as 4 longs */
+ lp = va_arg(*arg, ulong*);
+ for(i = 0; i < 4; i++)
+ hnputl(ip+4*i, *lp++);
+ p = ip;
+ goto common;
+ case 'V': /* v4 ip address */
+ p = va_arg(*arg, uchar*);
sprint(buf, ifmt, p[0], p[1], p[2], p[3]);
break;
- case 'i':
- hnputl(ip, va_arg(*arg, ulong));
- sprint(buf, ifmt, ip[0], ip[1], ip[2], ip[3]);
+ case 'M': /* ip mask */
+ p = va_arg(*arg, uchar*);
+
+ /* look for a prefix mask */
+ for(i = 0; i < 16; i++)
+ if(p[i] != 0xff)
+ break;
+ if(i < 16){
+ if((prefixvals[p[i]] & Isprefix) == 0)
+ goto common;
+ for(j = i+1; j < 16; j++)
+ if(p[j] != 0)
+ goto common;
+ n = 8*i + (prefixvals[p[i]] & ~Isprefix);
+ } else
+ n = 8*16;
+
+ /* got one, use /xx format */
+ sprint(buf, "/%d", n);
break;
default:
strcpy(buf, "(eipconv)");
@@ 146,21 210,20 @@ eipconv(va_list *arg, Fconv *f)
#define CLASS(p) ((*(uchar*)(p))>>6)
-ulong
-parseip(uchar *to, char *from)
+static char*
+v4parseip(uchar *to, char *from)
{
int i;
char *p;
p = from;
- memset(to, 0, 4);
for(i = 0; i < 4 && *p; i++){
to[i] = strtoul(p, &p, 0);
if(*p == '.')
p++;
}
switch(CLASS(to)){
- case 0: /* class A - 1 byte net */
+ case 0: /* class A - 1 uchar net */
case 1:
if(i == 3){
to[3] = to[2];
@@ 171,12 234,172 @@ parseip(uchar *to, char *from)
to[1] = 0;
}
break;
- case 2: /* class B - 2 byte net */
+ case 2: /* class B - 2 uchar net */
if(i == 3){
to[3] = to[2];
to[2] = 0;
}
break;
}
- return nhgetl(to);
+ return p;
+}
+
+int
+isv4(uchar *ip)
+{
+ return memcmp(ip, v4prefix, IPv4off) == 0;
+}
+
+void
+v4tov6(uchar *v6, uchar *v4)
+{
+ memmove(v6, v4prefix, IPv4off);
+ memmove(v6 + IPv4off, v4, IPv4addrlen);
+}
+
+int
+v6tov4(uchar *v4, uchar *v6)
+{
+ if(memcmp(v6, v4prefix, IPv4off) != 0)
+ return -1;
+ memmove(v4, v6 + IPv4off, IPv4addrlen);
+ return 0;
+}
+
+ulong
+parseip(uchar *to, char *from)
+{
+ int i, elipsis = 0, v4 = 1;
+ ulong x;
+ char *p, *op;
+
+ memset(to, 0, IPaddrlen);
+ p = from;
+ for(i = 0; i < 16 && *p; i+=2){
+ op = p;
+ x = strtoul(p, &p, 16);
+ if(*p == '.' || (*p == 0 && i == 0)){
+ p = v4parseip(to+i, op);
+ i += 2;
+ } else {
+ to[i] = x>>8;
+ to[i+1] = x;
+ }
+ if(*p == ':'){
+ v4 = 0;
+ if(*++p == ':'){
+ elipsis = i+2;
+ p++;
+ }
+ }
+ }
+ if(i < 16){
+ memmove(&to[elipsis+16-i], &to[elipsis], i-elipsis);
+ memset(&to[elipsis], 0, 16-i);
+ }
+ if(v4){
+ to[10] = to[11] = 0xff;
+ return nhgetl(to+12);
+ } else
+ return 6;
+}
+
+/*
+ * hack to allow ip v4 masks to be entered in the old
+ * style
+ */
+ulong
+parseipmask(uchar *to, char *from)
+{
+ ulong x;
+ int i;
+ uchar *p;
+
+ if(*from == '/'){
+ /* as a number of prefix bits */
+ i = atoi(from+1);
+ if(i < 0)
+ i = 0;
+ if(i > 128)
+ i = 128;
+ memset(to, 0, IPaddrlen);
+ for(p = to; i >= 8; i -= 8)
+ *p++ = 0xff;
+ if(i > 0)
+ *p = ~((1<<(8-i))-1);
+ x = nhgetl(to+IPv4off);
+ } else {
+ /* as a straight bit mask */
+ x = parseip(to, from);
+ if(memcmp(to, v4prefix, IPv4off) == 0)
+ memset(to, 0xff, IPv4off);
+ }
+ return x;
+}
+
+void
+maskip(uchar *from, uchar *mask, uchar *to)
+{
+ int i;
+
+ for(i = 0; i < IPaddrlen; i++)
+ to[i] = from[i] & mask[i];
+}
+
+uchar classmask[4][16] = {
+ 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,
+ 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,
+};
+
+uchar*
+defmask(uchar *ip)
+{
+ return classmask[ip[IPv4off]>>6];
+}
+
+/*
+ * parse a command written to a device
+ */
+Cmdbuf*
+parsecmd(char *p, int n)
+{
+ Cmdbuf *cb;
+
+ cb = smalloc(sizeof(*cb));
+
+ if(n > sizeof(cb->buf)-1)
+ n = sizeof(cb->buf)-1;
+ memmove(cb->buf, p, n);
+ cb->buf[n] = '\0';
+ cb->nf = parsefields(cb->buf, cb->f, nelem(cb->f), " ");
+ return cb;
+}
+
+/*
+ * parse a hex mac address
+ */
+int
+parsemac(uchar *to, char *from, int len)
+{
+ char nip[4];
+ char *p;
+ int i;
+
+ p = from;
+ memset(to, 0, len);
+ for(i = 0; i < len; i++){
+ if(*p == 0)
+ return -1;
+ nip[0] = *p++;
+ if(*p == 0)
+ return -1;
+ nip[1] = *p++;
+ nip[2] = 0;
+ to[i] = strtoul(nip, 0, 16);
+ if(*p == ':')
+ p++;
+ }
+ return 0;
}
A ip/ipifc.c => ip/ipifc.c +1156 -0
@@ 0,0 1,1156 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "ip.h"
+
+#define DPRINT if(0)print
+
+enum {
+ Maxmedia = 16,
+ Nself = Maxmedia*5,
+ NHASH = (1<<6),
+ NCACHE = 256,
+ QMAX = 64*1024-1,
+};
+
+ Proto ipifc;
+extern Fs fs;
+
+Medium *media[] =
+{
+ ðermedium,
+ &nullmedium,
+ 0
+};
+
+/*
+ * cache of local addresses (addresses we answer to)
+ */
+typedef struct Ipself Ipself;
+struct Ipself
+{
+ uchar a[IPaddrlen];
+ Ipself *hnext; /* next address in the hash table */
+ Iplink *link; /* binding twixt Ipself and Ipifc */
+ ulong expire;
+ uchar type; /* type of address */
+ int ref;
+ Ipself *next; /* free list */
+};
+
+typedef struct Ipselftab Ipselftab;
+struct Ipselftab
+{
+ QLock;
+ int inited;
+ int acceptall; /* true if an interface has the null address */
+ Ipself *hash[NHASH]; /* hash chains */
+};
+Ipselftab selftab;
+
+/*
+ * Multicast addresses are chained onto a Chan so that
+ * we can remove them when the Chan is closed.
+ */
+typedef struct Ipmcast Ipmcast;
+struct Ipmcast
+{
+ Ipmcast *next;
+ uchar ma[IPaddrlen]; /* multicast address */
+ uchar ia[IPaddrlen]; /* interface address */
+};
+
+/* quick hash for ip addresses */
+#define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
+
+static char tifc[] = "ifc ";
+
+static void addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
+static void remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a);
+static char* ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
+static char* ipifcleavemulti(Ipifc *ifc, char **argv, int argc);
+
+/*
+ * find the medium with this name
+ */
+Medium*
+ipfindmedium(char *name)
+{
+ Medium **mp;
+
+ for(mp = media; *mp != nil; mp++)
+ if(strcmp((*mp)->name, name) == 0)
+ break;
+ return *mp;
+}
+
+/*
+ * attach a device (or pkt driver) to the interface.
+ * called with c->car locked
+ */
+static char*
+ipifcbind(Conv *c, char **argv, int argc)
+{
+ Ipifc *ifc;
+ Medium *m;
+
+ if(argc < 2)
+ return Ebadarg;
+
+ ifc = (Ipifc*)c->ptcl;
+
+ /* bind the device to the interface */
+ m = ipfindmedium(argv[1]);
+ if(m == nil)
+ return "unknown interface type";
+
+ wlock(ifc);
+ if(ifc->m != nil){
+ wunlock(ifc);
+ return "interface already bound";
+ }
+ if(waserror()){
+ wunlock(ifc);
+ nexterror();
+ }
+
+ (*m->bind)(ifc, argc, argv);
+ if(argc > 2)
+ strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
+ else
+ sprint(ifc->dev, "%s%d", m->name, c->x);
+ ifc->dev[sizeof(ifc->dev)-1] = 0;
+ ifc->m = m;
+ ifc->minmtu = ifc->m->minmtu;
+ ifc->maxmtu = ifc->m->maxmtu;
+ ifc->ifcid++;
+
+ wunlock(ifc);
+ poperror();
+
+ return nil;
+}
+
+/*
+ * detach a device from an interface, close the interface
+ */
+static char*
+ipifcunbind(Ipifc *ifc)
+{
+ char *av[4];
+ char ip[32];
+ char mask[32];
+
+ if(waserror()){
+ wunlock(ifc);
+ nexterror();
+ }
+ wlock(ifc);
+
+ if(ipifcgrab(ifc) == 0);
+ goto out;
+
+ /* hangup queues to stop queuing of packets */
+ qhangup(ifc->conv->rq, "unbind");
+ qhangup(ifc->conv->wq, "unbind");
+
+ /* dissociate routes */
+ ifc->ifcid++;
+
+ /* disassociate logical interfaces */
+ av[0] = "remove";
+ av[1] = ip;
+ av[2] = mask;
+ av[3] = 0;
+ while(ifc->lifc){
+ sprint(ip, "%I", ifc->lifc->local);
+ sprint(mask, "%M", ifc->lifc->mask);
+ ipifcrem(ifc, av, 3, 0);
+ }
+
+ /* disassociate device */
+ (*ifc->m->unbind)(ifc);
+ memset(ifc->dev, 0, sizeof(ifc->dev));
+ ifc->arg = nil;
+ ifc->m = &nullmedium;
+ ifc->unbinding = 0;
+
+out:
+ wunlock(ifc);
+ poperror();
+ return nil;
+}
+
+static int
+ipifcstate(Conv *c, char *state, int n)
+{
+ Ipifc *ifc;
+ Iplifc *lifc;
+ int m;
+
+ ifc = (Ipifc*)c->ptcl;
+
+ m = snprint(state, n, "%-12.12s %-5d", ifc->dev, ifc->maxmtu);
+
+ rlock(ifc);
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next)
+ m += snprint(state+m, n - m,
+ " %-20.20I %-20.20M %-20.20I %-7d %-7d %-7d %-7d",
+ lifc->local, lifc->mask, lifc->remote,
+ ifc->in, ifc->out, ifc->inerr, ifc->outerr);
+ m += snprint(state+m, n - m, "\n");
+ runlock(ifc);
+ return m;
+}
+
+static int
+ipifclocal(Conv *c, char *state, int n)
+{
+ Ipifc *ifc;
+ Iplifc *lifc;
+ Iplink *link;
+ int m;
+
+ ifc = (Ipifc*)c->ptcl;
+
+ m = 0;
+
+ rlock(ifc);
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ m += snprint(state+m, n - m, "%-20.20I ->", lifc->local);
+ for(link = lifc->link; link; link = link->lifclink)
+ m += snprint(state+m, n - m, " %-20.20I", link->local->a);
+ m += snprint(state+m, n - m, "\n");
+ }
+ runlock(ifc);
+ return m;
+}
+
+static int
+ipifcinuse(Conv *c)
+{
+ Ipifc *ifc;
+
+ ifc = (Ipifc*)c->ptcl;
+ return ifc->m != nil;
+}
+
+/*
+ * called when a process writes to an interface's 'data'
+ */
+static void
+ipifckick(Conv *c, int)
+{
+ Block *bp;
+ Ipifc *ifc;
+
+ bp = qget(c->wq);
+ if(bp == nil)
+ return;
+
+ ifc = (Ipifc*)c->ptcl;
+ if(ifc->m == nil || ifc->m->pktin == nil)
+ freeb(bp);
+ else
+ (*ifc->m->pktin)(ifc, bp);
+}
+
+/*
+ * we'll have to have a kick routine at
+ * some point to deal with these
+ */
+static void
+ipifccreate(Conv *c)
+{
+ Ipifc *ifc;
+
+ c->rq = qopen(QMAX, 0, 0, 0);
+ c->wq = qopen(QMAX, 0, 0, 0);
+ ifc = (Ipifc*)c->ptcl;
+ ifc->conv = c;
+}
+
+/*
+ * called after last close of ipifc data or ctl
+ * called with c locked, we must unlock
+ */
+static void
+ipifcclose(Conv *c)
+{
+ /*
+ * nothing to do since conversation stays open
+ * till the device is unbound.
+ */
+ unlock(c);
+}
+
+/*
+ * add an address to an interface.
+ */
+char*
+ipifcadd(Ipifc *ifc, char **argv, int argc)
+{
+ uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
+ uchar bcast[IPaddrlen], net[IPaddrlen];
+ Iplifc *lifc, **l;
+ int i, type, mtu;
+
+ memset(ip, 0, IPaddrlen);
+ memset(mask, 0, IPaddrlen);
+ memset(rem, 0, IPaddrlen);
+ switch(argc){
+ case 5:
+ mtu = strtoul(argv[4], 0, 0);
+ if(mtu >= ifc->m->minmtu && mtu <= ifc->m->maxmtu)
+ ifc->maxmtu = mtu;
+ /* fall through */
+ case 4:
+ parseip(ip, argv[1]);
+ parseipmask(mask, argv[2]);
+ parseip(rem, argv[3]);
+ maskip(rem, mask, net);
+ break;
+ case 3:
+ parseip(ip, argv[1]);
+ parseipmask(mask, argv[2]);
+ maskip(ip, mask, rem);
+ maskip(rem, mask, net);
+ break;
+ case 2:
+ parseip(ip, argv[1]);
+ memmove(mask, defmask(ip), IPaddrlen);
+ maskip(ip, mask, rem);
+ maskip(rem, mask, net);
+ break;
+ default:
+ return Ebadarg;
+ break;
+ }
+
+ if(waserror()){
+ wunlock(ifc);
+ panic("ipifcadd");
+ }
+ 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)
+ goto out;
+
+ /* add the address to the list of logical ifc's for this ifc */
+ lifc = smalloc(sizeof(Iplifc));
+ ipmove(lifc->local, ip);
+ ipmove(lifc->mask, mask);
+ ipmove(lifc->remote, rem);
+ ipmove(lifc->net, net);
+ lifc->next = nil;
+ for(l = &ifc->lifc; *l; l = &(*l)->next)
+ ;
+ *l = lifc;
+
+ /* add a route for the local network */
+ type = Rifc;
+ if(ipcmp(mask, IPallbits) == 0)
+ type |= Rptpt;
+ if(isv4(ip))
+ v4addroute(tifc, rem+IPv4off, mask+IPv4off, ip+IPv4off, type);
+ else
+ v6addroute(tifc, ip, mask, rem, type);
+
+ addselfcache(ifc, lifc, ip, Runi);
+
+ /* add subnet directed broadcast addresses to the self cache */
+ for(i = 0; i < IPaddrlen; i++)
+ bcast[i] = (ip[i] & mask[i]) | ~mask[i];
+ addselfcache(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(ifc, lifc, bcast, Rbcast);
+
+ addselfcache(ifc, lifc, IPv4bcast, Rbcast);
+
+out:
+ wunlock(ifc);
+ poperror();
+ return nil;
+}
+
+/*
+ * remove an address from an interface.
+ * called with c->car locked
+ */
+char*
+ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock)
+{
+ uchar ip[IPaddrlen];
+ uchar mask[IPaddrlen];
+ Iplifc *lifc, **l;
+
+ if(argc < 3)
+ return Ebadarg;
+
+ parseip(ip, argv[1]);
+ parseipmask(mask, argv[2]);
+
+ if(dolock){
+ if(waserror()){
+ wunlock(ifc);
+ nexterror();
+ }
+ wlock(ifc);
+ }
+
+ /* find address on this interface and remove from chain */
+ lifc = nil;
+ for(l = &ifc->lifc; *l; l = &(*l)->next)
+ if(memcmp(ip, (*l)->local, IPaddrlen) == 0)
+ if(memcmp(mask, (*l)->mask, IPaddrlen) == 0){
+ lifc = *l;
+ *l = lifc->next;
+ break;
+ }
+
+ if(lifc == nil)
+ return "address not on this interface";
+
+ /* disassociate any addresses */
+ while(lifc->link)
+ remselfcache(ifc, lifc, lifc->link->local->a);
+
+ /* remove the route for this logical interface */
+ if(isv4(ip))
+ v4delroute(lifc->remote+IPv4off, lifc->mask+IPv4off);
+ else
+ v6delroute(lifc->remote, lifc->mask);
+
+ free(lifc);
+
+out:
+ if(dolock){
+ wunlock(ifc);
+ poperror();
+ }
+ return nil;
+}
+
+/*
+ * distrbute routes to active interfaces like the
+ * TRIP linecards
+ */
+void
+ipifcaddroute(int vers, uchar *addr, uchar *mask, uchar *gate, int type)
+{
+ Medium *m;
+ Conv **cp;
+ Ipifc *ifc;
+
+ for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
+ if(*cp != nil) {
+ ifc = (Ipifc*)(*cp)->ptcl;
+ m = ifc->m;
+ if(m->addroute != nil)
+ m->addroute(ifc, vers, addr, mask, gate, type);
+ }
+ }
+}
+
+void
+ipifcremroute(int vers, uchar *addr, uchar *mask)
+{
+ Medium *m;
+ Conv **cp;
+ Ipifc *ifc;
+
+ for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
+ if(*cp != nil) {
+ ifc = (Ipifc*)(*cp)->ptcl;
+ m = ifc->m;
+ if(m->remroute != nil)
+ m->remroute(ifc, vers, addr, mask);
+ }
+ }
+}
+
+/*
+ * associate an address with the interface. This wipes out any previous
+ * addresses. This is a macro that means, remove all the old interfaces
+ * and add a new one.
+ */
+static char*
+ipifcconnect(Conv* c, char **argv, int argc)
+{
+ char *err;
+ Ipifc *ifc;
+ char *av[4];
+ char ip[80], mask[80];
+
+ ifc = (Ipifc*)c->ptcl;
+
+ if(ifc->m == nil)
+ return "ipifc not yet bound to device";
+
+ av[0] = "remove";
+ av[1] = ip;
+ av[2] = mask;
+ av[3] = 0;
+ if(waserror()){
+ wunlock(ifc);
+ nexterror();
+ }
+ wlock(ifc);
+ while(ifc->lifc){
+ sprint(ip, "%I", ifc->lifc->local);
+ sprint(mask, "%I", ifc->lifc->mask);
+ ipifcrem(ifc, av, 3, 0);
+ }
+ wunlock(ifc);
+ poperror();
+
+ err = ipifcadd(ifc, argv, argc);
+ if(err)
+ return err;
+
+ Fsconnected(&fs, c, nil);
+
+ return nil;
+}
+
+/*
+ * non-standard control messages.
+ * called with c->car locked.
+ */
+static char*
+ipifcctl(Conv* c, char**argv, int argc)
+{
+ Ipifc *ifc;
+
+ ifc = (Ipifc*)c->ptcl;
+ if(strcmp(argv[0], "add") == 0)
+ return ipifcadd(ifc, argv, argc);
+ else if(strcmp(argv[0], "remove") == 0)
+ return ipifcrem(ifc, argv, argc, 1);
+ else if(strcmp(argv[0], "unbind") == 0)
+ return ipifcunbind(ifc);
+ else if(strcmp(argv[0], "joinmulti") == 0)
+ return ipifcjoinmulti(ifc, argv, argc);
+ else if(strcmp(argv[0], "leavemulti") == 0)
+ return ipifcleavemulti(ifc, argv, argc);
+ return "unsupported ctl";
+}
+
+void
+ipifcinit(Fs *fs)
+{
+ ipifc.name = "ipifc";
+ ipifc.kick = ipifckick;
+ ipifc.connect = ipifcconnect;
+ ipifc.announce = nil;
+ ipifc.bind = ipifcbind;
+ ipifc.state = ipifcstate;
+ ipifc.create = ipifccreate;
+ ipifc.close = ipifcclose;
+ ipifc.rcv = nil;
+ ipifc.ctl = ipifcctl;
+ ipifc.advise = nil;
+ ipifc.stats = ipstats;
+ ipifc.inuse = ipifcinuse;
+ ipifc.local = ipifclocal;
+ ipifc.ipproto = -1;
+ ipifc.nc = Maxmedia;
+ ipifc.ptclsize = sizeof(Ipifc);
+
+ Fsproto(fs, &ipifc);
+}
+
+/*
+ * add to self routing cache
+ * called with c->car locked
+ */
+static void
+addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
+{
+ Ipself *p;
+ Iplink *lp;
+ int h;
+
+ qlock(&selftab);
+
+ /* see if the address already exists */
+ h = hashipa(a);
+ for(p = selftab.hash[h]; p; p = p->next)
+ if(memcmp(a, p->a, IPaddrlen) == 0)
+ break;
+
+ /* allocate a local address and add to hash chain */
+ if(p == nil){
+ p = smalloc(sizeof(*p));
+ ipmove(p->a, a);
+ p->type = type;
+ p->next = selftab.hash[h];
+ selftab.hash[h] = p;
+
+ /* if the null address, accept all packets */
+ if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
+ selftab.acceptall = 1;
+ }
+
+ /* look for a link for this lifc */
+ for(lp = p->link; lp; lp = lp->locallink)
+ if(lp->lifc == lifc)
+ break;
+
+ /* allocate a lifc-to-local link and link to both */
+ if(lp == nil){
+ lp = smalloc(sizeof(*lp));
+ lp->ref = 1;
+ lp->lifc = lifc;
+ lp->local = p;
+ lp->locallink = p->link;
+ p->link = lp;
+ lp->lifclink = lifc->link;
+ lifc->link = lp;
+
+ /* add to routing table */
+ if(isv4(a))
+ v4addroute(tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type);
+ else
+ v6addroute(tifc, a, IPallbits, a, type);
+
+ if((type & Rmulti) && ifc->m->addmulti != nil)
+ (*ifc->m->addmulti)(ifc, a, lifc->local);
+ } else {
+ lp->ref++;
+ }
+
+ qunlock(&selftab);
+}
+
+/*
+ * These structures are unlinked from their chains while
+ * other threads may be using them. To avoid excessive locking,
+ * just put them aside for a while before freeing them.
+ * called with &selftab locked
+ */
+static Iplink *freeiplink;
+static Ipself *freeipself;
+
+static void
+iplinkfree(Iplink *p)
+{
+ Iplink **l, *np;
+ ulong now = msec;
+
+ l = &freeiplink;
+ for(np = *l; np; np = *l){
+ if(np->expire > now){
+ *l = np->next;
+ free(np);
+ continue;
+ }
+ l = &np->next;
+ }
+ p->expire = now + 5000; /* give other threads 5 secs to get out */
+ p->next = nil;
+ *l = p;
+}
+static void
+ipselffree(Ipself *p)
+{
+ Ipself **l, *np;
+ ulong now = msec;
+
+ l = &freeipself;
+ for(np = *l; np; np = *l){
+ if(np->expire > now){
+ *l = np->next;
+ free(np);
+ continue;
+ }
+ l = &np->next;
+ }
+ p->expire = now + 5000; /* give other threads 5 secs to get out */
+ p->next = nil;
+ *l = p;
+}
+
+/*
+ * Decrement reference for this address on this link.
+ * Unlink from selftab if this is the last ref.
+ * called with c->car locked
+ */
+static void
+remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a)
+{
+ Ipself *p, **l;
+ Iplink *lp, *llp, **ill, **lll;
+
+ qlock(&selftab);
+
+ /* find the unique selftab entry */
+ l = &selftab.hash[hashipa(a)];
+ for(p = *l; p; p = *l){
+ if(ipcmp(p->a, a) == 0)
+ break;
+ l = &p->next;
+ }
+
+ if(p == nil)
+ goto out;
+
+ /*
+ * walk down links from an ifc looking for one
+ * that matches the selftab entry
+ */
+ ill = &lifc->link;
+ for(lp = *ill; lp; lp = *ill){
+ if(lp->local == p)
+ break;
+ ill = &lp->lifclink;
+ }
+
+ if(lp == nil)
+ goto out;
+
+ /*
+ * walk down the links from the selftab looking for
+ * the one we just found
+ */
+ lll = &p->link;
+ for(llp = *lll; llp; llp = *lll){
+ if(llp == lp)
+ break;
+ lll = &lp->locallink;
+ }
+
+ if(llp == nil)
+ panic("remselfcache");
+
+ if(--(llp->ref) != 0)
+ goto out;
+
+ if((p->type & Rmulti) && ifc->m->remmulti != nil)
+ (*ifc->m->remmulti)(ifc, a, lifc->local);
+
+ /* ref == 0, remove from both chains and free the link */
+ *ill = lp->lifclink;
+ *lll = llp->locallink;
+ iplinkfree(lp);
+
+ /* remove from routing table */
+ if(isv4(a))
+ v4delroute(a+IPv4off, IPallbits+IPv4off);
+ else
+ v6delroute(a, IPallbits);
+
+ if(p->link != nil)
+ goto out;
+
+ /* no more links, remove from hash and free */
+ *l = p->next;
+ ipselffree(p);
+
+ /* if IPnoaddr, forget */
+ if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
+ selftab.acceptall = 0;
+
+out:
+ qunlock(&selftab);
+}
+
+static void
+dumpselftab(void)
+{
+ int i, count;
+ Ipself *p;
+
+ qlock(&selftab);
+ for(i = 0; i < NHASH; i++){
+ p = selftab.hash[i];
+ if(p == nil)
+ continue;
+ count = 0;
+ for(; p != nil && count++ < 6; p = p->next)
+ print("(%i %d %lux)", p->a, p->type, p);
+ print("\n");
+ }
+ qunlock(&selftab);
+}
+
+
+/*
+ * returns
+ * 0 - no match
+ * Runi
+ * Rbcast
+ * Rmcast
+ */
+int
+ipforme(uchar *addr)
+{
+ Ipself *p;
+ int count;
+
+ p = selftab.hash[hashipa(addr)];
+ count = 0;
+ for(; p; p = p->next){
+ if(count++ > 1000){ /* check for loops */
+ dumpselftab();
+ break;
+ }
+ if(ipcmp(addr, p->a) == 0)
+ return p->type;
+ }
+
+ /* hack to say accept anything */
+ if(selftab.acceptall)
+ return Runi;
+
+ return 0;
+}
+
+/*
+ * find the ifc on same net as the remote system. If none,
+ * return nil.
+ */
+Ipifc*
+findipifc(uchar *remote, int type)
+{
+ Ipifc *ifc;
+ Iplifc *lifc;
+ Conv **cp;
+ uchar gnet[IPaddrlen];
+
+ for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; 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){
+ qunlock(&ipifc);
+ return ifc;
+ }
+ }
+ }
+
+ /* for now for broadcast and mutlicast, just use first interface */
+ if(type & (Rbcast|Rmulti)){
+ for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
+ if(*cp == 0)
+ continue;
+ ifc = (Ipifc*)(*cp)->ptcl;
+ if(ifc->lifc != nil)
+ return ifc;
+ }
+ }
+
+ return nil;
+}
+
+/*
+ * find the local address 'closest' to the remote system, copy it to
+ * local and return the ifc for that address
+ */
+void
+findlocalip(uchar *local, uchar *remote)
+{
+ Ipifc *ifc;
+ Iplifc *lifc;
+ Conv **cp;
+ Route *r;
+ uchar gate[IPaddrlen];
+ uchar gnet[IPaddrlen];
+
+ qlock(&ipifc);
+ r = v6lookup(remote);
+
+ if(r != nil){
+ ifc = r->ifc;
+ if(r->type & Rv4)
+ v4tov6(gate, r->v4.gate);
+ else
+ ipmove(gate, r->v6.gate);
+
+ if(r->type & Rifc){
+ ipmove(local, gate);
+ goto out;
+ }
+
+ /* 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;
+ }
+ }
+ }
+
+ /* no match, choose first ifc local address */
+ for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
+ if(*cp == 0)
+ continue;
+ ifc = (Ipifc*)(*cp)->ptcl;
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ ipmove(local, lifc->local);
+ goto out;
+ }
+ }
+
+out:
+ qunlock(&ipifc);
+}
+
+/*
+ * return first v4 address associated with an interface
+ */
+int
+ipv4local(Ipifc *ifc, uchar *addr)
+{
+ Iplifc *lifc;
+
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ if(isv4(lifc->local)){
+ memmove(addr, lifc->local+IPv4off, IPv4addrlen);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * return first v6 address associated with an interface
+ */
+int
+ipv6local(Ipifc *ifc, uchar *addr)
+{
+ Iplifc *lifc;
+
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ if(!isv4(lifc->local)){
+ ipmove(addr, lifc->local);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * see if this address is bound to the interface
+ */
+Iplifc*
+iplocalonifc(Ipifc *ifc, uchar *ip)
+{
+ Iplifc *lifc;
+
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next)
+ if(ipcmp(ip, lifc->local) == 0)
+ return lifc;
+ return nil;
+}
+
+
+/*
+ * See if we're proxying for this address on this interface
+ */
+int
+ipproxyifc(Ipifc *ifc, uchar *ip)
+{
+ Route *r;
+ uchar net[IPaddrlen];
+ Iplifc *lifc;
+
+ /* see if this is a direct connected pt to pt address */
+ r = v6lookup(ip);
+ if(r == nil)
+ return 0;
+ if((r->type & Rifc) == 0)
+ return 0;
+ if((r->type & Rptpt) == 0)
+ return 0;
+
+ /* see if this is on the right interface */
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ maskip(ip, lifc->mask, net);
+ if(ipcmp(net, lifc->remote) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * return multicast version if any
+ */
+int
+ipismulticast(uchar *ip)
+{
+ if(isv4(ip)){
+ if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
+ return V4;
+ } else {
+ if(ip[0] == 0xff)
+ return V6;
+ }
+ return 0;
+}
+
+/*
+ * used to allow on the fly unbinds, return -1 if interface unusable
+ */
+int
+ipifccheckin(Ipifc *ifc, Medium *med)
+{
+ int rv;
+
+ lock(&ifc->idlock);
+ if(ifc->unbinding || ifc->m != med)
+ rv = -1;
+ else
+ rv = ++(ifc->ref);
+ if(ifc->ref < 0) panic("ipifccheckin");
+ unlock(&ifc->idlock);
+ return rv;
+}
+
+void
+ipifccheckout(Ipifc *ifc)
+{
+ lock(&ifc->idlock);
+ if(--(ifc->ref) == 0)
+ if(ifc->unbinding)
+ wakeup(&ifc->wait);
+ if(ifc->ref < 0) panic("ipifccheckin");
+ unlock(&ifc->idlock);
+}
+
+static int
+allout(void *x)
+{
+ Ipifc *ifc = x;
+
+ return ifc->ref == 0;
+}
+
+int
+ipifcgrab(Ipifc *ifc)
+{
+ lock(&ifc->idlock);
+ if(ifc->unbinding){
+ unlock(&ifc->idlock);
+ return 0;
+ }
+ ifc->unbinding = 1; /* after this ref can only go down */
+ unlock(&ifc->idlock);
+
+ sleep(&ifc->wait, allout, ifc);
+
+ return 1;
+}
+
+/*
+ * add a multicast address to an interface, called with c->car locked
+ */
+void
+ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
+{
+ Ipifc *ifc;
+ Iplifc *lifc;
+ Conv **p;
+ Ipmulti *multi, **l;
+
+ for(l = &c->multi; *l; l = &(*l)->next)
+ if(ipcmp(ma, (*l)->ma) == 0)
+ if(ipcmp(ia, (*l)->ia) == 0)
+ return; /* it's already there */
+
+ multi = *l = smalloc(sizeof(*multi));
+ ipmove(multi->ma, ma);
+ ipmove(multi->ia, ia);
+ multi->next = nil;
+
+ for(p = ipifc.conv; *p; p++){
+ if((*p)->inuse == 0)
+ continue;
+ ifc = (Ipifc*)(*p)->ptcl;
+ if(waserror()){
+ wunlock(ifc);
+ nexterror();
+ }
+ wlock(ifc);
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next)
+ if(ipcmp(ia, lifc->local) == 0)
+ addselfcache(ifc, lifc, ma, Rmulti);
+ wunlock(ifc);
+ poperror();
+ }
+}
+
+
+/*
+ * remove a multicast address from an interface, called with c->car locked
+ */
+void
+ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
+{
+ Ipmulti *multi, **l;
+ Iplifc *lifc;
+ Conv **p;
+ Ipifc *ifc;
+
+ for(l = &c->multi; *l; l = &(*l)->next)
+ if(ipcmp(ma, (*l)->ma) == 0)
+ if(ipcmp(ia, (*l)->ia) == 0)
+ break;
+
+ multi = *l;
+ if(multi == nil)
+ return; /* we don't have it open */
+
+ *l = multi->next;
+
+ for(p = ipifc.conv; *p; p++){
+ if((*p)->inuse == 0)
+ continue;
+
+ ifc = (Ipifc*)(*p)->ptcl;
+ if(waserror()){
+ wunlock(ifc);
+ nexterror();
+ }
+ wlock(ifc);
+ for(lifc = ifc->lifc; lifc; lifc = lifc->next)
+ if(ipcmp(ia, lifc->local) == 0)
+ remselfcache(ifc, lifc, ma);
+ wunlock(ifc);
+ poperror();
+ }
+
+ free(multi);
+}
+
+/*
+ * make lifc's join and leave multicast groups
+ */
+static char*
+ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
+{
+ USED(ifc, argv, argc);
+ return nil;
+}
+
+static char*
+ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
+{
+ USED(ifc, argv, argc);
+ return nil;
+}
+
A ip/iproute.c => ip/iproute.c +792 -0
@@ 0,0 1,792 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "ip.h"
+
+enum
+{
+ Lroot = 10,
+};
+
+Route *v4root[1<<Lroot], *v6root[1<<Lroot], *queue;
+
+static void walkadd(Route**, Route*);
+static void addnode(Route**, Route*);
+static void calcd(Route*);
+
+Route* v4freelist;
+Route* v6freelist;
+RWlock routelock;
+
+static void
+freeroute(Route *r)
+{
+ Route **l;
+
+ r->left = nil;
+ r->right = nil;
+ if(r->type & Rv4)
+ l = &v4freelist;
+ else
+ l = &v6freelist;
+ r->mid = *l;
+ *l = r;
+}
+
+static Route*
+allocroute(int type)
+{
+ Route *r;
+ int n;
+ Route **l;
+
+ if(type & Rv4){
+ n = sizeof(RouteTree) + sizeof(V4route);
+ l = &v4freelist;
+ } else {
+ n = sizeof(RouteTree) + sizeof(V6route);
+ l = &v6freelist;
+ }
+
+ r = *l;
+ if(r != nil){
+ *l = r->mid;
+ } else {
+ r = malloc(n);
+ if(r == nil)
+ panic("out of routing nodes");
+ }
+ memset(r, 0, n);
+ r->type = type;
+ r->ifc = nil;
+
+ return r;
+}
+
+static void
+addqueue(Route **q, Route *r)
+{
+ Route *l;
+
+ if(r == nil)
+ return;
+
+ l = allocroute(r->type);
+ l->mid = *q;
+ *q = l;
+ l->left = r;
+}
+
+/*
+ * compare 2 v6 addresses
+ */
+static int
+lcmp(ulong *a, ulong *b)
+{
+ int i;
+
+ for(i = 0; i < IPllen; i++){
+ if(a[i] > b[i])
+ return 1;
+ if(a[i] < b[i])
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * compare 2 v4 or v6 ranges
+ */
+enum
+{
+ Rpreceeds,
+ Rfollows,
+ Requals,
+ Rcontains,
+ Rcontained,
+};
+
+static int
+rangecompare(Route *a, Route *b)
+{
+ if(a->type & Rv4){
+ if(a->v4.endaddress < b->v4.address)
+ return Rpreceeds;
+
+ if(a->v4.address > b->v4.endaddress)
+ return Rfollows;
+
+ if(a->v4.address <= b->v4.address
+ && a->v4.endaddress >= b->v4.endaddress){
+ if(a->v4.address == b->v4.address
+ && a->v4.endaddress == b->v4.endaddress)
+ return Requals;
+ return Rcontains;
+ }
+ return Rcontained;
+ }
+
+ if(lcmp(a->v6.endaddress, b->v6.address) < 0)
+ return Rpreceeds;
+
+ if(lcmp(a->v6.address, b->v6.endaddress) > 0)
+ return Rfollows;
+
+ if(lcmp(a->v6.address, b->v6.address) <= 0
+ && lcmp(a->v6.endaddress, b->v6.endaddress) >= 0){
+ if(lcmp(a->v6.address, b->v6.address) == 0
+ && lcmp(a->v6.endaddress, b->v6.endaddress) == 0)
+ return Requals;
+ return Rcontains;
+ }
+
+ return Rcontained;
+}
+
+static void
+copygate(Route *old, Route *new)
+{
+ if(new->type & Rv4)
+ memmove(old->v4.gate, new->v4.gate, IPv4addrlen);
+ else
+ memmove(old->v6.gate, new->v6.gate, IPaddrlen);
+}
+
+/*
+ * walk down a tree adding nodes back in
+ */
+static void
+walkadd(Route **root, Route *p)
+{
+ Route *l, *r;
+
+ l = p->left;
+ r = p->right;
+ p->left = 0;
+ p->right = 0;
+ addnode(root, p);
+ if(l)
+ walkadd(root, l);
+ if(r)
+ walkadd(root, r);
+}
+
+/*
+ * calculate depth
+ */
+static void
+calcd(Route *p)
+{
+ Route *q;
+ int d;
+
+ if(p) {
+ d = 0;
+ q = p->left;
+ if(q)
+ d = q->depth;
+ q = p->right;
+ if(q && q->depth > d)
+ d = q->depth;
+ q = p->mid;
+ if(q && q->depth > d)
+ d = q->depth;
+ p->depth = d+1;
+ }
+}
+
+/*
+ * balance the tree at the current node
+ */
+static void
+balancetree(Route **cur)
+{
+ Route *p, *l, *r;
+ int dl, dr;
+
+ /*
+ * if left and right are
+ * too out of balance,
+ * rotate tree node
+ */
+ p = *cur;
+ dl = 0; if(l = p->left) dl = l->depth;
+ dr = 0; if(r = p->right) dr = r->depth;
+
+ if(dl > dr+1) {
+ p->left = l->right;
+ l->right = p;
+ *cur = l;
+ calcd(p);
+ calcd(l);
+ } else
+ if(dr > dl+1) {
+ p->right = r->left;
+ r->left = p;
+ *cur = r;
+ calcd(p);
+ calcd(r);
+ } else
+ calcd(p);
+}
+
+/*
+ * add a new node to the tree
+ */
+static void
+addnode(Route **cur, Route *new)
+{
+ Route *p;
+
+ p = *cur;
+ if(p == 0) {
+ *cur = new;
+ new->depth = 1;
+ return;
+ }
+
+ switch(rangecompare(new, p)){
+ case Rpreceeds:
+ addnode(&p->left, new);
+ break;
+ case Rfollows:
+ addnode(&p->right, new);
+ break;
+ case Rcontains:
+ /*
+ * if new node is superset
+ * of tree node,
+ * replace tree node and
+ * queue tree node to be
+ * merged into root.
+ */
+ *cur = new;
+ new->depth = 1;
+ addqueue(&queue, p);
+ break;
+ case Requals:
+ copygate(p, new);
+ freeroute(new);
+ break;
+ case Rcontained:
+ addnode(&p->mid, new);
+ break;
+ }
+
+ balancetree(cur);
+}
+
+#define V4H(a) ((a&0x07ffffff)>>(32-Lroot-5))
+
+void
+v4addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type)
+{
+ Route *p;
+ ulong sa;
+ ulong m;
+ ulong ea;
+ int h, eh;
+
+ m = nhgetl(mask);
+ sa = nhgetl(a) & m;
+ ea = sa | ~m;
+
+ eh = V4H(ea);
+ for(h=V4H(sa); h<=eh; h++) {
+ p = allocroute(Rv4 | type);
+ p->v4.address = sa;
+ p->v4.endaddress = ea;
+ memmove(p->v4.gate, gate, sizeof(p->v4.gate));
+ memmove(p->tag, tag, sizeof(p->tag));
+
+ wlock(&routelock);
+ addnode(&v4root[h], p);
+ while(p = queue) {
+ queue = p->mid;
+ walkadd(&v4root[h], p->left);
+ freeroute(p);
+ }
+ wunlock(&routelock);
+ }
+
+ ipifcaddroute(Rv4, a, mask, gate, type);
+}
+
+#define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
+
+void
+v6addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type)
+{
+ Route *p;
+ ulong sa[IPllen], ea[IPllen];
+ ulong x, y;
+ int h, eh;
+
+ for(h = 0; h < IPllen; h++){
+ x = nhgetl(a+4*h);
+ y = nhgetl(mask+4*h);
+ sa[h] = x & y;
+ ea[h] = x | ~y;
+ }
+
+ eh = V6H(ea);
+ for(h = V6H(sa); h <= eh; h++) {
+ p = allocroute(type);
+ memmove(p->v6.address, sa, IPaddrlen);
+ memmove(p->v6.endaddress, ea, IPaddrlen);
+ memmove(p->v6.gate, gate, IPaddrlen);
+ memmove(p->tag, tag, sizeof(p->tag));
+
+ wlock(&routelock);
+ addnode(&v6root[h], p);
+ while(p = queue) {
+ queue = p->mid;
+ walkadd(&v6root[h], p->left);
+ freeroute(p);
+ }
+ wunlock(&routelock);
+ }
+
+ ipifcaddroute(0, a, mask, gate, type);
+}
+
+Route**
+looknode(Route **cur, Route *r)
+{
+ Route *p;
+
+ for(;;){
+ p = *cur;
+ if(p == 0)
+ return 0;
+
+ switch(rangecompare(r, p)){
+ case Rcontains:
+ return 0;
+ case Rpreceeds:
+ cur = &p->left;
+ break;
+ case Rfollows:
+ cur = &p->right;
+ break;
+ case Rcontained:
+ cur = &p->mid;
+ break;
+ case Requals:
+ return cur;
+ }
+ }
+}
+
+void
+v4delroute(uchar *a, uchar *mask)
+{
+ Route **r, *p;
+ Route rt;
+ int h, eh;
+ ulong m;
+
+ m = nhgetl(mask);
+ rt.v4.address = nhgetl(a) & m;
+ rt.v4.endaddress = rt.v4.address | ~m;
+ rt.type = Rv4;
+
+ eh = V4H(rt.v4.endaddress);
+ for(h=V4H(rt.v4.address); h<=eh; h++) {
+ wlock(&routelock);
+ r = looknode(&v4root[h], &rt);
+ if(r) {
+ p = *r;
+ *r = 0;
+ addqueue(&queue, p->left);
+ addqueue(&queue, p->mid);
+ addqueue(&queue, p->right);
+ freeroute(p);
+ while(p = queue) {
+ queue = p->mid;
+ walkadd(&v4root[h], p->left);
+ freeroute(p);
+ }
+ }
+ wunlock(&routelock);
+ }
+
+ ipifcremroute(Rv4, a, mask);
+}
+
+void
+v6delroute(uchar *a, uchar *mask)
+{
+ Route **r, *p;
+ Route rt;
+ int h, eh;
+ ulong x, y;
+
+ for(h = 0; h < IPllen; h++){
+ x = nhgetl(a+4*h);
+ y = nhgetl(mask+4*h);
+ rt.v6.address[h] = x & y;
+ rt.v6.endaddress[h] = x | ~y;
+ }
+ rt.type = 0;
+
+ eh = V6H(rt.v6.endaddress);
+ for(h=V6H(rt.v6.address); h<=eh; h++) {
+ wlock(&routelock);
+ r = looknode(&v6root[h], &rt);
+ if(r) {
+ p = *r;
+ *r = 0;
+ addqueue(&queue, p->left);
+ addqueue(&queue, p->mid);
+ addqueue(&queue, p->right);
+ freeroute(p);
+ while(p = queue) {
+ queue = p->mid;
+ walkadd(&v6root[h], p->left);
+ freeroute(p);
+ }
+ }
+ wunlock(&routelock);
+ }
+
+ ipifcremroute(0, a, mask);
+}
+
+Route*
+v4lookup(uchar *a)
+{
+ Route *p, *q;
+ ulong la;
+ uchar gate[IPaddrlen];
+
+ la = nhgetl(a);
+ q = nil;
+ for(p=v4root[V4H(la)]; p;)
+ if(la >= p->v4.address) {
+ if(la <= p->v4.endaddress) {
+ q = p;
+ p = p->mid;
+ } else
+ p = p->right;
+ } else
+ p = p->left;
+
+ if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
+ v4tov6(gate, q->v4.gate);
+ q->ifc = findipifc(gate, q->type);
+ if(q->ifc == nil)
+ return nil;
+ q->ifcid = q->ifc->ifcid;
+ }
+
+ return q;
+}
+
+Route*
+v6lookup(uchar *a)
+{
+ Route *p, *q;
+ ulong la[IPllen];
+ int h;
+ ulong x, y;
+
+ if(memcmp(a, v4prefix, 12) == 0){
+ q = v4lookup(a+12);
+ if(q != nil)
+ return q;
+ }
+
+ for(h = 0; h < IPllen; h++)
+ la[h] = nhgetl(a+4*h);
+
+ q = 0;
+ for(p=v6root[V6H(la)]; p;){
+ for(h = 0; h < IPllen; h++){
+ x = la[h];
+ y = p->v6.address[h];
+ if(x == y)
+ continue;
+ if(x < y){
+ p = p->left;
+ goto next;
+ }
+ break;
+ }
+ for(h = 0; h < IPllen; h++){
+ x = la[h];
+ y = p->v6.endaddress[h];
+ if(x == y)
+ continue;
+ if(x > y){
+ p = p->right;
+ goto next;
+ }
+ break;
+ }
+ q = p;
+ p = p->mid;
+next: ;
+ }
+
+ if(q && q->ifc == nil){
+ q->ifc = findipifc(q->v6.gate, q->type);
+ if(q->ifc == nil)
+ return nil;
+ if(q->ifcid != q->ifc->ifcid)
+ return nil;
+ }
+
+ return q;
+}
+
+enum
+{
+ Rlinelen= 89,
+};
+
+char *rformat = "%-24.24I %-24.24M %-24.24I %4.4s %4.4s %3s\n";
+
+void
+convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc)
+{
+ int i;
+ char *p = t;
+
+ if(r->type & Rv4){
+ memmove(addr, v4prefix, IPv4off);
+ hnputl(addr+IPv4off, r->v4.address);
+ memset(mask, 0xff, IPv4off);
+ hnputl(mask+IPv4off, ~(r->v4.endaddress ^ r->v4.address));
+ memmove(gate, v4prefix, IPv4off);
+ memmove(gate+IPv4off, r->v4.gate, IPv4addrlen);
+ } else {
+ for(i = 0; i < IPllen; i++){
+ hnputl(addr + 4*i, r->v6.address[i]);
+ hnputl(mask + 4*i, ~(r->v6.endaddress[i] ^ r->v6.address[i]));
+ }
+ memmove(gate, r->v6.gate, IPaddrlen);
+ }
+
+ memset(t, ' ', 4);
+ t[4] = 0;
+ if(r->type & Rv4)
+ *p++ = '4';
+ else
+ *p++ = '6';
+ if(r->type & Rifc)
+ *p++ = 'i';
+ if(r->type & Runi)
+ *p++ = 'u';
+ else if(r->type & Rbcast)
+ *p++ = 'b';
+ else if(r->type & Rmulti)
+ *p++ = 'm';
+ if(r->type & Rptpt)
+ *p = 'p';
+
+ if(r->ifc)
+ *nifc = r->ifc->conv->x;
+ else
+ *nifc = -1;
+}
+
+/*
+ * this code is not in rr to reduce stack size
+ */
+static void
+sprintroute(Route *r, Routewalk *rw)
+{
+ int nifc;
+ char t[5], *iname, ifbuf[5];
+ uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
+
+ if(rw->o >= 0) {
+ convroute(r, addr, mask, gate, t, &nifc);
+ iname = "-";
+ if(nifc != -1) {
+ iname = ifbuf;
+ sprint(ifbuf, "%d", nifc);
+ }
+ sprint(rw->p, rformat, addr, mask, gate, t, r->tag, iname);
+ rw->p += Rlinelen;
+ }
+ rw->o++;
+}
+
+/*
+ * recurse descending tree, applying the function in Routewalk
+ */
+static int
+rr(Route *r, Routewalk *rw)
+{
+ int h;
+
+ if(rw->n <= rw->o)
+ return 0;
+ if(r == nil)
+ return 1;
+
+ if(rr(r->left, rw) == 0)
+ return 0;
+
+ if(r->type & Rv4)
+ h = V4H(r->v4.address);
+ else
+ h = V6H(r->v6.address);
+
+ if(h == rw->h)
+ rw->walk(r, rw);
+
+ if(rr(r->mid, rw) == 0)
+ return 0;
+
+ return rr(r->right, rw);
+}
+
+void
+ipwalkroutes(Routewalk *rw)
+{
+ rlock(&routelock);
+ if(rw->n > rw->o) {
+ for(rw->h = 0; rw->h < nelem(v4root); rw->h++)
+ if(rr(v4root[rw->h], rw) == 0)
+ break;
+ }
+ if(rw->n > rw->o) {
+ for(rw->h = 0; rw->h < nelem(v6root); rw->h++)
+ if(rr(v6root[rw->h], rw) == 0)
+ break;
+ }
+ runlock(&routelock);
+}
+
+long
+routeread(char *p, ulong offset, int n)
+{
+ Routewalk rw;
+
+ if(offset % Rlinelen)
+ return 0;
+
+ rw.p = p;
+ rw.n = n/Rlinelen;
+ rw.o = -(offset/Rlinelen);
+ rw.walk = sprintroute;
+
+ ipwalkroutes(&rw);
+
+ if(rw.o < 0)
+ rw.o = 0;
+
+ return rw.o*Rlinelen;
+}
+
+/*
+ * this code is not in routeflush to reduce stack size
+ */
+void
+delroute(Route *r)
+{
+ uchar addr[IPaddrlen];
+ uchar mask[IPaddrlen];
+ uchar gate[IPaddrlen];
+ char t[5];
+ int nifc;
+
+ convroute(r, addr, mask, gate, t, &nifc);
+ if(r->type & Rv4)
+ v4delroute(addr+IPv4off, mask+IPv4off);
+ else
+ v6delroute(addr, mask);
+}
+
+/*
+ * recurse until one route is deleted
+ * returns 0 if nothing is deleted, 1 otherwise
+ */
+int
+routeflush(Route *r)
+{
+ if(r == nil)
+ return 0;
+ if(routeflush(r->mid))
+ return 1;
+ if(routeflush(r->left))
+ return 1;
+ if(routeflush(r->right))
+ return 1;
+ if((r->type & Rifc) == 0){
+ delroute(r);
+ return 1;
+ }
+ return 0;
+}
+
+long
+routewrite(Chan *c, char *p, int n)
+{
+ int h;
+ char *tag;
+ Cmdbuf *cb;
+ uchar addr[IPaddrlen];
+ uchar mask[IPaddrlen];
+ uchar gate[IPaddrlen];
+
+ cb = parsecmd(p, n);
+ if(waserror()){
+ free(cb);
+ nexterror();
+ }
+
+ if(strcmp(cb->f[0], "flush") == 0){
+ wlock(&routelock);
+ for(h = 0; h < nelem(v4root); h++)
+ while(routeflush(v4root[h]) == 1)
+ ;
+ for(h = 0; h < nelem(v6root); h++)
+ while(routeflush(v6root[h]) == 1)
+ ;
+ wunlock(&routelock);
+ } 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(addr+IPv4off, mask+IPv4off);
+ else
+ v6delroute(addr, mask);
+ } 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)
+ tag = c->tag;
+ if(memcmp(addr, v4prefix, IPv4off) == 0)
+ v4addroute(tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
+ else
+ v6addroute(tag, addr, mask, gate, 0);
+ } else if(strcmp(cb->f[0], "tag") == 0) {
+ if(cb->nf < 2)
+ error(Ebadarg);
+
+ h = strlen(cb->f[1]);
+ if(h > sizeof(c->tag))
+ h = sizeof(c->tag);
+ strncpy(c->tag, cb->f[1], h);
+ if(h < 4)
+ memset(c->tag+h, ' ', sizeof(c->tag)-h);
+ }
+
+ poperror();
+ free(cb);
+ return n;
+}
M ip/netlog.c => ip/netlog.c +11 -7
@@ 7,7 7,8 @@
#include "../ip/ip.h"
int logmask; /* mask of things to debug */
-Ipaddr iponly; /* ip address to print debugging for */
+uchar iponly[IPaddrlen]; /* ip address to print debugging for */
+int iponlyset;
enum {
Nlog = 4*1024,
@@ 62,11 63,8 @@ netlogopen(void)
nexterror();
}
if(alog.opens == 0){
- if(alog.buf == nil){
+ if(alog.buf == nil)
alog.buf = malloc(Nlog);
- if(alog.buf == nil)
- error(Enomem);
- }
alog.rptr = alog.buf;
alog.end = alog.buf + Nlog;
}
@@ 175,7 173,11 @@ netlogctl(char* s, int len)
else if(strcmp("clear", fields[0]) == 0)
set = 0;
else if(strcmp("only", fields[0]) == 0){
- iponly = parseip(addr, fields[1]);
+ parseip(iponly, fields[1]);
+ if(ipcmp(iponly, IPnoaddr) == 0)
+ iponlyset = 0;
+ else
+ iponlyset = 1;
return nil;
} else
return Ebadnetctl;
@@ 206,13 208,15 @@ netlog(int mask, char *fmt, ...)
int i, n;
va_list arg;
- if(alog.opens == 0 || !(logmask & mask))
+ if(!(logmask & mask))
return;
va_start(arg, fmt);
n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
va_end(arg);
+print("%s", buf);
+
if(alog.opens == 0)
return;
A ip/nullmedium.c => ip/nullmedium.c +46 -0
@@ 0,0 1,46 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "ip.h"
+#include "kernel.h"
+
+static void
+nullbind(Ipifc*, int, char**)
+{
+ error("can't bind null device");
+}
+
+static void
+nullunbind(Ipifc*)
+{
+}
+
+static void
+nullbwrite(Ipifc*, Block*, int, uchar*)
+{
+ error("nullbwrite");
+}
+
+Medium nullmedium =
+{
+ "null",
+ 0, /* medium header size */
+ 0, /* default min mtu */
+ 0, /* default max mtu */
+ 0, /* mac address length */
+ nullbind,
+ nullunbind,
+ nullbwrite,
+ nil, /* addmulti */
+ nil, /* remmulti */
+ nil, /* pktin */
+ nil, /* addroute */
+ nil, /* remroute */
+ nil, /* flushroute */
+ nil, /* joinmulti */
+ nil, /* leave multi */
+};
A ip/pktmedium.c => ip/pktmedium.c +75 -0
@@ 0,0 1,75 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "ip.h"
+#include "kernel.h"
+
+
+static void pktbind(Ipifc *ifc, int argc, char **argv);
+static void pktunbind(Ipifc *ifc);
+static void pktbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
+static void pktin(Ipifc *ifc, Block *bp);
+
+Medium pktmedium =
+{
+ "pkt",
+ 14,
+ 60,
+ 1514,
+ 6,
+ pktbind,
+ pktunbind,
+ pktbwrite,
+ nil, /* addmulti */
+ nil, /* remmulti */
+ pktin,
+ nil, /* addroute */
+ nil, /* remroute */
+ nil, /* flushroute */
+ nil, /* joinmulti */
+ nil, /* leave multi */
+};
+
+/*
+ * called to bind an IP ifc to an ethernet device
+ * called with ifc wlock'd
+ */
+static void
+pktbind(Ipifc*, int, char**)
+{
+}
+
+/*
+ * called with ifc wlock'd
+ */
+static void
+pktunbind(Ipifc*)
+{
+}
+
+/*
+ * called by ipoput with a single packet to write
+ */
+static void
+pktbwrite(Ipifc *ifc, Block *bp, int, uchar*)
+{
+ /* enqueue onto the conversation's rq */
+ bp = concatblock(bp);
+ qpass(ifc->conv->rq, bp);
+}
+
+/*
+ * called when someone write's to 'data' with ifc rlocked
+ */
+static void
+pktin(Ipifc *ifc, Block *bp)
+{
+ if(ifc->lifc == nil)
+ freeb(bp);
+ else
+ ipiput(ifc->lifc->local, bp);
+}
M ip/ptclbsum.c => ip/ptclbsum.c +2 -2
@@ 8,11 8,11 @@
#include "ip.h"
static short endian = 1;
-static byte* aendian = (byte*)&endian;
+static uchar* aendian = (uchar*)&endian;
#define LITTLE *aendian
ushort
-ptclbsum(byte *addr, int len)
+ptclbsum(uchar *addr, int len)
{
ulong losum, hisum, mdsum, x;
ulong t1, t2;
M ip/tcp.c => ip/tcp.c +124 -128
@@ 14,6 14,7 @@ enum
TCP_IPLEN = 8,
TCP_PHDRSIZE = 12,
TCP_HDRSIZE = 20,
+ TCP_TCBPHDRSZ = 40,
TCP_PKT = TCP_IPLEN+TCP_PHDRSIZE,
TimerOFF = 0,
TimerON = 1,
@@ 85,27 86,27 @@ struct Timer
typedef struct Tcphdr Tcphdr;
struct Tcphdr
{
- byte vihl; /* Version and header length */
- byte tos; /* Type of service */
- byte length[2]; /* packet length */
- byte id[2]; /* Identification */
- byte frag[2]; /* Fragment information */
- byte Unused;
- byte proto;
- byte tcplen[2];
- byte tcpsrc[4];
- byte tcpdst[4];
- byte tcpsport[2];
- byte tcpdport[2];
- byte tcpseq[4];
- byte tcpack[4];
- byte tcpflag[2];
- byte tcpwin[2];
- byte tcpcksum[2];
- byte tcpurg[2];
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar length[2]; /* packet length */
+ uchar id[2]; /* Identification */
+ uchar frag[2]; /* Fragment information */
+ uchar Unused;
+ uchar proto;
+ uchar tcplen[2];
+ uchar tcpsrc[4];
+ uchar tcpdst[4];
+ 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 */
- byte tcpopt[2];
- byte tcpmss[2];
+ uchar tcpopt[2];
+ uchar tcpmss[2];
};
typedef struct Tcp Tcp;
@@ 115,7 116,7 @@ struct Tcp
ushort dest;
ulong seq;
ulong ack;
- byte flags;
+ uchar flags;
ushort wnd;
ushort urg;
ushort mss;
@@ 134,9 135,9 @@ typedef struct Tcpctl Tcpctl;
struct Tcpctl
{
QLock;
- byte state; /* Connection state */
- byte type; /* Listening or active connection */
- byte code; /* Icmp code */
+ uchar state; /* Connection state */
+ uchar type; /* Listening or active connection */
+ uchar code; /* Icmp code */
struct {
ulong una; /* Unacked data pointer */
ulong nxt; /* Next sequence expected */
@@ 147,7 148,7 @@ struct Tcpctl
ulong wl2;
} snd;
struct {
- ulong nxt; /* Receive pointer to next byte slot */
+ ulong nxt; /* Receive pointer to next uchar slot */
ushort wnd; /* Receive window incoming */
ulong urg; /* Urgent pointer */
int blocked;
@@ 162,8 163,8 @@ struct Tcpctl
ushort window; /* Recevive window */
int max_snd; /* Max send */
ulong last_ack; /* Last acknowledege received */
- byte backoff; /* Exponential backoff counter */
- byte flags; /* State flags */
+ uchar backoff; /* Exponential backoff counter */
+ uchar flags; /* State flags */
ulong sndcnt; /* Amount of data in send queue */
Reseq *reseq; /* Resequencing queue */
Timer timer; /* Activity timer */
@@ 175,10 176,11 @@ struct Tcpctl
int kacounter; /* count down for keep alive */
int f2counter; /* count down for finwait2 state */
uint sndsyntime; /* time syn sent */
- char ascstate[128];
+
+ Tcphdr protohdr; /* prototype header */
};
-#define DBG(x) if((logmask & Logtcpmsg) && (iponly == 0 || x == iponly))netlog
+#define DBG(x) if((logmask & Logtcpmsg) && (iponlyset == 0 || memcmp(x, iponly+12, 4) == 0))netlog
Proto tcp;
int tcp_irtt = DEF_RTT; /* Initial guess at round trip time */
@@ 189,14 191,14 @@ QLock tl; /* Protect timer list */
static struct Tcpstats
{
ulong dup; /* (partially) duplicated packets */
- ulong dupb; /* duplicated bytes */
+ ulong dupb; /* duplicated uchars */
} tstats;
void addreseq(Tcpctl*, Tcp*, Block*, ushort);
void getreseq(Tcpctl*, Tcp*, Block**, ushort*);
void localclose(Conv*, char*);
void procsyn(Conv*, Tcp*);
-void tcpiput(Media*, Block*);
+void tcpiput(uchar*, Block*);
void tcpoutput(Conv*);
int tcptrim(Tcpctl*, Tcp*, Block**, ushort*);
void tcpstart(Conv*, int, ushort);
@@ 206,10 208,10 @@ void tcprcvwin(Conv*);
void tcpacktimer(Conv*);
void
-tcpsetstate(Conv *s, byte newstate)
+tcpsetstate(Conv *s, uchar newstate)
{
Tcpctl *tcb;
- byte oldstate;
+ uchar oldstate;
tcb = (Tcpctl*)s->ptcl;
@@ 231,7 233,7 @@ tcpsetstate(Conv *s, byte newstate)
qclose(s->eq);
s->lport = 0; /* This connection is toast */
s->rport = 0;
- s->raddr = 0;
+ ipmove(s->raddr, IPnoaddr);
case Close_wait: /* Remote closes */
qhangup(s->rq, nil);
@@ 255,29 257,26 @@ tcpconnect(Conv *c, char **argv, int argc)
return nil;
}
-int
-tcpstate(char **msg, Conv *c)
+static int
+tcpstate(Conv *c, char *state, int n)
{
Tcpctl *s;
- int isclose;
s = (Tcpctl*)(c->ptcl);
- isclose = 0;
- if(s->state == Closed)
- isclose = 1;
-
-/* snprint(s->ascstate, sizeof(s->ascstate),
- "tcnt %d tnxt %lux tuna %lux twnd %d rack %lux rnxt %lux rwnd %d",
- s->sndcnt, s->snd.nxt, s->snd.una, s->snd.wnd,
- s->last_ack, s->rcv.nxt, s->rcv.wnd);*/
- snprint(s->ascstate, sizeof(s->ascstate),
+ return snprint(state, n,
"%s srtt %d mdev %d timer.start %d timer.count %d\n",
tcpstates[s->state], s->srtt, s->mdev,
s->timer.start, s->timer.count);
+}
- *msg = s->ascstate;
- return isclose;
+static int
+tcpinuse(Conv *c)
+{
+ Tcpctl *s;
+
+ s = (Tcpctl*)(c->ptcl);
+ return s->state != Closed;
}
static char*
@@ 533,6 532,7 @@ void
inittcpctl(Conv *s)
{
Tcpctl *tcb;
+ Tcphdr *h;
tcb = (Tcpctl*)s->ptcl;
@@ 550,21 550,30 @@ inittcpctl(Conv *s)
tcb->acktimer.start = TCP_ACK / MSPTICK;
tcb->acktimer.func = tcpacktimer;
tcb->acktimer.arg = s;
+
+ /* create a prototype(pseudo) header */
+ if(ipcmp(s->laddr, IPnoaddr) == 0)
+ findlocalip(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);
}
/* mtu (- TCP + IP hdr len) of 1st hop */
int
tcpmtu(Conv *s)
{
- Media *m;
- byte dst[4], dummy[4];
+ Ipifc *ifc;
int mtu;
mtu = 0;
- hnputl(dst, s->raddr);
- m = Mediaroute(dst, dummy);
- if(m != nil)
- mtu = m->maxmtu - m->hsize - (TCP_PKT + TCP_HDRSIZE);
+ ifc = findipifc(s->raddr, 0);
+ if(ifc != nil)
+ mtu = ifc->maxmtu - ifc->m->hsize - (TCP_PKT + TCP_HDRSIZE);
if(mtu < 4)
mtu = DEF_MSS;
return mtu;
@@ 647,23 656,16 @@ htontcp(Tcp *tcph, Block *data, Tcphdr *ph)
data->wp += hdrlen + TCP_PKT;
}
-
- memmove(data->rp, ph, TCP_PKT);
-
+ /* copy in pseudo ip header plus port numbers */
h = (Tcphdr *)(data->rp);
- h->proto = IP_TCPPROTO;
- h->frag[0] = 0;
- h->frag[1] = 0;
+ memmove(h, ph, TCP_TCBPHDRSZ);
+
+ /* copy in variable bits */
hnputs(h->tcplen, hdrlen + dlen);
- hnputs(h->tcpsport, tcph->source);
- hnputs(h->tcpdport, tcph->dest);
hnputl(h->tcpseq, tcph->seq);
hnputl(h->tcpack, tcph->ack);
hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags);
hnputs(h->tcpwin, tcph->wnd);
- h->tcpcksum[0] = 0;
- h->tcpcksum[1] = 0;
- h->Unused = 0;
hnputs(h->tcpurg, tcph->urg);
if(tcph->mss != 0){
@@ 674,7 676,7 @@ htontcp(Tcp *tcph, Block *data, Tcphdr *ph)
csum = ptclcsum(data, TCP_IPLEN, hdrlen+dlen+TCP_PHDRSIZE);
hnputs(h->tcpcksum, csum);
- DBG(nhgetl(h->tcpdst))(Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n",
+ DBG(h->tcpdst)(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);
@@ 686,7 688,7 @@ int
ntohtcp(Tcp *tcph, Block **bpp)
{
Tcphdr *h;
- byte *optr;
+ uchar *optr;
ushort hdrlen;
ushort i, optlen;
@@ 715,7 717,7 @@ ntohtcp(Tcp *tcph, Block **bpp)
if(*bpp == nil)
return -1;
- DBG(nhgetl(h->tcpsrc))(Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n",
+ DBG(h->tcpsrc)(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);
@@ 754,27 756,28 @@ tcpsndsyn(Tcpctl *tcb)
tcb->sndsyntime = msec;
}
+
+/*
+ * called with v4 (4 byte) addresses
+ */
void
-sndrst(Ipaddr source, Ipaddr dest, ushort length, Tcp *seg)
+sndrst(uchar *source, uchar *dest, ushort length, Tcp *seg)
{
- ushort tmp;
Tcphdr ph;
Block *hbp;
- byte rflags;
+ uchar rflags;
if(seg->flags & RST)
return;
-
- hnputl(ph.tcpsrc, dest);
- hnputl(ph.tcpdst, source);
+ /* 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);
-
- /* Swap port numbers */
- tmp = seg->dest;
- seg->dest = seg->source;
- seg->source = tmp;
+ hnputs(ph.tcpsport, seg->dest);
+ hnputs(ph.tcpdport, seg->source);
rflags = RST;
@@ 811,7 814,6 @@ char*
tcphangup(Conv *s)
{
Tcp seg;
- byte dst[4];
Tcpctl *tcb;
Tcphdr ph;
Block *hbp;
@@ 823,8 825,6 @@ tcphangup(Conv *s)
}
qlock(tcb);
if(s->raddr != 0) {
- seg.source = s->lport;
- seg.dest = s->rport;
seg.flags = RST | ACK;
seg.ack = tcb->rcv.nxt;
seg.seq = tcb->snd.ptr;
@@ 832,15 832,8 @@ tcphangup(Conv *s)
seg.urg = 0;
seg.mss = 0;
tcb->last_ack = tcb->rcv.nxt;
- if(s->laddr == 0) {
- hnputl(dst, s->raddr);
- s->laddr = Mediagetsrc(dst);
- }
- hnputl(ph.tcpsrc, s->laddr);
- hnputl(ph.tcpdst, s->raddr);
- ph.proto = IP_TCPPROTO;
hnputs(ph.tcplen, TCP_HDRSIZE);
- hbp = htontcp(&seg, nil, &ph);
+ hbp = htontcp(&seg, nil, &tcb->protohdr);
ipoput(hbp, 0, s->ttl);
}
localclose(s, nil);
@@ 850,10 843,11 @@ tcphangup(Conv *s)
}
Conv*
-tcpincoming(Conv *s, Tcp *segp, Ipaddr src, Ipaddr dst)
+tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst)
{
Conv *new;
Tcpctl *tcb;
+ Tcphdr *h;
new = Fsnewcall(&fs, s, src, segp->source, dst, segp->dest);
if(new == nil)
@@ 867,6 861,14 @@ tcpincoming(Conv *s, Tcp *segp, Ipaddr src, Ipaddr dst)
tcb->acktimer.arg = new;
tcb->acktimer.state = TimerOFF;
+ 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);
+
return new;
}
@@ 1030,21 1032,20 @@ update(Conv *s, Tcp *seg)
}
void
-tcpiput(Media *m, Block *bp)
+tcpiput(uchar*, Block *bp)
{
Tcp seg;
Tcphdr *h;
int hdrlen;
Tcpctl *tcb;
ushort length;
- Ipaddr source, dest;
+ uchar source[IPaddrlen], dest[IPaddrlen];
Conv *spec, *gen, *s, **p;
- USED(m);
h = (Tcphdr*)(bp->rp);
- dest = nhgetl(h->tcpdst);
- source = nhgetl(h->tcpsrc);
+ v4tov6(dest, h->tcpdst);
+ v4tov6(source, h->tcpsrc);
length = nhgets(h->length);
h->Unused = 0;
@@ 1076,8 1077,9 @@ tcpiput(Media *m, Block *bp)
/* Look for a connection. failing that look for a listener. */
for(p = tcp.conv; *p; p++) {
s = *p;
- if(s->rport == seg.source &&
- s->lport == seg.dest && s->raddr == source)
+ if(s->rport == seg.source)
+ if(s->lport == seg.dest)
+ if(ipcmp(s->raddr, source) == 0)
break;
}
s = *p;
@@ 1116,7 1118,7 @@ tcpiput(Media *m, Block *bp)
continue;
if(tcb->state != Listen)
continue;
- if(s->rport == 0 && s->raddr == 0) {
+ if(s->rport == 0 && ipcmp(s->raddr, IPnoaddr) == 0) {
if(s->lport == seg.dest){
spec = s;
break;
@@ 1414,7 1416,6 @@ tcpoutput(Conv *s)
int x;
Tcp seg;
int msgs;
- Tcphdr ph;
Tcpctl *tcb;
Block *hbp, *bp;
int sndcnt, n, first;
@@ 1547,17 1548,8 @@ tcpoutput(Conv *s)
if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
tcb->snd.nxt = tcb->snd.ptr;
- /* Fill in fields of pseudo IP header */
- hnputl(ph.tcpdst, s->raddr);
- if(s->laddr == 0)
- s->laddr = Mediagetsrc(ph.tcpdst);
-
- hnputl(ph.tcpsrc, s->laddr);
- hnputs(ph.tcpsport, s->lport);
- hnputs(ph.tcpdport, s->rport);
-
/* Build header, link data and compute cksum */
- hbp = htontcp(&seg, bp, &ph);
+ hbp = htontcp(&seg, bp, &tcb->protohdr);
if(hbp == nil) {
freeblist(bp);
return;
@@ 1588,13 1580,12 @@ tcpoutput(Conv *s)
}
/*
- * the BSD convention (hack?) for keep alives. resend last byte acked.
+ * the BSD convention (hack?) for keep alives. resend last uchar acked.
*/
void
tcpkeepalive(Conv *s)
{
Tcp seg;
- Tcphdr ph;
Tcpctl *tcb;
Block *hbp,*dbp;
@@ 1618,16 1609,8 @@ tcpkeepalive(Conv *s)
dbp->wp++;
}
- /* Fill in fields of pseudo IP header */
- hnputl(ph.tcpdst, s->raddr);
- if(s->laddr == 0)
- s->laddr = Mediagetsrc(ph.tcpdst);
- hnputl(ph.tcpsrc, s->laddr);
- hnputs(ph.tcpsport, s->lport);
- hnputs(ph.tcpdport, s->rport);
-
/* Build header, link data and compute cksum */
- hbp = htontcp(&seg, dbp, &ph);
+ hbp = htontcp(&seg, dbp, &tcb->protohdr);
if(hbp == nil) {
freeblist(dbp);
return;
@@ 1792,7 1775,7 @@ tcptrim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
{
ushort len;
Block *nbp;
- byte accept;
+ uchar accept;
int dupcnt, excess;
accept = 0;
@@ 1866,22 1849,25 @@ tcpadvise(Block *bp, char *msg)
{
Tcphdr *h;
Tcpctl *tcb;
- Ipaddr source, dest;
+ uchar source[IPaddrlen];
+ uchar dest[IPaddrlen];
ushort psource, pdest;
Conv *s, **p;
h = (Tcphdr*)(bp->rp);
- dest = nhgetl(h->tcpdst);
- source = nhgetl(h->tcpsrc);
+ v4tov6(dest, h->tcpdst);
+ v4tov6(source, h->tcpsrc);
psource = nhgets(h->tcpsport);
pdest = nhgets(h->tcpdport);
/* Look for a connection */
for(p = tcp.conv; *p; p++) {
s = *p;
- if(s->rport == pdest && s->lport == psource)
- if(s->raddr == dest && s->laddr == source){
+ if(s->rport == pdest)
+ if(s->lport == psource)
+ if(ipcmp(s->raddr, dest) == 0)
+ if(ipcmp(s->laddr, source) == 0){
tcb = (Tcpctl*)s->ptcl;
qlock(tcb);
switch(tcb->state){
@@ 1896,6 1882,7 @@ tcpadvise(Block *bp, char *msg)
freeblist(bp);
}
+/* called with c->car qlocked */
char*
tcpctl(Conv* c, char** f, int n)
{
@@ 1907,7 1894,14 @@ tcpctl(Conv* c, char** f, int n)
int
tcpstats(char *buf, int len)
{
- return snprint(buf, len, "\tdupp %d dupb %d\n", tstats.dup, tstats.dupb);
+ int n;
+
+ n = snprint(buf, len,
+ "tcp: csum %d hlen %d len %d order %d rexmit %d",
+ tcp.csumerr, tcp.hlenerr, tcp.lenerr, tcp.order, tcp.rexmit);
+ n += snprint(buf+n, len-n, " dupp %d dupb %d\n",
+ tstats.dup, tstats.dupb);
+ return n;
}
void
@@ 1924,6 1918,7 @@ tcpinit(Fs *fs)
tcp.rcv = tcpiput;
tcp.advise = tcpadvise;
tcp.stats = tcpstats;
+ tcp.inuse = tcpinuse;
tcp.ipproto = IP_TCPPROTO;
tcp.nc = Nchans;
tcp.ptclsize = sizeof(Tcpctl);
@@ 1932,3 1927,4 @@ tcpinit(Fs *fs)
Fsproto(fs, &tcp);
}
+
M ip/udp.c => ip/udp.c +77 -82
@@ 15,7 15,7 @@ enum
UDP_HDRSIZE = 20,
UDP_IPHDR = 8,
IP_UDPPROTO = 17,
- UDP_USEAD = 12,
+ UDP_USEAD = 36,
Udprxms = 200,
Udptickms = 100,
@@ 26,22 26,22 @@ typedef struct Udphdr Udphdr;
struct Udphdr
{
/* ip header */
- byte vihl; /* Version and header length */
- byte tos; /* Type of service */
- byte length[2]; /* packet length */
- byte id[2]; /* Identification */
- byte frag[2]; /* Fragment information */
- byte Unused;
- byte udpproto; /* Protocol */
- byte udpplen[2]; /* Header plus data length */
- byte udpsrc[4]; /* Ip source */
- byte udpdst[4]; /* Ip destination */
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar length[2]; /* packet length */
+ uchar id[2]; /* Identification */
+ uchar frag[2]; /* Fragment information */
+ uchar Unused;
+ uchar udpproto; /* Protocol */
+ uchar udpplen[2]; /* Header plus data length */
+ uchar udpsrc[4]; /* Ip source */
+ uchar udpdst[4]; /* Ip destination */
/* udp header */
- byte udpsport[2]; /* Source port */
- byte udpdport[2]; /* Destination port */
- byte udplen[2]; /* data length */
- byte udpcksum[2]; /* Checksum */
+ uchar udpsport[2]; /* Source port */
+ uchar udpdport[2]; /* Destination port */
+ uchar udplen[2]; /* data length */
+ uchar udpcksum[2]; /* Checksum */
};
/*
@@ 51,7 51,7 @@ typedef struct Udpcb Udpcb;
struct Udpcb
{
QLock;
- byte headers;
+ uchar headers;
};
Proto udp;
@@ 71,12 71,11 @@ udpconnect(Conv *c, char **argv, int argc)
return e;
}
-int
-udpstate(char **s, Conv *c)
+static int
+udpstate(Conv *c, char *state, int n)
{
USED(c);
- *s = "Datagram";
- return 1;
+ return snprint(state, n, "%s", "Datagram");
}
static char*
@@ 107,8 106,8 @@ udpclose(Conv *c)
qclose(c->rq);
qclose(c->wq);
qclose(c->eq);
- c->laddr = 0;
- c->raddr = 0;
+ ipmove(c->laddr, IPnoaddr);
+ ipmove(c->raddr, IPnoaddr);
c->lport = 0;
c->rport = 0;
@@ 119,17 118,16 @@ udpclose(Conv *c)
}
void
-udpkick(Conv *c, int l)
+udpkick(Conv *c, int)
{
Udphdr *uh;
ushort rport;
- Ipaddr laddr, raddr;
+ uchar laddr[IPaddrlen], raddr[IPaddrlen];
Block *bp;
Udpcb *ucb;
int dlen, ptcllen;
- USED(l);
-
+ netlog(Logudp, "udp: kick\n");
bp = qget(c->wq);
if(bp == nil)
return;
@@ 138,24 136,20 @@ udpkick(Conv *c, int l)
if(ucb->headers) {
/* get user specified addresses */
bp = pullupblock(bp, UDP_USEAD);
- if(bp == nil) {
- freeblist(bp);
+ if(bp == nil)
return;
- }
- raddr = nhgetl(bp->rp);
- bp->rp += 4;
- laddr = nhgetl(bp->rp);
- if(laddr != 0 && Mediaforme(bp->rp) <= 0)
- laddr = 0;
- bp->rp += 4;
+ ipmove(raddr, bp->rp);
+ bp->rp += IPaddrlen;
+ ipmove(laddr, bp->rp);
+ bp->rp += IPaddrlen;
+ if(ipforme(laddr) != Runi)
+ findlocalip(laddr, raddr); /* pick interface closest to dest */
rport = nhgets(bp->rp);
bp->rp += 2;
/* ignore local port number */
bp->rp += 2;
} else {
- raddr = 0;
rport = 0;
- laddr = 0;
}
dlen = blocklen(bp);
@@ 174,16 168,15 @@ udpkick(Conv *c, int l)
uh->frag[1] = 0;
hnputs(uh->udpplen, ptcllen);
if(ucb->headers) {
- hnputl(uh->udpdst, raddr);
+ v6tov4(uh->udpdst, raddr);
hnputs(uh->udpdport, rport);
- if(laddr)
- hnputl(uh->udpsrc, laddr);
- else
- hnputl(uh->udpsrc, Mediagetsrc(uh->udpdst));
+ v6tov4(uh->udpsrc, laddr);
} else {
- hnputl(uh->udpdst, c->raddr);
+ v6tov4(uh->udpdst, c->raddr);
hnputs(uh->udpdport, c->rport);
- hnputl(uh->udpsrc, c->laddr);
+ if(ipcmp(c->laddr, IPnoaddr) == 0)
+ findlocalip(c->laddr, c->raddr); /* pick interface closest to dest */
+ v6tov4(uh->udpsrc, c->laddr);
}
hnputs(uh->udpsport, c->lport);
hnputs(uh->udplen, ptcllen);
@@ 196,18 189,15 @@ udpkick(Conv *c, int l)
}
void
-udpiput(Media *m, Block *bp)
+udpiput(uchar *ia, Block *bp)
{
int len, olen, ottl;
Udphdr *uh;
Conv *c, **p;
Udpcb *ucb;
- Ipaddr raddr, laddr;
+ uchar raddr[IPaddrlen], laddr[IPaddrlen];
ushort rport, lport;
- uchar dst[IPaddrlen];
- uchar src[IPaddrlen];
- USED(m);
uh = (Udphdr*)(bp->rp);
/* Put back pseudo header for checksum (remember old values for icmpnoconv()) */
@@ 217,17 207,15 @@ udpiput(Media *m, Block *bp)
olen = nhgets(uh->udpplen);
hnputs(uh->udpplen, len);
- raddr = nhgetl(uh->udpsrc);
- laddr = nhgetl(uh->udpdst);
+ v4tov6(raddr, uh->udpsrc);
+ v4tov6(laddr, uh->udpdst);
lport = nhgets(uh->udpdport);
rport = nhgets(uh->udpsport);
- memmove(src, uh->udpsrc, IPaddrlen);
- memmove(dst, uh->udpdst, IPaddrlen);
if(udpsum && nhgets(uh->udpcksum)) {
if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) {
udp.csumerr++;
- netlog(Logudp, "udp: checksum error %I\n", src);
+ netlog(Logudp, "udp: checksum error %I\n", raddr);
freeblist(bp);
return;
}
@@ 244,10 232,10 @@ udpiput(Media *m, Block *bp)
}
if(*p == nil) {
- netlog(Logudp, "udp: no conv %I.%d -> %I.%d\n", src, rport,
- dst, lport);
+ netlog(Logudp, "udp: no conv %I.%d -> %I.%d\n", raddr, rport,
+ laddr, lport);
/* don't complain about broadcasts... */
- if(Mediaforme(dst) > 0){
+ if(ipforme(raddr) == 0){
uh->Unused = ottl;
hnputs(uh->udpplen, olen);
icmpnoconv(bp);
@@ 262,51 250,47 @@ udpiput(Media *m, Block *bp)
len -= (UDP_HDRSIZE-UDP_PHDRSIZE);
bp = trimblock(bp, UDP_IPHDR+UDP_HDRSIZE, len);
if(bp == nil){
- netlog(Logudp, "udp: len err %I.%d -> %I.%d\n", src, rport,
- dst, lport);
+ netlog(Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
+ laddr, lport);
udp.lenerr++;
return;
}
- netlog(Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", src, rport,
- dst, lport, len);
+ netlog(Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
+ laddr, lport, len);
ucb = (Udpcb*)c->ptcl;
if(ucb->headers) {
/* pass the src address */
bp = padblock(bp, UDP_USEAD);
- hnputl(bp->rp, raddr);
- if(Mediaforme(dst) > 0)
- hnputl(bp->rp+4, laddr);
- else if(m != 0)
- hnputl(bp->rp+4, m->myip[0]);
- else if(media != 0)
- hnputl(bp->rp+4, media->myip[0]);
+ ipmove(bp->rp, raddr);
+ if(ipforme(laddr) == Runi)
+ ipmove(bp->rp+IPaddrlen, laddr);
else
- hnputl(bp->rp+4, laddr);
- hnputs(bp->rp+8, rport);
- hnputs(bp->rp+10, lport);
+ ipmove(bp->rp+IPaddrlen, ia);
+ hnputs(bp->rp+2*IPaddrlen, rport);
+ hnputs(bp->rp+2*IPaddrlen+2, lport);
} else {
/* connection oriented udp */
if(c->raddr == 0){
/* save the src address in the conversation */
- c->raddr = raddr;
+ ipmove(c->raddr, raddr);
c->rport = rport;
/* reply with the same ip address (if not broadcast) */
- if(Mediaforme(dst) > 0)
- c->laddr = laddr;
+ if(ipforme(laddr) == Runi)
+ ipmove(c->laddr, laddr);
else
- c->laddr = m->myip[0];
+ ipmove(c->laddr, ia);
}
}
if(bp->next)
bp = concatblock(bp);
if(qfull(c->rq)){
- netlog(Logudp, "udp: qfull %I.%d -> %I.%d\n", src, rport,
- dst, lport);
+ netlog(Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
+ laddr, lport);
freeblist(bp);
}else
qpass(c->rq, bp);
@@ 333,22 317,24 @@ void
udpadvise(Block *bp, char *msg)
{
Udphdr *h;
- Ipaddr source, dest;
+ uchar source[IPaddrlen], dest[IPaddrlen];
ushort psource, pdest;
Conv *s, **p;
h = (Udphdr*)(bp->rp);
- dest = nhgetl(h->udpdst);
- source = nhgetl(h->udpsrc);
+ v4tov6(dest, h->udpdst);
+ v4tov6(source, h->udpsrc);
psource = nhgets(h->udpsport);
pdest = nhgets(h->udpdport);
/* Look for a connection */
for(p = udp.conv; *p; p++) {
s = *p;
- if(s->rport == pdest && s->lport == psource)
- if(s->raddr == dest && s->laddr == source){
+ if(s->rport == pdest)
+ if(s->lport == psource)
+ if(ipcmp(s->raddr, dest) == 0)
+ if(ipcmp(s->laddr, source) == 0){
qhangup(s->rq, msg);
qhangup(s->wq, msg);
break;
@@ 357,6 343,14 @@ udpadvise(Block *bp, char *msg)
freeblist(bp);
}
+int
+udpstats(char *buf, int len)
+{
+ return snprint(buf, len,
+ "udp: csum %d hlen %d len %d order %d rexmit %d\n",
+ udp.csumerr, udp.hlenerr, udp.lenerr, udp.order, udp.rexmit);
+}
+
void
udpinit(Fs *fs)
{
@@ 370,6 364,7 @@ udpinit(Fs *fs)
udp.close = udpclose;
udp.rcv = udpiput;
udp.advise = udpadvise;
+ udp.stats = udpstats;
udp.ipproto = IP_UDPPROTO;
udp.nc = 16;
udp.ptclsize = sizeof(Udpcb);
M port/portdat.h => port/portdat.h +1 -0
@@ 158,6 158,7 @@ struct Chan
Qid pgrpid; /* for #p/notepg */
Mnt* mntptr; /* for devmnt */
ulong mid; /* for ns in devproc */
+ char tag[4]; /* for iproute */
};
Chan* mchan; /* channel to mounted server */
Qid mqid; /* qid of root of mount point */