M ip/ethermedium.c => ip/ethermedium.c +9 -17
@@ 45,6 45,7 @@ Medium ethermedium =
nil, /* flushroute */
nil, /* joinmulti */
nil, /* leavemulti */
+ 0, /* don't unbind on last close */
};
typedef struct Etherrock Etherrock;
@@ 205,7 206,7 @@ etherunbind(Ipifc *ifc)
}
/*
- * called by ipoput with a single block to write
+ * called by ipoput with a single block to write with ifc rlock'd
*/
static void
etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
@@ 215,17 216,6 @@ etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
uchar mac[6];
Etherrock *er = ifc->arg;
- if(waserror()) {
- print("etherbwrite failed\n");
- ipifccheckout(ifc);
- return;
- }
- if(ipifccheckin(ifc, ðermedium) < 0){
- freeb(bp);
- poperror();
- return;
- }
-
/* get mac address of destination */
a = arpget(bp, version, ðermedium, ip, mac);
if(a){
@@ 233,7 223,7 @@ etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
bp = multicastarp(a, mac);
if(bp == nil){
sendarp(ifc, a);
- goto out;
+ return;
}
}
@@ 261,10 251,6 @@ etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
devtab[er->mchan->type]->bwrite(er->mchan, bp, 0);
ifc->out++;
-
-out:
- ipifccheckout(ifc);
- poperror();
}
/*
@@ 276,22 262,28 @@ etherread(void *a)
Ipifc *ifc;
Block *bp;
Etherrock *er;
+ int locked = 0;
ifc = a;
er = ifc->arg;
er->readp = up; /* hide identity under a rock for unbind */
if(waserror()){
+ if(locked)
+ runlock(ifc);
er->readp = 0;
pexit("hangup", 1);
}
for(;;){
bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxmtu, 0);
+ rlock(ifc); locked = 1; USED(locked);
ifc->in++;
bp->rp += ifc->m->hsize;
if(ifc->lifc == nil)
freeb(bp);
else
ipiput(ifc->lifc->local, bp);
+ runlock(ifc); locked = 0; USED(locked);
+
}
}
M ip/il.c => ip/il.c +1 -0
@@ 347,6 347,7 @@ ilxstats(char *buf, int len)
il.csumerr, il.hlenerr, il.lenerr, il.order, il.rexmit);
n += snprint(buf+n, len-n, " dupp %d dupb %d\n",
ilstats.dup, ilstats.dupb);
+ return n;
}
void
M ip/ip.c => ip/ip.c +13 -1
@@ 127,6 127,14 @@ ipoput(Block *bp, int gating, int ttl)
}
ifc = r->ifc;
+ if(waserror()){
+ runlock(ifc);
+ nexterror();
+ }
+ rlock(ifc);
+ if(ifc->m == nil)
+ goto raise;
+
/* If we dont need to fragment just send it */
medialen = ifc->m->maxmtu - ifc->m->hsize;
if(len <= medialen) {
@@ 141,6 149,8 @@ ipoput(Block *bp, int gating, int ttl)
/*print("ipoput %V->%V via %V\n", eh->src, eh->dst, gate);*/
ifc->m->bwrite(ifc, bp, V4, gate);
+ runlock(ifc);
+ poperror();
return;
}
@@ 203,7 213,7 @@ ipoput(Block *bp, int gating, int ttl)
chunk -= blklen;
if(xp->rp == xp->wp)
xp = xp->next;
- }
+ }
feh->cksum[0] = 0;
feh->cksum[1] = 0;
@@ 212,6 222,8 @@ ipoput(Block *bp, int gating, int ttl)
}
raise:
+ runlock(ifc);
+ poperror();
freeblist(bp);
}
M ip/ip.h => ip/ip.h +4 -2
@@ 116,6 116,8 @@ struct Medium
/* for routing multicast groups */
void (*joinmulti)(Ipifc *ifc, uchar *a, uchar *ia, uchar **iap);
void (*leavemulti)(Ipifc *ifc, uchar *a, uchar *ia);
+
+ int unbindonclose; /* if non-zero, unbind on last close */
};
/* logical interface associated with a physical one */
@@ 132,9 134,9 @@ struct Iplifc
/* binding twixt Ipself and Ipifc */
struct Iplink
{
- Ipself *local;
+ Ipself *self;
Iplifc *lifc;
- Iplink *locallink; /* next link for this local address */
+ Iplink *selflink; /* next link for this local address */
Iplink *lifclink; /* next link for this ifc */
ulong expire;
Iplink *next; /* free list */
M ip/ipifc.c => ip/ipifc.c +42 -90
@@ 23,6 23,7 @@ extern Fs fs;
Medium *media[] =
{
ðermedium,
+ &pktmedium,
&nullmedium,
0
};
@@ 151,16 152,18 @@ ipifcunbind(Ipifc *ifc)
}
wlock(ifc);
- if(ipifcgrab(ifc) == 0);
- goto out;
+ /* dissociate routes */
+ ifc->ifcid++;
+
+ /* disassociate device */
+ (*ifc->m->unbind)(ifc);
+ memset(ifc->dev, 0, sizeof(ifc->dev));
+ ifc->arg = nil;
/* hangup queues to stop queuing of packets */
qhangup(ifc->conv->rq, "unbind");
qhangup(ifc->conv->wq, "unbind");
- /* dissociate routes */
- ifc->ifcid++;
-
/* disassociate logical interfaces */
av[0] = "remove";
av[1] = ip;
@@ 172,14 175,7 @@ ipifcunbind(Ipifc *ifc)
ipifcrem(ifc, av, 3, 0);
}
- /* disassociate device */
- (*ifc->m->unbind)(ifc);
- memset(ifc->dev, 0, sizeof(ifc->dev));
- ifc->arg = nil;
- ifc->m = &nullmedium;
- ifc->unbinding = 0;
-
-out:
+ ifc->m = nil;
wunlock(ifc);
poperror();
return nil;
@@ 223,7 219,7 @@ ipifclocal(Conv *c, char *state, int n)
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
m += snprint(state+m, n - m, "%-20.20I ->", lifc->local);
for(link = lifc->link; link; link = link->lifclink)
- m += snprint(state+m, n - m, " %-20.20I", link->local->a);
+ m += snprint(state+m, n - m, " %-20.20I", link->self->a);
m += snprint(state+m, n - m, "\n");
}
runlock(ifc);
@@ 272,6 268,8 @@ ipifccreate(Conv *c)
c->wq = qopen(QMAX, 0, 0, 0);
ifc = (Ipifc*)c->ptcl;
ifc->conv = c;
+ ifc->unbinding = 0;
+ ifc->m = nil;
}
/*
@@ 281,10 279,13 @@ ipifccreate(Conv *c)
static void
ipifcclose(Conv *c)
{
- /*
- * nothing to do since conversation stays open
- * till the device is unbound.
- */
+ Ipifc *ifc;
+ Medium *m;
+
+ ifc = (Ipifc*)c->ptcl;
+ m = ifc->m;
+ if(m != nil && m->unbindonclose)
+ ipifcunbind(ifc);
unlock(c);
}
@@ 423,7 424,7 @@ ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock)
/* disassociate any addresses */
while(lifc->link)
- remselfcache(ifc, lifc, lifc->link->local->a);
+ remselfcache(ifc, lifc, lifc->link->self->a);
/* remove the route for this logical interface */
if(isv4(ip))
@@ 456,6 457,8 @@ ipifcaddroute(int vers, uchar *addr, uchar *mask, uchar *gate, int type)
if(*cp != nil) {
ifc = (Ipifc*)(*cp)->ptcl;
m = ifc->m;
+ if(m == nil)
+ continue;
if(m->addroute != nil)
m->addroute(ifc, vers, addr, mask, gate, type);
}
@@ 473,6 476,8 @@ ipifcremroute(int vers, uchar *addr, uchar *mask)
if(*cp != nil) {
ifc = (Ipifc*)(*cp)->ptcl;
m = ifc->m;
+ if(m == nil)
+ continue;
if(m->remroute != nil)
m->remroute(ifc, vers, addr, mask);
}
@@ 603,7 608,7 @@ addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
}
/* look for a link for this lifc */
- for(lp = p->link; lp; lp = lp->locallink)
+ for(lp = p->link; lp; lp = lp->selflink)
if(lp->lifc == lifc)
break;
@@ 612,8 617,8 @@ addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
lp = smalloc(sizeof(*lp));
lp->ref = 1;
lp->lifc = lifc;
- lp->local = p;
- lp->locallink = p->link;
+ lp->self = p;
+ lp->selflink = p->link;
p->link = lp;
lp->lifclink = lifc->link;
lifc->link = lp;
@@ 690,7 695,7 @@ static void
remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a)
{
Ipself *p, **l;
- Iplink *lp, *llp, **ill, **lll;
+ Iplink *link, **l_self, **l_lifc;
qlock(&selftab);
@@ 709,40 714,40 @@ remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a)
* walk down links from an ifc looking for one
* that matches the selftab entry
*/
- ill = &lifc->link;
- for(lp = *ill; lp; lp = *ill){
- if(lp->local == p)
+ l_lifc = &lifc->link;
+ for(link = *l_lifc; link; link = *l_lifc){
+ if(link->self == p)
break;
- ill = &lp->lifclink;
+ l_lifc = &link->lifclink;
}
- if(lp == nil)
+ if(link == nil)
goto out;
/*
* walk down the links from the selftab looking for
* the one we just found
*/
- lll = &p->link;
- for(llp = *lll; llp; llp = *lll){
- if(llp == lp)
+ l_self = &p->link;
+ for(link = *l_self; link; link = *l_self){
+ if(link == *(l_lifc))
break;
- lll = &lp->locallink;
+ l_self = &link->selflink;
}
- if(llp == nil)
+ if(link == nil)
panic("remselfcache");
- if(--(llp->ref) != 0)
+ if(--(link->ref) != 0)
goto out;
if((p->type & Rmulti) && ifc->m->remmulti != nil)
(*ifc->m->remmulti)(ifc, a, lifc->local);
/* ref == 0, remove from both chains and free the link */
- *ill = lp->lifclink;
- *lll = llp->locallink;
- iplinkfree(lp);
+ *l_lifc = link->lifclink;
+ *l_self = link->selflink;
+ iplinkfree(link);
/* remove from routing table */
if(isv4(a))
@@ 1004,59 1009,6 @@ ipismulticast(uchar *ip)
}
/*
- * used to allow on the fly unbinds, return -1 if interface unusable
- */
-int
-ipifccheckin(Ipifc *ifc, Medium *med)
-{
- int rv;
-
- lock(&ifc->idlock);
- if(ifc->unbinding || ifc->m != med)
- rv = -1;
- else
- rv = ++(ifc->ref);
- if(ifc->ref < 0) panic("ipifccheckin");
- unlock(&ifc->idlock);
- return rv;
-}
-
-void
-ipifccheckout(Ipifc *ifc)
-{
- lock(&ifc->idlock);
- if(--(ifc->ref) == 0)
- if(ifc->unbinding)
- wakeup(&ifc->wait);
- if(ifc->ref < 0) panic("ipifccheckin");
- unlock(&ifc->idlock);
-}
-
-static int
-allout(void *x)
-{
- Ipifc *ifc = x;
-
- return ifc->ref == 0;
-}
-
-int
-ipifcgrab(Ipifc *ifc)
-{
- lock(&ifc->idlock);
- if(ifc->unbinding){
- unlock(&ifc->idlock);
- return 0;
- }
- ifc->unbinding = 1; /* after this ref can only go down */
- unlock(&ifc->idlock);
-
- sleep(&ifc->wait, allout, ifc);
-
- return 1;
-}
-
-/*
* add a multicast address to an interface, called with c->car locked
*/
void
M ip/netlog.c => ip/netlog.c +0 -1
@@ 152,7 152,6 @@ netlogctl(char* s, int len)
int i, n, set;
Logflag *f;
char *fields[10], *p, buf[256];
- uchar addr[IPaddrlen];
if(len == 0)
return Ebadnetctl;
M ip/nullmedium.c => ip/nullmedium.c +1 -0
@@ 43,4 43,5 @@ Medium nullmedium =
nil, /* flushroute */
nil, /* joinmulti */
nil, /* leave multi */
+ 0, /* don't unbind on last close */
};
M ip/pktmedium.c => ip/pktmedium.c +1 -0
@@ 32,6 32,7 @@ Medium pktmedium =
nil, /* flushroute */
nil, /* joinmulti */
nil, /* leave multi */
+ 1, /* unbind on last close */
};
/*