ref: c2dd9b1da7659c9ac42e7612e5621e9426956c73
parent: dc8432d4593c7a4b0a187d0174d4e4e603e456f6
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Apr 8 17:15:00 EDT 2018
devip: implement source specific routing
--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -74,7 +74,7 @@
}
/*
- * create a new arp entry for an ip address.
+ * create a new arp entry for an ip address on ifc.
*/
static Arpent*
newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
@@ -82,7 +82,6 @@
uint t;
Block *xp;
Arpent *a, *e, *f, **l;
- Medium *m = ifc->m;
int empty;
/* find oldest entry */
@@ -128,10 +127,9 @@
a->hash = *l;
*l = a;
- memmove(a->ip, ip, sizeof(a->ip));
+ ipmove(a->ip, ip);
a->utime = NOW;
a->ctime = 0;
- a->type = m;
a->rtime = NOW + ReTransTimer;
a->rxtsrem = MAX_MULTICAST_SOLICIT;
@@ -172,8 +170,10 @@
a->utime = 0;
a->ctime = 0;
- a->type = 0;
a->state = 0;
+
+ a->ifc = nil;
+ a->ifcid = 0;
/* take out of current chain */
l = &arp->hash[haship(a->ip)];
@@ -198,7 +198,6 @@
a->hash = nil;
freeblistchain(a->hold);
a->hold = a->last = nil;
- a->ifc = nil;
}
/*
@@ -212,7 +211,6 @@
{
int hash;
Arpent *a;
- Medium *type = ifc->m;
uchar v6ip[IPaddrlen];
if(version == V4){
@@ -223,11 +221,9 @@
qlock(arp);
hash = haship(ip);
for(a = arp->hash[hash]; a != nil; a = a->hash){
- if(ipcmp(ip, a->ip) == 0)
- if(type == a->type)
+ if(a->ifc == ifc && a->ifcid == ifc->ifcid && ipcmp(ip, a->ip) == 0)
break;
}
-
if(a == nil){
a = newarp6(arp, ip, ifc, (version != V4));
a->state = AWAIT;
@@ -245,7 +241,7 @@
return a; /* return with arp qlocked */
}
- memmove(mac, a->mac, a->type->maclen);
+ memmove(mac, a->mac, ifc->m->maclen);
/* remove old entries */
if(NOW - a->ctime > 15*60*1000)
@@ -286,13 +282,10 @@
l = &f->nextrxt;
}
}
-
memmove(a->mac, mac, type->maclen);
- a->type = type;
a->state = AOK;
a->utime = NOW;
bp = a->hold;
- assert(bp->list == nil);
a->hold = a->last = nil;
qunlock(arp);
@@ -299,50 +292,43 @@
return bp;
}
-void
-arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
+int
+arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *src, int refresh)
{
Arp *arp;
Route *r;
Arpent *a, *f, **l;
Ipifc *ifc;
- Medium *type;
Block *bp, *next;
+ Medium *m;
uchar v6ip[IPaddrlen];
arp = fs->arp;
-
- if(n != 6)
- return;
-
switch(version){
case V4:
- r = v4lookup(fs, ip, nil);
+ r = v4lookup(fs, ip, src, nil);
v4tov6(v6ip, ip);
ip = v6ip;
break;
case V6:
- r = v6lookup(fs, ip, nil);
+ r = v6lookup(fs, ip, src, nil);
break;
default:
panic("arpenter: version %d", version);
- return; /* to supress warnings */
+ return -1; /* to supress warnings */
}
+ if(r == nil || (ifc = r->ifc) == nil || (m = ifc->m) == nil || m->maclen != n || m->maclen == 0)
+ return -1;
- if(r == nil)
- return;
-
- ifc = r->ifc;
- type = ifc->m;
-
qlock(arp);
for(a = arp->hash[haship(ip)]; a != nil; a = a->hash){
- if(a->type != type || (a->state != AWAIT && a->state != AOK))
+ if(a->state != AWAIT && a->state != AOK)
continue;
-
+ if(a->ifc != ifc || a->ifcid != ifc->ifcid)
+ continue;
if(ipcmp(a->ip, ip) == 0){
a->state = AOK;
- memmove(a->mac, mac, type->maclen);
+ memmove(a->mac, mac, n);
if(version == V6){
/* take out of re-transmit chain */
@@ -356,8 +342,6 @@
}
}
- a->ifc = ifc;
- a->ifcid = ifc->ifcid;
bp = a->hold;
a->hold = a->last = nil;
if(version == V4)
@@ -367,22 +351,29 @@
qunlock(arp);
while(bp != nil){
+ if(!canrlock(ifc)){
+ freeblistchain(bp);
+ break;
+ }
+ if(ifc->m != m){
+ runlock(ifc);
+ freeblistchain(bp);
+ break;
+ }
next = bp->list;
+ bp->list = nil;
if(waserror()){
- freeblistchain(next);
runlock(ifc);
- nexterror();
+ freeblistchain(next);
+ break;
}
- rlock(ifc);
- if(ifc->m != nil)
- ifc->m->bwrite(ifc, concatblock(bp), version, ip);
- else
- freeblist(bp);
+ m->bwrite(ifc, concatblock(bp), version, ip);
runlock(ifc);
poperror();
bp = next;
}
- return;
+
+ return 1;
}
}
@@ -389,12 +380,12 @@
if(refresh == 0){
a = newarp6(arp, ip, ifc, 0);
a->state = AOK;
- a->type = type;
a->ctime = NOW;
- memmove(a->mac, mac, type->maclen);
+ memmove(a->mac, mac, n);
}
qunlock(arp);
+ return refresh == 0;
}
int
@@ -401,12 +392,11 @@
arpwrite(Fs *fs, char *s, int len)
{
int n;
- Route *r;
Arp *arp;
- Arpent *a;
+ Arpent *a, *x;
Medium *m;
- char *f[4], buf[256];
- uchar ip[IPaddrlen], mac[MAClen];
+ char *f[5], buf[256];
+ uchar ip[IPaddrlen], src[IPaddrlen], mac[MAClen];
arp = fs->arp;
@@ -419,7 +409,7 @@
if(len > 0 && buf[len-1] == '\n')
buf[len-1] = 0;
- n = getfields(buf, f, 4, 1, " ");
+ n = getfields(buf, f, nelem(f), 1, " ");
if(strcmp(f[0], "flush") == 0){
qlock(arp);
for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
@@ -428,6 +418,8 @@
a->hash = nil;
a->state = 0;
a->utime = 0;
+ a->ifc = nil;
+ a->ifcid = 0;
freeblistchain(a->hold);
a->hold = a->last = nil;
}
@@ -442,47 +434,49 @@
default:
error(Ebadarg);
case 3:
- if (parseip(ip, f[1]) == -1)
+ if(parseip(ip, f[1]) == -1)
error(Ebadip);
- if(isv4(ip))
- r = v4lookup(fs, ip+IPv4off, nil);
- else
- r = v6lookup(fs, ip, nil);
- if(r == nil)
- error("Destination unreachable");
- m = r->ifc->m;
- n = parsemac(mac, f[2], m->maclen);
+ if((n = parsemac(mac, f[2], sizeof(mac))) <= 0)
+ error(Ebadarp);
+ findlocalip(fs, src, ip);
break;
case 4:
m = ipfindmedium(f[1]);
- if(m == nil)
+ if(m == nil || m->maclen == 0)
error(Ebadarp);
- if (parseip(ip, f[2]) == -1)
+ if(parseip(ip, f[2]) == -1)
error(Ebadip);
- n = parsemac(mac, f[3], m->maclen);
+ if((n = parsemac(mac, f[3], sizeof(mac))) != m->maclen)
+ error(Ebadarp);
+ findlocalip(fs, src, ip);
break;
+ case 5:
+ m = ipfindmedium(f[1]);
+ if(m == nil || m->maclen == 0)
+ error(Ebadarp);
+ if(parseip(ip, f[2]) == -1)
+ error(Ebadip);
+ if((n = parsemac(mac, f[3], sizeof(mac))) != m->maclen)
+ error(Ebadarp);
+ if(parseip(src, f[4]) == -1)
+ error(Ebadip);
+ break;
}
-
- if(m->ares == nil)
- error(Ebadarp);
-
- m->ares(fs, V6, ip, mac, n, 0);
+ if(arpenter(fs, V6, ip, mac, n, src, 0) <= 0)
+ error("destination unreachable");
} else if(strcmp(f[0], "del") == 0){
- if(n != 2)
+ if (n != 2)
error(Ebadarg);
-
if (parseip(ip, f[1]) == -1)
error(Ebadip);
-
qlock(arp);
- for(a = arp->hash[haship(ip)]; a != nil; a = a->hash)
- if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
- break;
-
- if(a != nil){
- cleanarpent(arp, a);
- memset(a->ip, 0, sizeof(a->ip));
- memset(a->mac, 0, sizeof(a->mac));
+ for(a = arp->hash[haship(ip)]; a != nil; a = x){
+ x = a->hash;
+ if(ipcmp(ip, a->ip) == 0){
+ cleanarpent(arp, a);
+ memset(a->ip, 0, sizeof(a->ip));
+ memset(a->mac, 0, sizeof(a->mac));
+ }
}
qunlock(arp);
} else
@@ -491,13 +485,6 @@
return len;
}
-enum
-{
- Alinelen= 90,
-};
-
-char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
-
static void
convmac(char *p, uchar *mac, int n)
{
@@ -506,34 +493,40 @@
}
int
-arpread(Arp *arp, char *p, ulong offset, int len)
+arpread(Arp *arp, char *s, ulong offset, int len)
{
+ uchar ip[IPaddrlen], src[IPaddrlen];
+ char mac[2*MAClen+1], *p, *state;
+ Ipifc *ifc;
Arpent *a;
- int n;
- char mac[2*MAClen+1];
+ long n, o;
- if(offset % Alinelen)
- return 0;
-
- offset = offset/Alinelen;
- len = len/Alinelen;
-
- n = 0;
+ p = s;
+ o = -offset;
for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
- if(a->state == 0)
+ if(a->state == 0 || (ifc = a->ifc) == nil || a->ifcid != ifc->ifcid)
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);
+ state = arpstate[a->state];
+ ipmove(ip, a->ip);
+ convmac(mac, a->mac, ifc->m->maclen);
qunlock(arp);
+
+ ipv6local(ifc, src, ip);
+ n = snprint(p, len, "%-6.6s %-4.4s %-40.40I %-16.16s %I\n",
+ ifc->m->name, state, ip, mac, src);
+ if(o < 0) {
+ if(n > -o)
+ memmove(p, p-o, n+o);
+ o += n;
+ } else {
+ len -= n;
+ p += n;
+ }
}
- return n;
+ return p - s;
}
void
@@ -547,7 +540,7 @@
ipmove(src, ((Ip6hdr*)a->last->rp)->src);
arprelease(f->arp, a);
- if(iplocalonifc(ifc, src) || ipproxyifc(f, ifc, src))
+ if(iplocalonifc(ifc, src) != nil || ipproxyifc(f, ifc, src))
goto send;
} else {
arprelease(f->arp, a);
--- a/sys/src/9/ip/devip.c
+++ b/sys/src/9/ip/devip.c
@@ -848,7 +848,7 @@
else {
if(parseip(addr, str) == -1)
return Ebadip;
- if(ipforme(c->p->f, addr) || ipismulticast(addr))
+ if(ipforme(c->p->f, addr) != 0 || ipismulticast(addr))
ipmove(c->laddr, addr);
else
return "not a local IP address";
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -33,9 +33,9 @@
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 void etherareg(Fs *f, Ipifc *ifc, uchar *ip, uchar *proxy);
static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
static void sendarp(Ipifc *ifc, Arpent *a);
-static void sendgarp(Ipifc *ifc, uchar*);
static int multicastea(uchar *ea, uchar *ip);
static void recvarpproc(void*);
static void resolveaddr6(Ipifc *ifc, Arpent *a);
@@ -53,8 +53,7 @@
.bwrite= etherbwrite,
.addmulti= etheraddmulti,
.remmulti= etherremmulti,
-.ares= arpenter,
-.areg= sendgarp,
+.areg= etherareg,
.pref2addr= etherpref2addr,
};
@@ -70,8 +69,7 @@
.bwrite= etherbwrite,
.addmulti= etheraddmulti,
.remmulti= etherremmulti,
-.ares= arpenter,
-.areg= sendgarp,
+.areg= etherareg,
.pref2addr= etherpref2addr,
};
@@ -271,7 +269,7 @@
/* get mac address of destination */
a = arpget(er->f->arp, bp, version, ifc, ip, mac);
- if(a){
+ if(a != nil){
/* check for broadcast or multicast */
bp = multicastarp(er->f, a, ifc->m, mac);
if(bp==nil){
@@ -471,8 +469,8 @@
arprelease(er->f->arp, a);
n = sizeof(Etherarp);
- if(n < a->type->mintu)
- n = a->type->mintu;
+ if(n < ifc->m->mintu)
+ n = ifc->m->mintu;
bp = allocb(n);
memset(bp->rp, 0, n);
e = (Etherarp*)bp->rp;
@@ -536,10 +534,6 @@
Etherarp *e;
Etherrock *er = ifc->arg;
- /* don't arp for our initial non address */
- if(ipcmp(ip, IPnoaddr) == 0)
- return;
-
n = sizeof(Etherarp);
if(n < ifc->m->mintu)
n = ifc->m->mintu;
@@ -585,7 +579,7 @@
case ARPREPLY:
/* check for machine using my ip address */
v4tov6(ip, e->spa);
- if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
+ if(iplocalonifc(ifc, ip) != nil || ipproxyifc(er->f, ifc, ip)){
if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
print("arprep: 0x%E/0x%E also has ip addr %V\n",
e->s, e->sha, e->spa);
@@ -594,14 +588,13 @@
}
/* make sure we're not entering broadcast addresses */
- if(ipcmp(ip, ipbroadcast) == 0 ||
- !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
+ if(ipcmp(ip, ipbroadcast) == 0 || memcmp(e->sha, etherbroadcast, sizeof(e->sha)) == 0){
print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
e->s, e->sha, e->spa);
break;
}
- arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
+ arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), e->tpa, 0);
break;
case ARPREQUEST:
@@ -611,9 +604,9 @@
/* check for machine using my ip or ether address */
v4tov6(ip, e->spa);
- if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
+ if(iplocalonifc(ifc, ip) != nil || ipproxyifc(er->f, ifc, ip)){
if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
- if (memcmp(eprinted, e->spa, sizeof(e->spa))){
+ if(memcmp(eprinted, e->spa, sizeof(e->spa)) != 0){
/* print only once */
print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
memmove(eprinted, e->spa, sizeof(e->spa));
@@ -627,12 +620,11 @@
}
/* refresh what we know about sender */
- arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
+ arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), e->tpa, 1);
/* answer only requests for our address or systems we're proxying for */
v4tov6(ip, e->tpa);
- if(!iplocalonifc(ifc, ip))
- if(!ipproxyifc(er->f, ifc, ip))
+ if(iplocalonifc(ifc, ip) == nil && !ipproxyifc(er->f, ifc, ip))
break;
n = sizeof(Etherarp);
@@ -742,7 +734,7 @@
static void
etherpref2addr(uchar *pref, uchar *ea)
{
- pref[8] = ea[0] | 0x2;
+ pref[8] = ea[0] ^ 0x2;
pref[9] = ea[1];
pref[10] = ea[2];
pref[11] = 0xFF;
@@ -750,4 +742,32 @@
pref[13] = ea[3];
pref[14] = ea[4];
pref[15] = ea[5];
+}
+
+static void
+etherareg(Fs *f, Ipifc *ifc, uchar *ip, uchar *proxy)
+{
+ static char tdad[] = "dad6";
+ uchar mcast[IPaddrlen];
+
+ if(ipcmp(ip, IPnoaddr) == 0)
+ return;
+
+ if(isv4(ip)){
+ sendgarp(ifc, ip);
+ return;
+ }
+
+ if(!iptentative(f, ip)){
+ icmpna(f, proxy, v6allnodesL, ip, ifc->mac, 1<<5);
+ return;
+ }
+
+ /* temporarily add route for duplicate address detection */
+ ipv62smcast(mcast, ip);
+ addroute(f, mcast, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
+
+ icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
+
+ remroute(f, mcast, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
}
--- a/sys/src/9/ip/icmp.c
+++ b/sys/src/9/ip/icmp.c
@@ -200,7 +200,7 @@
if(ipismulticast(addr))
return 0;
i = ipforme(f, addr);
- return i == 0 || (i & Runi) != 0;
+ return i == 0 || i == Runi;
}
static int
@@ -211,7 +211,7 @@
v4tov6(addr, ip4);
if(ipismulticast(addr))
return 0;
- return (ipforme(f, addr) & Runi) != 0;
+ return ipforme(f, addr) == Runi;
}
void
@@ -401,7 +401,7 @@
break;
case Unreachable:
if(p->code >= nelem(unreachcode)) {
- snprint(m2, sizeof m2, "unreachable %V->%V code %d",
+ snprint(m2, sizeof m2, "unreachable %V -> %V code %d",
p->src, p->dst, p->code);
msg = m2;
} else
@@ -452,7 +452,7 @@
freeblist(bp);
}
-void
+static void
icmpadvise(Proto *icmp, Block *bp, char *msg)
{
Conv **c, *s;
@@ -478,7 +478,7 @@
freeblist(bp);
}
-int
+static int
icmpstats(Proto *icmp, char *buf, int len)
{
Icmppriv *priv;
--- a/sys/src/9/ip/icmp6.c
+++ b/sys/src/9/ip/icmp6.c
@@ -211,7 +211,7 @@
return nbp;
}
-void
+static void
icmpadvise6(Proto *icmp, Block *bp, char *msg)
{
ushort recid;
@@ -223,7 +223,8 @@
for(c = icmp->conv; *c; c++) {
s = *c;
- if(s->lport == recid && ipcmp(s->raddr, p->dst) == 0){
+ if(s->lport == recid)
+ if(ipcmp(s->laddr, p->dst) == 0 || ipcmp(s->raddr, p->dst) == 0){
if(s->ignoreadvice)
break;
qhangup(s->rq, msg);
@@ -280,7 +281,7 @@
ipoput6(c->p->f, bp, 0, c->ttl, c->tos, nil);
}
-char*
+static char*
icmpctl6(Conv *c, char **argv, int argc)
{
Icmpcb6 *icb;
@@ -311,10 +312,14 @@
for(c = icmp->conv; *c; c++){
s = *c;
- if(s->lport == recid && ipcmp(s->raddr, addr) == 0){
+ if(s->lport != recid)
+ continue;
+ if(ipcmp(s->laddr, addr) == 0){
qpass(s->rq, concatblock(bp));
return;
}
+ if(ipcmp(s->raddr, addr) == 0)
+ qpass(s->rq, copyblock(bp, blocklen(bp)));
}
freeblist(bp);
@@ -416,7 +421,7 @@
np->ttl = HOP_LIMIT;
np->vcf[0] = 0x06 << 4;
ipriv->out[NbrAdvert]++;
- netlog(f, Logicmp, "sending neighbor advertisement %I\n", src);
+ netlog(f, Logicmp, "sending neighbor advertisement %I\n", targ);
ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
}
@@ -692,26 +697,19 @@
int t;
rlock(ifc);
- if(ipproxyifc(f, ifc, target)) {
- runlock(ifc);
- return Tuniproxy;
- }
-
- for(lifc = ifc->lifc; lifc; lifc = lifc->next)
- if(ipcmp(lifc->local, target) == 0) {
- t = (lifc->tentative)? Tunitent: Tunirany;
- runlock(ifc);
- return t;
- }
-
+ if((lifc = iplocalonifc(ifc, target)) != nil)
+ t = lifc->tentative? Tunitent: Tunirany;
+ else if(ipproxyifc(f, ifc, target))
+ t = Tuniproxy;
+ else
+ t = 0;
runlock(ifc);
- return 0;
+ return t;
}
static void
icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp)
{
- int refresh = 1;
char *msg, m2[128];
uchar pktflags;
uchar *packet = bp->rp;
@@ -797,16 +795,12 @@
/* fall through */
case Tuniproxy:
- if(ipcmp(np->src, v6Unspecified) != 0) {
- arpenter(icmp->f, V6, np->src, np->lnaddr,
- 8*np->olen-2, 0);
+ if(ipv6local(ipifc, lsrc, np->src)) {
+ arpenter(icmp->f, V6, np->src, np->lnaddr, 8*np->olen-2, lsrc, 0);
pktflags |= Sflag;
- }
- if(!ipv6local(ipifc, lsrc, np->src))
- break;
- icmpna(icmp->f, lsrc,
- (ipcmp(np->src, v6Unspecified) == 0?
- v6allnodesL: np->src),
+ } else
+ ipmove(lsrc, np->target);
+ icmpna(icmp->f, lsrc, (pktflags & Sflag) ? np->src : v6allnodesL,
np->target, ipifc->mac, pktflags);
break;
case Tunitent:
@@ -830,9 +824,10 @@
* the arp table.
*/
lifc = iplocalonifc(ipifc, np->target);
- if(lifc && lifc->tentative)
- refresh = 0;
- arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, refresh);
+ if(lifc != nil && lifc->tentative)
+ arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, np->target, 0);
+ else if(ipv6local(ipifc, lsrc, np->target))
+ arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, lsrc, 1);
freeblist(bp);
break;
@@ -846,7 +841,7 @@
freeblist(bp);
}
-int
+static int
icmpstats6(Proto *icmp6, char *buf, int len)
{
Icmppriv6 *priv;
@@ -872,6 +867,14 @@
extern char* icmpconnect(Conv *c, char **argv, int argc);
extern void icmpclose(Conv *c);
+static void
+icmpclose6(Conv *c)
+{
+ Icmpcb6 *icb = (Icmpcb6*)c->ptcl;
+ icb->headers = 0;
+ icmpclose(c);
+}
+
void
icmp6init(Fs *fs)
{
@@ -883,7 +886,7 @@
icmp6->announce = icmpannounce;
icmp6->state = icmpstate;
icmp6->create = icmpcreate6;
- icmp6->close = icmpclose;
+ icmp6->close = icmpclose6;
icmp6->rcv = icmpiput6;
icmp6->stats = icmpstats6;
icmp6->ctl = icmpctl6;
--- a/sys/src/9/ip/ip.c
+++ b/sys/src/9/ip/ip.c
@@ -124,7 +124,7 @@
Block *xp, *nb;
Ip4hdr *eh, *feh;
int lid, len, seglen, chunk, dlen, blklen, offset, medialen;
- Route *r, *sr;
+ Route *r;
IP *ip;
int rv = 0;
@@ -154,25 +154,17 @@
goto free;
}
- r = v4lookup(f, eh->dst, rh);
- if(r == nil){
+ r = v4lookup(f, eh->dst, eh->src, rh);
+ if(r == nil || (ifc = r->ifc) == nil){
ip->stats[OutNoRoutes]++;
- netlog(f, Logip, "no interface %V\n", eh->dst);
+ netlog(f, Logip, "no interface %V -> %V\n", eh->src, eh->dst);
rv = -1;
goto free;
}
- ifc = r->ifc;
- if(r->type & (Rifc|Runi))
+ if(r->type & (Rifc|Runi|Rbcast|Rmulti))
gate = eh->dst;
else
- if(r->type & (Rbcast|Rmulti)) {
- gate = eh->dst;
- sr = v4lookup(f, eh->src, nil);
- if(sr != nil && (sr->type & Runi))
- ifc = sr->ifc;
- }
- else
gate = r->v4.gate;
if(!gating)
@@ -380,7 +372,7 @@
/* don't forward to source's network */
rh.r = nil;
- r = v4lookup(f, h->dst, &rh);
+ r = v4lookup(f, h->dst, h->src, &rh);
if(r == nil || r->ifc == ifc){
ip->stats[OutDiscards]++;
freeblist(bp);
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -39,7 +39,7 @@
Maxproto= 20,
Maxincall= 10,
Nchans= 1024,
- MAClen= 16, /* longest mac address */
+ MAClen= 8, /* longest mac address */
MAXTTL= 255,
DFLTTOS= 0,
@@ -242,18 +242,8 @@
/* process packets written to 'data' */
void (*pktin)(Fs *f, 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);
- void (*leavemulti)(Ipifc *ifc, uchar *a, uchar *ia);
-
/* address resolution */
- void (*ares)(Fs*, int, uchar*, uchar*, int, int); /* resolve */
- void (*areg)(Ipifc*, uchar*); /* register */
+ void (*areg)(Fs *f, Ipifc *ifc, uchar *ip, uchar *proxy); /* register */
/* v6 address generation */
void (*pref2addr)(uchar *pref, uchar *ea);
@@ -268,6 +258,7 @@
uchar mask[IPaddrlen];
uchar remote[IPaddrlen];
uchar net[IPaddrlen];
+ uchar type; /* ruoute type */
uchar tentative; /* =1 => v6 dup disc on, =0 => confirmed unique */
uchar onlink; /* =1 => onlink, =0 offlink. */
uchar autoflag; /* v6 autonomous flag */
@@ -509,13 +500,11 @@
* iproute.c
*/
typedef struct RouteTree RouteTree;
-typedef struct Routewalk Routewalk;
typedef struct V4route V4route;
typedef struct V6route V6route;
enum
{
-
/* type bits */
Rv4= (1<<0), /* this is a version 4 route */
Rifc= (1<<1), /* this route is a directly connected interface */
@@ -524,27 +513,18 @@
Rbcast= (1<<4), /* a broadcast self address */
Rmulti= (1<<5), /* a multicast self address */
Rproxy= (1<<6), /* this route should be proxied */
+ Rsrc= (1<<7), /* source specific route */
};
-struct Routewalk
-{
- int o;
- int h;
- char* p;
- char* e;
- void* state;
- void (*walk)(Route*, Routewalk*);
-};
-
struct RouteTree
{
- Route* right;
- Route* left;
- Route* mid;
+ Route *mid;
+ Route *left;
+ Route *right;
+ Ipifc *ifc;
+ uchar ifcid; /* must match ifc->id */
uchar depth;
uchar type;
- uchar ifcid; /* must match ifc->id */
- Ipifc *ifc;
char tag[4];
int ref;
};
@@ -553,6 +533,10 @@
{
ulong address;
ulong endaddress;
+
+ ulong source;
+ ulong endsource;
+
uchar gate[IPv4addrlen];
};
@@ -560,6 +544,10 @@
{
ulong address[IPllen];
ulong endaddress[IPllen];
+
+ ulong source[IPllen];
+ ulong endsource[IPllen];
+
uchar gate[IPaddrlen];
};
@@ -572,17 +560,14 @@
V4route v4;
};
};
-extern void v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type);
-extern void v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type);
-extern void v4delroute(Fs *f, uchar *a, uchar *mask, int dolock);
-extern void v6delroute(Fs *f, uchar *a, uchar *mask, int dolock);
-extern Route* v4lookup(Fs *f, uchar *a, Routehint *h);
-extern Route* v6lookup(Fs *f, uchar *a, Routehint *h);
+
+extern void addroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag);
+extern void remroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag);
+extern Route* v4lookup(Fs *f, uchar *a, uchar *s, Routehint *h);
+extern Route* v6lookup(Fs *f, uchar *a, uchar *s, Routehint *h);
extern long routeread(Fs *f, char*, ulong, int);
extern long routewrite(Fs *f, Chan*, char*, int);
-extern void routetype(int, char*);
-extern void ipwalkroutes(Fs*, Routewalk*);
-extern void convroute(Route*, uchar*, uchar*, uchar*, char*, int*);
+extern void routetype(int type, char p[8]);
/*
* devip.c
@@ -607,7 +592,6 @@
{
uchar ip[IPaddrlen];
uchar mac[MAClen];
- Medium *type; /* media type */
Arpent* hash;
Block* hold;
Block* last;
@@ -627,7 +611,7 @@
extern Arpent* arpget(Arp*, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *h);
extern void arprelease(Arp*, Arpent *a);
extern Block* arpresolve(Arp*, Arpent *a, Medium *type, uchar *mac);
-extern void arpenter(Fs*, int version, uchar *ip, uchar *mac, int len, int norefresh);
+extern int arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *src, int norefresh);
extern void ndpsendsol(Fs*, Ipifc*, Arpent*);
/*
@@ -674,21 +658,16 @@
extern void addipmedium(Medium *med);
extern int ipforme(Fs*, uchar *addr);
extern int iptentative(Fs*, uchar *addr);
-extern int ipisbm(uchar *);
-extern int ipismulticast(uchar *);
-extern Ipifc* findipifc(Fs*, uchar *remote, int type);
+extern int ipisbm(uchar *ip);
+extern int ipismulticast(uchar *ip);
+extern Ipifc* findipifc(Fs*, uchar *local, uchar *remote, int type);
+extern Ipifc* findipifcstr(Fs *f, char *s);
extern void findlocalip(Fs*, uchar *local, uchar *remote);
extern int ipv4local(Ipifc *ifc, uchar *local, uchar *remote);
extern int ipv6local(Ipifc *ifc, uchar *local, uchar *remote);
extern Iplifc* iplocalonifc(Ipifc *ifc, uchar *ip);
+extern Iplifc* ipremoteonifc(Ipifc *ifc, uchar *ip);
extern int ipproxyifc(Fs *f, 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(Fs*, int, uchar*, uchar*, uchar*, int);
-extern void ipifcremroute(Fs*, int, uchar*, uchar*);
extern void ipifcremmulti(Conv *c, uchar *ma, uchar *ia);
extern void ipifcaddmulti(Conv *c, uchar *ma, uchar *ia);
extern char* ipifcrem(Ipifc *ifc, char **argv, int argc);
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -61,11 +61,54 @@
static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
-static char* ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
-static char* ipifcleavemulti(Ipifc *ifc, char **argv, int argc);
-static void ipifcregisterproxy(Fs*, Ipifc*, uchar*);
-static char* ipifcremlifc(Ipifc*, Iplifc*);
+static void ipifcregisterproxy(Fs*, Ipifc*, uchar*, int);
+static char* ipifcremlifc(Ipifc*, Iplifc**);
+enum {
+ unknownv6, /* UGH */
+ unspecifiedv6,
+ linklocalv6,
+ globalv6,
+};
+
+static int
+v6addrtype(uchar *addr)
+{
+ if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
+ return unknownv6;
+ else if(islinklocal(addr) ||
+ isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
+ return linklocalv6;
+ else
+ return globalv6;
+}
+
+#define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
+ (lifc)->origint + (lifc)->preflt >= NOW/1000)
+
+static uchar*
+defsmask(uchar *a)
+{
+ if(v6addrtype(a) == linklocalv6)
+ return IPallbits;
+ return IPnoaddr;
+}
+
+static int
+comprefixlen(uchar *a, uchar *b, int n)
+{
+ int i, c;
+
+ for(i = 0; i < n; i++){
+ if((c = a[i] ^ b[i]) == 0)
+ continue;
+ for(i <<= 3; (c & 0x80) == 0; i++)
+ c <<= 1;
+ return i;
+ }
+ return i << 3;
+}
+
/*
* link in a new medium
*/
@@ -181,18 +224,18 @@
}
/* disassociate logical interfaces (before zeroing ifc->arg) */
- while(ifc->lifc){
- err = ipifcremlifc(ifc, ifc->lifc);
+ while(ifc->lifc != nil){
+ err = ipifcremlifc(ifc, &ifc->lifc);
/*
* note: err non-zero means lifc not found,
* which can't happen in this case.
*/
- if(err)
+ if(err != nil)
error(err);
}
/* disassociate device */
- if(ifc->m && ifc->m->unbind)
+ if(ifc->m != nil && ifc->m->unbind != nil)
(*ifc->m->unbind)(ifc);
memset(ifc->dev, 0, sizeof(ifc->dev));
ifc->arg = nil;
@@ -257,9 +300,9 @@
m = 0;
rlock(ifc);
- for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
- for(link = lifc->link; link; link = link->lifclink)
+ for(link = lifc->link; link != nil; link = link->lifclink)
m += snprint(state+m, n - m, " %-40.40I", link->self->a);
m += snprint(state+m, n - m, "\n");
}
@@ -299,7 +342,7 @@
runlock(ifc);
nexterror();
}
- if(ifc->m && ifc->m->pktin)
+ if(ifc->m != nil && ifc->m->pktin != nil)
(*ifc->m->pktin)(c->p->f, ifc, bp);
else
freeb(bp);
@@ -335,11 +378,9 @@
ipifcclose(Conv *c)
{
Ipifc *ifc;
- Medium *m;
ifc = (Ipifc*)c->ptcl;
- m = ifc->m;
- if(m && m->unbindonclose)
+ if(ifc->m != nil && ifc->m->unbindonclose)
ipifcunbind(ifc);
}
@@ -366,13 +407,14 @@
char*
ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
{
- int i, type, mtu, sendnbrdisc = 0;
uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
uchar bcast[IPaddrlen], net[IPaddrlen];
Iplifc *lifc, **l;
+ int i, type, mtu;
+ Medium *m;
Fs *f;
- if(ifc->m == nil)
+ if((m = ifc->m) == nil)
return "ipifc not yet bound to device";
f = ifc->conv->p->f;
@@ -388,7 +430,7 @@
/* fall through */
case 5:
mtu = strtoul(argv[4], 0, 0);
- if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
+ if(mtu >= m->mintu && mtu <= m->maxtu)
ifc->maxtu = mtu;
/* fall through */
case 4:
@@ -414,8 +456,16 @@
default:
return Ebadarg;
}
- if(isv4(ip))
+
+ /* check for point-to-point interface */
+ if(ipcmp(ip, v6loopback) != 0) /* skip v6 loopback, it's a special address */
+ if(ipcmp(mask, IPallbits) == 0)
+ type |= Rptpt;
+
+ if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0){
+ type |= Rv4;
tentative = 0;
+ }
wlock(ifc);
if(waserror()){
@@ -424,19 +474,21 @@
}
/* 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) {
- if(lifc->tentative != tentative)
- lifc->tentative = tentative;
- if(lifcp) {
- lifc->onlink = lifcp->onlink;
- lifc->autoflag = lifcp->autoflag;
- lifc->validlt = lifcp->validlt;
- lifc->preflt = lifcp->preflt;
- lifc->origint = lifcp->origint;
- }
- goto out;
+ if((lifc = iplocalonifc(ifc, ip)) != nil){
+ if(lifcp != nil) {
+ lifc->onlink = lifcp->onlink;
+ lifc->autoflag = lifcp->autoflag;
+ lifc->validlt = lifcp->validlt;
+ lifc->preflt = lifcp->preflt;
+ lifc->origint = lifcp->origint;
}
+ if(lifc->tentative != tentative){
+ lifc->tentative = tentative;
+ goto done;
+ }
+ wunlock(ifc);
+ poperror();
+ return nil;
}
/* add the address to the list of logical ifc's for this ifc */
@@ -445,8 +497,9 @@
ipmove(lifc->mask, mask);
ipmove(lifc->remote, rem);
ipmove(lifc->net, net);
+ lifc->type = type;
lifc->tentative = tentative;
- if(lifcp) {
+ if(lifcp != nil) {
lifc->onlink = lifcp->onlink;
lifc->autoflag = lifcp->autoflag;
lifc->validlt = lifcp->validlt;
@@ -459,29 +512,22 @@
}
lifc->next = nil;
- for(l = &ifc->lifc; *l; l = &(*l)->next)
+ for(l = &ifc->lifc; *l != nil; l = &(*l)->next)
;
*l = lifc;
- /* check for point-to-point interface */
- if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
- if(ipcmp(mask, IPallbits) == 0)
- type |= Rptpt;
+ addroute(f, rem, mask, ip, defsmask(ip), rem, type, ifc, tifc);
- /* add local routes */
- if(isv4(ip))
- v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
- else
- v6addroute(f, tifc, rem, mask, rem, type);
-
addselfcache(f, ifc, lifc, ip, Runi);
- if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
- ipifcregisterproxy(f, ifc, rem);
- goto out;
+ /* register proxy */
+ if(type & Rptpt){
+ if(type & Rproxy)
+ ipifcregisterproxy(f, ifc, rem, 1);
+ goto done;
}
- if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
+ if(type & Rv4) {
/* add subnet directed broadcast address to the self cache */
for(i = 0; i < IPaddrlen; i++)
bcast[i] = (ip[i] & mask[i]) | ~mask[i];
@@ -505,15 +551,15 @@
addselfcache(f, ifc, lifc, bcast, Rbcast);
addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
- }
- else {
+ } else {
if(ipcmp(ip, v6loopback) == 0) {
/* add node-local mcast address */
addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
/* add route for all node multicast */
- v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
- v6allnodesN, Rmulti);
+ addroute(f, v6allnodesN, v6allnodesNmask,
+ ip, IPallbits,
+ v6allnodesN, Rmulti, ifc, tifc);
}
/* add all nodes multicast address */
@@ -520,30 +566,22 @@
addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
/* add route for all nodes multicast */
- v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
- Rmulti);
+ addroute(f, v6allnodesL, v6allnodesLmask,
+ ip, IPallbits,
+ v6allnodesL, Rmulti, ifc, tifc);
/* add solicited-node multicast address */
ipv62smcast(bcast, ip);
addselfcache(f, ifc, lifc, bcast, Rmulti);
-
- sendnbrdisc = 1;
}
- /* register the address on this network for address resolution */
- if(isv4(ip) && ifc->m->areg)
- (*ifc->m->areg)(ifc, ip);
-
-out:
+done:
wunlock(ifc);
poperror();
- if(!isv4(ip) && ipcmp(ip, IPnoaddr) != 0){
- if(!tentative)
- arpenter(f, V6, ip, ifc->mac, 6, 0);
- else if(sendnbrdisc)
- icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
- }
+ /* register the address on this network for address resolution */
+ if(m->areg != nil)
+ (*m->areg)(f, ifc, ip, ip);
return nil;
}
@@ -553,41 +591,44 @@
* always called with ifc wlock'd
*/
static char*
-ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
+ipifcremlifc(Ipifc *ifc, Iplifc **l)
{
- Iplifc **l;
- Fs *f;
+ Iplifc *lifc = *l;
+ Fs *f = ifc->conv->p->f;
- f = ifc->conv->p->f;
-
- /*
- * find address on this interface and remove from chain.
- * for pt to pt we actually specify the remote address as the
- * addresss to remove.
- */
- for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
- ;
- if(*l == nil)
+ if(lifc == nil)
return "address not on this interface";
*l = lifc->next;
/* disassociate any addresses */
- while(lifc->link)
+ while(lifc->link != nil)
remselfcache(f, ifc, lifc, lifc->link->self->a);
/* remove the route for this logical interface */
- if(isv4(lifc->local))
- v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
- else {
- v6delroute(f, lifc->remote, lifc->mask, 1);
+ remroute(f, lifc->remote, lifc->mask,
+ lifc->local, defsmask(lifc->local),
+ lifc->remote, lifc->type, ifc, tifc);
+
+ /* unregister proxy */
+ if(lifc->type & Rptpt){
+ if(lifc->type & Rproxy)
+ ipifcregisterproxy(f, ifc, lifc->remote, 0);
+ goto done;
+ }
+
+ /* remove route for all nodes multicast */
+ if((lifc->type & Rv4) == 0){
if(ipcmp(lifc->local, v6loopback) == 0)
- /* remove route for all node multicast */
- v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
- else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
- /* remove route for all link multicast */
- v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
+ remroute(f, v6allnodesN, v6allnodesNmask,
+ lifc->local, IPallbits,
+ v6allnodesN, Rmulti, ifc, tifc);
+
+ remroute(f, v6allnodesL, v6allnodesLmask,
+ lifc->local, IPallbits,
+ v6allnodesL, Rmulti, ifc, tifc);
}
+done:
free(lifc);
return nil;
}
@@ -601,19 +642,17 @@
{
char *rv;
uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
- Iplifc *lifc;
+ Iplifc *lifc, **l;
if(argc < 3)
return Ebadarg;
-
- if (parseip(ip, argv[1]) == -1)
+ if(parseip(ip, argv[1]) == -1)
return Ebadip;
parseipmask(mask, argv[2]);
if(argc < 4)
maskip(ip, mask, rem);
- else
- if (parseip(rem, argv[3]) == -1)
- return Ebadip;
+ else if(parseip(rem, argv[3]) == -1)
+ return Ebadip;
/*
* find address on this interface and remove from chain.
@@ -621,62 +660,20 @@
* addresss to remove.
*/
wlock(ifc);
+ l = &ifc->lifc;
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
- if (memcmp(ip, lifc->local, IPaddrlen) == 0
- && memcmp(mask, lifc->mask, IPaddrlen) == 0
- && memcmp(rem, lifc->remote, IPaddrlen) == 0)
+ if(ipcmp(ip, lifc->local) == 0
+ && ipcmp(mask, lifc->mask) == 0
+ && ipcmp(rem, lifc->remote) == 0)
break;
+ l = &lifc->next;
}
- rv = ipifcremlifc(ifc, lifc);
+ rv = ipifcremlifc(ifc, l);
wunlock(ifc);
return rv;
}
/*
- * distribute routes to active interfaces like the
- * TRIP linecards
- */
-void
-ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
-{
- Medium *m;
- Conv **cp, **e;
- Ipifc *ifc;
-
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp != nil) {
- ifc = (Ipifc*)(*cp)->ptcl;
- m = ifc->m;
- if(m && m->addroute)
- (*m->addroute)(ifc, vers, addr, mask, gate, type);
- }
- }
-}
-
-void
-ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
-{
- Medium *m;
- Conv **cp, **e;
- Ipifc *ifc;
-
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp != nil) {
- ifc = (Ipifc*)(*cp)->ptcl;
- m = ifc->m;
- if(m && m->remroute){
- if(!waserror()){
- (*m->remroute)(ifc, vers, addr, mask);
- poperror();
- }
- }
- }
- }
-}
-
-/*
* 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.
@@ -693,9 +690,9 @@
return "ipifc not yet bound to device";
wlock(ifc);
- while(ifc->lifc){
- err = ipifcremlifc(ifc, ifc->lifc);
- if(err){
+ while(ifc->lifc != nil){
+ err = ipifcremlifc(ifc, &ifc->lifc);
+ if(err != nil){
wunlock(ifc);
return err;
}
@@ -765,7 +762,7 @@
* called with c->car locked.
*/
static char*
-ipifcctl(Conv* c, char**argv, int argc)
+ipifcctl(Conv* c, char **argv, int argc)
{
Ipifc *ifc;
int i;
@@ -779,10 +776,6 @@
return ipifcrem(ifc, argv, argc);
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);
else if(strcmp(argv[0], "mtu") == 0)
return ipifcsetmtu(ifc, argv, argc);
else if(strcmp(argv[0], "reassemble") == 0){
@@ -845,10 +838,12 @@
static void
addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
{
- Ipself *p;
Iplink *lp;
+ Ipself *p;
int h;
+ type |= (lifc->type & Rv4);
+
qlock(f->self);
if(waserror()){
qunlock(f->self);
@@ -857,8 +852,8 @@
/* see if the address already exists */
h = hashipa(a);
- for(p = f->self->hash[h]; p; p = p->next)
- if(memcmp(a, p->a, IPaddrlen) == 0)
+ for(p = f->self->hash[h]; p != nil; p = p->next)
+ if(ipcmp(a, p->a) == 0)
break;
/* allocate a local address and add to hash chain */
@@ -875,7 +870,7 @@
}
/* look for a link for this lifc */
- for(lp = p->link; lp; lp = lp->selflink)
+ for(lp = p->link; lp != nil; lp = lp->selflink)
if(lp->lifc == lifc)
break;
@@ -891,13 +886,11 @@
lifc->link = lp;
/* add to routing table */
- if(isv4(a))
- v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
- a+IPv4off, type);
- else
- v6addroute(f, tifc, a, IPallbits, a, type);
+ addroute(f, a, IPallbits,
+ lifc->local, defsmask(a),
+ a, type, ifc, tifc);
- if((type & Rmulti) && ifc->m->addmulti)
+ if((type & Rmulti) && ifc->m->addmulti != nil)
(*ifc->m->addmulti)(ifc, a, lifc->local);
} else
lp->ref++;
@@ -922,8 +915,8 @@
ulong now = NOW;
l = &freeiplink;
- for(np = *l; np; np = *l){
- if(np->expire > now){
+ for(np = *l; np != nil; np = *l){
+ if((long)(now - np->expire) >= 0){
*l = np->next;
free(np);
continue;
@@ -942,8 +935,8 @@
ulong now = NOW;
l = &freeipself;
- for(np = *l; np; np = *l){
- if(np->expire > now){
+ for(np = *l; np != nil; np = *l){
+ if((long)(now - np->expire) >= 0){
*l = np->next;
free(np);
continue;
@@ -970,7 +963,7 @@
/* find the unique selftab entry */
l = &f->self->hash[hashipa(a)];
- for(p = *l; p; p = *l){
+ for(p = *l; p != nil; p = *l){
if(ipcmp(p->a, a) == 0)
break;
l = &p->next;
@@ -984,7 +977,7 @@
* that matches the selftab entry
*/
l_lifc = &lifc->link;
- for(link = *l_lifc; link; link = *l_lifc){
+ for(link = *l_lifc; link != nil; link = *l_lifc){
if(link->self == p)
break;
l_lifc = &link->lifclink;
@@ -998,7 +991,7 @@
* the one we just found
*/
l_self = &p->link;
- for(link = *l_self; link; link = *l_self){
+ for(link = *l_self; link != nil; link = *l_self){
if(link == *l_lifc)
break;
l_self = &link->selflink;
@@ -1010,7 +1003,12 @@
if(--(link->ref) != 0)
goto out;
- if((p->type & Rmulti) && ifc->m->remmulti){
+ /* remove from routing table */
+ remroute(f, a, IPallbits,
+ lifc->local, defsmask(a),
+ a, p->type, ifc, tifc);
+
+ if((p->type & Rmulti) && ifc->m->remmulti != nil){
if(!waserror()){
(*ifc->m->remmulti)(ifc, a, lifc->local);
poperror();
@@ -1025,30 +1023,18 @@
if(p->link != nil)
goto out;
- /* remove from routing table */
- if(isv4(a))
- v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
- else
- v6delroute(f, a, IPallbits, 1);
+ /* if null address, forget */
+ if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
+ f->self->acceptall = 0;
/* 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)
- f->self->acceptall = 0;
-
out:
qunlock(f->self);
}
-static char *stformat = "%-44.44I %2.2d %4.4s\n";
-enum
-{
- Nstformat= 41,
-};
-
long
ipselftabread(Fs *f, char *cp, ulong offset, int n)
{
@@ -1063,10 +1049,11 @@
for(i = 0; i < NHASH && m < n; i++){
for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
nifc = 0;
- for(link = p->link; link; link = link->selflink)
+ for(link = p->link; link != nil; link = link->selflink)
nifc++;
routetype(p->type, state);
- m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
+ m += snprint(cp + m, n - m, "%-44.44I %2.2d %4.4s\n",
+ p->a, nifc, state);
if(off > 0){
off -= m;
m = 0;
@@ -1082,11 +1069,10 @@
{
Ipself *p;
- p = f->self->hash[hashipa(addr)];
- for(; p; p = p->next){
+ for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next)
if(ipcmp(addr, p->a) == 0)
return p->link->lifc->tentative;
- }
+
return 0;
}
@@ -1102,15 +1088,14 @@
{
Ipself *p;
- p = f->self->hash[hashipa(addr)];
- for(; p; p = p->next){
+ for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next)
if(ipcmp(addr, p->a) == 0)
- return p->type;
- }
+ return p->type & (Runi|Rbcast|Rmulti);
/* hack to say accept anything */
if(f->self->acceptall)
return Runi;
+
return 0;
}
@@ -1119,70 +1104,64 @@
* return nil.
*/
Ipifc*
-findipifc(Fs *f, uchar *remote, int type)
+findipifc(Fs *f, uchar *local, uchar *remote, int type)
{
+ uchar gnet[IPaddrlen];
Ipifc *ifc, *x;
Iplifc *lifc;
Conv **cp, **e;
- uchar gnet[IPaddrlen], xmask[IPaddrlen];
+ int spec, xspec;
x = nil;
- memset(xmask, 0, IPaddrlen);
+ xspec = 0;
/* find most specific match */
e = &f->ipifc->conv[f->ipifc->nc];
for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == 0)
+ if(*cp == nil)
continue;
ifc = (Ipifc*)(*cp)->ptcl;
- for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+ if(type & Runi){
+ if(ipcmp(remote, lifc->local) == 0)
+ return ifc;
+ } else if(type & (Rbcast|Rmulti)) {
+ if(ipcmp(local, lifc->local) == 0)
+ return ifc;
+ }
maskip(remote, lifc->mask, gnet);
if(ipcmp(gnet, lifc->net) == 0){
- if(x == nil || ipcmp(lifc->mask, xmask) > 0){
+ spec = comprefixlen(remote, lifc->local, IPaddrlen);
+ if(spec > xspec){
x = ifc;
- ipmove(xmask, lifc->mask);
+ xspec = spec;
}
}
}
}
- if(x != nil)
- return x;
+ return x;
+}
- /* for now for broadcast and multicast, just use first interface */
- if(type & (Rbcast|Rmulti)){
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == 0)
- continue;
- ifc = (Ipifc*)(*cp)->ptcl;
- if(ifc->lifc != nil)
- return ifc;
- }
+Ipifc*
+findipifcstr(Fs *f, char *s)
+{
+ uchar ip[IPaddrlen];
+ Conv *c;
+ char *p;
+ long x;
+
+ x = strtol(s, &p, 10);
+ if(p > s && *p == '\0'){
+ if(x < 0)
+ return nil;
+ if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil)
+ return (Ipifc*)c->ptcl;
}
+ if(parseip(ip, s) != -1)
+ return findipifc(f, IPnoaddr, ip, Runi);
return nil;
}
-enum {
- unknownv6, /* UGH */
- unspecifiedv6,
- linklocalv6,
- globalv6,
-};
-
-int
-v6addrtype(uchar *addr)
-{
- if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
- return unknownv6;
- else if(islinklocal(addr) ||
- isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
- return linklocalv6;
- else
- return globalv6;
-}
-
-#define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
- (lifc)->origint + (lifc)->preflt >= NOW/1000)
-
static void
findprimaryipv6(Fs *f, uchar *local)
{
@@ -1200,10 +1179,10 @@
*/
e = &f->ipifc->conv[f->ipifc->nc];
for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == 0)
+ if(*cp == nil)
continue;
ifc = (Ipifc*)(*cp)->ptcl;
- for(lifc = ifc->lifc; lifc; lifc = lifc->next){
+ for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
atypel = v6addrtype(lifc->local);
if(atypel > atype && v6addrcurr(lifc)) {
ipmove(local, lifc->local);
@@ -1216,7 +1195,7 @@
}
/*
- * returns first ip address configured
+ * returns first v4 address configured
*/
static void
findprimaryipv4(Fs *f, uchar *local)
@@ -1228,10 +1207,10 @@
/* find first ifc local address */
e = &f->ipifc->conv[f->ipifc->nc];
for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == 0)
+ if(*cp == nil)
continue;
ifc = (Ipifc*)(*cp)->ptcl;
- if((lifc = ifc->lifc) != nil){
+ if((lifc = ifc->lifc) != nil && (lifc->type & Rv4) != 0){
ipmove(local, lifc->local);
return;
}
@@ -1239,21 +1218,6 @@
ipmove(local, IPnoaddr);
}
-static int
-comprefixlen(uchar *a, uchar *b, int n)
-{
- int i, c;
-
- for(i = 0; i < n; i++){
- if((c = a[i] ^ b[i]) == 0)
- continue;
- for(i <<= 3; (c & 0x80) == 0; i++)
- c <<= 1;
- return i;
- }
- return i << 3;
-}
-
/*
* return v4 address associated with an interface close to remote
*/
@@ -1265,7 +1229,7 @@
b = -1;
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
- if(!isv4(lifc->local))
+ if((lifc->type & Rv4) == 0)
continue;
a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
if(a > b){
@@ -1337,27 +1301,38 @@
return b.atype >= atype;
}
-/*
- * find the local address 'closest' to the remote system, copy it to local
- */
void
findlocalip(Fs *f, uchar *local, uchar *remote)
{
Route *r;
+ Ipifc *ifc;
+ Iplifc *lifc;
+ Conv **cp, **e;
qlock(f->ipifc);
- if((r = v6lookup(f, remote, nil)) != nil){
- if(r->type & Runi){
- ipmove(local, remote);
- goto out;
- }
- if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
- ipmove(local, v4prefix);
- if(ipv4local(r->ifc, local+IPv4off, r->v4.gate))
+ e = &f->ipifc->conv[f->ipifc->nc];
+ for(cp = f->ipifc->conv; cp < e; cp++){
+ if(*cp == nil)
+ continue;
+ ifc = (Ipifc*)(*cp)->ptcl;
+ for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+ if(lifc->tentative)
+ continue;
+ r = v6lookup(f, remote, lifc->local, nil);
+ if(r == nil || (ifc = r->ifc) == nil)
+ continue;
+ if(r->type & Runi){
+ ipmove(local, remote);
goto out;
+ }
+ if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
+ ipmove(local, v4prefix);
+ if(ipv4local(ifc, local+IPv4off, r->v4.gate))
+ goto out;
+ }
+ if(ipv6local(ifc, local, remote))
+ goto out;
}
- if(ipv6local(r->ifc, local, remote))
- goto out;
}
if(isv4(remote))
findprimaryipv4(f, local);
@@ -1367,6 +1342,7 @@
qunlock(f->ipifc);
}
+
/*
* see if this address is bound to the interface
*/
@@ -1375,13 +1351,28 @@
{
Iplifc *lifc;
- for(lifc = ifc->lifc; lifc; lifc = lifc->next)
+ for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
if(ipcmp(ip, lifc->local) == 0)
return lifc;
+
return nil;
}
+Iplifc*
+ipremoteonifc(Ipifc *ifc, uchar *ip)
+{
+ uchar net[IPaddrlen];
+ Iplifc *lifc;
+ for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+ maskip(ip, lifc->mask, net);
+ if(ipcmp(net, lifc->remote) == 0)
+ return lifc;
+ }
+ return nil;
+}
+
+
/*
* See if we're proxying for this address on this interface
*/
@@ -1389,21 +1380,13 @@
ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
{
Route *r;
- uchar net[IPaddrlen];
- Iplifc *lifc;
/* see if this is a direct connected pt to pt address */
- r = v6lookup(f, ip, nil);
+ r = v6lookup(f, ip, ip, nil);
if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
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 ipremoteonifc(ifc, ip) != nil;
}
/*
@@ -1441,15 +1424,15 @@
void
ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
{
- Ipifc *ifc;
- Iplifc *lifc;
- Conv **p;
Ipmulti *multi, **l;
+ Conv **cp, **e;
+ Iplifc *lifc;
+ Ipifc *ifc;
Fs *f;
f = c->p->f;
- for(l = &c->multi; *l; l = &(*l)->next)
+ for(l = &c->multi; *l != nil; l = &(*l)->next)
if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
return; /* it's already there */
@@ -1458,18 +1441,18 @@
ipmove(multi->ia, ia);
multi->next = nil;
- for(p = f->ipifc->conv; *p; p++){
- if((*p)->inuse == 0)
+ e = &f->ipifc->conv[f->ipifc->nc];
+ for(cp = f->ipifc->conv; cp < e; cp++){
+ if((*cp) == nil || (*cp)->inuse == 0)
continue;
- ifc = (Ipifc*)(*p)->ptcl;
+ ifc = (Ipifc*)(*cp)->ptcl;
wlock(ifc);
if(waserror()){
wunlock(ifc);
nexterror();
}
- for(lifc = ifc->lifc; lifc; lifc = lifc->next)
- if(ipcmp(ia, lifc->local) == 0)
- addselfcache(f, ifc, lifc, ma, Rmulti);
+ if((lifc = iplocalonifc(ifc, ia)) != nil)
+ addselfcache(f, ifc, lifc, ma, Rmulti);
wunlock(ifc);
poperror();
}
@@ -1483,14 +1466,14 @@
ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
{
Ipmulti *multi, **l;
+ Conv **cp, **e;
Iplifc *lifc;
- Conv **p;
Ipifc *ifc;
Fs *f;
f = c->p->f;
- for(l = &c->multi; *l; l = &(*l)->next)
+ for(l = &c->multi; *l != nil; l = &(*l)->next)
if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
break;
@@ -1500,102 +1483,62 @@
*l = multi->next;
- for(p = f->ipifc->conv; *p; p++){
- if((*p)->inuse == 0)
+ e = &f->ipifc->conv[f->ipifc->nc];
+ for(cp = f->ipifc->conv; cp < e; cp++){
+ if((*cp) == nil || (*cp)->inuse == 0)
continue;
-
- ifc = (Ipifc*)(*p)->ptcl;
+ ifc = (Ipifc*)(*cp)->ptcl;
wlock(ifc);
- for(lifc = ifc->lifc; lifc; lifc = lifc->next)
- if(ipcmp(ia, lifc->local) == 0)
- remselfcache(f, ifc, lifc, ma);
+ if(waserror()){
+ wunlock(ifc);
+ nexterror();
+ }
+ if((lifc = iplocalonifc(ifc, ia)) != nil)
+ remselfcache(f, 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;
-}
-
static void
-ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
+ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
{
+ uchar proxy[IPaddrlen];
Conv **cp, **e;
- Ipifc *nifc;
Iplifc *lifc;
+ Ipifc *nifc;
Medium *m;
- uchar net[IPaddrlen];
- /* register the address on any network that will proxy for us */
+ /* register the address on any interface that will proxy for the ip */
e = &f->ipifc->conv[f->ipifc->nc];
+ for(cp = f->ipifc->conv; cp < e; cp++){
+ if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
+ continue;
- if(!isv4(ip)) { /* V6 */
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
- continue;
- rlock(nifc);
- m = nifc->m;
- if(m == nil || m->addmulti == nil) {
- runlock(nifc);
- continue;
- }
- if(waserror()){
- runlock(nifc);
- nexterror();
- }
- for(lifc = nifc->lifc; lifc; lifc = lifc->next){
- maskip(ip, lifc->mask, net);
- if(ipcmp(net, lifc->remote) == 0) {
- /* add solicited-node multicast addr */
- ipv62smcast(net, ip);
- addselfcache(f, nifc, lifc, net, Rmulti);
- arpenter(f, V6, ip, nifc->mac, 6, 0);
- break;
- }
- }
- runlock(nifc);
- poperror();
+ wlock(nifc);
+ m = nifc->m;
+ if(m == nil || m->areg == nil || waserror()){
+ wunlock(nifc);
+ continue;
}
- }
- else { /* V4 */
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
- continue;
- rlock(nifc);
- m = nifc->m;
- if(m == nil || m->areg == nil){
- runlock(nifc);
- continue;
+ if((lifc = ipremoteonifc(nifc, ip)) != nil){
+ if((lifc->type & Rv4) == 0){
+ /* add solicited-node multicast addr */
+ ipv62smcast(proxy, ip);
+ if(add)
+ addselfcache(f, nifc, lifc, proxy, Rmulti);
+ else
+ remselfcache(f, nifc, lifc, proxy);
}
- if(waserror()){
- runlock(nifc);
- nexterror();
- }
- for(lifc = nifc->lifc; lifc; lifc = lifc->next){
- maskip(ip, lifc->mask, net);
- if(ipcmp(net, lifc->remote) == 0){
- (*m->areg)(nifc, ip);
- break;
- }
- }
- runlock(nifc);
- poperror();
+ ipmove(proxy, lifc->local);
}
+ wunlock(nifc);
+ poperror();
+
+ if(add && lifc != nil)
+ (*m->areg)(f, nifc, ip, proxy);
}
}
--- a/sys/src/9/ip/iproute.c
+++ b/sys/src/9/ip/iproute.c
@@ -35,9 +35,8 @@
static Route*
allocroute(int type)
{
- Route *r;
+ Route *r, **l;
int n;
- Route **l;
if(type & Rv4){
n = sizeof(RouteTree) + sizeof(V4route);
@@ -72,9 +71,9 @@
return;
l = allocroute(r->type);
+ l->left = r;
l->mid = *q;
*q = l;
- l->left = r;
}
/*
@@ -99,11 +98,11 @@
*/
enum
{
- Rpreceeds,
- Rfollows,
- Requals,
- Rcontains,
- Rcontained,
+ Rpreceeds, /* a left of b */
+ Rfollows, /* a right of b */
+ Requals, /* a equals b */
+ Rcontains, /* a contians b */
+ Roverlaps, /* a overlaps b */
};
static int
@@ -112,44 +111,87 @@
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;
+ && a->v4.endaddress == b->v4.endaddress){
+ if(a->v4.source <= b->v4.source
+ && a->v4.endsource >= b->v4.endsource){
+ if(a->v4.source == b->v4.source
+ && a->v4.endsource == b->v4.endsource)
+ return Requals;
+ return Rcontains;
+ }
+ return Roverlaps;
+ }
return Rcontains;
}
- return Rcontained;
+ return Roverlaps;
}
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;
+ && lcmp(a->v6.endaddress, b->v6.endaddress) == 0){
+ if(lcmp(a->v6.source, b->v6.source) <= 0
+ && lcmp(a->v6.endsource, b->v6.endsource) >= 0){
+ if(lcmp(a->v6.source, b->v6.source) == 0
+ && lcmp(a->v6.endsource, b->v6.endsource) == 0)
+ return Requals;
+ return Rcontains;
+ }
+ return Roverlaps;
+ }
return Rcontains;
}
+ return Roverlaps;
+}
- return Rcontained;
+/* return 1 if a matches b, otherwise 0 */
+static int
+matchroute(Route *a, Route *b)
+{
+ if(a == b)
+ return 1;
+
+ if((a->type^b->type) & (Rifc|Runi|Rmulti|Rbcast))
+ return 0;
+
+ if(a->type & Rv4){
+ if(memcmp(a->v4.gate, IPnoaddr+IPv4off, IPv4addrlen) != 0
+ && memcmp(a->v4.gate, b->v4.gate, IPv4addrlen) != 0)
+ return 0;
+ } else {
+ if(ipcmp(a->v6.gate, IPnoaddr) != 0
+ && ipcmp(a->v6.gate, b->v6.gate) != 0)
+ return 0;
+ }
+
+ if(a->ifc != nil && b->ifc != nil && (a->ifc != b->ifc || a->ifcid != b->ifcid))
+ return 0;
+
+ if(*a->tag != 0 && strncmp(a->tag, b->tag, sizeof(a->tag)) != 0)
+ return 0;
+
+ return 1;
}
static void
copygate(Route *old, Route *new)
{
+ old->type = new->type;
+ old->ifc = new->ifc;
+ old->ifcid = new->ifcid;
if(new->type & Rv4)
memmove(old->v4.gate, new->v4.gate, IPv4addrlen);
else
- memmove(old->v6.gate, new->v6.gate, IPaddrlen);
+ ipmove(old->v6.gate, new->v6.gate);
}
/*
@@ -162,12 +204,12 @@
l = p->left;
r = p->right;
- p->left = 0;
- p->right = 0;
+ p->left = nil;
+ p->right = nil;
addnode(f, root, p);
- if(l)
+ if(l != nil)
walkadd(f, root, l);
- if(r)
+ if(r != nil)
walkadd(f, root, r);
}
@@ -180,16 +222,16 @@
Route *q;
int d;
- if(p) {
+ if(p != nil) {
d = 0;
q = p->left;
- if(q)
+ if(q != nil)
d = q->depth;
q = p->right;
- if(q && q->depth > d)
+ if(q != nil && q->depth > d)
d = q->depth;
q = p->mid;
- if(q && q->depth > d)
+ if(q != nil && q->depth > d)
d = q->depth;
p->depth = d+1;
}
@@ -210,8 +252,8 @@
* rotate tree node
*/
p = *cur;
- dl = 0; if(l = p->left) dl = l->depth;
- dr = 0; if(r = p->right) dr = r->depth;
+ dl = 0; if((l = p->left) != nil) dl = l->depth;
+ dr = 0; if((r = p->right) != nil) dr = r->depth;
if(dl > dr+1) {
p->left = l->right;
@@ -239,7 +281,7 @@
Route *p;
p = *cur;
- if(p == 0) {
+ if(p == nil) {
*cur = new;
new->depth = 1;
return;
@@ -269,15 +311,13 @@
* supercede the old entry if the old one isn't
* a local interface.
*/
- if((p->type & Rifc) == 0){
- p->type = new->type;
- p->ifcid = -1;
+ if((p->type & Rifc) == 0)
copygate(p, new);
- } else if(new->type & Rifc)
+ else if(new->type & Rifc)
p->ref++;
freeroute(new);
break;
- case Rcontained:
+ case Roverlaps:
addnode(f, &p->mid, new);
break;
}
@@ -285,201 +325,220 @@
balancetree(cur);
}
-#define V4H(a) ((a&0x07ffffff)>>(32-Lroot-5))
-
-void
-v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
+/*
+ * find node matching r
+ */
+static Route**
+looknode(Route **cur, Route *r)
{
Route *p;
- ulong sa;
- ulong m;
- ulong ea;
- int h, eh;
- m = nhgetl(mask);
- sa = nhgetl(a) & m;
- ea = sa | ~m;
+ for(;;){
+ p = *cur;
+ if(p == nil)
+ return nil;
+ switch(rangecompare(r, p)){
+ case Rcontains:
+ return nil;
+ case Rpreceeds:
+ cur = &p->left;
+ break;
+ case Rfollows:
+ cur = &p->right;
+ break;
+ case Roverlaps:
+ cur = &p->mid;
+ break;
+ case Requals:
+ if((p->type & Rifc) == 0 && !matchroute(r, p))
+ return nil;
+ return cur;
+ }
+ }
+}
- 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));
+static Route*
+looknodetag(Route *r, char *tag)
+{
+ Route *x;
- wlock(&routelock);
- addnode(f, &f->v4root[h], p);
- while(p = f->queue) {
- f->queue = p->mid;
- walkadd(f, &f->v4root[h], p->left);
- freeroute(p);
- }
- wunlock(&routelock);
+ if(r == nil)
+ return nil;
+
+ if((x = looknodetag(r->mid, tag)) != nil)
+ return x;
+ if((x = looknodetag(r->left, tag)) != nil)
+ return x;
+ if((x = looknodetag(r->right, tag)) != nil)
+ return x;
+
+ if((r->type & Rifc) == 0){
+ if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0)
+ return r;
}
- v4routegeneration++;
- ipifcaddroute(f, Rv4, a, mask, gate, type);
+ return nil;
}
-#define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
+#define V4H(a) ((a&0x07ffffff)>>(32-Lroot-5))
+#define V6H(a) (((a)[IPllen-1]&0x07ffffff)>>(32-Lroot-5))
-void
-v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
+static void
+routeadd(Fs *f, Route *r)
{
- Route *p;
- ulong sa[IPllen], ea[IPllen];
- ulong x, y;
- int h, eh;
+ Route **h, **e, *p;
- for(h = 0; h < IPllen; h++){
- x = nhgetl(a+4*h);
- y = nhgetl(mask+4*h);
- sa[h] = x & y;
- ea[h] = x | ~y;
+ if(r->type & Rv4){
+ h = &f->v4root[V4H(r->v4.address)];
+ e = &f->v4root[V4H(r->v4.endaddress)];
+ } else {
+ h = &f->v6root[V6H(r->v6.address)];
+ e = &f->v6root[V6H(r->v6.endaddress)];
}
- 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));
+ for(; h <= e; h++) {
+ p = allocroute(r->type);
- wlock(&routelock);
- addnode(f, &f->v6root[h], p);
- while(p = f->queue) {
+ p->ifc = r->ifc;
+ p->ifcid = r->ifcid;
+
+ if(r->type & Rv4)
+ memmove(&p->v4, &r->v4, sizeof(r->v4));
+ else
+ memmove(&p->v6, &r->v6, sizeof(r->v6));
+
+ memmove(p->tag, r->tag, sizeof(r->tag));
+
+ addnode(f, h, p);
+ while((p = f->queue) != nil) {
f->queue = p->mid;
- walkadd(f, &f->v6root[h], p->left);
+ walkadd(f, h, p->left);
freeroute(p);
}
- wunlock(&routelock);
}
- v6routegeneration++;
- ipifcaddroute(f, 0, a, mask, gate, type);
+ if(r->type & Rv4)
+ v4routegeneration++;
+ else
+ v6routegeneration++;
}
-Route**
-looknode(Route **cur, Route *r)
+static void
+routerem(Fs *f, Route *r)
{
- Route *p;
+ Route **h, **e, **l, *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;
- }
+ if(r->type & Rv4){
+ h = &f->v4root[V4H(r->v4.address)];
+ e = &f->v4root[V4H(r->v4.endaddress)];
+ } else {
+ h = &f->v6root[V6H(r->v6.address)];
+ e = &f->v6root[V6H(r->v6.endaddress)];
}
-}
-void
-v4delroute(Fs *f, uchar *a, uchar *mask, int dolock)
-{
- Route **r, *p;
- Route rt;
- int h, eh;
- ulong m;
+ for(; h <= e; h++) {
+ if((l = looknode(h, r)) == nil)
+ continue;
+ p = *l;
+ if(--(p->ref) != 0)
+ continue;
+ *l = nil;
+ addqueue(&f->queue, p->left);
+ addqueue(&f->queue, p->mid);
+ addqueue(&f->queue, p->right);
+ freeroute(p);
- 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++) {
- if(dolock)
- wlock(&routelock);
- r = looknode(&f->v4root[h], &rt);
- if(r) {
- p = *r;
- if(--(p->ref) == 0){
- *r = 0;
- addqueue(&f->queue, p->left);
- addqueue(&f->queue, p->mid);
- addqueue(&f->queue, p->right);
- freeroute(p);
- while(p = f->queue) {
- f->queue = p->mid;
- walkadd(f, &f->v4root[h], p->left);
- freeroute(p);
- }
- }
+ while((p = f->queue) != nil) {
+ f->queue = p->mid;
+ walkadd(f, h, p->left);
+ freeroute(p);
}
- if(dolock)
- wunlock(&routelock);
}
- v4routegeneration++;
- ipifcremroute(f, Rv4, a, mask);
+ if(r->type & Rv4)
+ v4routegeneration++;
+ else
+ v6routegeneration++;
}
-void
-v6delroute(Fs *f, uchar *a, uchar *mask, int dolock)
+static Route
+mkroute(uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag)
{
- Route **r, *p;
- Route rt;
- int h, eh;
ulong x, y;
+ Route r;
+ int h;
- 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;
+ memset(&r, 0, sizeof(r));
- eh = V6H(rt.v6.endaddress);
- for(h=V6H(rt.v6.address); h<=eh; h++) {
- if(dolock)
- wlock(&routelock);
- r = looknode(&f->v6root[h], &rt);
- if(r) {
- p = *r;
- if(--(p->ref) == 0){
- *r = 0;
- addqueue(&f->queue, p->left);
- addqueue(&f->queue, p->mid);
- addqueue(&f->queue, p->right);
- freeroute(p);
- while(p = f->queue) {
- f->queue = p->mid;
- walkadd(f, &f->v6root[h], p->left);
- freeroute(p);
- }
- }
+ r.type = type;
+
+ if(type & Rv4){
+ x = nhgetl(a+IPv4off);
+ y = nhgetl(mask+IPv4off);
+ r.v4.address = x & y;
+ r.v4.endaddress = x | ~y;
+
+ x = nhgetl(s+IPv4off);
+ y = nhgetl(smask+IPv4off);
+ if(y != 0)
+ r.type |= Rsrc;
+ r.v4.source = x & y;
+ r.v4.endsource = x | ~y;
+
+ memmove(r.v4.gate, gate+IPv4off, IPv4addrlen);
+ } else {
+ for(h = 0; h < IPllen; h++){
+ x = nhgetl(a+4*h);
+ y = nhgetl(mask+4*h);
+ r.v6.address[h] = x & y;
+ r.v6.endaddress[h] = x | ~y;
+
+ x = nhgetl(s+4*h);
+ y = nhgetl(smask+4*h);
+ if(y != 0)
+ r.type |= Rsrc;
+ r.v6.source[h] = x & y;
+ r.v6.endsource[h] = x | ~y;
}
- if(dolock)
- wunlock(&routelock);
+
+ memmove(r.v6.gate, gate, IPaddrlen);
}
- v6routegeneration++;
- ipifcremroute(f, 0, a, mask);
+ if(ifc != nil){
+ r.ifc = ifc;
+ r.ifcid = ifc->ifcid;
+ }
+
+ if(tag != nil)
+ strncpy(r.tag, tag, sizeof(r.tag));
+
+ return r;
}
+void
+addroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag)
+{
+ Route r = mkroute(a, mask, s, smask, gate, type, ifc, tag);
+ wlock(&routelock);
+ routeadd(f, &r);
+ wunlock(&routelock);
+}
+
+void
+remroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag)
+{
+ Route r = mkroute(a, mask, s, smask, gate, type, ifc, tag);
+ wlock(&routelock);
+ routerem(f, &r);
+ wunlock(&routelock);
+}
+
Route*
-v4lookup(Fs *f, uchar *a, Routehint *rh)
+v4lookup(Fs *f, uchar *a, uchar *s, Routehint *rh)
{
+ uchar local[IPaddrlen], gate[IPaddrlen];
+ ulong la, ls;
Route *p, *q;
- ulong la;
- uchar gate[IPaddrlen];
Ipifc *ifc;
if(rh != nil && rh->r != nil && rh->r->ifc != nil && rh->rgen == v4routegeneration)
@@ -486,24 +545,39 @@
return rh->r;
la = nhgetl(a);
+ ls = nhgetl(s);
q = nil;
- for(p=f->v4root[V4H(la)]; p;)
- if(la >= p->v4.address) {
- if(la <= p->v4.endaddress) {
- q = p;
- p = p->mid;
- } else
- p = p->right;
- } else
+ for(p = f->v4root[V4H(la)]; p != nil;){
+ if(la < p->v4.address){
p = p->left;
+ continue;
+ }
+ if(la > p->v4.endaddress){
+ p = p->right;
+ continue;
+ }
+ if(p->type & Rsrc){
+ if(ls < p->v4.source){
+ p = p->mid;
+ continue;
+ }
+ if(ls > p->v4.endsource){
+ p = p->mid;
+ continue;
+ }
+ }
+ q = p;
+ p = p->mid;
+ }
- if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
+ if(q != nil && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
if(q->type & Rifc) {
hnputl(gate+IPv4off, q->v4.address);
memmove(gate, v4prefix, IPv4off);
} else
v4tov6(gate, q->v4.gate);
- ifc = findipifc(f, gate, q->type);
+ v4tov6(local, s);
+ ifc = findipifc(f, local, gate, q->type);
if(ifc == nil)
return nil;
q->ifc = ifc;
@@ -519,29 +593,30 @@
}
Route*
-v6lookup(Fs *f, uchar *a, Routehint *rh)
+v6lookup(Fs *f, uchar *a, uchar *s, Routehint *rh)
{
- Route *p, *q;
- ulong la[IPllen];
- int h;
- ulong x, y;
uchar gate[IPaddrlen];
+ ulong la[IPllen], ls[IPllen];
+ ulong x, y;
+ Route *p, *q;
Ipifc *ifc;
+ int h;
- if(memcmp(a, v4prefix, IPv4off) == 0){
- q = v4lookup(f, a+IPv4off, rh);
- if(q != nil)
- return q;
- }
+ if(isv4(a) && isv4(s))
+ return v4lookup(f, a+IPv4off, s+IPv4off, rh);
+ if(isv4(s))
+ return nil;
if(rh != nil && rh->r != nil && rh->r->ifc != nil && rh->rgen == v6routegeneration)
return rh->r;
- for(h = 0; h < IPllen; h++)
+ for(h = 0; h < IPllen; h++){
la[h] = nhgetl(a+4*h);
+ ls[h] = nhgetl(s+4*h);
+ }
q = nil;
- for(p=f->v6root[V6H(la)]; p;){
+ for(p = f->v6root[V6H(la)]; p != nil;){
for(h = 0; h < IPllen; h++){
x = la[h];
y = p->v6.address[h];
@@ -564,18 +639,42 @@
}
break;
}
+ if(p->type & Rsrc){
+ for(h = 0; h < IPllen; h++){
+ x = ls[h];
+ y = p->v6.source[h];
+ if(x == y)
+ continue;
+ if(x < y){
+ p = p->mid;
+ goto next;
+ }
+ break;
+ }
+ for(h = 0; h < IPllen; h++){
+ x = ls[h];
+ y = p->v6.endsource[h];
+ if(x == y)
+ continue;
+ if(x > y){
+ p = p->mid;
+ goto next;
+ }
+ break;
+ }
+ }
q = p;
p = p->mid;
next: ;
}
- if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
+ if(q != nil && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
if(q->type & Rifc) {
for(h = 0; h < IPllen; h++)
hnputl(gate+4*h, q->v6.address[h]);
- ifc = findipifc(f, gate, q->type);
+ ifc = findipifc(f, s, gate, q->type);
} else
- ifc = findipifc(f, q->v6.gate, q->type);
+ ifc = findipifc(f, s, q->v6.gate, q->type);
if(ifc == nil)
return nil;
q->ifc = ifc;
@@ -590,17 +689,49 @@
return q;
}
+static int
+parseroutetype(char *p)
+{
+ int type = 0;
+ switch(*p++){
+ default: return -1;
+ case '4': type |= Rv4;
+ case '6': break;
+ }
+ for(;;) switch(*p++){
+ default:
+ return -1;
+ case 'i':
+ if(((type ^= Rifc) & Rifc) != Rifc) return -1;
+ break;
+ case 'u':
+ if(((type ^= Runi) & (Runi|Rbcast|Rmulti)) != Runi) return -1;
+ break;
+ case 'b':
+ if(((type ^= Rbcast) & (Runi|Rbcast|Rmulti)) != Rbcast) return -1;
+ break;
+ case 'm':
+ if(((type ^= Rmulti) & (Runi|Rbcast|Rmulti)) != Rmulti) return -1;
+ break;
+ case 'p':
+ if(((type ^= Rptpt) & Rptpt) != Rptpt) return -1;
+ break;
+ case '\0':
+ return type;
+ }
+}
+
void
-routetype(int type, char *p)
+routetype(int type, char p[8])
{
- memset(p, ' ', 4);
- p[4] = 0;
if(type & Rv4)
*p++ = '4';
else
*p++ = '6';
+
if(type & Rifc)
*p++ = 'i';
+
if(type & Runi)
*p++ = 'u';
else if(type & Rbcast)
@@ -607,14 +738,14 @@
*p++ = 'b';
else if(type & Rmulti)
*p++ = 'm';
+
if(type & Rptpt)
- *p = 'p';
+ *p++ = 'p';
+ *p = 0;
}
-static char *rformat = "%-15I %-4M %-15I %4.4s %4.4s %3s\n";
-
-void
-convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc)
+static void
+convroute(Route *r, uchar *addr, uchar *mask, uchar *src, uchar *smask, uchar *gate)
{
int i;
@@ -621,8 +752,16 @@
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(src, v4prefix, IPv4off);
+ hnputl(src+IPv4off, r->v4.source);
+
+ memset(smask, 0xff, IPv4off);
+ hnputl(smask+IPv4off, ~(r->v4.endsource ^ r->v4.source));
+
memmove(gate, v4prefix, IPv4off);
memmove(gate+IPv4off, r->v4.gate, IPv4addrlen);
} else {
@@ -629,162 +768,187 @@
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]));
+ hnputl(src + 4*i, r->v6.source[i]);
+ hnputl(smask + 4*i, ~(r->v6.endsource[i] ^ r->v6.source[i]));
}
memmove(gate, r->v6.gate, IPaddrlen);
}
+}
- routetype(r->type, t);
+static char*
+seprintroute(char *p, char *e, Route *r)
+{
+ uchar addr[IPaddrlen], mask[IPaddrlen], src[IPaddrlen], smask[IPaddrlen], gate[IPaddrlen];
+ char type[8], ifbuf[4], *iname;
- if(r->ifc)
- *nifc = r->ifc->conv->x;
+ convroute(r, addr, mask, src, smask, gate);
+ routetype(r->type, type);
+ if(r->ifc != nil && r->ifcid == r->ifc->ifcid)
+ snprint(iname = ifbuf, sizeof ifbuf, "%d", r->ifc->conv->x);
else
- *nifc = -1;
+ iname = "-";
+ return seprint(p, e, "%-15I %-4M %-15I %-4s %4.4s %3s %-15I %-4M\n",
+ addr, mask, gate, type, r->tag, iname, src, smask);
}
-/*
- * this code is not in rr to reduce stack size
- */
-static void
-sprintroute(Route *r, Routewalk *rw)
+typedef struct Routewalk Routewalk;
+struct Routewalk
{
- int nifc, n;
- char t[5], *iname, ifbuf[5];
- uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen];
- char *p;
+ int o;
+ int h;
+ char* p;
+ char* e;
+};
- convroute(r, addr, mask, gate, t, &nifc);
- iname = "-";
- if(nifc != -1) {
- iname = ifbuf;
- snprint(ifbuf, sizeof ifbuf, "%d", nifc);
- }
- p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname);
+static int
+rr1(Routewalk *rw, Route *r)
+{
+ int n = seprintroute(rw->p, rw->e, r) - rw->p;
if(rw->o < 0){
- n = p - rw->p;
if(n > -rw->o){
- memmove(rw->p, rw->p-rw->o, n+rw->o);
- rw->p = p + rw->o;
+ memmove(rw->p, rw->p - rw->o, n + rw->o);
+ rw->p += n + rw->o;
}
rw->o += n;
} else
- rw->p = p;
+ rw->p += n;
+ return rw->p < rw->e;
}
-/*
- * recurse descending tree, applying the function in Routewalk
- */
static int
rr(Route *r, Routewalk *rw)
{
int h;
- if(rw->e <= rw->p)
- 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(h == rw->h){
+ if(rr1(rw, r) == 0)
+ return 0;
+ }
if(rr(r->mid, rw) == 0)
return 0;
-
return rr(r->right, rw);
}
-void
-ipwalkroutes(Fs *f, Routewalk *rw)
+long
+routeread(Fs *f, char *p, ulong offset, int n)
{
+ Routewalk rw[1];
+
+ rw->p = p;
+ rw->e = p+n;
+ rw->o = -offset;
+ if(rw->o > 0)
+ return 0;
+
rlock(&routelock);
- if(rw->e > rw->p) {
+ if(rw->p < rw->e) {
for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++)
if(rr(f->v4root[rw->h], rw) == 0)
break;
}
- if(rw->e > rw->p) {
+ if(rw->p < rw->e) {
for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++)
if(rr(f->v6root[rw->h], rw) == 0)
break;
}
runlock(&routelock);
-}
-long
-routeread(Fs *f, char *p, ulong offset, int n)
-{
- Routewalk rw;
-
- rw.p = p;
- rw.e = p+n;
- rw.o = -offset;
- rw.walk = sprintroute;
-
- ipwalkroutes(f, &rw);
-
- return rw.p - p;
+ return rw->p - p;
}
/*
- * this code is not in routeflush to reduce stack size
+ * 4 add addr mask gate
+ * 5 add addr mask gate ifc
+ * 6 add addr mask gate src smask
+ * 7 add addr mask gate ifc src smask
+ * 8 add addr mask gate tag ifc src smask
+ * 9 add addr mask gate type tag ifc src smask
+ * 3 remove addr mask
+ * 4 remove addr mask gate
+ * 5 remove addr mask src smask
+ * 6 remove addr mask gate src smask
+ * 7 remove addr mask gate ifc src smask
+ * 8 remove addr mask gate tag ifc src smask
+ * 9 remove addr mask gate type tag ifc src smask
*/
-void
-delroute(Fs *f, Route *r, int dolock)
+static Route
+parseroute(Fs *f, char **argv, int argc)
{
- uchar addr[IPaddrlen];
- uchar mask[IPaddrlen];
+ uchar addr[IPaddrlen], mask[IPaddrlen];
+ uchar src[IPaddrlen], smask[IPaddrlen];
uchar gate[IPaddrlen];
- char t[5];
- int nifc;
+ Ipifc *ifc;
+ char *tag;
+ int type;
- convroute(r, addr, mask, gate, t, &nifc);
- if(r->type & Rv4)
- v4delroute(f, addr+IPv4off, mask+IPv4off, dolock);
- else
- v6delroute(f, addr, mask, dolock);
-}
+ type = 0;
+ tag = nil;
+ ifc = nil;
+ ipmove(gate, IPnoaddr);
+ ipmove(src, IPnoaddr);
+ ipmove(smask, IPnoaddr);
-/*
- * recurse until one route is deleted
- * returns 0 if nothing is deleted, 1 otherwise
- */
-int
-routeflush(Fs *f, Route *r, char *tag)
-{
- if(r == nil)
- return 0;
- if(routeflush(f, r->mid, tag))
- return 1;
- if(routeflush(f, r->left, tag))
- return 1;
- if(routeflush(f, r->right, tag))
- return 1;
- if((r->type & Rifc) == 0){
- if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0){
- delroute(f, r, 0);
- return 1;
- }
+ if(argc < 3)
+ error(Ebadctl);
+ if(parseip(addr, argv[1]) == -1)
+ error(Ebadip);
+ parseipmask(mask, argv[2]);
+
+ if(strcmp(argv[0], "add") == 0 || (argc > 3 && argc != 5)){
+ if(argc < 4)
+ error(Ebadctl);
+ if(parseip(gate, argv[3]) == -1)
+ error(Ebadip);
}
- return 0;
+ if(argc > 4 && (strcmp(argv[0], "add") != 0 || argc != 5)){
+ if(parseip(src, argv[argc-2]) == -1)
+ error(Ebadip);
+ parseipmask(smask, argv[argc-1]);
+ }
+ if(argc == 5 && strcmp(argv[0], "add") == 0)
+ ifc = findipifcstr(f, argv[4]);
+ if(argc > 6)
+ ifc = findipifcstr(f, argv[argc-3]);
+ if(argc > 7)
+ tag = argv[argc-4];
+ if(argc > 8){
+ if((type = parseroutetype(argv[argc-5])) < 0)
+ error(Ebadctl);
+ } else {
+ if(isv4(addr))
+ type |= Rv4;
+ }
+ if(argc > 9)
+ error(Ebadctl);
+
+ if(type & Rv4){
+ if(!isv4(addr))
+ error(Ebadip);
+ if(ipcmp(smask, IPnoaddr) != 0 && !isv4(src))
+ error(Ebadip);
+ if(ipcmp(gate, IPnoaddr) != 0 && !isv4(gate))
+ error(Ebadip);
+ } else {
+ if(isv4(addr))
+ error(Ebadip);
+ }
+
+ return mkroute(addr, mask, src, smask, gate, type, ifc, tag);
}
long
routewrite(Fs *f, Chan *c, char *p, int n)
{
- int h, changed;
- char *tag;
Cmdbuf *cb;
- uchar addr[IPaddrlen];
- uchar mask[IPaddrlen];
- uchar gate[IPaddrlen];
- IPaux *a, *na;
+ IPaux *a;
cb = parsecmd(p, n);
if(waserror()){
@@ -794,52 +958,35 @@
if(cb->nf < 1)
error("short control request");
if(strcmp(cb->f[0], "flush") == 0){
- tag = cb->f[1];
+ char *tag = cb->nf < 2 ? nil : cb->f[1];
+ Route *x;
+ int h;
+
+ wlock(&routelock);
for(h = 0; h < nelem(f->v4root); h++)
- for(changed = 1; changed;){
- wlock(&routelock);
- changed = routeflush(f, f->v4root[h], tag);
- wunlock(&routelock);
- }
+ while((x = looknodetag(f->v4root[h], tag)) != nil)
+ routerem(f, x);
for(h = 0; h < nelem(f->v6root); h++)
- for(changed = 1; changed;){
- wlock(&routelock);
- changed = routeflush(f, f->v6root[h], tag);
- wunlock(&routelock);
- }
- } else if(strcmp(cb->f[0], "remove") == 0){
- if(cb->nf < 3)
- error(Ebadarg);
- if (parseip(addr, cb->f[1]) == -1)
- error(Ebadip);
- parseipmask(mask, cb->f[2]);
- if(memcmp(addr, v4prefix, IPv4off) == 0)
- v4delroute(f, addr+IPv4off, mask+IPv4off, 1);
- else
- v6delroute(f, addr, mask, 1);
- } else if(strcmp(cb->f[0], "add") == 0){
- if(cb->nf < 4)
- error(Ebadarg);
- if(parseip(addr, cb->f[1]) == -1 ||
- parseip(gate, cb->f[3]) == -1)
- error(Ebadip);
- parseipmask(mask, cb->f[2]);
- tag = "none";
- if(c != nil){
+ while((x = looknodetag(f->v6root[h], tag)) != nil)
+ routerem(f, x);
+ wunlock(&routelock);
+ } else if(strcmp(cb->f[0], "add") == 0 || strcmp(cb->f[0], "remove") == 0){
+ Route r = parseroute(f, cb->f, cb->nf);
+ if(*r.tag == 0){
a = c->aux;
- tag = a->tag;
+ strncpy(r.tag, a->tag, sizeof(r.tag));
}
- if(memcmp(addr, v4prefix, IPv4off) == 0)
- v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
+ wlock(&routelock);
+ if(strcmp(cb->f[0], "add") == 0)
+ routeadd(f, &r);
else
- v6addroute(f, tag, addr, mask, gate, 0);
+ routerem(f, &r);
+ wunlock(&routelock);
} else if(strcmp(cb->f[0], "tag") == 0) {
if(cb->nf < 2)
error(Ebadarg);
-
a = c->aux;
- na = newipaux(a->owner, cb->f[1]);
- c->aux = na;
+ c->aux = newipaux(a->owner, cb->f[1]);
free(a);
} else
error(Ebadctl);
--- a/sys/src/9/ip/ipv6.c
+++ b/sys/src/9/ip/ipv6.c
@@ -38,7 +38,7 @@
IP *ip;
Ip6hdr *eh;
Ipifc *ifc;
- Route *r, *sr;
+ Route *r;
ip = f->ip;
@@ -74,23 +74,16 @@
goto free;
}
- r = v6lookup(f, eh->dst, rh);
- if(r == nil){
+ r = v6lookup(f, eh->dst, eh->src, rh);
+ if(r == nil || (r->type & Rv4) != 0 || (ifc = r->ifc) == nil){
ip->stats[OutNoRoutes]++;
- netlog(f, Logip, "no interface %I\n", eh->dst);
+ netlog(f, Logip, "no interface %I -> %I\n", eh->src, eh->dst);
rv = -1;
goto free;
}
- ifc = r->ifc;
- if(r->type & (Rifc|Runi))
+ if(r->type & (Rifc|Runi|Rbcast|Rmulti))
gate = eh->dst;
- else if(r->type & (Rbcast|Rmulti)) {
- gate = eh->dst;
- sr = v6lookup(f, eh->src, nil);
- if(sr && (sr->type & Runi))
- ifc = sr->ifc;
- }
else
gate = r->v6.gate;
@@ -226,7 +219,6 @@
{
int hl, hop, tos, notforme, tentative;
uchar proto;
- uchar v6dst[IPaddrlen];
IP *ip;
Ip6hdr *h;
Proto *p;
@@ -251,11 +243,9 @@
}
h = (Ip6hdr *)bp->rp;
+ notforme = ipforme(f, h->dst) == 0;
+ tentative = iptentative(f, h->dst);
- memmove(&v6dst[0], &h->dst[0], IPaddrlen);
- notforme = ipforme(f, v6dst) == 0;
- tentative = iptentative(f, v6dst);
-
if(tentative && h->proto != ICMPv6) {
print("tentative addr, drop\n");
freeblist(bp);
@@ -290,8 +280,8 @@
/* don't forward to source's network */
rh.r = nil;
- r = v6lookup(f, h->dst, &rh);
- if(r == nil || r->ifc == ifc){
+ r = v6lookup(f, h->dst, h->src, &rh);
+ if(r == nil || (r->type & Rv4) != 0 || r->ifc == ifc){
ip->stats[OutDiscards]++;
freeblist(bp);
return;
--- a/sys/src/9/ip/rudp.c
+++ b/sys/src/9/ip/rudp.c
@@ -564,10 +564,10 @@
c->rport = rport;
/* reply with the same ip address (if not broadcast) */
- if(ipforme(f, laddr) == Runi)
- ipmove(c->laddr, laddr);
- else
+ if(ipforme(f, laddr) != Runi)
ipv6local(ifc, c->laddr, c->raddr);
+ else
+ ipmove(c->laddr, laddr);
}
break;
}
--- a/sys/src/9/ip/tcp.c
+++ b/sys/src/9/ip/tcp.c
@@ -864,8 +864,7 @@
* otherwise, we use the default MSS which assumes a
* safe minimum MTU of 1280 bytes for V6.
*/
- if(r != nil){
- ifc = r->ifc;
+ if(r != nil && (ifc = r->ifc) != nil){
mtu = ifc->maxtu - ifc->m->hsize;
if(version == V4)
return mtu - (TCP4_PKT + TCP4_HDRSIZE);
@@ -1314,7 +1313,7 @@
tcb->sndsyntime = NOW;
/* set desired mss and scale */
- tcb->mss = tcpmtu(v6lookup(s->p->f, s->raddr, s), s->ipversion, &tcb->scale);
+ tcb->mss = tcpmtu(v6lookup(s->p->f, s->raddr, s->laddr, s), s->ipversion, &tcb->scale);
tpriv = s->p->priv;
tpriv->stats[Mss] = tcb->mss;
}
@@ -1492,7 +1491,7 @@
seg.ack = lp->irs+1;
seg.flags = SYN|ACK;
seg.urg = 0;
- seg.mss = tcpmtu(v6lookup(tcp->f, lp->raddr, nil), lp->version, &scale);
+ seg.mss = tcpmtu(v6lookup(tcp->f, lp->raddr, lp->laddr, nil), lp->version, &scale);
seg.wnd = QMAX;
/* if the other side set scale, we should too */
@@ -1768,7 +1767,7 @@
tcb->flags |= SYNACK;
/* set desired mss and scale */
- tcb->mss = tcpmtu(v6lookup(s->p->f, src, s), version, &tcb->scale);
+ tcb->mss = tcpmtu(v6lookup(s->p->f, src, dst, s), version, &tcb->scale);
/* our sending max segment size cannot be bigger than what he asked for */
if(lp->mss != 0 && lp->mss < tcb->mss)