shithub: riscv

Download patch

ref: 71f807873b43a4d2a2e2c9d1acbe1d97b5fdf18c
parent: 8ce98a0b32111228827de661fe96efd52ee1b4bf
author: cinap_lenrek <[email protected]>
date: Sun Mar 18 03:50:48 EDT 2018

devip: more v6 improvements

ipv4local() and ipv6local() now take remote address argument,
returning the closest local address to the source. this
implements the standartized source address selection rules
instead of just returning the first local v4 or v6 address.

the source address selection was broken for esp, rudp an udp,
blindly assuming ifc->lifc->local being a valid v4 address.
use ipv6local() instead.

the v6 routing code used to lookup source address route to
decide to drop the packet instead of checking the interface
on the destination route.

factor out the route hint from Conv and put it in Routehint
structure. avoiding stack bloat in v4 routing. implement the
same trick for v6 avoiding second route lookup in ipoput6.

fix memory leak in icmpv6 router solicitation handling.

remove old unfinished handling of multiple v6 routers. should
implement source specific routes instead.

avoid duplication, use common convipvers() function.

use isv4() instead of memcmp v4prefix.

--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -539,7 +539,6 @@
 extern int
 rxmitsols(Arp *arp)
 {
-	uint sflag;
 	Block *next, *xp;
 	Arpent *a, *b, **l;
 	Fs *f;
@@ -582,8 +581,8 @@
 
 
 	qunlock(arp);	/* for icmpns */
-	if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC) 
-		icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 
+	if(ipv6local(ifc, ipsrc, a->ip)) 
+		icmpns(f, ipsrc, SRC_UNI, a->ip, TARG_MULTI, ifc->mac); 
 
 	runlock(ifc);
 	qlock(arp);	
--- a/sys/src/9/ip/devip.c
+++ b/sys/src/9/ip/devip.c
@@ -919,12 +919,7 @@
 			return p;
 	}
 
-	if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
-		memcmp(c->laddr, v4prefix, IPv4off) == 0)
-		|| ipcmp(c->raddr, IPnoaddr) == 0)
-		c->ipversion = V4;
-	else
-		c->ipversion = V6;
+	c->ipversion = convipvers(c);
 
 	return nil;
 }
@@ -1150,12 +1145,6 @@
 			if (parseip(ia, cb->f[1]) == -1)
 				error(Ebadip);
 			ipifcremmulti(c, c->raddr, ia);
-		} else if(strcmp(cb->f[0], "maxfragsize") == 0){
-			if(cb->nf < 2)
-				error("maxfragsize needs size");
-
-			c->maxfragsize = (int)strtol(cb->f[1], nil, 0);
-			
 		} else if(x->ctl != nil) {
 			p = x->ctl(c, cb->f, cb->nf);
 			if(p != nil)
@@ -1329,7 +1318,6 @@
 	c->lport = 0;
 	c->rport = 0;
 	c->restricted = 0;
-	c->maxfragsize = 0;
 	c->ttl = MAXTTL;
 	qreopen(c->rq);
 	qreopen(c->wq);
--- a/sys/src/9/ip/esp.c
+++ b/sys/src/9/ip/esp.c
@@ -267,17 +267,6 @@
 }
 
 static int
-convipvers(Conv *c)
-{
-	if((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
-	    memcmp(c->laddr, v4prefix, IPv4off) == 0) ||
-	    ipcmp(c->raddr, IPnoaddr) == 0)
-		return V4;
-	else
-		return V6;
-}
-
-static int
 pktipvers(Fs *f, Block **bpp)
 {
 	if (*bpp == nil || BLEN(*bpp) == 0) {
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -477,7 +477,7 @@
 	memset(bp->rp, 0, n);
 	e = (Etherarp*)bp->rp;
 	memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
-	ipv4local(ifc, e->spa);
+	ipv4local(ifc, e->spa, e->tpa);
 	memmove(e->sha, ifc->mac, sizeof(e->sha));
 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
 	memmove(e->s, ifc->mac, sizeof(e->s));
@@ -496,7 +496,6 @@
 static void
 resolveaddr6(Ipifc *ifc, Arpent *a)
 {
-	int sflag;
 	Block *bp;
 	Etherrock *er = ifc->arg;
 	uchar ipsrc[IPaddrlen];
@@ -526,8 +525,8 @@
 	a->rxtsrem--;
 	arprelease(er->f->arp, a);
 
-	if(sflag = ipv6anylocal(ifc, ipsrc))
-		icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
+	if(ipv6local(ifc, ipsrc, a->ip))
+		icmpns(er->f, ipsrc, SRC_UNI, a->ip, TARG_MULTI, ifc->mac);
 }
 
 /*
--- a/sys/src/9/ip/icmp6.c
+++ b/sys/src/9/ip/icmp6.c
@@ -331,7 +331,7 @@
 	ipmove(addr, p->src);
 	if(!isv6mcast(p->dst))
 		ipmove(p->src, p->dst);
-	else if (!ipv6anylocal(ifc, p->src))
+	else if (!ipv6local(ifc, p->src, addr))
 		return nil;
 	ipmove(p->dst, addr);
 	p->type = EchoReplyV6;
@@ -440,7 +440,7 @@
 	np = (IPICMP *)nbp->rp;
 
 	rlock(ifc);
-	if(ipv6anylocal(ifc, np->src))
+	if(ipv6local(ifc, np->src, p->src))
 		netlog(f, Logicmp, "send icmphostunr -> src %I dst %I\n", p->src, p->dst);
 	else {
 		netlog(f, Logicmp, "icmphostunr fail -> src %I dst %I\n", p->src, p->dst);
@@ -487,7 +487,7 @@
 	nbp = newIPICMP(sz);
 	np = (IPICMP *) nbp->rp;
 
-	if(ipv6anylocal(ifc, np->src))
+	if(ipv6local(ifc, np->src, p->src))
 		netlog(f, Logicmp, "send icmpttlexceeded6 -> src %I dst %I\n",
 			p->src, p->dst);
 	else {
@@ -526,7 +526,7 @@
 	nbp = newIPICMP(sz);
 	np = (IPICMP *)nbp->rp;
 
-	if(ipv6anylocal(ifc, np->src))
+	if(ipv6local(ifc, np->src, p->src))
 		netlog(f, Logicmp, "send icmppkttoobig6 -> src %I dst %I\n",
 			p->src, p->dst);
 	else {
@@ -778,18 +778,11 @@
 			}
 			bp->rp -= IPICMPSZ;
 		}
-
 		goticmpkt6(icmp, bp, 0);
 		break;
 
 	case RouterAdvert:
 	case RouterSolicit:
-		/* using lsrc as a temp, munge hdr for goticmp6 */
-		if (0) {
-			memmove(lsrc, p->src, IPaddrlen);
-			memmove(p->src, p->dst, IPaddrlen);
-			memmove(p->dst, lsrc, IPaddrlen);
-		}
 		goticmpkt6(icmp, bp, p->type);
 		break;
 
@@ -809,21 +802,21 @@
 					8*np->olen-2, 0);
 				pktflags |= Sflag;
 			}
-			if(ipv6local(ipifc, lsrc))
-				icmpna(icmp->f, lsrc,
-					(ipcmp(np->src, v6Unspecified) == 0?
-						v6allnodesL: np->src),
-					np->target, ipifc->mac, pktflags);
-			else
-				freeblist(bp);
+			if(!ipv6local(ipifc, lsrc, np->src))
+				break;
+			icmpna(icmp->f, lsrc,
+				(ipcmp(np->src, v6Unspecified) == 0?
+					v6allnodesL: np->src),
+				np->target, ipifc->mac, pktflags);
 			break;
-
 		case Tunitent:
-			/* not clear what needs to be done. send up
-			 * an icmp mesg saying don't use this address? */
-		default:
-			freeblist(bp);
+			/*
+			 * not clear what needs to be done. send up
+			 * an icmp mesg saying don't use this address?
+			 */
+			break;
 		}
+		freeblist(bp);
 		break;
 
 	case NbrAdvert:
@@ -839,8 +832,7 @@
 		lifc = iplocalonifc(ipifc, np->target);
 		if(lifc && lifc->tentative)
 			refresh = 0;
-		arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2,
-			refresh);
+		arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, refresh);
 		freeblist(bp);
 		break;
 
--- a/sys/src/9/ip/ip.c
+++ b/sys/src/9/ip/ip.c
@@ -63,8 +63,6 @@
 
 	v6p->hp.rxmithost	= 1000;		/* v6 RETRANS_TIMER */
 
-	v6p->cdrouter 		= -1;
-
 	f->v6p			= v6p;
 }
 
@@ -118,7 +116,7 @@
 }
 
 int
-ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
+ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh)
 {
 	Ipifc *ifc;
 	uchar *gate;
@@ -156,7 +154,7 @@
 		goto free;
 	}
 
-	r = v4lookup(f, eh->dst, c);
+	r = v4lookup(f, eh->dst, rh);
 	if(r == nil){
 		ip->stats[OutNoRoutes]++;
 		netlog(f, Logip, "no interface %V\n", eh->dst);
@@ -193,10 +191,7 @@
 		goto raise;
 
 	/* If we dont need to fragment just send it */
-	if(c && c->maxfragsize && c->maxfragsize < ifc->maxtu)
-		medialen = c->maxfragsize - ifc->m->hsize;
-	else
-		medialen = ifc->maxtu - ifc->m->hsize;
+	medialen = ifc->maxtu - ifc->m->hsize;
 	if(len <= medialen) {
 		if(!gating)
 			hnputs(eh->id, incref(&ip->id4));
@@ -315,8 +310,6 @@
 	int notforme;
 	uchar *dp, v6dst[IPaddrlen];
 	IP *ip;
-	Route *r;
-	Conv conv;
 
 	if(BLKIPVER(bp) != IP_VER4) {
 		ipiput6(f, ifc, bp);
@@ -377,6 +370,9 @@
 
 	/* route */
 	if(notforme) {
+		Route *r;
+		Routehint rh;
+
 		if(!ip->iprouting){
 			freeblist(bp);
 			return;
@@ -383,9 +379,8 @@
 		}
 
 		/* don't forward to source's network */
-		memmove(&conv, ifc->conv, sizeof conv);
-		conv.r = nil;
-		r = v4lookup(f, h->dst, &conv);
+		rh.r = nil;
+		r = v4lookup(f, h->dst, &rh);
 		if(r == nil || r->ifc == ifc){
 			ip->stats[OutDiscards]++;
 			freeblist(bp);
@@ -419,7 +414,7 @@
 		ip->stats[ForwDatagrams]++;
 		tos = h->tos;
 		hop = h->ttl;
-		ipoput4(f, bp, 1, hop - 1, tos, &conv);
+		ipoput4(f, bp, 1, hop - 1, tos, &rh);
 		return;
 	}
 
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -21,10 +21,10 @@
 typedef struct	Arpent	Arpent;
 typedef struct	Arp Arp;
 typedef struct	Route	Route;
+typedef struct	Routehint Routehint;
 
 typedef struct	Routerparams	Routerparams;
 typedef struct 	Hostparams	Hostparams;
-typedef struct 	v6router	v6router;
 typedef struct	v6params	v6params;
 
 #pragma incomplete Arp
@@ -164,6 +164,12 @@
 	uchar	dst[4];		/* IP destination */
 };
 
+struct Routehint
+{
+	Route	*r;			/* last route used */
+	ulong	rgen;			/* routetable generation for *r */
+};
+
 /*
  *  one per conversation directory
  */
@@ -191,8 +197,6 @@
 	int	length;
 	int	state;
 
-	int	maxfragsize;		/* If set, used for fragmentation */
-
 	/* udp specific */
 	int	headers;		/* data src/dst headers in udp */
 	int	reliable;		/* true if reliable udp */
@@ -217,8 +221,7 @@
 
 	void*	ptcl;			/* protocol specific stuff */
 
-	Route	*r;			/* last route used */
-	ulong	rgen;			/* routetable generation for *r */
+	Routehint;
 };
 
 struct Medium
@@ -443,23 +446,10 @@
 	long	ndbmtime;
 };
 
-/* one per default router known to host */
-struct v6router {
-	uchar	inuse;
-	Ipifc	*ifc;
-	int	ifcid;
-	uchar	routeraddr[IPaddrlen];
-	long	ltorigin;
-	Routerparams	rp;
-};
-
 struct v6params
 {
 	Routerparams	rp;		/* v6 params, one copy per node now */
 	Hostparams	hp;
-	v6router	v6rlist[3];	/* max 3 default routers, currently */
-	int		cdrouter;	/* uses only v6rlist[cdrouter] if   */
-					/* cdrouter >= 0. */
 };
 
 
@@ -586,8 +576,8 @@
 extern void	v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type);
 extern void	v4delroute(Fs *f, uchar *a, uchar *mask, int dolock);
 extern void	v6delroute(Fs *f, uchar *a, uchar *mask, int dolock);
-extern Route*	v4lookup(Fs *f, uchar *a, Conv *c);
-extern Route*	v6lookup(Fs *f, uchar *a, Conv *c);
+extern Route*	v4lookup(Fs *f, uchar *a, Routehint *h);
+extern Route*	v6lookup(Fs *f, uchar *a, Routehint *h);
 extern long	routeread(Fs *f, char*, ulong, int);
 extern long	routewrite(Fs *f, Chan*, char*, int);
 extern void	routetype(int, char*);
@@ -654,6 +644,7 @@
 extern void	v4tov6(uchar *v6, uchar *v4);
 extern int	v6tov4(uchar *v4, uchar *v6);
 extern int	eipfmt(Fmt*);
+extern int	convipvers(Conv *c);
 
 #define	ipmove(x, y) memmove(x, y, IPaddrlen)
 #define	ipcmp(x, y) ( (x)[IPaddrlen-1] != (y)[IPaddrlen-1] || memcmp(x, y, IPaddrlen) )
@@ -686,9 +677,8 @@
 extern int	ipismulticast(uchar *);
 extern Ipifc*	findipifc(Fs*, uchar *remote, int type);
 extern void	findlocalip(Fs*, uchar *local, uchar *remote);
-extern int	ipv4local(Ipifc *ifc, uchar *addr);
-extern int	ipv6local(Ipifc *ifc, uchar *addr);
-extern int	ipv6anylocal(Ipifc *ifc, uchar *addr);
+extern int	ipv4local(Ipifc *ifc, uchar *local, uchar *remote);
+extern int	ipv6local(Ipifc *ifc, uchar *local, uchar *remote);
 extern Iplifc*	iplocalonifc(Ipifc *ifc, uchar *ip);
 extern int	ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip);
 extern int	ipismulticast(uchar *ip);
@@ -714,8 +704,8 @@
 extern ushort	ipcsum(uchar*);
 extern void	ipiput4(Fs*, Ipifc*, Block*);
 extern void	ipiput6(Fs*, Ipifc*, Block*);
-extern int	ipoput4(Fs*, Block*, int, int, int, Conv*);
-extern int	ipoput6(Fs*, Block*, int, int, int, Conv*);
+extern int	ipoput4(Fs*, Block*, int, int, int, Routehint*);
+extern int	ipoput6(Fs*, Block*, int, int, int, Routehint*);
 extern int	ipstats(Fs*, char*, int);
 extern ushort	ptclbsum(uchar*, int);
 extern ushort	ptclcsum(Block*, int, int);
--- a/sys/src/9/ip/ipaux.c
+++ b/sys/src/9/ip/ipaux.c
@@ -366,3 +366,12 @@
 	unlock(ht);
 	return nil;
 }
+
+int
+convipvers(Conv *c)
+{
+	if(isv4(c->raddr) && isv4(c->laddr) || ipcmp(c->raddr, IPnoaddr) == 0)
+		return V4;
+	else
+		return V6;
+}
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -1095,7 +1095,7 @@
  *	0		- no match
  *	Runi
  *	Rbcast
- *	Rmcast
+ *	Rmulti
  */
 int
 ipforme(Fs *f, uchar *addr)
@@ -1163,7 +1163,6 @@
 
 enum {
 	unknownv6,		/* UGH */
-//	multicastv6,
 	unspecifiedv6,
 	linklocalv6,
 	globalv6,
@@ -1237,140 +1236,135 @@
 			return;
 		}
 	}
+	ipmove(local, IPnoaddr);
 }
 
-/*
- *  find the local address 'closest' to the remote system, copy it to
- *  local and return the ifc for that address
- */
-void
-findlocalip(Fs *f, uchar *local, uchar *remote)
+static int
+comprefixlen(uchar *a, uchar *b, int n)
 {
-	int version, atype = unspecifiedv6, atypel = unknownv6;
-	int atyper, deprecated;
-	uchar gate[IPaddrlen], gnet[IPaddrlen];
-	Ipifc *ifc;
-	Iplifc *lifc;
-	Route *r;
+	int i, c;
 
-	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);
-		}
-
-		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);
-		}
+	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;
 	}
-
-	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 i << 3;
 }
 
 /*
- *  return first v4 address associated with an interface
+ *  return v4 address associated with an interface close to remote
  */
 int
-ipv4local(Ipifc *ifc, uchar *addr)
+ipv4local(Ipifc *ifc, uchar *local, uchar *remote)
 {
 	Iplifc *lifc;
+	int a, b;
 
-	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
-		if(isv4(lifc->local)){
-			memmove(addr, lifc->local+IPv4off, IPv4addrlen);
-			return 1;
+	b = -1;
+	for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+		if(!isv4(lifc->local))
+			continue;
+		a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
+		if(a > b){
+			b = a;
+			memmove(local, lifc->local+IPv4off, IPv4addrlen);
 		}
 	}
-	return 0;
+	return b >= 0;
 }
 
 /*
- *  return first v6 address associated with an interface
+ *  return v6 address associated with an interface close to remote
  */
 int
-ipv6local(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) && !(lifc->tentative)){
-			ipmove(addr, lifc->local);
-			return 1;
+	if(isv4(remote)){
+		ipmove(local, v4prefix);
+		return ipv4local(ifc, local+IPv4off, remote+IPv4off);
+	}
+
+	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;
+
+		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)
+/*
+ *  find the local address 'closest' to the remote system, copy it to local
+ */
+void
+findlocalip(Fs *f, uchar *local, uchar *remote)
 {
-	Iplifc *lifc;
+	Route *r;
 
-	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
-		if(!isv4(lifc->local)){
-			ipmove(addr, lifc->local);
-			return SRC_UNI;
+	qlock(f->ipifc);
+	if((r = v6lookup(f, remote, nil)) != nil){
+		if(r->type & Runi){
+			ipmove(local, remote);
+			goto out;
 		}
+		if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
+			ipmove(local, v4prefix);
+			if(ipv4local(r->ifc, local+IPv4off, r->v4.gate))
+				goto out;
+		}
+		if(ipv6local(r->ifc, local, remote))
+			goto out;
 	}
-	return SRC_UNSPEC;
+	if(isv4(remote))
+		findprimaryipv4(f, local);
+	else
+		findprimaryipv6(f, local);
+out:
+	qunlock(f->ipifc);
 }
 
 /*
@@ -1604,29 +1598,6 @@
 		}
 	}
 }
-
-
-/* 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;
-
-	v6delroute(f, v6Unspecified, v6Unspecified, 1);
-	v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
-}
-
-enum {
-	Ngates = 3,
-};
 
 char*
 ipifcadd6(Ipifc *ifc, char**argv, int argc)
--- a/sys/src/9/ip/iproute.c
+++ b/sys/src/9/ip/iproute.c
@@ -323,7 +323,6 @@
 }
 
 #define	V6H(a)	(((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
-#define ISDFLT(a, mask, tag) ((ipcmp((a),v6Unspecified)==0) && (ipcmp((mask),v6Unspecified)==0) && (strcmp((tag), "ra")!=0))
 
 void
 v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
@@ -333,12 +332,6 @@
 	ulong x, y;
 	int h, eh;
 
-	/*
-	if(ISDFLT(a, mask, tag))
-		f->v6p->cdrouter = -1;
-	*/
-
-
 	for(h = 0; h < IPllen; h++){
 		x = nhgetl(a+4*h);
 		y = nhgetl(mask+4*h);
@@ -482,7 +475,7 @@
 }
 
 Route*
-v4lookup(Fs *f, uchar *a, Conv *c)
+v4lookup(Fs *f, uchar *a, Routehint *rh)
 {
 	Route *p, *q;
 	ulong la;
@@ -489,8 +482,8 @@
 	uchar gate[IPaddrlen];
 	Ipifc *ifc;
 
-	if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v4routegeneration)
-		return c->r;
+	if(rh != nil && rh->r != nil && rh->r->ifc != nil && rh->rgen == v4routegeneration)
+		return rh->r;
 
 	la = nhgetl(a);
 	q = nil;
@@ -517,9 +510,9 @@
 		q->ifcid = ifc->ifcid;
 	}
 
-	if(c != nil){
-		c->r = q;
-		c->rgen = v4routegeneration;
+	if(rh != nil){
+		rh->r = q;
+		rh->rgen = v4routegeneration;
 	}
 
 	return q;
@@ -526,7 +519,7 @@
 }
 
 Route*
-v6lookup(Fs *f, uchar *a, Conv *c)
+v6lookup(Fs *f, uchar *a, Routehint *rh)
 {
 	Route *p, *q;
 	ulong la[IPllen];
@@ -536,18 +529,18 @@
 	Ipifc *ifc;
 
 	if(memcmp(a, v4prefix, IPv4off) == 0){
-		q = v4lookup(f, a+IPv4off, c);
+		q = v4lookup(f, a+IPv4off, rh);
 		if(q != nil)
 			return q;
 	}
 
-	if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v6routegeneration)
-		return c->r;
+	if(rh != nil && rh->r != nil && rh->r->ifc != nil && rh->rgen == v6routegeneration)
+		return rh->r;
 
 	for(h = 0; h < IPllen; h++)
 		la[h] = nhgetl(a+4*h);
 
-	q = 0;
+	q = nil;
 	for(p=f->v6root[V6H(la)]; p;){
 		for(h = 0; h < IPllen; h++){
 			x = la[h];
@@ -588,9 +581,10 @@
 		q->ifc = ifc;
 		q->ifcid = ifc->ifcid;
 	}
-	if(c != nil){
-		c->r = q;
-		c->rgen = v6routegeneration;
+
+	if(rh != nil){
+		rh->r = q;
+		rh->rgen = v6routegeneration;
 	}
 	
 	return q;
--- a/sys/src/9/ip/ipv6.c
+++ b/sys/src/9/ip/ipv6.c
@@ -28,7 +28,7 @@
 int		unfraglen(Block *bp, uchar *nexthdr, int setfh);
 
 int
-ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
+ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh)
 {
 	int medialen, len, chunk, uflen, flen, seglen, lid, offset, fragoff;
 	int morefrags, blklen, rv = 0, tentative;
@@ -74,9 +74,8 @@
 		goto free;
 	}
 
-	r = v6lookup(f, eh->dst, c);
+	r = v6lookup(f, eh->dst, rh);
 	if(r == nil){
-//		print("no route for %I, src %I free\n", eh->dst, eh->src);
 		ip->stats[OutNoRoutes]++;
 		netlog(f, Logip, "no interface %I\n", eh->dst);
 		rv = -1;
@@ -231,7 +230,6 @@
 	IP *ip;
 	Ip6hdr *h;
 	Proto *p;
-	Route *r, *sr;
 
 	ip = f->ip;
 	ip->stats[InReceives]++;
@@ -274,6 +272,9 @@
 
 	/* route */
 	if(notforme) {
+		Route *r;
+		Routehint rh;
+
 		if(!ip->iprouting){
 			freeblist(bp);
 			return;
@@ -288,10 +289,9 @@
 		}
 			
 		/* don't forward to source's network */
-		sr = v6lookup(f, h->src, nil);
-		r  = v6lookup(f, h->dst, nil);
-
-		if(r == nil || sr == r){
+		rh.r = nil;
+		r  = v6lookup(f, h->dst, &rh);
+		if(r == nil || r->ifc == ifc){
 			ip->stats[OutDiscards]++;
 			freeblist(bp);
 			return;
@@ -315,7 +315,7 @@
 		h = (Ip6hdr *)bp->rp;
 		tos = IPV6CLASS(h);
 		hop = h->ttl;
-		ipoput6(f, bp, 1, hop-1, tos, nil);
+		ipoput6(f, bp, 1, hop-1, tos, &rh);
 		return;
 	}
 
--- a/sys/src/9/ip/rudp.c
+++ b/sys/src/9/ip/rudp.c
@@ -567,7 +567,7 @@
 			if(ipforme(f, laddr) == Runi)
 				ipmove(c->laddr, laddr);
 			else
-				v4tov6(c->laddr, ifc->lifc->local);
+				ipv6local(ifc, c->laddr, c->raddr);
 		}
 		break;
 	}
--- a/sys/src/9/ip/udp.c
+++ b/sys/src/9/ip/udp.c
@@ -189,7 +189,7 @@
 	Udppriv *upriv;
 	Fs *f;
 	int version;
-	Conv *rc;
+	Routehint *rh;
 
 	upriv = c->p->priv;
 	f = c->p->f;
@@ -222,18 +222,12 @@
 	}
 
 	if(ucb->headers) {
-		if(memcmp(laddr, v4prefix, IPv4off) == 0
-		|| ipcmp(laddr, IPnoaddr) == 0)
-			version = 4;
+		if(isv4(laddr) || ipcmp(laddr, IPnoaddr) == 0)
+			version = V4;
 		else
-			version = 6;
+			version = V6;
 	} else {
-		if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
-			memcmp(c->laddr, v4prefix, IPv4off) == 0)
-			|| ipcmp(c->raddr, IPnoaddr) == 0)
-			version = 4;
-		else
-			version = 6;
+		version = convipvers(c);
 	}
 
 	dlen = blocklen(bp);
@@ -253,7 +247,7 @@
 			v6tov4(uh4->udpdst, raddr);
 			hnputs(uh4->udpdport, rport);
 			v6tov4(uh4->udpsrc, laddr);
-			rc = nil;
+			rh = nil;
 		} else {
 			v6tov4(uh4->udpdst, c->raddr);
 			hnputs(uh4->udpdport, c->rport);
@@ -260,7 +254,7 @@
 			if(ipcmp(c->laddr, IPnoaddr) == 0)
 				findlocalip(f, c->laddr, c->raddr);
 			v6tov4(uh4->udpsrc, c->laddr);
-			rc = c;
+			rh = c;
 		}
 		hnputs(uh4->udpsport, c->lport);
 		hnputs(uh4->udplen, ptcllen);
@@ -269,7 +263,7 @@
 		hnputs(uh4->udpcksum,
 		       ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));
 		uh4->vihl = IP_VER4;
-		ipoput4(f, bp, 0, c->ttl, c->tos, rc);
+		ipoput4(f, bp, 0, c->ttl, c->tos, rh);
 		break;
 
 	case V6:
@@ -287,7 +281,7 @@
 			ipmove(uh6->udpdst, raddr);
 			hnputs(uh6->udpdport, rport);
 			ipmove(uh6->udpsrc, laddr);
-			rc = nil;
+			rh = nil;
 		} else {
 			ipmove(uh6->udpdst, c->raddr);
 			hnputs(uh6->udpdport, c->rport);
@@ -294,7 +288,7 @@
 			if(ipcmp(c->laddr, IPnoaddr) == 0)
 				findlocalip(f, c->laddr, c->raddr);
 			ipmove(uh6->udpsrc, c->laddr);
-			rc = c;
+			rh = c;
 		}
 		hnputs(uh6->udpsport, c->lport);
 		hnputs(uh6->udplen, ptcllen);
@@ -306,7 +300,7 @@
 		uh6->viclfl[0] = IP_VER6;
 		hnputs(uh6->len, ptcllen);
 		uh6->nextheader = IP_UDPPROTO;
-		ipoput6(f, bp, 0, c->ttl, c->tos, rc);
+		ipoput6(f, bp, 0, c->ttl, c->tos, rh);
 		break;
 
 	default:
@@ -336,7 +330,7 @@
 	upriv->ustats.udpInDatagrams++;
 
 	uh4 = (Udp4hdr*)(bp->rp);
-	version = ((uh4->vihl&0xF0)==IP_VER6) ? 6 : 4;
+	version = ((uh4->vihl&0xF0)==IP_VER6) ? V6 : V4;
 
 	/* Put back pseudo header for checksum
 	 * (remember old values for icmpnoconv()) */
@@ -424,18 +418,8 @@
 	if(c->state == Announced){
 		if(ucb->headers == 0){
 			/* create a new conversation */
-			if(ipforme(f, laddr) != Runi) {
-				switch(version){
-				case V4:
-					v4tov6(laddr, ifc->lifc->local);
-					break;
-				case V6:
-					ipmove(laddr, ifc->lifc->local);
-					break;
-				default:
-					panic("udpiput3: version %d", version);
-				}
-			}
+			if(ipforme(f, laddr) != Runi)
+				ipv6local(ifc, laddr, raddr);
 			c = Fsnewcall(c, raddr, rport, laddr, lport, version);
 			if(c == nil){
 				qunlock(udp);
@@ -533,7 +517,7 @@
 	int version;
 
 	h4 = (Udp4hdr*)(bp->rp);
-	version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4;
+	version = ((h4->vihl&0xF0)==IP_VER6) ? V6 : V4;
 
 	switch(version) {
 	case V4: