devip: fix ipv6 icmp unreachable handling, fix retransmit, fix ifc locking, remove tentative check

This commit is contained in:
cinap_lenrek 2018-04-22 18:54:13 +02:00
parent c80d94304d
commit 20b9326dad
7 changed files with 237 additions and 235 deletions

View file

@ -293,33 +293,38 @@ arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
}
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;
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 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *src, int refr
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 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *src, int refr
a->ctime = NOW;
memmove(a->mac, mac, n);
}
qunlock(arp);
runlock(ifc);
return refresh == 0;
}
@ -396,7 +391,7 @@ arpwrite(Fs *fs, char *s, int len)
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 @@ arpwrite(Fs *fs, char *s, int len)
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 @@ arpwrite(Fs *fs, char *s, int len)
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 @@ arpwrite(Fs *fs, char *s, int len)
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 @@ convmac(char *p, uchar *mac, int n)
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 @@ arpread(Arp *arp, char *s, ulong offset, int len)
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 @@ ndpsendsol(Fs *f, Ipifc *ifc, Arpent *a)
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 @@ rxmitsols(Arp *arp)
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 @@ dodrops:
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);
}

View file

@ -472,7 +472,7 @@ espiput(Proto *esp, Ipifc*, Block *bp)
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) {

View file

@ -33,7 +33,7 @@ static void etherunbind(Ipifc *ifc);
static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
static 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 @@ etherbind(Ipifc *ifc, int argc, char **argv)
poperror();
kproc("etherread4", etherread4, ifc);
kproc("recvarpproc", recvarpproc, ifc);
kproc("etherread6", etherread6, ifc);
kproc("recvarpproc", recvarpproc, ifc);
}
/*
@ -231,27 +231,27 @@ etherunbind(Ipifc *ifc)
{
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)
cclose(er->mchan6);
if(er->cchan6 != nil)
cclose(er->cchan6);
if(er->achan != nil)
cclose(er->achan);
free(er);
}
@ -329,7 +329,7 @@ etherread4(void *a)
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 @@ etherread6(void *a)
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 @@ recvarp(Ipifc *ifc)
if(ebp == nil)
return;
if(!canrlock(ifc)){
freeb(ebp);
return;
}
e = (Etherarp*)ebp->rp;
switch(nhgets(e->op)) {
default:
@ -647,8 +652,14 @@ recvarp(Ipifc *ifc)
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 @@ recvarpproc(void *v)
er->arpp = up;
if(waserror()){
er->arpp = 0;
er->arpp = nil;
pexit("hangup", 1);
}
for(;;)
@ -745,10 +756,10 @@ etherpref2addr(uchar *pref, uchar *ea)
}
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 @@ etherareg(Fs *f, Ipifc *ifc, uchar *ip, uchar *proxy)
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;
}
if(ipcmp(lifc->local, ip) != 0)
return;
/* temporarily add route for duplicate address detection */
ipv62smcast(mcast, ip);
addroute(f, mcast, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
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);
}

View file

@ -99,6 +99,7 @@ ip_init(Fs *f)
IP *ip;
ip = smalloc(sizeof(IP));
ip->stats[DefaultTTL] = MAXTTL;
initfrag(ip, 100);
f->ip = ip;
@ -362,7 +363,7 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
if(notforme) {
Route *r;
Routehint rh;
Ipifc *toifc;
Ipifc *nifc;
if(!ip->iprouting)
goto drop;
@ -370,8 +371,8 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
/* 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 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
}
/* 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 @@ ipstats(Fs *f, char *buf, int len)
int i;
ip = f->ip;
ip->stats[DefaultTTL] = MAXTTL;
p = buf;
e = p+len;
for(i = 0; i < Nipstats; i++)
@ -467,7 +466,7 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
/*
* 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 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
/*
* 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 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
}
/* 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 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
*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 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
* 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 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
/* 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 @@ ipfragfree4(IP *ip, Fragment4 *frag)
{
Fragment4 *fl, **l;
if(frag->blist)
if(frag->blist != nil)
freeblist(frag->blist);
frag->src = 0;
@ -630,7 +629,7 @@ ipfragfree4(IP *ip, Fragment4 *frag)
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 @@ ipfragallo4(IP *ip)
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);
}

View file

@ -243,7 +243,7 @@ struct Medium
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 int arpwrite(Fs*, char*, int);
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 pktmedium;
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);

View file

@ -61,6 +61,7 @@ static char tifc[] = "ifc ";
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 @@ ipifcunbind(Ipifc *ifc)
/* 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 @@ ipifcstate(Conv *c, char *state, int n)
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 @@ ipifclocal(Conv *c, char *state, int n)
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 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
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 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
/* 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 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
}
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 @@ done:
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 @@ ipifcconnect(Conv* c, char **argv, int argc)
wunlock(ifc);
err = ipifcadd(ifc, argv, argc, 0, nil);
if(err)
if(err != nil)
return err;
Fsconnected(c, nil);
@ -1069,18 +1063,6 @@ ipselftabread(Fs *f, char *cp, ulong offset, int n)
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 @@ Ipifc*
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 @@ findipifc(Fs *f, uchar *local, uchar *remote, int type)
}
}
}
runlock(ifc);
}
return x;
}
@ -1159,7 +1141,7 @@ findipifcstr(Fs *f, char *s)
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 @@ findipifcstr(Fs *f, char *s)
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 @@ findprimaryipv6(Fs *f, uchar *local)
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 @@ void
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,20 +1399,6 @@ ipismulticast(uchar *ip)
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 @@ void
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 @@ ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
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 @@ void
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 @@ ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
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 @@ ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
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);
}
}

View file

@ -31,7 +31,7 @@ int
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 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh)
/* 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 @@ free:
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 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
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 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
}
/* 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 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
/* 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 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
}
/* 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 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
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 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
/*
* 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 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
/*
* 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 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
}
/* 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 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
*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 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
* 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 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
* 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;