shithub: riscv

Download patch

ref: 14f0eae74a9a9f5c5caebbecb11b136a12e65a22
parent: 04d6a2acecfe4fe44947da8b676f63bcd0f3c0fe
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Nov 18 12:58:10 EST 2023

devip: have findipifc() return rlock'd interface, allow to use "del" instead of "remove" for route and interface operations

The findipifc() function is kind of useless when
it returns an unlocked interface without also
providing the ifcid as the interface can be
subject to reconfiguration while unlocked.

Instead, we make findipifc() keep the interface
that it returns locked.

This is also needed for v4source() and v6source()
functions, which call ipv4local()/ipv4local()
which in turn walk the local interface chain,
and must do so under the rlock.

Also, accept the "del" verb in addition to
"remove" to keep it consistent, which also
leads to much more consistent naming in the code.
Abbreviating remove to "rem" can collide with
abbreviations for remote.

--- a/sys/man/3/ip
+++ b/sys/man/3/ip
@@ -210,8 +210,8 @@
 .IR trampoline (8)
 to a different ip stack. 
 .TP
-.BI remove\  "local mask"
-Remove a local IP address from an interface.
+.BI del\  "local mask"
+Delete a local IP address from an interface.
 .TP
 .BI mtu\  n
 Set the maximum transfer unit for this device to
@@ -271,8 +271,8 @@
 .I Media-addr
 on this interface as a local address.
 .TP
-.BI remmulti\  Media-addr
-Remove the multicast address
+.BI delmulti\  Media-addr
+Delete the multicast address
 .I Media-addr
 from this interface.
 .TP
@@ -310,8 +310,8 @@
 .RE
 .PD
 .TP
-.B remove6
-Remove local IPv6 addresses that have expired ther
+.B del6
+Delete local IPv6 addresses that have expired ther
 valid life-time.
 .TP
 .BI "ra6 " "keyword value ..."
@@ -465,20 +465,20 @@
 .B "-"
 when unspecified.
 .TP
-.BI remove\  "target mask"
+.BI del\  "target mask"
 .TP
-.BI remove\  "target mask nexthop"
+.BI del\  "target mask nexthop"
 .TP
-.BI remove\  "target mask source smask"
+.BI del\  "target mask source smask"
 .TP
-.BI remove\  "target mask nexthop source smask"
+.BI del\  "target mask nexthop source smask"
 .TP
-.BI remove\  "target mask nexthop interface source smask"
+.BI del\  "target mask nexthop interface source smask"
 .TP
-.BI remove\  "target mask nexthop flags interface source smask"
+.BI del\  "target mask nexthop flags interface source smask"
 .TP
-.BI remove\  "target mask nexthop flags tag interface source smask"
-Remove the matching route.
+.BI del\  "target mask nexthop flags tag interface source smask"
+Delete the matching route.
 .
 .SS "Address resolution
 The file
@@ -662,7 +662,7 @@
 to receive incoming calls.
 .PP
 The following control messages are supported:
-.TF "\fLremmulti \fIip\fR"
+.TF "\fLdelmulti \fIip\fR"
 .PD
 .TP
 .BI connect\  ip-address ! port "!r " local
@@ -760,8 +760,8 @@
 is present,
 use it as the interface's multicast address.
 .TP
-.BI remmulti\  ip
-Remove the address
+.BI delmulti\  ip
+Delete the address
 .I ip
 from this multicast interface.
 .PP
--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -494,7 +494,6 @@
 		}
 		if((ifc = findipifc(fs, ia, ia, Runi)) == nil)
 			error("no interface");
-		rlock(ifc);
 		if(!ipv6local(ifc, ia, 0, ip) || arpenter(fs, V6, ip, mac, n, ia, ifc, 0) < 0){
 			runlock(ifc);
 			error("destination unreachable");
@@ -522,8 +521,6 @@
 
 		if((ifc = findipifc(fs, ip, ip, Runi)) == nil)
 			error("no interface");
-
-		rlock(ifc);
 		if(waserror()){
 			runlock(ifc);
 			nexterror();
--- a/sys/src/9/ip/devip.c
+++ b/sys/src/9/ip/devip.c
@@ -571,7 +571,7 @@
 	cv->perm = 0660;
 
 	while((mp = cv->multi) != nil)
-		ipifcremmulti(cv, mp->ma, mp->ia);
+		ipifcdelmulti(cv, mp->ma, mp->ia);
 
 	if(cv->p->close != nil)
 		(*cv->p->close)(cv);
@@ -1210,15 +1210,16 @@
 					error(Ebadip);
 				ipifcaddmulti(c, ma, ia);
 			}
-		} else if(strcmp(cb->f[0], "remmulti") == 0){
+		} else if (strcmp(cb->f[0], "delmulti") == 0
+			|| strcmp(cb->f[0], "remmulti") == 0){
 			if(cb->nf < 2)
-				error("remmulti needs interface address");
+				error("delmulti needs interface address");
 			if (parseip(ia, cb->f[1]) == -1)
 				error(Ebadip);
 			if(ipcmp(c->raddr, IPnoaddr) == 0 || ipismulticast(c->laddr))
-				ipifcremmulti(c, c->laddr, ia);
+				ipifcdelmulti(c, c->laddr, ia);
 			else
-				ipifcremmulti(c, c->raddr, ia);
+				ipifcdelmulti(c, c->raddr, ia);
 		} else if(x->ctl != nil) {
 			p = (*x->ctl)(c, cb->f, cb->nf);
 			if(p != nil)
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -23,7 +23,7 @@
 static void	etherunbind(Ipifc *ifc);
 static void	etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh);
 static void	etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
-static void	etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
+static void	etherdelmulti(Ipifc *ifc, uchar *a, uchar *ia);
 static void	etherareg(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip);
 static Block*	multicastarp(Fs *f, Arpent *a, uchar *mac, Routehint *rh);
 static Block*	newEARP(void);
@@ -43,7 +43,7 @@
 .unbind=	etherunbind,
 .bwrite=	etherbwrite,
 .addmulti=	etheraddmulti,
-.remmulti=	etherremmulti,
+.delmulti=	etherdelmulti,
 .areg=		etherareg,
 .pref2addr=	etherpref2addr,
 };
@@ -59,7 +59,7 @@
 .unbind=	etherunbind,
 .bwrite=	etherbwrite,
 .addmulti=	etheraddmulti,
-.remmulti=	etherremmulti,
+.delmulti=	etherdelmulti,
 .areg=		etherareg,
 .pref2addr=	etherpref2addr,
 };
@@ -419,7 +419,7 @@
 }
 
 static void
-etherremmulti(Ipifc *ifc, uchar *a, uchar *)
+etherdelmulti(Ipifc *ifc, uchar *a, uchar *)
 {
 	uchar mac[6];
 	char buf[64];
@@ -436,7 +436,7 @@
 		devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
 		break;
 	default:
-		panic("etherremmulti: version %d", version);
+		panic("etherdelmulti: version %d", version);
 	}
 }
 
@@ -734,10 +734,10 @@
 	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);
+		delroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
 		nexterror();
 	}
 	icmpns6(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac, 6);
 	poperror();
-	remroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
+	delroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad);
 }
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -309,7 +309,7 @@
 
 	/* for arming interfaces to receive multicast */
 	void	(*addmulti)(Ipifc *ifc, uchar *a, uchar *ia);
-	void	(*remmulti)(Ipifc *ifc, uchar *a, uchar *ia);
+	void	(*delmulti)(Ipifc *ifc, uchar *a, uchar *ia);
 
 	/* process packets written to 'data' */
 	void	(*pktin)(Fs *f, Ipifc *ifc, Block *bp);
@@ -478,7 +478,7 @@
 	int	np;
 	Proto*	p[Maxproto+1];		/* list of supported protocols */
 	Proto*	t2p[256];		/* vector of all protocols */
-	Proto*	ipifc;			/* kludge for ipifcremroute & ipifcaddroute */
+	Proto*	ipifc;			/* kludge for findipifc */
 	Proto*	ipmux;			/* kludge for finding an ip multiplexor */
 
 	IP	*ip;
@@ -623,7 +623,7 @@
 };
 
 extern void	addroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag);
-extern void	remroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag);
+extern void	delroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag);
 extern Route*	v4lookup(Fs *f, uchar *a, uchar *s, Routehint *rh);
 extern Route*	v6lookup(Fs *f, uchar *a, uchar *s, Routehint *rh);
 extern Route*	v4source(Fs *f, uchar *a, uchar *s);
@@ -734,13 +734,13 @@
 extern Iplifc*	iplocalonifc(Ipifc *ifc, uchar *ip);
 extern Iplifc*	ipremoteonifc(Ipifc *ifc, uchar *ip);
 extern Ipmulti*	ipifcgetmulti(Fs *f, Ipifc *ifc, uchar *ma);
-extern void	ipifcremmulti(Conv *c, uchar *ma, uchar *ia);
 extern void	ipifcaddmulti(Conv *c, uchar *ma, uchar *ia);
-extern char*	ipifcrem(Ipifc *ifc, char **argv, int argc);
+extern void	ipifcdelmulti(Conv *c, uchar *ma, uchar *ia);
 extern char*	ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp);
+extern char*	ipifcdel(Ipifc *ifc, char **argv, int argc);
 extern long	ipselftabread(Fs*, char *a, ulong offset, int n);
 extern char*	ipifcadd6(Ipifc *ifc, char**argv, int argc);
-extern char*	ipifcremove6(Ipifc *ifc, char**argv, int argc);
+extern char*	ipifcdel6(Ipifc *ifc, char**argv, int argc);
 extern char*	mediumunbindifc(Ipifc *ifc);
 
 /*
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -47,10 +47,10 @@
 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	delselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
 static void	ipifcregisteraddr(Fs*, Ipifc*, Iplifc*, uchar*);
 static void	ipifcregisterproxy(Fs*, Ipifc*, uchar*, int);
-static char*	ipifcremlifc(Ipifc*, Iplifc**);
+static char*	ipifcdellifc(Ipifc*, Iplifc**);
 
 static char Ebound[] = "interface already bound";
 static char Eunbound[] = "interface not bound";
@@ -206,7 +206,7 @@
 
 	/* disassociate logical interfaces */
 	while(ifc->lifc != nil)
-		ipifcremlifc(ifc, &ifc->lifc);
+		ipifcdellifc(ifc, &ifc->lifc);
 
 	/* disassociate device */
 	if(m->unbind != nil){
@@ -693,7 +693,7 @@
  *	called with ifc wlock'd
  */
 static char*
-ipifcremlifc(Ipifc *ifc, Iplifc **l)
+ipifcdellifc(Ipifc *ifc, Iplifc **l)
 {
 	Iplifc *lifc = *l;
 	Fs *f = ifc->conv->p->f;
@@ -704,15 +704,15 @@
 
 	/* disassociate any addresses */
 	while(lifc->link != nil)
-		remselfcache(f, ifc, lifc, lifc->link->self->a);
+		delselfcache(f, ifc, lifc, lifc->link->self->a);
 
 	/* remove the route for this logical interface */
 	if(lifc->onlink){
-		remroute(f, lifc->remote, lifc->mask,
+		delroute(f, lifc->remote, lifc->mask,
 			lifc->local, IPallbits,
 			lifc->remote, lifc->type&~Rtrans, ifc, tifc);
 		if(v6addrtype(lifc->local) != linklocalv6)
-			remroute(f, lifc->remote, lifc->mask,
+			delroute(f, lifc->remote, lifc->mask,
 				lifc->local, IPnoaddr,
 				lifc->remote, lifc->type, ifc, tifc);
 	}
@@ -731,11 +731,11 @@
 	/* remove route for all nodes multicast */
 	if((lifc->type & Rv4) == 0){
 		if(ipcmp(lifc->local, v6loopback) == 0){
-			remroute(f, v6allnodesN, v6allnodesNmask,
+			delroute(f, v6allnodesN, v6allnodesNmask,
 				lifc->local, IPallbits,
 				v6allnodesN, Rmulti, ifc, tifc);
 		}
-		remroute(f, v6allnodesL, v6allnodesLmask,
+		delroute(f, v6allnodesL, v6allnodesLmask,
 			lifc->local, IPallbits,
 			v6allnodesL, Rmulti, ifc, tifc);
 	}
@@ -749,7 +749,7 @@
  *  remove an address from an interface.
  */
 char*
-ipifcrem(Ipifc *ifc, char **argv, int argc)
+ipifcdel(Ipifc *ifc, char **argv, int argc)
 {
 	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
 	Iplifc *lifc, **l;
@@ -778,7 +778,7 @@
 			break;
 		l = &lifc->next;
 	}
-	err = ipifcremlifc(ifc, l);
+	err = ipifcdellifc(ifc, l);
 	wunlock(ifc);
 	return err;
 }
@@ -796,7 +796,7 @@
 
 	wlock(ifc);
 	while(ifc->lifc != nil)
-		ipifcremlifc(ifc, &ifc->lifc);
+		ipifcdellifc(ifc, &ifc->lifc);
 	wunlock(ifc);
 
 	err = ipifcadd(ifc, argv, argc, 0, nil);
@@ -882,14 +882,14 @@
 		err = ipifcadd(ifc, argv, argc, 0, nil);
 	else if(strcmp(argv[0], "try") == 0)
 		err = ipifcadd(ifc, argv, argc, 1, nil);
-	else if(strcmp(argv[0], "remove") == 0)
-		err = ipifcrem(ifc, argv, argc);
+	else if(strcmp(argv[0], "del") == 0 || strcmp(argv[0], "remove") == 0)
+		err = ipifcdel(ifc, argv, argc);
 	else if(strcmp(argv[0], "unbind") == 0)
 		err = ipifcunbind(ifc);
 	else if(strcmp(argv[0], "add6") == 0)
 		err = ipifcadd6(ifc, argv, argc);
-	else if(strcmp(argv[0], "remove6") == 0)
-		err = ipifcremove6(ifc, argv, argc);
+	else if(strcmp(argv[0], "del6") == 0 || strcmp(argv[0], "remove6") == 0)
+		err = ipifcdel6(ifc, argv, argc);
 	else {
 		wlock(ifc);
 		if(ifc->m == nil || ifc->m == &unboundmedium){
@@ -944,7 +944,7 @@
 	ipifc->nc = Maxmedia;
 	ipifc->ptclsize = sizeof(Ipifc);
 
-	f->ipifc = ipifc;	/* hack for ipifcremroute, findipifc, ... */
+	f->ipifc = ipifc;
 	f->self = smalloc(sizeof(Ipselftab));	/* hack for ipforme */
 
 	Fsproto(f, ipifc);
@@ -1086,7 +1086,7 @@
  *  Unlink from selftab if this is the last ref.
  */
 static void
-remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
+delselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
 {
 	Ipself *p, **l;
 	Iplink *link, **l_self, **l_lifc;
@@ -1130,7 +1130,7 @@
 	}
 
 	if(link == nil)
-		panic("remselfcache");
+		panic("delselfcache");
 
 	if(--(link->ref) != 0)
 		goto out;
@@ -1147,9 +1147,9 @@
 				poperror();
 			}
 		}
-		if(ifc->m->remmulti != nil){
+		if(ifc->m->delmulti != nil){
 			if(!waserror()){
-				(*ifc->m->remmulti)(ifc, a, lifc->local);
+				(*ifc->m->delmulti)(ifc, a, lifc->local);
 				poperror();
 			}
 		}
@@ -1156,7 +1156,7 @@
 	}
 
 	/* remove from routing table */
-	remroute(f, a, IPallbits,
+	delroute(f, a, IPallbits,
 		lifc->local, 
 		((p->type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
 			IPallbits : IPnoaddr,
@@ -1228,8 +1228,8 @@
 }
 
 /*
- *  find the ifc on same net as the remote system.  If none,
- *  return nil.
+ *  find the ifc on same net as the remote system.
+ *  returns the rlocked ifc, otherwise nil.
  */
 Ipifc*
 findipifc(Fs *f, uchar *local, uchar *remote, int type)
@@ -1236,11 +1236,13 @@
 {
 	uchar gnet[IPaddrlen];
 	int spec, xspec;
-	Ipifc *ifc, *x;
+	uchar xifcid;
+	Ipifc *x, *ifc;
 	Iplifc *lifc;
 	Conv **cp;
 
 	x = nil;
+	xifcid = 0;
 	xspec = 0;
 	for(cp = f->ipifc->conv; *cp != nil; cp++){
 		ifc = (Ipifc*)(*cp)->ptcl;
@@ -1248,14 +1250,11 @@
 			continue;
 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
 			if(type & Runi){
-				if(ipcmp(remote, lifc->local) == 0){
-				Found:
-					runlock(ifc);
+				if(ipcmp(remote, lifc->local) == 0)
 					return ifc;
-				}
 			} else if(type & (Rbcast|Rmulti)) {
 				if(ipcmp(local, lifc->local) == 0)
-					goto Found;
+					return ifc;
 			}
 			maskip(remote, lifc->mask, gnet);
 			if(ipcmp(gnet, lifc->net) == 0){
@@ -1262,6 +1261,7 @@
 				spec = comprefixlen(remote, lifc->local, IPaddrlen);
 				if(spec > xspec){
 					x = ifc;
+					xifcid = ifc->ifcid;
 					xspec = spec;
 				}
 			}
@@ -1268,7 +1268,12 @@
 		}
 		runlock(ifc);
 	}
-	return x;
+	if(x != nil && canrlock(x)){
+		if(x->ifcid == xifcid)
+			return x;
+		runlock(x);
+	}
+	return nil;
 }
 
 Ipifc*
@@ -1275,20 +1280,25 @@
 findipifcstr(Fs *f, char *s)
 {
 	uchar ip[IPaddrlen];
+	Ipifc *ifc;
 	Conv *c;
 	char *p;
 	long x;
 
+	ifc = nil;
 	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;
+		if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil){
+			if(ipifcinuse(c)){
+				ifc = (Ipifc*)c->ptcl;
+				rlock(ifc);
+			}
+		}
+	} else if(parseip(ip, s) != -1)
+		ifc = findipifc(f, ip, ip, Runi);
+	return ifc;
 }
 
 /*
@@ -1590,7 +1600,6 @@
 
 	f = c->p->f;
 	if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
-		rlock(ifc);
 		if(waserror()){
 			runlock(ifc);
 			nexterror();
@@ -1618,7 +1627,7 @@
  *  remove a multicast address from an interface.
  */
 void
-ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
+ipifcdelmulti(Conv *c, uchar *ma, uchar *ia)
 {
 	Ipmulti *multi, **l;
 	Iplifc *lifc;
@@ -1638,15 +1647,14 @@
 
 	f = c->p->f;
 	if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
-		rlock(ifc);
 		if(!waserror()){
 			if((lifc = iplocalonifc(ifc, ia)) != nil)
-				remselfcache(f, ifc, lifc, ma);
+				delselfcache(f, ifc, lifc, ma);
 			poperror();
 		}
 		if(!isv4(ia) && !islinklocal(ia) && !waserror()){
 			if((lifc = iplinklocalifc(ifc)) != nil)
-				remselfcache(f, ifc, lifc, ma);
+				delselfcache(f, ifc, lifc, ma);
 			poperror();
 		}
 		runlock(ifc);
@@ -1694,7 +1702,7 @@
 			if(add)
 				addselfcache(f, nifc, lifc, a, Rmulti);
 			else
-				remselfcache(f, nifc, lifc, a);
+				delselfcache(f, nifc, lifc, a);
 		}
 		if(add)
 			ipifcregisteraddr(f, nifc, lifc, ip);
@@ -1773,7 +1781,7 @@
 }
 
 char*
-ipifcremove6(Ipifc *ifc, char**, int argc)
+ipifcdel6(Ipifc *ifc, char**, int argc)
 {
 	Iplifc *lifc, **l;
 	ulong now;
@@ -1786,7 +1794,7 @@
 	for(l = &ifc->lifc; (lifc = *l) != nil;) {
 		if((lifc->type & Rv4) == 0)
 		if(lifc->validlt != ~0UL && lifc->validlt < now-lifc->origint)
-			if(ipifcremlifc(ifc, l) == nil)
+			if(ipifcdellifc(ifc, l) == nil)
 				continue;
 		l = &lifc->next;
 	}
--- a/sys/src/9/ip/iproute.c
+++ b/sys/src/9/ip/iproute.c
@@ -425,7 +425,7 @@
 }
 
 static void
-routerem(Fs *f, Route *r)
+routedel(Fs *f, Route *r)
 {
 	Route **h, **e, **l, *p, *q;
 
@@ -464,7 +464,7 @@
 }
 
 static Route
-mkroute(uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag)
+mkroute(uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, uchar ifcid, char *tag)
 {
 	ulong x, y;
 	Route r;
@@ -508,7 +508,7 @@
 
 	if(ifc != nil){
 		r.ifc = ifc;
-		r.ifcid = ifc->ifcid;
+		r.ifcid = ifcid;
 	}
 
 	if(tag != nil)
@@ -520,7 +520,7 @@
 void
 addroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag)
 {
-	Route r = mkroute(a, mask, s, smask, gate, type, ifc, tag);
+	Route r = mkroute(a, mask, s, smask, gate, type, ifc, ifc->ifcid, tag);
 	wlock(&routelock);
 	routeadd(f, &r);
 	wunlock(&routelock);
@@ -527,15 +527,18 @@
 }
 
 void
-remroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag)
+delroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag)
 {
-	Route r = mkroute(a, mask, s, smask, gate, type, ifc, tag);
+	Route r = mkroute(a, mask, s, smask, gate, type, ifc, ifc->ifcid, tag);
 	wlock(&routelock);
-	routerem(f, &r);
+	routedel(f, &r);
 	wunlock(&routelock);
 }
 
-/* get the outgoing interface for route r */
+/*
+ * get the outgoing interface for route r,
+ * interface is returned rlocked.
+ */
 static Ipifc*
 routefindipifc(Route *r, Fs *f)
 {
@@ -544,8 +547,12 @@
 	int i;
 
 	ifc = r->ifc;
-	if(ifc != nil && ifc->ifcid == r->ifcid)
-		return ifc;
+	if(ifc != nil && canrlock(ifc)){
+		if(ifc->ifcid == r->ifcid)
+			return ifc;
+		runlock(ifc);
+		r->ifc = nil;
+	}
 
 	if(r->type & Rsrc) {
 		if(r->type & Rv4) {
@@ -574,11 +581,11 @@
 			ipmove(gate, r->v6.gate);
 	}
 
-	if((ifc = findipifc(f, local, gate, r->type)) == nil)
-		return nil;
-
-	r->ifc = ifc;
-	r->ifcid = ifc->ifcid;
+	ifc = findipifc(f, local, gate, r->type);
+	if(ifc != nil) {
+		r->ifc = ifc;
+		r->ifcid = ifc->ifcid;
+	}
 	return ifc;
 }
 
@@ -633,11 +640,15 @@
 		p = p->mid;
 	}
 	if(q != nil){
-		if(routefindipifc(q, f) == nil)
+		ifc = routefindipifc(q, f);
+		if(ifc == nil)
 			q = nil;
-		else if(rh != nil){
-			rh->r = q;
-			rh->rgen = v4routegeneration;
+		else {
+			if(rh != nil){
+				rh->r = q;
+				rh->rgen = v4routegeneration;
+			}
+			runlock(ifc);
 		}
 	}
 	runlock(&routelock);
@@ -726,11 +737,15 @@
 next:		;
 	}
 	if(q != nil){
-		if(routefindipifc(q, f) == nil)
+		ifc = routefindipifc(q, f);
+		if(ifc == nil)
 			q = nil;
-		else if(rh != nil){
-			rh->r = q;
-			rh->rgen = v6routegeneration;
+		else {
+			if(rh != nil){
+				rh->r = q;
+				rh->rgen = v6routegeneration;
+			}
+			runlock(ifc);
 		}
 	}
 	runlock(&routelock);
@@ -767,6 +782,12 @@
 			p = p->right;
 			continue;
 		}
+
+		ifc = routefindipifc(p, f);
+		if(ifc == nil){
+			p = p->mid;
+			continue;
+		}
 		splen = 0;
 		if(p->type & Rsrc){
 			/* calculate local prefix length for source specific routes */
@@ -774,12 +795,13 @@
 				splen++;
 			hnputl(src, p->v4.source);
 		}
-		if((ifc = routefindipifc(p, f)) == nil
-		|| !ipv4local(ifc, src, splen, (p->type & (Rifc|Rbcast|Rmulti|Rv4))==Rv4? p->v4.gate: a)){
+		if(!ipv4local(ifc, src, splen, (p->type & (Rifc|Rbcast|Rmulti|Rv4))==Rv4? p->v4.gate: a)){
+			runlock(ifc);
 			p = p->mid;
 			continue;
 		}
 		memmove(s, src, IPv4addrlen);
+		runlock(ifc);
 		q = p;
 		p = p->mid;
 	}
@@ -823,6 +845,12 @@
 			}
 			break;
 		}
+
+		ifc = routefindipifc(p, f);
+		if(ifc == nil){
+			p = p->mid;
+			continue;
+		}
 		splen = 0;
 		if(p->type & Rsrc){
 			/* calculate local prefix length for source specific routes */
@@ -836,12 +864,13 @@
 				splen += 32;
 			}
 		}
-		if((ifc = routefindipifc(p, f)) == nil
-		|| !ipv6local(ifc, src, splen, a)){
+		if(!ipv6local(ifc, src, splen, a)){
+			runlock(ifc);
 			p = p->mid;
 			continue;
 		}
 		ipmove(s, src);
+		runlock(ifc);
 		q = p;
 		p = p->mid;
 next:		;
@@ -1045,13 +1074,13 @@
  *	7	add	addr	mask	gate			ifc	src	smask
  *	8	add	addr	mask	gate	type		ifc	src	smask
  *	9	add	addr	mask	gate	type	tag	ifc	src	smask
- *	3	remove	addr	mask
- *	4	remove	addr	mask	gate
- *	5	remove	addr	mask					src	smask
- *	6	remove	addr	mask	gate				src	smask
- *	7	remove	addr	mask	gate			ifc	src	smask
- *	8	remove	addr	mask	gate	type		ifc	src	smask
- *	9	remove	addr	mask	gate	type	tag	ifc	src	smask
+ *	3	del	addr	mask
+ *	4	del	addr	mask	gate
+ *	5	del	addr	mask					src	smask
+ *	6	del	addr	mask	gate				src	smask
+ *	7	del	addr	mask	gate			ifc	src	smask
+ *	8	del	addr	mask	gate	type		ifc	src	smask
+ *	9	del	addr	mask	gate	type	tag	ifc	src	smask
  */
 static Route
 parseroute(Fs *f, char **argv, int argc)
@@ -1060,6 +1089,7 @@
 	uchar src[IPaddrlen], smask[IPaddrlen];
 	uchar gate[IPaddrlen];
 	Ipifc *ifc;
+	uchar ifcid;
 	char *tag;
 	int type;
 
@@ -1066,6 +1096,7 @@
 	type = 0;
 	tag = nil;
 	ifc = nil;
+	ifcid = 0;
 	ipmove(gate, IPnoaddr);
 	ipmove(src, IPnoaddr);
 	ipmove(smask, IPnoaddr);
@@ -1092,6 +1123,10 @@
 		ifc = findipifcstr(f, argv[4]);
 	if(argc > 6)
 		ifc = findipifcstr(f, argv[argc-3]);
+	if(ifc != nil){
+		ifcid = ifc->ifcid;
+		runlock(ifc);
+	}
 
 	if(argc > 7 && (type = parseroutetype(argv[4])) < 0)
 		error(Ebadctl);
@@ -1113,7 +1148,7 @@
 			error(Ebadip);
 	}
 
-	return mkroute(addr, mask, src, smask, gate, type, ifc, tag);	
+	return mkroute(addr, mask, src, smask, gate, type, ifc, ifcid, tag);	
 }
 
 long
@@ -1138,15 +1173,17 @@
 		for(h = 0; h < nelem(f->v4root); h++)
 			while((x = looknodetag(f->v4root[h], tag)) != nil){
 				memmove(&r, x, sizeof(RouteTree) + sizeof(V4route));
-				routerem(f, &r);
+				routedel(f, &r);
 			}
 		for(h = 0; h < nelem(f->v6root); h++)
 			while((x = looknodetag(f->v6root[h], tag)) != nil){
 				memmove(&r, x, sizeof(RouteTree) + sizeof(V6route));
-				routerem(f, &r);
+				routedel(f, &r);
 			}
 		wunlock(&routelock);
-	} else if(strcmp(cb->f[0], "add") == 0 || strcmp(cb->f[0], "remove") == 0){
+	} else if(strcmp(cb->f[0], "add") == 0
+		||strcmp(cb->f[0], "del") == 0
+		||strcmp(cb->f[0], "remove") == 0){
 		r = parseroute(f, cb->f, cb->nf);
 		if(*r.tag == 0){
 			a = c->aux;
@@ -1156,7 +1193,7 @@
 		if(strcmp(cb->f[0], "add") == 0)
 			routeadd(f, &r);
 		else
-			routerem(f, &r);
+			routedel(f, &r);
 		wunlock(&routelock);
 	} else if(strcmp(cb->f[0], "tag") == 0) {
 		if(cb->nf < 2)
--- a/sys/src/9/port/netif.c
+++ b/sys/src/9/port/netif.c
@@ -341,13 +341,14 @@
 		nif->bypass = f;
 	} else if(matchtoken(buf, "headersonly")){
 		f->headersonly = 1;
-	} else if((p = matchtoken(buf, "addmulti")) != 0){
+	} else if((p = matchtoken(buf, "addmulti")) != nil){
 		if(parseaddr(binaddr, p, nif->alen) < 0)
 			error("bad address");
 		p = netmulti(nif, f, binaddr, 1);
 		if(p)
 			error(p);
-	} else if((p = matchtoken(buf, "remmulti")) != 0){
+	} else if((p = matchtoken(buf, "delmulti")) != nil
+		||(p = matchtoken(buf, "remmulti")) != nil){
 		if(parseaddr(binaddr, p, nif->alen) < 0)
 			error("bad address");
 		p = netmulti(nif, f, binaddr, 0);
--- a/sys/src/cmd/nusb/ether/ether.c
+++ b/sys/src/cmd/nusb/ether/ether.c
@@ -421,7 +421,7 @@
 				if(nprom++ == 0 && eppromiscuous != nil)
 					(*eppromiscuous)(epctl, 1);
 			}
-		} else if(n >= 9+12 && (memcmp(p, "addmulti ", 9)==0 || memcmp(p, "remmulti ", 9)==0)){
+		} else if(n >= 9+12 && (memcmp(p, "addmulti ", 9)==0 || memcmp(p, "delmulti ", 9)==0 || memcmp(p, "remmulti ", 9)==0)){
 			uchar ea[Eaddrlen];
 			int i;
 
@@ -431,7 +431,7 @@
 			}
 			i = activemulti(ea);
 			if(i >= 0){
-				if(*p == 'r'){
+				if(*p != 'a'){
 					memmove(multiaddr[i], multiaddr[--nmulti], Eaddrlen);
 					if(epmulticast != nil)
 						(*epmulticast)(epctl, ea, 0);