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 == ~0UL || \
+ (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
ifc->maxtu = ifc->m->maxtu;
if(ifc->m->unbindonclose == 0)
ifc->conv->inuse++;
- ifc->rp.mflag = 0; /* default not managed */
- ifc->rp.oflag = 0;
- ifc->rp.maxraint = 600000; /* millisecs */
- ifc->rp.minraint = 200000;
- ifc->rp.linkmtu = 0; /* no mtu sent */
- ifc->rp.reachtime = 0;
- ifc->rp.rxmitra = 0;
- ifc->rp.ttl = MAXTTL;
- ifc->rp.routerlt = 3 * ifc->rp.maxraint;
+
+ /* default router paramters */
+ ifc->rp = c->p->f->v6p->rp;
/* any ancillary structures (like routes) no longer pertain */
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 */
return nil;
}
-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";
+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 speed %d delay %d\n";
char slineformat[] = " %-40I %-10M %-40I %-12lud %-12lud\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)
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");
}
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'
*/
runlock(ifc);
nexterror();
}
- if(ifc->m && ifc->m->pktin)
+ if(ifc->m != nil && ifc->m->pktin != nil)
(*ifc->m->pktin)(c->p->f, ifc, bp);
else
freeb(bp);
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);
}
/*
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);
}
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);
/* 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)
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){
+ wunlock(ifc);
+ return "ipifc not yet bound to device";
+ }
+ f = ifc->conv->p->f;
if(waserror()){
wunlock(ifc);
- nexterror();
+ 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 */
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;
lifc->origint = lifcp->origint;
} else { /* default values */
lifc->onlink = lifc->autoflag = 1;
- lifc->validlt = lifc->preflt = ~0L;
+ lifc->validlt = lifc->preflt = ~0UL;
lifc->origint = NOW / 1000;
}
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];
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)
- (*ifc->m->areg)(ifc, ip);
-
-out:
+done:
wunlock(ifc);
poperror();
- if(tentative && sendnbrdisc)
- icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
+ ipifcregisteraddr(f, ifc, ip, ip);
+
return nil;
}
* 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;
}
{
char *rv;
uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
- Iplifc *lifc;
+ Iplifc *lifc, **l;
if(argc < 3)
return Ebadarg;
-
- if (parseip(ip, argv[1]) == -1)
+ if(parseip(ip, argv[1]) == -1)
return Ebadip;
parseipmask(mask, argv[2]);
if(argc < 4)
maskip(ip, mask, rem);
- else
- if (parseip(rem, argv[3]) == -1)
- return Ebadip;
+ else if(parseip(rem, argv[3]) == -1)
+ return Ebadip;
/*
* find address on this interface and remove from chain.
* addresss to remove.
*/
wlock(ifc);
+ l = &ifc->lifc;
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
- if (memcmp(ip, lifc->local, IPaddrlen) == 0
- && memcmp(mask, lifc->mask, IPaddrlen) == 0
- && memcmp(rem, lifc->remote, IPaddrlen) == 0)
+ if(ipcmp(ip, lifc->local) == 0
+ && ipcmp(mask, lifc->mask) == 0
+ && ipcmp(rem, lifc->remote) == 0)
break;
+ l = &lifc->next;
}
- rv = ipifcremlifc(ifc, lifc);
+ rv = ipifcremlifc(ifc, l);
wunlock(ifc);
return rv;
}
-/*
- * distribute routes to active interfaces like the
- * TRIP linecards
- */
-void
-ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
-{
- Medium *m;
- Conv **cp, **e;
- Ipifc *ifc;
-
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp != nil) {
- ifc = (Ipifc*)(*cp)->ptcl;
- m = ifc->m;
- if(m && m->addroute)
- (*m->addroute)(ifc, vers, addr, mask, gate, type);
- }
- }
-}
-
-void
-ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
-{
- Medium *m;
- Conv **cp, **e;
- Ipifc *ifc;
-
- e = &f->ipifc->conv[f->ipifc->nc];
- for(cp = f->ipifc->conv; cp < e; cp++){
- if(*cp != nil) {
- ifc = (Ipifc*)(*cp)->ptcl;
- m = ifc->m;
- if(m && m->remroute){
- if(!waserror()){
- (*m->remroute)(ifc, vers, addr, mask);
- poperror();
- }
- }
- }
- }
-}
-
/*
* associate an address with the interface. This wipes out any previous
* addresses. This is a macro that means, remove all the old interfaces
return "ipifc not yet bound to device";
wlock(ifc);
- while(ifc->lifc){
- err = ipifcremlifc(ifc, ifc->lifc);
- if(err){
+ while(ifc->lifc != nil){
+ err = ipifcremlifc(ifc, &ifc->lifc);
+ if(err != nil){
wunlock(ifc);
return err;
}
wunlock(ifc);
err = ipifcadd(ifc, argv, argc, 0, nil);
- if(err)
+ if(err != nil)
return err;
Fsconnected(c, nil);
char*
ipifcra6(Ipifc *ifc, char **argv, int argc)
{
- int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
+ int i, argsleft;
+ uchar sendra, recvra;
+ Routerparams rp;
- argsleft = argc - 1;
i = 1;
-
- if(argsleft % 2 != 0)
+ argsleft = argc - 1;
+ if((argsleft % 2) != 0)
return Ebadarg;
+ sendra = ifc->sendra6;
+ recvra = ifc->recvra6;
+ rp = ifc->rp;
+
while (argsleft > 1) {
if(strcmp(argv[i], "recvra") == 0)
- ifc->recvra6 = (atoi(argv[i+1]) != 0);
+ recvra = atoi(argv[i+1]) != 0;
else if(strcmp(argv[i], "sendra") == 0)
- ifc->sendra6 = (atoi(argv[i+1]) != 0);
+ sendra = atoi(argv[i+1]) != 0;
else if(strcmp(argv[i], "mflag") == 0)
- ifc->rp.mflag = (atoi(argv[i+1]) != 0);
+ rp.mflag = atoi(argv[i+1]) != 0;
else if(strcmp(argv[i], "oflag") == 0)
- ifc->rp.oflag = (atoi(argv[i+1]) != 0);
+ rp.oflag = atoi(argv[i+1]) != 0;
else if(strcmp(argv[i], "maxraint") == 0)
- ifc->rp.maxraint = atoi(argv[i+1]);
+ rp.maxraint = atoi(argv[i+1]);
else if(strcmp(argv[i], "minraint") == 0)
- ifc->rp.minraint = atoi(argv[i+1]);
+ rp.minraint = atoi(argv[i+1]);
else if(strcmp(argv[i], "linkmtu") == 0)
- ifc->rp.linkmtu = atoi(argv[i+1]);
+ rp.linkmtu = atoi(argv[i+1]);
else if(strcmp(argv[i], "reachtime") == 0)
- ifc->rp.reachtime = atoi(argv[i+1]);
+ rp.reachtime = atoi(argv[i+1]);
else if(strcmp(argv[i], "rxmitra") == 0)
- ifc->rp.rxmitra = atoi(argv[i+1]);
+ rp.rxmitra = atoi(argv[i+1]);
else if(strcmp(argv[i], "ttl") == 0)
- ifc->rp.ttl = atoi(argv[i+1]);
+ rp.ttl = atoi(argv[i+1]);
else if(strcmp(argv[i], "routerlt") == 0)
- ifc->rp.routerlt = atoi(argv[i+1]);
+ rp.routerlt = atoi(argv[i+1]);
else
return Ebadarg;
}
/* consistency check */
- if(ifc->rp.maxraint < ifc->rp.minraint) {
- ifc->rp.maxraint = vmax;
- ifc->rp.minraint = vmin;
+ if(rp.maxraint < rp.minraint)
return Ebadarg;
- }
+
+ ifc->rp = rp;
+ ifc->sendra6 = sendra;
+ ifc->recvra6 = recvra;
+
return nil;
}
* 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)
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)
return ipifcadd6(ifc, argv, argc);
+ else if(strcmp(argv[0], "remove6") == 0)
+ return ipifcremove6(ifc, argv, argc);
else if(strcmp(argv[0], "ra6") == 0)
return ipifcra6(ifc, argv, argc);
return "unsupported ctl";
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);
/* 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 */
}
/* 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;
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)
+ if((type & Rmulti) && ifc->m->addmulti != nil)
(*ifc->m->addmulti)(ifc, a, lifc->local);
} else
lp->ref++;
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;
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;
/* 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;
* 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;
* 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;
if(--(link->ref) != 0)
goto out;
- if((p->type & Rmulti) && ifc->m->remmulti){
+ /* 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();
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)
{
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;
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;
}
* 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 || ipcmp(lifc->local, IPnoaddr) == 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 != nil; lifc = lifc->next){
+ if(lifc->tentative)
+ continue;
- for(lifc = ifc->lifc; lifc; lifc = lifc->next){
- if(!isv4(lifc->local) && !(lifc->tentative)){
- ipmove(addr, lifc->local);
- return 1;
+ 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(lifc = ifc->lifc; lifc; lifc = lifc->next){
- if(!isv4(lifc->local)){
- ipmove(addr, lifc->local);
- return SRC_UNI;
+ 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 || (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
*/
{
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;
}
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;
}
/*
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
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;
+ if(isv4(ma) != isv4(ia))
+ error("incompatible multicast/interface ip address");
- 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 */
- multi = *l = smalloc(sizeof(*multi));
- ipmove(multi->ma, ma);
- 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();
}
- 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();
}
+
+ multi = smalloc(sizeof(*multi));
+ ipmove(multi->ma, ma);
+ ipmove(multi->ia, ia);
+ multi->next = nil;
+ *l = multi;
}
{
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;
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;
+ 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);
}
-
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;
- }
- if(waserror()){
- runlock(nifc);
- nexterror();
- }
- for(lifc = nifc->lifc; lifc; lifc = lifc->next){
- maskip(ip, lifc->mask, net);
- if(ipcmp(net, lifc->remote) == 0) {
- /* add solicited-node multicast addr */
- ipv62smcast(net, ip);
- addselfcache(f, nifc, lifc, net, Rmulti);
- arpenter(f, V6, ip, nifc->mac, 6, 0);
- // (*m->addmulti)(nifc, net, ip);
- break;
- }
- }
- runlock(nifc);
- poperror();
+ 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;
- }
- if(waserror()){
- runlock(nifc);
- nexterror();
- }
- for(lifc = nifc->lifc; lifc; lifc = lifc->next){
- maskip(ip, lifc->mask, net);
- if(ipcmp(net, lifc->remote) == 0){
- (*m->areg)(nifc, ip);
- break;
- }
- }
- runlock(nifc);
- poperror();
+ 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 = lifc.preflt = ~0UL;
+ lifc.origint = NOW / 1000;
switch(argc) {
case 7:
- preflt = atoi(argv[6]);
+ lifc.preflt = strtoul(argv[6], 0, 10);
/* fall through */
case 6:
- validlt = atoi(argv[5]);
+ lifc.validlt = strtoul(argv[5], 0, 10);
/* 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]);
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 == nil)
return Ebadarg;
(*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);
+}
+
+char*
+ipifcremove6(Ipifc *ifc, char**, int argc)
+{
+ Iplifc *lifc, **l;
+
+ if(argc != 1)
+ return Ebadarg;
+
+ wlock(ifc);
+ for(l = &ifc->lifc; (lifc = *l) != nil;) {
+ if((lifc->type & Rv4) == 0)
+ if(lifc->validlt != ~0UL && lifc->origint + lifc->validlt < NOW/1000){
+ if(ipifcremlifc(ifc, l) == nil)
+ continue;
+ }
+ l = &lifc->next;
+ }
+ wunlock(ifc);
+
+ return nil;
}