ref: 20b9326daddd52ffe534a968fb596af1674f53cc
parent: c80d94304d0b9946c822e073b637760a0894522a
author: cinap_lenrek <[email protected]>
date: Sun Apr 22 14:54:13 EDT 2018
devip: fix ipv6 icmp unreachable handling, fix retransmit, fix ifc locking, remove tentative check
--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -293,7 +293,7 @@
}
int
-arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *src, int refresh)
+arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *ia, int refresh)
{
Arp *arp;
Route *r;
@@ -300,26 +300,31 @@
Arpent *a, *f, **l;
Ipifc *ifc;
Block *bp, *next;
- Medium *m;
uchar v6ip[IPaddrlen];
arp = fs->arp;
switch(version){
case V4:
- r = v4lookup(fs, ip, src, nil);
+ r = v4lookup(fs, ip, ia, nil);
v4tov6(v6ip, ip);
ip = v6ip;
break;
case V6:
- r = v6lookup(fs, ip, src, nil);
+ r = v6lookup(fs, ip, ia, nil);
break;
default:
panic("arpenter: version %d", version);
return -1; /* to supress warnings */
}
- if(r == nil || (ifc = r->ifc) == nil || (m = ifc->m) == nil || m->maclen != n || m->maclen == 0)
+ if(r == nil || (ifc = r->ifc) == nil)
return -1;
+ rlock(ifc);
+ if(ifc->m == nil || ifc->m->maclen != n || ifc->m->maclen == 0){
+ runlock(ifc);
+ return -1;
+ }
+
qlock(arp);
for(a = arp->hash[haship(ip)]; a != nil; a = a->hash){
if(a->state != AWAIT && a->state != AOK)
@@ -351,28 +356,17 @@
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()){
- runlock(ifc);
freeblistchain(next);
break;
}
- m->bwrite(ifc, concatblock(bp), version, ip);
- runlock(ifc);
+ ifc->m->bwrite(ifc, concatblock(bp), version, ip);
poperror();
bp = next;
}
-
+ runlock(ifc);
return 1;
}
}
@@ -383,8 +377,9 @@
a->ctime = NOW;
memmove(a->mac, mac, n);
}
-
qunlock(arp);
+ runlock(ifc);
+
return refresh == 0;
}
@@ -396,7 +391,7 @@
Arpent *a, *x;
Medium *m;
char *f[5], buf[256];
- uchar ip[IPaddrlen], src[IPaddrlen], mac[MAClen];
+ uchar ip[IPaddrlen], ia[IPaddrlen], mac[MAClen];
arp = fs->arp;
@@ -438,7 +433,7 @@
error(Ebadip);
if((n = parsemac(mac, f[2], sizeof(mac))) <= 0)
error(Ebadarp);
- findlocalip(fs, src, ip);
+ findlocalip(fs, ia, ip);
break;
case 4:
m = ipfindmedium(f[1]);
@@ -448,7 +443,7 @@
error(Ebadip);
if((n = parsemac(mac, f[3], sizeof(mac))) != m->maclen)
error(Ebadarp);
- findlocalip(fs, src, ip);
+ findlocalip(fs, ia, ip);
break;
case 5:
m = ipfindmedium(f[1]);
@@ -458,11 +453,11 @@
error(Ebadip);
if((n = parsemac(mac, f[3], sizeof(mac))) != m->maclen)
error(Ebadarp);
- if(parseip(src, f[4]) == -1)
+ if(parseip(ia, f[4]) == -1)
error(Ebadip);
break;
}
- if(arpenter(fs, V6, ip, mac, n, src, 0) <= 0)
+ if(arpenter(fs, V6, ip, mac, n, ia, 0) <= 0)
error("destination unreachable");
} else if(strcmp(f[0], "del") == 0){
if (n != 2)
@@ -495,8 +490,8 @@
int
arpread(Arp *arp, char *s, ulong offset, int len)
{
- uchar ip[IPaddrlen], src[IPaddrlen];
- char mac[2*MAClen+1], *p, *state;
+ char mac[2*MAClen+1], *state, *mname, *p;
+ uchar ip[IPaddrlen], ia[IPaddrlen];
Ipifc *ifc;
Arpent *a;
long n, o;
@@ -504,18 +499,25 @@
p = s;
o = -offset;
for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
- if(a->state == 0 || (ifc = a->ifc) == nil || a->ifcid != ifc->ifcid)
+ if(a->state == 0 || (ifc = a->ifc) == nil)
continue;
+ rlock(ifc);
qlock(arp);
state = arpstate[a->state];
ipmove(ip, a->ip);
+ if(ifc->m == nil || a->ifcid != ifc->ifcid || !ipv6local(ifc, ia, ip)){
+ qunlock(arp);
+ runlock(ifc);
+ continue;
+ }
+ mname = ifc->m->name;
convmac(mac, a->mac, ifc->m->maclen);
qunlock(arp);
+ runlock(ifc);
- 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);
+ mname, state, ip, mac, ia);
if(o < 0) {
if(n > -o)
memmove(p, p-o, n+o);
@@ -549,17 +551,20 @@
if(!ipv6local(ifc, src, targ))
return;
send:
- icmpns(f, src, SRC_UNI, targ, TARG_MULTI, ifc->mac);
+ if(!waserror()){
+ icmpns(f, src, SRC_UNI, targ, TARG_MULTI, ifc->mac);
+ poperror();
+ }
}
-int
+long
rxmitsols(Arp *arp)
{
Block *next, *xp;
Arpent *a, *b, **l;
- Fs *f;
- Ipifc *ifc = nil;
+ Ipifc *ifc;
long nrxt;
+ Fs *f;
qlock(arp);
f = arp->f;
@@ -573,6 +578,7 @@
if(nrxt > 3*ReTransTimer/4)
goto dodrops; /* return nrxt; */
+ ifc = nil;
for(; a != nil; a = a->nextrxt){
ifc = a->ifc;
if(a->rxtsrem > 0 && ifc != nil && canrlock(ifc)){
@@ -628,8 +634,19 @@
qunlock(arp);
for(; xp != nil; xp = next){
+ Ip6hdr *eh;
+ Route *r;
+
next = xp->list;
- icmphostunr6(f, ifc, xp, Icmp6_adr_unreach, 1);
+ eh = (Ip6hdr*)xp->rp;
+ r = v6lookup(f, eh->src, eh->dst, nil);
+ if(r != nil && (ifc = r->ifc) != nil && canrlock(ifc)){
+ if(!waserror()){
+ icmphostunr6(f, ifc, xp, Icmp6_adr_unreach, (r->type & Runi) != 0);
+ poperror();
+ }
+ runlock(ifc);
+ }
freeblist(xp);
}
--- a/sys/src/9/ip/esp.c
+++ b/sys/src/9/ip/esp.c
@@ -472,7 +472,7 @@
ecb = c->ptcl;
/* too hard to do decryption/authentication on block lists */
- if(bp->next)
+ if(bp->next != nil)
bp = concatblock(bp);
if(BLEN(bp) < vers.hdrlen + ecb->espivlen + Esptaillen + ecb->ahlen) {
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -33,7 +33,7 @@
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 void etherareg(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip);
static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
static void sendarp(Ipifc *ifc, Arpent *a);
static int multicastea(uchar *ea, uchar *ip);
@@ -219,8 +219,8 @@
poperror();
kproc("etherread4", etherread4, ifc);
- kproc("recvarpproc", recvarpproc, ifc);
kproc("etherread6", etherread6, ifc);
+ kproc("recvarpproc", recvarpproc, ifc);
}
/*
@@ -231,21 +231,19 @@
{
Etherrock *er = ifc->arg;
- if(er->read4p)
+ if(er->read4p != nil)
postnote(er->read4p, 1, "unbind", 0);
- if(er->read6p)
+ if(er->read6p != nil)
postnote(er->read6p, 1, "unbind", 0);
- if(er->arpp)
+ if(er->arpp != nil)
postnote(er->arpp, 1, "unbind", 0);
/* wait for readers to die */
- while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
+ while(er->arpp != nil || er->read4p != nil || er->read6p != nil)
tsleep(&up->sleep, return0, 0, 300);
if(er->mchan4 != nil)
cclose(er->mchan4);
- if(er->achan != nil)
- cclose(er->achan);
if(er->cchan4 != nil)
cclose(er->cchan4);
if(er->mchan6 != nil)
@@ -252,6 +250,8 @@
cclose(er->mchan6);
if(er->cchan6 != nil)
cclose(er->cchan6);
+ if(er->achan != nil)
+ cclose(er->achan);
free(er);
}
@@ -329,7 +329,7 @@
er = ifc->arg;
er->read4p = up; /* hide identity under a rock for unbind */
if(waserror()){
- er->read4p = 0;
+ er->read4p = nil;
pexit("hangup", 1);
}
for(;;){
@@ -369,7 +369,7 @@
er = ifc->arg;
er->read6p = up; /* hide identity under a rock for unbind */
if(waserror()){
- er->read6p = 0;
+ er->read6p = nil;
pexit("hangup", 1);
}
for(;;){
@@ -571,6 +571,11 @@
if(ebp == nil)
return;
+ if(!canrlock(ifc)){
+ freeb(ebp);
+ return;
+ }
+
e = (Etherarp*)ebp->rp;
switch(nhgets(e->op)) {
default:
@@ -647,8 +652,14 @@
memmove(r->s, ifc->mac, sizeof(r->s));
rbp->wp += n;
+ runlock(ifc);
+ freeb(ebp);
+
devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
+ return;
}
+
+ runlock(ifc);
freeb(ebp);
}
@@ -660,7 +671,7 @@
er->arpp = up;
if(waserror()){
- er->arpp = 0;
+ er->arpp = nil;
pexit("hangup", 1);
}
for(;;)
@@ -745,10 +756,10 @@
}
static void
-etherareg(Fs *f, Ipifc *ifc, uchar *ip, uchar *proxy)
+etherareg(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip)
{
static char tdad[] = "dad6";
- uchar mcast[IPaddrlen];
+ uchar a[IPaddrlen];
if(ipcmp(ip, IPnoaddr) == 0)
return;
@@ -758,16 +769,25 @@
return;
}
- if(!iptentative(f, ip)){
- icmpna(f, proxy, v6allnodesL, ip, ifc->mac, 1<<5);
+ if((lifc->type&Rv4) != 0)
return;
+
+ if(!lifc->tentative){
+ icmpna(f, lifc->local, 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);
+ if(ipcmp(lifc->local, ip) != 0)
+ return;
+ /* temporarily add route for duplicate address detection */
+ ipv62smcast(a, ip);
+ addroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
+ if(waserror()){
+ remroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
+ nexterror();
+ }
icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
-
- remroute(f, mcast, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
+ poperror();
+ remroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
}
--- a/sys/src/9/ip/ip.c
+++ b/sys/src/9/ip/ip.c
@@ -99,6 +99,7 @@
IP *ip;
ip = smalloc(sizeof(IP));
+ ip->stats[DefaultTTL] = MAXTTL;
initfrag(ip, 100);
f->ip = ip;
@@ -362,7 +363,7 @@
if(notforme) {
Route *r;
Routehint rh;
- Ipifc *toifc;
+ Ipifc *nifc;
if(!ip->iprouting)
goto drop;
@@ -370,8 +371,8 @@
/* don't forward to source's network */
rh.r = nil;
r = v4lookup(f, h->dst, h->src, &rh);
- if(r == nil || (toifc = r->ifc) == nil
- || (toifc == ifc && !ifc->reflect)){
+ if(r == nil || (nifc = r->ifc) == nil
+ || (nifc == ifc && !ifc->reflect)){
ip->stats[OutDiscards]++;
goto drop;
}
@@ -385,7 +386,7 @@
}
/* reassemble if the interface expects it */
- if(toifc->reassemble){
+ if(nifc->reassemble){
frag = nhgets(h->frag);
if(frag & ~IP_DF) {
h->tos = 0;
@@ -441,8 +442,6 @@
int i;
ip = f->ip;
- ip->stats[DefaultTTL] = MAXTTL;
-
p = buf;
e = p+len;
for(i = 0; i < Nipstats; i++)
@@ -467,7 +466,7 @@
/*
* block lists are too hard, pullupblock into a single block
*/
- if(bp->next){
+ if(bp->next != nil){
bp = pullupblock(bp, blocklen(bp));
ih = (Ip4hdr*)(bp->rp);
}
@@ -477,7 +476,7 @@
/*
* find a reassembly queue for this fragment
*/
- for(f = ip->flisthead4; f; f = fnext){
+ for(f = ip->flisthead4; f != nil; f = fnext){
fnext = f->next; /* because ipfragfree4 changes the list */
if(f->src == src && f->dst == dst && f->id == id)
break;
@@ -536,7 +535,7 @@
}
/* Check overlap of a previous fragment - trim away as necessary */
- if(prev) {
+ if(prev != nil) {
ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff;
if(ovlap > 0) {
if(ovlap >= BKFG(bp)->flen) {
@@ -553,11 +552,11 @@
*l = bp;
/* Check to see if succeeding segments overlap */
- if(bp->next) {
+ if(bp->next != nil) {
l = &bp->next;
fend = BKFG(bp)->foff + BKFG(bp)->flen;
/* Take completely covered segments out */
- while(*l) {
+ while(*l != nil) {
ovlap = fend - BKFG(*l)->foff;
if(ovlap <= 0)
break;
@@ -581,7 +580,7 @@
* without IP_MF set, we're done.
*/
pktposn = 0;
- for(bl = f->blist; bl; bl = bl->next) {
+ for(bl = f->blist; bl != nil; bl = bl->next) {
if(BKFG(bl)->foff != pktposn)
break;
if((BLKIP(bl)->frag[0]&(IP_MF>>8)) == 0) {
@@ -592,7 +591,7 @@
/* Pullup all the fragment headers and
* return a complete packet
*/
- for(bl = bl->next; bl; bl = bl->next) {
+ for(bl = bl->next; bl != nil; bl = bl->next) {
fragsize = BKFG(bl)->flen;
len += fragsize;
bl->rp += IP4HDR;
@@ -622,7 +621,7 @@
{
Fragment4 *fl, **l;
- if(frag->blist)
+ if(frag->blist != nil)
freeblist(frag->blist);
frag->src = 0;
@@ -630,7 +629,7 @@
frag->blist = nil;
l = &ip->flisthead4;
- for(fl = *l; fl; fl = fl->next) {
+ for(fl = *l; fl != nil; fl = fl->next) {
if(fl == frag) {
*l = frag->next;
break;
@@ -653,7 +652,7 @@
while(ip->fragfree4 == nil) {
/* free last entry on fraglist */
- for(f = ip->flisthead4; f->next; f = f->next)
+ for(f = ip->flisthead4; f->next != nil; f = f->next)
;
ipfragfree4(ip, f);
}
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -243,7 +243,7 @@
void (*pktin)(Fs *f, Ipifc *ifc, Block *bp);
/* address resolution */
- void (*areg)(Fs *f, Ipifc *ifc, uchar *ip, uchar *proxy); /* register */
+ void (*areg)(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip);
/* v6 address generation */
void (*pref2addr)(uchar *pref, uchar *ea);
@@ -608,7 +608,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 int arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *src, int norefresh);
+extern int arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *ia, int norefresh);
extern void ndpsendsol(Fs*, Ipifc*, Arpent*);
/*
@@ -654,8 +654,6 @@
extern Medium* ipfindmedium(char *name);
extern void addipmedium(Medium *med);
extern int ipforme(Fs*, uchar *addr);
-extern int iptentative(Fs*, uchar *addr);
-extern int ipisbm(uchar *ip);
extern int ipismulticast(uchar *ip);
extern Ipifc* findipifc(Fs*, uchar *local, uchar *remote, int type);
extern Ipifc* findipifcstr(Fs *f, char *s);
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -61,6 +61,7 @@
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 void ipifcregisteraddr(Fs*, Ipifc*, uchar *, uchar *);
static void ipifcregisterproxy(Fs*, Ipifc*, uchar*, int);
static char* ipifcremlifc(Ipifc*, Iplifc**);
@@ -218,10 +219,6 @@
/* disassociate logical interfaces (before zeroing ifc->arg) */
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 != nil)
error(err);
}
@@ -273,7 +270,7 @@
ifc->in, ifc->out, ifc->inerr, ifc->outerr);
rlock(ifc);
- for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
+ for(lifc = ifc->lifc; lifc != nil && n > m; lifc = lifc->next)
m += snprint(state+m, n - m, slineformat, lifc->local,
lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
if(ifc->lifc == nil)
@@ -291,9 +288,8 @@
int m;
ifc = (Ipifc*)c->ptcl;
- m = 0;
-
rlock(ifc);
+ m = 0;
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
for(link = lifc->link; link != nil; link = link->lifclink)
@@ -405,14 +401,9 @@
uchar bcast[IPaddrlen], net[IPaddrlen];
Iplifc *lifc, **l;
int i, type, mtu;
- Medium *m;
Fs *f;
- if((m = ifc->m) == nil)
- return "ipifc not yet bound to device";
-
- f = ifc->conv->p->f;
-
+ mtu = 0;
type = Rifc;
memset(ip, 0, IPaddrlen);
memset(mask, 0, IPaddrlen);
@@ -424,8 +415,6 @@
/* fall through */
case 5:
mtu = strtoul(argv[4], 0, 0);
- if(mtu >= m->mintu && mtu <= m->maxtu)
- ifc->maxtu = mtu;
/* fall through */
case 4:
if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
@@ -462,11 +451,18 @@
}
wlock(ifc);
+ if(ifc->m == nil)
+ return "ipifc not yet bound to device";
+
+ f = ifc->conv->p->f;
if(waserror()){
wunlock(ifc);
- nexterror();
+ return up->errstr;
}
+ if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
+ ifc->maxtu = mtu;
+
/* ignore if this is already a local address for this ifc */
if((lifc = iplocalonifc(ifc, ip)) != nil){
if(lifcp != nil) {
@@ -576,9 +572,7 @@
wunlock(ifc);
poperror();
- /* register the address on this network for address resolution */
- if(m->areg != nil)
- (*m->areg)(f, ifc, ip, ip);
+ ipifcregisteraddr(f, ifc, ip, ip);
return nil;
}
@@ -701,7 +695,7 @@
wunlock(ifc);
err = ipifcadd(ifc, argv, argc, 0, nil);
- if(err)
+ if(err != nil)
return err;
Fsconnected(c, nil);
@@ -1069,18 +1063,6 @@
return m;
}
-int
-iptentative(Fs *f, uchar *addr)
-{
- Ipself *p;
-
- 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;
-}
-
/*
* returns
* 0 - no match
@@ -1112,27 +1094,26 @@
findipifc(Fs *f, uchar *local, uchar *remote, int type)
{
uchar gnet[IPaddrlen];
+ int spec, xspec;
Ipifc *ifc, *x;
Iplifc *lifc;
- Conv **cp, **e;
- int spec, xspec;
+ Conv **cp;
x = nil;
xspec = 0;
-
- /* find most specific match */
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == nil)
- continue;
+ for(cp = f->ipifc->conv; *cp != nil; cp++){
ifc = (Ipifc*)(*cp)->ptcl;
+ rlock(ifc);
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
if(type & Runi){
- if(ipcmp(remote, lifc->local) == 0)
+ if(ipcmp(remote, lifc->local) == 0){
+ Found:
+ runlock(ifc);
return ifc;
+ }
} else if(type & (Rbcast|Rmulti)) {
if(ipcmp(local, lifc->local) == 0)
- return ifc;
+ goto Found;
}
maskip(remote, lifc->mask, gnet);
if(ipcmp(gnet, lifc->net) == 0){
@@ -1143,6 +1124,7 @@
}
}
}
+ runlock(ifc);
}
return x;
}
@@ -1159,7 +1141,7 @@
if(p > s && *p == '\0'){
if(x < 0)
return nil;
- if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil)
+ if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil && ipifcinuse(c))
return (Ipifc*)c->ptcl;
}
if(parseip(ip, s) != -1)
@@ -1167,35 +1149,36 @@
return nil;
}
+/*
+ * find "best" (global > link local > unspecified)
+ * local address; address must be current.
+ */
static void
findprimaryipv6(Fs *f, uchar *local)
{
int atype, atypel;
- Conv **cp, **e;
- Ipifc *ifc;
Iplifc *lifc;
+ Ipifc *ifc;
+ Conv **cp;
ipmove(local, v6Unspecified);
atype = unspecifiedv6;
- /*
- * find "best" (global > link local > unspecified)
- * local address; address must be current.
- */
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == nil)
- continue;
+ for(cp = f->ipifc->conv; *cp != nil; cp++){
ifc = (Ipifc*)(*cp)->ptcl;
+ rlock(ifc);
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
atypel = v6addrtype(lifc->local);
if(atypel > atype && v6addrcurr(lifc)) {
ipmove(local, lifc->local);
atype = atypel;
- if(atype == globalv6)
+ if(atype == globalv6){
+ runlock(ifc);
return;
+ }
}
}
+ runlock(ifc);
}
}
@@ -1205,20 +1188,22 @@
static void
findprimaryipv4(Fs *f, uchar *local)
{
- Conv **cp, **e;
- Ipifc *ifc;
Iplifc *lifc;
+ Ipifc *ifc;
+ Conv **cp;
/* find first ifc local address */
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == nil)
- continue;
+ for(cp = f->ipifc->conv; *cp != nil; cp++){
ifc = (Ipifc*)(*cp)->ptcl;
- if((lifc = ifc->lifc) != nil && (lifc->type & Rv4) != 0){
- ipmove(local, lifc->local);
- return;
+ rlock(ifc);
+ for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+ if((lifc->type & Rv4) != 0){
+ ipmove(local, lifc->local);
+ runlock(ifc);
+ return;
+ }
}
+ runlock(ifc);
}
ipmove(local, IPnoaddr);
}
@@ -1310,41 +1295,47 @@
findlocalip(Fs *f, uchar *local, uchar *remote)
{
Route *r;
- Ipifc *ifc;
Iplifc *lifc;
- Conv **cp, **e;
+ Ipifc *ifc, *nifc;
+ Conv **cp;
- qlock(f->ipifc);
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp == nil)
- continue;
+ for(cp = f->ipifc->conv; *cp != nil; cp++){
ifc = (Ipifc*)(*cp)->ptcl;
+ rlock(ifc);
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)
+ if(r == nil || (nifc = r->ifc) == nil)
continue;
if(r->type & Runi){
ipmove(local, remote);
- goto out;
+ runlock(ifc);
+ return;
}
+ if(nifc != ifc) rlock(nifc);
if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
ipmove(local, v4prefix);
- if(ipv4local(ifc, local+IPv4off, r->v4.gate))
- goto out;
+ if(ipv4local(nifc, local+IPv4off, r->v4.gate)){
+ if(nifc != ifc) runlock(nifc);
+ runlock(ifc);
+ return;
+ }
}
- if(ipv6local(ifc, local, remote))
- goto out;
+ if(ipv6local(nifc, local, remote)){
+ if(nifc != ifc) runlock(nifc);
+ runlock(ifc);
+ return;
+ }
+ if(nifc != ifc) runlock(nifc);
}
+ runlock(ifc);
}
if(isv4(remote))
findprimaryipv4(f, local);
else
findprimaryipv6(f, local);
-out:
- qunlock(f->ipifc);
}
@@ -1408,21 +1399,7 @@
return V6;
return 0;
}
-int
-ipisbm(uchar *ip)
-{
- if(isv4(ip)){
- if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
- return V4;
- else if(ipcmp(ip, IPv4bcast) == 0)
- return V4;
- }
- else if(ip[0] == 0xff)
- return V6;
- return 0;
-}
-
/*
* add a multicast address to an interface, called with c->car locked
*/
@@ -1430,13 +1407,10 @@
ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
{
Ipmulti *multi, **l;
- Conv **cp, **e;
Iplifc *lifc;
Ipifc *ifc;
Fs *f;
- f = c->p->f;
-
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 */
@@ -1446,11 +1420,8 @@
ipmove(multi->ia, ia);
multi->next = nil;
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if((*cp) == nil || (*cp)->inuse == 0)
- continue;
- ifc = (Ipifc*)(*cp)->ptcl;
+ f = c->p->f;
+ if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
wlock(ifc);
if(waserror()){
wunlock(ifc);
@@ -1471,13 +1442,10 @@
ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
{
Ipmulti *multi, **l;
- Conv **cp, **e;
Iplifc *lifc;
Ipifc *ifc;
Fs *f;
- f = c->p->f;
-
for(l = &c->multi; *l != nil; l = &(*l)->next)
if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
break;
@@ -1487,12 +1455,10 @@
return; /* we don't have it open */
*l = multi->next;
+ free(multi);
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if((*cp) == nil || (*cp)->inuse == 0)
- continue;
- ifc = (Ipifc*)(*cp)->ptcl;
+ f = c->p->f;
+ if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
wlock(ifc);
if(waserror()){
wunlock(ifc);
@@ -1504,46 +1470,63 @@
poperror();
}
- free(multi);
}
+/* register the address on this network for address resolution */
static void
+ipifcregisteraddr(Fs *f, Ipifc *ifc, uchar *ia, uchar *ip)
+{
+ Iplifc *lifc;
+
+ rlock(ifc);
+ if(waserror()){
+ runlock(ifc);
+ print("ipifcregisteraddr %s %I %I: %s\n", ifc->dev, ia, ip, up->errstr);
+ return;
+ }
+ lifc = iplocalonifc(ifc, ia);
+ if(lifc != nil && ifc->m != nil && ifc->m->areg != nil)
+ (*ifc->m->areg)(f, ifc, lifc, ip);
+ runlock(ifc);
+ poperror();
+}
+
+static void
ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
{
- uchar proxy[IPaddrlen];
- Conv **cp, **e;
+ uchar a[IPaddrlen];
Iplifc *lifc;
Ipifc *nifc;
- Medium *m;
+ Conv **cp;
/* 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)
+ for(cp = f->ipifc->conv; *cp != nil; cp++){
+ nifc = (Ipifc*)(*cp)->ptcl;
+ if(nifc == ifc)
continue;
wlock(nifc);
- m = nifc->m;
- if(m == nil || m->areg == nil || waserror()){
+ if(nifc->m == nil
+ || (lifc = ipremoteonifc(nifc, ip)) == nil
+ || (lifc->type & Rptpt) != 0
+ || waserror()){
wunlock(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);
- }
- ipmove(proxy, lifc->local);
+ if((lifc->type & Rv4) == 0){
+ /* add solicited-node multicast addr */
+ ipv62smcast(a, ip);
+ if(add)
+ addselfcache(f, nifc, lifc, a, Rmulti);
+ else
+ remselfcache(f, nifc, lifc, a);
}
+ ipmove(a, lifc->local);
wunlock(nifc);
poperror();
- if(add && lifc != nil)
- (*m->areg)(f, nifc, ip, proxy);
+ if(add)
+ ipifcregisteraddr(f, nifc, a, ip);
}
}
--- a/sys/src/9/ip/ipv6.c
+++ b/sys/src/9/ip/ipv6.c
@@ -31,7 +31,7 @@
ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh)
{
int medialen, len, chunk, uflen, flen, seglen, lid, offset, fragoff;
- int morefrags, blklen, rv = 0, tentative;
+ int morefrags, blklen, rv = 0;
uchar *gate, nexthdr;
Block *xp, *nb;
Fraghdr6 fraghdr;
@@ -50,13 +50,6 @@
/* Number of uchars in data and ip header to write */
len = blocklen(bp);
- tentative = iptentative(f, eh->src);
- if(tentative){
- netlog(f, Logip, "reject tx of packet with tentative src address %I\n",
- eh->src);
- goto free;
- }
-
if(gating){
chunk = nhgets(eh->ploadlen);
if(chunk > len){
@@ -217,7 +210,7 @@
void
ipiput6(Fs *f, Ipifc *ifc, Block *bp)
{
- int hl, hop, tos, notforme, tentative;
+ int hl, hop, tos;
uchar proto;
IP *ip;
Ip6hdr *h;
@@ -242,16 +235,8 @@
return;
}
- h = (Ip6hdr *)bp->rp;
- notforme = ipforme(f, h->dst) == 0;
- tentative = iptentative(f, h->dst);
-
- if(tentative && h->proto != ICMPv6) {
- print("tentative addr, drop\n");
- goto drop;
- }
-
/* Check header version */
+ h = (Ip6hdr *)bp->rp;
if(BLKIPVER(bp) != IP_VER6) {
ip->stats[InHdrErrors]++;
netlog(f, Logip, "ip: bad version %ux\n", (h->vcf[0]&0xF0)>>2);
@@ -259,10 +244,10 @@
}
/* route */
- if(notforme) {
+ if(ipforme(f, h->dst) == 0) {
Route *r;
Routehint rh;
- Ipifc *toifc;
+ Ipifc *nifc;
if(!ip->iprouting)
goto drop;
@@ -277,8 +262,8 @@
/* don't forward to source's network */
rh.r = nil;
r = v6lookup(f, h->dst, h->src, &rh);
- if(r == nil || (toifc = r->ifc) == nil || (r->type & Rv4) != 0
- || (toifc == ifc && !ifc->reflect)){
+ if(r == nil || (nifc = r->ifc) == nil || (r->type & Rv4) != 0
+ || (nifc == ifc && !ifc->reflect)){
ip->stats[OutDiscards]++;
goto drop;
}
@@ -292,7 +277,7 @@
}
/* process headers & reassemble if the interface expects it */
- bp = procxtns(ip, bp, toifc->reassemble);
+ bp = procxtns(ip, bp, nifc->reassemble);
if(bp == nil)
return;
@@ -312,7 +297,7 @@
h = (Ip6hdr *) (bp->rp);
proto = h->proto;
p = Fsrcvpcol(f, proto);
- if(p && p->rcv) {
+ if(p != nil && p->rcv != nil) {
ip->stats[InDelivers]++;
(*p->rcv)(p, ifc, bp);
return;
@@ -455,7 +440,7 @@
/*
* block lists are too hard, pullupblock into a single block
*/
- if(bp->next){
+ if(bp->next != nil){
bp = pullupblock(bp, blocklen(bp));
ih = (Ip6hdr *)bp->rp;
}
@@ -465,7 +450,7 @@
/*
* find a reassembly queue for this fragment
*/
- for(f = ip->flisthead6; f; f = fnext){
+ for(f = ip->flisthead6; f != nil; f = fnext){
fnext = f->next;
if(ipcmp(f->src, src)==0 && ipcmp(f->dst, dst)==0 && f->id == id)
break;
@@ -524,7 +509,7 @@
}
/* Check overlap of a previous fragment - trim away as necessary */
- if(prev) {
+ if(prev != nil) {
ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff;
if(ovlap > 0) {
if(ovlap >= BKFG(bp)->flen) {
@@ -541,12 +526,12 @@
*l = bp;
/* Check to see if succeeding segments overlap */
- if(bp->next) {
+ if(bp->next != nil) {
l = &bp->next;
fend = BKFG(bp)->foff + BKFG(bp)->flen;
/* Take completely covered segments out */
- while(*l) {
+ while(*l != nil) {
ovlap = fend - BKFG(*l)->foff;
if(ovlap <= 0)
break;
@@ -570,7 +555,7 @@
* with the trailing bit of fraghdr->offsetRM[1] set, we're done.
*/
pktposn = 0;
- for(bl = f->blist; bl && BKFG(bl)->foff == pktposn; bl = bl->next) {
+ for(bl = f->blist; bl != nil && BKFG(bl)->foff == pktposn; bl = bl->next) {
fraghdr = (Fraghdr6 *)(bl->rp + uflen);
if((fraghdr->offsetRM[1] & 1) == 0) {
bl = f->blist;
@@ -584,7 +569,7 @@
* Pullup all the fragment headers and
* return a complete packet
*/
- for(bl = bl->next; bl; bl = bl->next) {
+ for(bl = bl->next; bl != nil; bl = bl->next) {
fragsize = BKFG(bl)->flen;
len += fragsize;
bl->rp += uflen + IP6FHDR;