X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=sys%2Fsrc%2F9%2Fip%2Fipifc.c;h=29b82e61a003cad8a87164ad2c172512c5bae356;hb=71402b2ea15d0e2bf939b6e095ad56fa14ab2d0a;hp=ffb1ad225d1d52414278ed288c1641b13483ac65;hpb=9500191af630673a28266cab9b4e109275847c90;p=plan9front.git diff --git a/sys/src/9/ip/ipifc.c b/sys/src/9/ip/ipifc.c index ffb1ad225..29b82e61a 100644 --- a/sys/src/9/ip/ipifc.c +++ b/sys/src/9/ip/ipifc.c @@ -61,10 +61,46 @@ 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 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 ipifcregisteraddr(Fs*, Ipifc*, uchar *, uchar *); +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 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 @@ -174,33 +210,26 @@ ipifcunbind(Ipifc *ifc) { char *err; + wlock(ifc); if(waserror()){ wunlock(ifc); nexterror(); } - wlock(ifc); - - /* dissociate routes */ - if(ifc->m != nil && ifc->m->unbindonclose == 0) - ifc->conv->inuse--; - ifc->ifcid++; /* disassociate logical interfaces (before zeroing ifc->arg) */ - while(ifc->lifc){ - err = ipifcremlifc(ifc, ifc->lifc); - /* - * note: err non-zero means lifc not found, - * which can't happen in this case. - */ - if(err) + while(ifc->lifc != nil){ + err = ipifcremlifc(ifc, &ifc->lifc); + 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; + + ifc->reflect = 0; ifc->reassemble = 0; /* close queues to stop queuing of packets */ @@ -208,7 +237,12 @@ ipifcunbind(Ipifc *ifc) qclose(ifc->conv->wq); qclose(ifc->conv->sq); + /* dissociate routes */ + ifc->ifcid++; + if(ifc->m != nil && ifc->m->unbindonclose == 0) + ifc->conv->inuse--; ifc->m = nil; + wunlock(ifc); poperror(); return nil; @@ -216,7 +250,7 @@ ipifcunbind(Ipifc *ifc) char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag" " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt" -" %d pktin %lud pktout %lud errin %lud errout %lud\n"; +" %d pktin %lud pktout %lud errin %lud errout %lud speed %d delay %d\n"; char slineformat[] = " %-40I %-10M %-40I %-12lud %-12lud\n"; @@ -233,10 +267,11 @@ ipifcstate(Conv *c, char *state, int n) ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint, ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime, ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt, - ifc->in, ifc->out, ifc->inerr, ifc->outerr); + ifc->in, ifc->out, ifc->inerr, ifc->outerr, + ifc->speed, ifc->delay); 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) @@ -254,12 +289,11 @@ ipifclocal(Conv *c, char *state, int n) int m; ifc = (Ipifc*)c->ptcl; - m = 0; - rlock(ifc); - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ + 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; 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"); } @@ -276,6 +310,50 @@ ipifcinuse(Conv *c) return ifc->m != nil; } +static void +ipifcsetdelay(Ipifc *ifc, int delay) +{ + if(delay < 0) + delay = 0; + else if(delay > 1000) + delay = 1000; + ifc->delay = delay; + ifc->burst = ((vlong)delay * ifc->speed) / 8000; + if(ifc->burst < ifc->maxtu) + ifc->burst = ifc->maxtu; +} + +static void +ipifcsetspeed(Ipifc *ifc, int speed) +{ + if(speed < 0) + speed = 0; + ifc->speed = speed; + ifc->load = 0; + ipifcsetdelay(ifc, ifc->delay); +} + +void +ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip) +{ + if(ifc->speed){ + ulong now = MACHP(0)->ticks; + int dt = TK2MS(now - ifc->ticks); + ifc->ticks = now; + ifc->load -= ((vlong)dt * ifc->speed) / 8000; + if(ifc->load < 0 || dt < 0 || dt > 1000) + ifc->load = 0; + else if(ifc->load > ifc->burst){ + freeblist(bp); + return; + } + } + bp = concatblock(bp); + ifc->load += BLEN(bp); + ifc->m->bwrite(ifc, bp, version, ip); +} + + /* * called when a process writes to an interface's 'data' */ @@ -299,10 +377,10 @@ ipifckick(void *x) runlock(ifc); nexterror(); } - if(ifc->m == nil || ifc->m->pktin == nil) - freeb(bp); - else + if(ifc->m != nil && ifc->m->pktin != nil) (*ifc->m->pktin)(c->p->f, ifc, bp); + else + freeb(bp); runlock(ifc); poperror(); } @@ -322,9 +400,11 @@ ipifccreate(Conv *c) error(Enomem); ifc = (Ipifc*)c->ptcl; ifc->conv = c; - ifc->unbinding = 0; ifc->m = nil; + ifc->reflect = 0; ifc->reassemble = 0; + ipifcsetspeed(ifc, 0); + ipifcsetdelay(ifc, 40); } /* @@ -335,11 +415,9 @@ static void 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,17 +444,13 @@ ipifcsetmtu(Ipifc *ifc, char **argv, int argc) 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; Fs *f; - if(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); @@ -388,8 +462,6 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) /* fall through */ case 5: mtu = strtoul(argv[4], 0, 0); - if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu) - ifc->maxtu = mtu; /* fall through */ case 4: if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1) @@ -414,24 +486,46 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) 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(ifc->m == nil) + return "ipifc not yet bound to device"; + + f = ifc->conv->p->f; + if(waserror()){ + wunlock(ifc); + return up->errstr; + } + + if(mtu > 0 && mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu) + ifc->maxtu = mtu; /* 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 */ @@ -440,8 +534,9 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) 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; @@ -454,29 +549,25 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) } 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; - - /* add local routes */ - if(isv4(ip)) - v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type); - else - v6addroute(f, tifc, rem, mask, rem, type); + /* add route for this logical interface */ + addroute(f, rem, mask, ip, IPallbits, rem, type, ifc, tifc); + if(v6addrtype(ip) != linklocalv6) + addroute(f, rem, mask, ip, IPnoaddr, rem, type, ifc, tifc); 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]; @@ -500,39 +591,36 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) 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 */ 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 != nil) - (*ifc->m->areg)(ifc, ip); - -out: +done: wunlock(ifc); - if(tentative && sendnbrdisc) - icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac); + poperror(); + + ipifcregisteraddr(f, ifc, ip, ip); + return nil; } @@ -541,41 +629,48 @@ out: * always called with ifc wlock'd */ static char* -ipifcremlifc(Ipifc *ifc, Iplifc *lifc) +ipifcremlifc(Ipifc *ifc, Iplifc **l) { - Iplifc **l; - Fs *f; - - f = ifc->conv->p->f; + Iplifc *lifc = *l; + Fs *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, IPallbits, + lifc->remote, lifc->type, ifc, tifc); + if(v6addrtype(lifc->local) != linklocalv6) + remroute(f, lifc->remote, lifc->mask, + lifc->local, IPnoaddr, + 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; } @@ -589,79 +684,37 @@ ipifcrem(Ipifc *ifc, char **argv, int argc) { 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; - - wlock(ifc); + else if(parseip(rem, argv[3]) == -1) + return Ebadip; /* * find address on this interface and remove from chain. * for pt to pt we actually specify the remote address as the * 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) - m->remroute(ifc, vers, addr, mask); - } - } -} - /* * associate an address with the interface. This wipes out any previous * addresses. This is a macro that means, remove all the old interfaces @@ -678,21 +731,18 @@ ipifcconnect(Conv* c, char **argv, int argc) if(ifc->m == nil) return "ipifc not yet bound to device"; - if(waserror()){ - wunlock(ifc); - nexterror(); - } wlock(ifc); - while(ifc->lifc){ - err = ipifcremlifc(ifc, ifc->lifc); - if(err) - error(err); + while(ifc->lifc != nil){ + err = ipifcremlifc(ifc, &ifc->lifc); + if(err != nil){ + wunlock(ifc); + return err; + } } wunlock(ifc); - poperror(); err = ipifcadd(ifc, argv, argc, 0, nil); - if(err) + if(err != nil) return err; Fsconnected(c, nil); @@ -754,10 +804,9 @@ ipifcra6(Ipifc *ifc, char **argv, int argc) * 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; ifc = (Ipifc*)c->ptcl; if(strcmp(argv[0], "add") == 0) @@ -768,21 +817,26 @@ ipifcctl(Conv* c, char**argv, int argc) 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){ - ifc->reassemble = 1; + else if(strcmp(argv[0], "speed") == 0){ + ipifcsetspeed(ifc, argc>1? atoi(argv[1]): 0); + return nil; + } + else if(strcmp(argv[0], "delay") == 0){ + ipifcsetdelay(ifc, argc>1? atoi(argv[1]): 0); return nil; } else if(strcmp(argv[0], "iprouting") == 0){ - i = 1; - if(argc > 1) - i = atoi(argv[1]); - iprouting(c->p->f, i); + iprouting(c->p->f, argc>1? atoi(argv[1]): 1); + return nil; + } + else if(strcmp(argv[0], "reflect") == 0){ + ifc->reflect = argc>1? atoi(argv[1]): 1; + return nil; + } + else if(strcmp(argv[0], "reassemble") == 0){ + ifc->reassemble = argc>1? atoi(argv[1]): 1; return nil; } else if(strcmp(argv[0], "add6") == 0) @@ -834,16 +888,22 @@ ipifcinit(Fs *f) 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); + nexterror(); + } /* 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 */ @@ -860,7 +920,7 @@ addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) } /* 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; @@ -876,11 +936,11 @@ addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) 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, + ((type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ? + IPallbits : IPnoaddr, + a, type, ifc, tifc); if((type & Rmulti) && ifc->m->addmulti != nil) (*ifc->m->addmulti)(ifc, a, lifc->local); @@ -888,6 +948,7 @@ addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) lp->ref++; qunlock(f->self); + poperror(); } /* @@ -906,8 +967,8 @@ iplinkfree(Iplink *p) 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; @@ -926,8 +987,8 @@ ipselffree(Ipself *p) 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; @@ -954,7 +1015,7 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) /* 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; @@ -968,7 +1029,7 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) * 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; @@ -982,7 +1043,7 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) * 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; @@ -994,8 +1055,19 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) if(--(link->ref) != 0) goto out; - if((p->type & Rmulti) && ifc->m->remmulti != nil) - (*ifc->m->remmulti)(ifc, a, lifc->local); + /* remove from routing table */ + remroute(f, a, IPallbits, + lifc->local, + ((p->type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ? + IPallbits : IPnoaddr, + a, p->type, ifc, tifc); + + if((p->type & Rmulti) && ifc->m->remmulti != nil){ + if(!waserror()){ + (*ifc->m->remmulti)(ifc, a, lifc->local); + poperror(); + } + } /* ref == 0, remove from both chains and free the link */ *l_lifc = link->lifclink; @@ -1005,30 +1077,18 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) 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) { @@ -1043,10 +1103,11 @@ ipselftabread(Fs *f, char *cp, ulong offset, int n) 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; @@ -1057,40 +1118,26 @@ ipselftabread(Fs *f, char *cp, ulong offset, int n) return m; } -int -iptentative(Fs *f, uchar *addr) -{ - Ipself *p; - - p = f->self->hash[hashipa(addr)]; - for(; p; p = p->next){ - if(ipcmp(addr, p->a) == 0) - return p->link->lifc->tentative; - } - return 0; -} - /* * returns * 0 - no match * Runi * Rbcast - * Rmcast + * Rmulti */ int ipforme(Fs *f, uchar *addr) { 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; } @@ -1099,260 +1146,254 @@ ipforme(Fs *f, uchar *addr) * return nil. */ Ipifc* -findipifc(Fs *f, uchar *remote, int type) +findipifc(Fs *f, uchar *local, uchar *remote, int type) { + uchar gnet[IPaddrlen]; + int spec, xspec; Ipifc *ifc, *x; Iplifc *lifc; - Conv **cp, **e; - uchar gnet[IPaddrlen], xmask[IPaddrlen]; + Conv **cp; x = nil; - memset(xmask, 0, IPaddrlen); - - /* find most specific match */ - e = &f->ipifc->conv[f->ipifc->nc]; - for(cp = f->ipifc->conv; cp < e; cp++){ - if(*cp == 0) - continue; + xspec = 0; + for(cp = f->ipifc->conv; *cp != nil; cp++){ ifc = (Ipifc*)(*cp)->ptcl; - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ + rlock(ifc); + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ + if(type & Runi){ + if(ipcmp(remote, lifc->local) == 0){ + Found: + runlock(ifc); + return ifc; + } + } else if(type & (Rbcast|Rmulti)) { + if(ipcmp(local, lifc->local) == 0) + goto Found; + } 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; } } } + runlock(ifc); } - if(x != nil) - 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; - } - } - return nil; + return x; } -enum { - unknownv6, /* UGH */ -// multicastv6, - unspecifiedv6, - linklocalv6, - globalv6, -}; - -int -v6addrtype(uchar *addr) +Ipifc* +findipifcstr(Fs *f, char *s) { - 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; + 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 && ipifcinuse(c)) + return (Ipifc*)c->ptcl; + } + if(parseip(ip, s) != -1) + return findipifc(f, ip, ip, Runi); + return nil; } -#define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \ - (lifc)->origint + (lifc)->preflt >= NOW/1000) - +/* + * 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 == 0) - continue; + for(cp = f->ipifc->conv; *cp != nil; cp++){ ifc = (Ipifc*)(*cp)->ptcl; - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ + 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); } } /* - * returns first ip address configured + * returns first v4 address configured */ 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 == 0) - continue; + for(cp = f->ipifc->conv; *cp != nil; cp++){ ifc = (Ipifc*)(*cp)->ptcl; - if((lifc = ifc->lifc) != nil){ - 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); } /* - * find the local address 'closest' to the remote system, copy it to - * local and return the ifc for that address + * return v4 address associated with an interface close to remote */ -void -findlocalip(Fs *f, uchar *local, uchar *remote) +int +ipv4local(Ipifc *ifc, uchar *local, uchar *remote) { - int version, atype = unspecifiedv6, atypel = unknownv6; - int atyper, deprecated; - uchar gate[IPaddrlen], gnet[IPaddrlen]; - Ipifc *ifc; Iplifc *lifc; - Route *r; - - USED(atype); - USED(atypel); - qlock(f->ipifc); - r = v6lookup(f, remote, nil); - version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6; - - if(r != nil){ - ifc = r->ifc; - if(r->type & Rv4) - v4tov6(gate, r->v4.gate); - else { - ipmove(gate, r->v6.gate); - ipmove(local, v6Unspecified); - } + int a, b; - switch(version) { - case V4: - /* find ifc address closest to the gateway to use */ - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ - maskip(gate, lifc->mask, gnet); - if(ipcmp(gnet, lifc->net) == 0){ - ipmove(local, lifc->local); - goto out; - } - } - break; - case V6: - /* find ifc address with scope matching the destination */ - atyper = v6addrtype(remote); - deprecated = 0; - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ - atypel = v6addrtype(lifc->local); - /* prefer appropriate scope */ - if(atypel > atype && atype < atyper || - atypel < atype && atype > atyper){ - ipmove(local, lifc->local); - deprecated = !v6addrcurr(lifc); - atype = atypel; - } else if(atypel == atype){ - /* avoid deprecated addresses */ - if(deprecated && v6addrcurr(lifc)){ - ipmove(local, lifc->local); - atype = atypel; - deprecated = 0; - } - } - if(atype == atyper && !deprecated) - goto out; - } - if(atype >= atyper) - goto out; - break; - default: - panic("findlocalip: version %d", version); + b = -1; + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ + if((lifc->type & Rv4) == 0) + continue; + a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen); + if(a > b){ + b = a; + memmove(local, lifc->local+IPv4off, IPv4addrlen); } } - - switch(version){ - case V4: - findprimaryipv4(f, local); - break; - case V6: - findprimaryipv6(f, local); - break; - default: - panic("findlocalip2: version %d", version); - } - -out: - qunlock(f->ipifc); + return b >= 0; } /* - * return first v4 address associated with an interface + * return v6 address associated with an interface close to remote */ int -ipv4local(Ipifc *ifc, uchar *addr) +ipv6local(Ipifc *ifc, uchar *local, uchar *remote) { + struct { + int atype; + int deprecated; + int comprefixlen; + } a, b; + int atype; Iplifc *lifc; - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ - if(isv4(lifc->local)){ - memmove(addr, lifc->local+IPv4off, IPv4addrlen); - return 1; - } + if(isv4(remote)){ + ipmove(local, v4prefix); + return ipv4local(ifc, local+IPv4off, remote+IPv4off); } - return 0; -} -/* - * return first v6 address associated with an interface - */ -int -ipv6local(Ipifc *ifc, uchar *addr) -{ - Iplifc *lifc; + atype = v6addrtype(remote); + ipmove(local, v6Unspecified); + b.atype = unknownv6; + b.deprecated = 1; + b.comprefixlen = 0; - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ - if(!isv4(lifc->local) && !(lifc->tentative)){ - ipmove(addr, lifc->local); - return 1; + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ + if(lifc->tentative) + continue; + + a.atype = v6addrtype(lifc->local); + a.deprecated = !v6addrcurr(lifc); + a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen); + + /* prefer appropriate scope */ + if(a.atype != b.atype){ + if(a.atype > b.atype && b.atype < atype || + a.atype < b.atype && b.atype > atype) + goto Good; + continue; } + /* prefer non-deprecated addresses */ + if(a.deprecated != b.deprecated){ + if(b.deprecated) + goto Good; + continue; + } + /* prefer longer common prefix */ + if(a.comprefixlen != b.comprefixlen){ + if(a.comprefixlen > b.comprefixlen) + goto Good; + continue; + } + continue; + Good: + b = a; + ipmove(local, lifc->local); } - return 0; + + return b.atype >= atype; } -int -ipv6anylocal(Ipifc *ifc, uchar *addr) +void +findlocalip(Fs *f, uchar *local, uchar *remote) { + Route *r; Iplifc *lifc; + Ipifc *ifc, *nifc; + Conv **cp; + + 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; - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ - if(!isv4(lifc->local)){ - ipmove(addr, lifc->local); - return SRC_UNI; + r = v6lookup(f, remote, lifc->local, nil); + if(r == nil || (nifc = r->ifc) == nil) + continue; + if(r->type & Runi){ + ipmove(local, remote); + runlock(ifc); + return; + } + if(nifc != ifc) rlock(nifc); + if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){ + ipmove(local, v4prefix); + if(ipv4local(nifc, local+IPv4off, r->v4.gate)){ + if(nifc != ifc) runlock(nifc); + runlock(ifc); + return; + } + } + if(ipv6local(nifc, local, remote)){ + if(nifc != ifc) runlock(nifc); + runlock(ifc); + return; + } + if(nifc != ifc) runlock(nifc); } + runlock(ifc); } - return SRC_UNSPEC; + if(isv4(remote)) + findprimaryipv4(f, local); + else + findprimaryipv6(f, local); } + /* * see if this address is bound to the interface */ @@ -1361,9 +1402,24 @@ iplocalonifc(Ipifc *ifc, uchar *ip) { 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; } @@ -1375,21 +1431,13 @@ int 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; } /* @@ -1406,20 +1454,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 @@ -1427,15 +1461,12 @@ ipisbm(uchar *ip) void ipifcaddmulti(Conv *c, uchar *ma, uchar *ia) { - Ipifc *ifc; - Iplifc *lifc; - Conv **p; Ipmulti *multi, **l; + 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 */ @@ -1444,18 +1475,15 @@ ipifcaddmulti(Conv *c, uchar *ma, uchar *ia) ipmove(multi->ia, ia); multi->next = nil; - for(p = f->ipifc->conv; *p; p++){ - if((*p)->inuse == 0) - continue; - ifc = (Ipifc*)(*p)->ptcl; + f = c->p->f; + if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){ + wlock(ifc); if(waserror()){ wunlock(ifc); nexterror(); } - wlock(ifc); - 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(); } @@ -1470,13 +1498,10 @@ ipifcremmulti(Conv *c, uchar *ma, uchar *ia) { Ipmulti *multi, **l; 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; @@ -1485,148 +1510,106 @@ ipifcremmulti(Conv *c, uchar *ma, uchar *ia) return; /* we don't have it open */ *l = multi->next; + multi->next = nil; - for(p = f->ipifc->conv; *p; p++){ - if((*p)->inuse == 0) - continue; - - ifc = (Ipifc*)(*p)->ptcl; - if(waserror()){ - wunlock(ifc); - nexterror(); - } + f = c->p->f; + if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){ wlock(ifc); - for(lifc = ifc->lifc; lifc; lifc = lifc->next) - if(ipcmp(ia, lifc->local) == 0) + if(!waserror()){ + if((lifc = iplocalonifc(ifc, ia)) != nil) remselfcache(f, ifc, lifc, ma); + poperror(); + } wunlock(ifc); - poperror(); } - free(multi); } -/* - * make lifc's join and leave multicast groups - */ -static char* -ipifcjoinmulti(Ipifc *ifc, char **argv, int argc) +/* register the address on this network for address resolution */ +static void +ipifcregisteraddr(Fs *f, Ipifc *ifc, uchar *ia, uchar *ip) { - USED(ifc, argv, argc); - return nil; -} + Iplifc *lifc; -static char* -ipifcleavemulti(Ipifc *ifc, char **argv, int argc) -{ - USED(ifc, argv, argc); - return nil; + 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) +ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add) { - Conv **cp, **e; - Ipifc *nifc; + uchar a[IPaddrlen]; Iplifc *lifc; - Medium *m; - uchar net[IPaddrlen]; + Ipifc *nifc; + Conv **cp; - /* register the address on any network that will proxy for us */ - e = &f->ipifc->conv[f->ipifc->nc]; + /* register the address on any interface that will proxy for the ip */ + for(cp = f->ipifc->conv; *cp != nil; cp++){ + nifc = (Ipifc*)(*cp)->ptcl; + if(nifc == 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; - } - 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); - // (*m->addmulti)(nifc, net, ip); - break; - } - } - runlock(nifc); + wlock(nifc); + if(nifc->m == nil + || (lifc = ipremoteonifc(nifc, ip)) == nil + || (lifc->type & Rptpt) != 0 + || 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; - } - 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); + 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); } - } -} - - -/* added for new v6 mesg types */ -static void -adddefroute6(Fs *f, uchar *gate, int force) -{ - Route *r; - - r = v6lookup(f, v6Unspecified, nil); - /* - * route entries generated by all other means take precedence - * over router announcements. - */ - if (r && !force && strcmp(r->tag, "ra") != 0) - return; + ipmove(a, lifc->local); + wunlock(nifc); + poperror(); - v6delroute(f, v6Unspecified, v6Unspecified, 1); - v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0); + if(add) + ipifcregisteraddr(f, nifc, a, ip); + } } -enum { - Ngates = 3, -}; - char* ipifcadd6(Ipifc *ifc, char**argv, int argc) { int plen = 64; - long origint = NOW / 1000, preflt = ~0L, validlt = ~0L; char addr[40], preflen[6]; char *params[3]; - uchar autoflag = 1, onlink = 1; uchar prefix[IPaddrlen]; - Iplifc *lifc; + Iplifc lifc; + + lifc.onlink = 1; + lifc.autoflag = 1; + lifc.validlt = ~0L; + lifc.preflt = ~0L; + lifc.origint = NOW / 1000; switch(argc) { case 7: - preflt = atoi(argv[6]); + lifc.preflt = atoi(argv[6]); /* fall through */ case 6: - validlt = atoi(argv[5]); + lifc.validlt = atoi(argv[5]); /* fall through */ case 5: - autoflag = atoi(argv[4]); + lifc.autoflag = atoi(argv[4]) != 0; /* fall through */ case 4: - onlink = atoi(argv[3]); + lifc.onlink = atoi(argv[3]) != 0; /* fall through */ case 3: plen = atoi(argv[2]); @@ -1637,26 +1620,20 @@ ipifcadd6(Ipifc *ifc, char**argv, int argc) return Ebadarg; } - if (parseip(prefix, argv[1]) != 6 || validlt < preflt || plen < 0 || + if (parseip(prefix, argv[1]) != 6 || lifc.validlt < lifc.preflt || plen < 0 || plen > 64 || islinklocal(prefix)) return Ebadarg; - lifc = smalloc(sizeof(Iplifc)); - lifc->onlink = (onlink != 0); - lifc->autoflag = (autoflag != 0); - lifc->validlt = validlt; - lifc->preflt = preflt; - lifc->origint = origint; - /* issue "add" ctl msg for v6 link-local addr and prefix len */ - if(!ifc->m->pref2addr) + if(ifc->m->pref2addr == nil) return Ebadarg; - ifc->m->pref2addr(prefix, ifc->mac); /* mac → v6 link-local addr */ + (*ifc->m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */ + sprint(addr, "%I", prefix); sprint(preflen, "/%d", plen); params[0] = "add"; params[1] = addr; params[2] = preflen; - return ipifcadd(ifc, params, 3, 0, lifc); + return ipifcadd(ifc, params, 3, 0, &lifc); }