shithub: riscv

Download patch

ref: 5aae3d344b9f362539f06d20ea5ca80a0c8b3a78
parent: 20b9326daddd52ffe534a968fb596af1674f53cc
author: cinap_lenrek <[email protected]>
date: Tue Apr 24 16:21:09 EDT 2018

devip: improve arp and ndp code

there appears to be confusion about the refresh flag of arpenter().
when we get an arp reply, it makes more sense to just refresh
waiting/existing entries instead creating a new one as we do not
know if we are going to communicate with the remote host in the future.

when we see an arp request for ourselfs however, we want to always
enter the senders address into the arp cache as it is likely the sender
attempts to communicate with us and with the arp entry, we can reply
immidiately.

reject senders from multicast/broadcast mac addresses. thats just silly.

we can get rid of the multicast/broadcast ip checks in ethermedium and
do it in arpenter() instead, checking the route type for the target to
see if its a non unicast target.

enforce strict separation of interface's arp entries by passing a
rlock'd ifc explicitely to arpenter, which we compare against the route
target interface. this makes sure arp/ndp replies only affect entries for
the receiving interface.

handle neighbor solicitation retransmission in nbsendsol() only. that is,
both ethermedium and the rxmitproc just call nbsendsol() which maintains
the timers and counters and handles the rotation on the re-transmission
chain.

--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -73,133 +73,106 @@
 	}
 }
 
-/*
- *  create a new arp entry for an ip address on ifc.
- */
-static Arpent*
-newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
+/* take out of re-transmit chain */
+static Arpent**
+rxmtunchain(Arp *arp, Arpent *a)
 {
-	uint t;
-	Block *xp;
-	Arpent *a, *e, *f, **l;
-	int empty;
+	Arpent **l;
 
-	/* find oldest entry */
-	e = &arp->cache[NCACHE];
-	a = arp->cache;
-	t = a->utime;
-	for(f = a; f < e; f++){
-		if(f->utime < t){
-			t = f->utime;
-			a = f;
+	for(l = &arp->rxmt; *l != nil; l = &((*l)->nextrxt)){
+		if(*l == a){
+			*l = a->nextrxt;
+			break;
 		}
 	}
+	a->nextrxt = nil;
+	return l;
+}
 
+static void
+cleanarpent(Arp *arp, Arpent *a)
+{
+	Arpent **l;
+	Block *bp;
+
+	/* take out of current chain */
+	for(l = &arp->hash[haship(a->ip)]; *l != nil; l = &((*l)->hash)){
+		if(*l == a){
+			*l = a->hash;
+			break;
+		}
+	}
+	a->hash = nil;
+
 	/* dump waiting packets */
-	xp = a->hold;
+	bp = a->hold;
 	a->hold = nil;
 	if(isv4(a->ip))
-		freeblistchain(xp);
-	else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
-		if(xp != nil){
-			if(arp->dropf == nil) 
-				arp->dropf = xp;
+		freeblistchain(bp);
+	else {
+		rxmtunchain(arp, a);
+
+		/* queue icmp unreachable for rxmitproc later on, w/o arp lock */
+		if(bp != nil){
+			if(arp->dropf == nil)
+				arp->dropf = bp;
 			else
-				arp->dropl->list = xp;
+				arp->dropl->list = bp;
 			arp->dropl = a->last;
-			wakeup(&arp->rxmtq);
+
+			if(bp == arp->dropf)
+				wakeup(&arp->rxmtq);
 		}
 	}
 	a->last = nil;
 
-	/* take out of current chain */
-	l = &arp->hash[haship(a->ip)];
-	for(f = *l; f != nil; f = f->hash){
-		if(f == a){
-			*l = a->hash;
-			break;
-		}
-		l = &f->hash;
-	}
+	a->ifc = nil;
+	a->ifcid = 0;
 
-	/* insert into new chain */
-	l = &arp->hash[haship(ip)];
-	a->hash = *l;
-	*l = a;
+	a->state = 0;
+	a->rxtsrem = 0;
 
-	ipmove(a->ip, ip);
-	a->utime = NOW;
+	a->utime = 0;
 	a->ctime = 0;
 
-	a->rtime = NOW + ReTransTimer;
-	a->rxtsrem = MAX_MULTICAST_SOLICIT;
-	a->ifc = ifc;
-	a->ifcid = ifc->ifcid;
+	memset(a->ip, 0, sizeof(a->ip));
+	memset(a->mac, 0, sizeof(a->mac));
+}
 
-	/* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
-	if(!ipismulticast(a->ip) && addrxt){
-		l = &arp->rxmt;
-		empty = (*l == nil);
+/*
+ *  create a new arp entry for an ip address on ifc.
+ */
+static Arpent*
+newarpent(Arp *arp, uchar *ip, Ipifc *ifc)
+{
+	Arpent *a, *e, *f, **l;
+	ulong t;
 
-		for(f = *l; f != nil; f = f->nextrxt){
-			if(f == a){
-				*l = a->nextrxt;
-				break;
-			}
-			l = &f->nextrxt;
+	/* find oldest entry */
+	e = &arp->cache[NCACHE];
+	a = arp->cache;
+	t = a->utime;
+	for(f = a; f < e; f++){
+		if(f->utime < t){
+			t = f->utime;
+			a = f;
 		}
-		for(f = *l; f != nil; f = f->nextrxt)
-			l = &f->nextrxt;
-
-		*l = a;
-		if(empty) 
-			wakeup(&arp->rxmtq);
 	}
+	cleanarpent(arp, a);
 
-	a->nextrxt = nil;
+	ipmove(a->ip, ip);
+	a->ifc = ifc;
+	a->ifcid = ifc->ifcid;
 
+	/* insert into new chain */
+	l = &arp->hash[haship(ip)];
+	a->hash = *l;
+	*l = a;
+
 	return a;
 }
 
-/* called with arp qlocked */
 
-static void
-cleanarpent(Arp *arp, Arpent *a)
-{
-	Arpent *f, **l;
-
-	a->utime = 0;
-	a->ctime = 0;
-	a->state = 0;
-
-	a->ifc = nil;
-	a->ifcid = 0;
-	
-	/* take out of current chain */
-	l = &arp->hash[haship(a->ip)];
-	for(f = *l; f != nil; f = f->hash){
-		if(f == a){
-			*l = a->hash;
-			break;
-		}
-		l = &f->hash;
-	}
-
-	/* take out of re-transmit chain */
-	l = &arp->rxmt;
-	for(f = *l; f != nil; f = f->nextrxt){
-		if(f == a){
-			*l = a->nextrxt;
-			break;
-		}
-		l = &f->nextrxt;
-	}
-	a->nextrxt = nil;
-	a->hash = nil;
-	freeblistchain(a->hold);
-	a->hold = a->last = nil;
-}
-
 /*
  *  fill in the media address if we have it.  Otherwise return an
  *  Arpent that represents the state of the address resolution FSM
@@ -225,7 +198,7 @@
 			break;
 	}
 	if(a == nil){
-		a = newarp6(arp, ip, ifc, (version != V4));
+		a = newarpent(arp, ip, ifc);
 		a->state = AWAIT;
 	}
 	a->utime = NOW;
@@ -270,21 +243,14 @@
 arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
 {
 	Block *bp;
-	Arpent *f, **l;
 
-	if(!isv4(a->ip)){
-		l = &arp->rxmt;
-		for(f = *l; f != nil; f = f->nextrxt){
-			if(f == a){
-				*l = a->nextrxt;
-				break;
-			}
-			l = &f->nextrxt;
-		}
-	}
 	memmove(a->mac, mac, type->maclen);
+	if(a->state == AWAIT && !isv4(a->ip)){
+		rxmtunchain(arp, a);
+		a->rxtsrem = 0;
+	}
 	a->state = AOK;
-	a->utime = NOW;
+	a->ctime = a->utime = NOW;
 	bp = a->hold;
 	a->hold = a->last = nil;
 	qunlock(arp);
@@ -293,16 +259,17 @@
 }
 
 int
-arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *ia, int refresh)
+arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *ifc, int refresh)
 {
-	Arp *arp;
-	Route *r;
-	Arpent *a, *f, **l;
-	Ipifc *ifc;
-	Block *bp, *next;
 	uchar v6ip[IPaddrlen];
+	Block *bp, *next;
+	Arpent *a;
+	Route *r;
+	Arp *arp;
 
-	arp = fs->arp;
+	if(ifc->m == nil || ifc->m->maclen != n || ifc->m->maclen == 0)
+		return -1;
+
 	switch(version){
 	case V4:
 		r = v4lookup(fs, ip, ia, nil);
@@ -316,46 +283,20 @@
 		panic("arpenter: version %d", version);
 		return -1;	/* to supress warnings */
 	}
-	if(r == nil || (ifc = r->ifc) == nil)
-		return -1;
 
-	rlock(ifc);
-	if(ifc->m == nil || ifc->m->maclen != n || ifc->m->maclen == 0){
-		runlock(ifc);
+	if(r == nil || r->ifc != ifc || (r->type & (Rbcast|Rmulti)) != 0)
 		return -1;
-	}
 
+	arp = fs->arp;
 	qlock(arp);
 	for(a = arp->hash[haship(ip)]; a != nil; a = a->hash){
-		if(a->state != AWAIT && a->state != AOK)
-			continue;
 		if(a->ifc != ifc || a->ifcid != ifc->ifcid)
 			continue;
 		if(ipcmp(a->ip, ip) == 0){
-			a->state = AOK;
-			memmove(a->mac, mac, n);
-
-			if(version == V6){
-				/* take out of re-transmit chain */
-				l = &arp->rxmt;
-				for(f = *l; f != nil; f = f->nextrxt){
-					if(f == a){
-						*l = a->nextrxt;
-						break;
-					}
-					l = &f->nextrxt;
-				}
-			}
-
-			bp = a->hold;
-			a->hold = a->last = nil;
 			if(version == V4)
 				ip += IPv4off;
-			a->utime = NOW;
-			a->ctime = a->utime;
-			qunlock(arp);
-
-			while(bp != nil){
+			bp = arpresolve(arp, a, ifc->m, mac);	/* unlocks arp */
+			for(; bp != nil; bp = next){
 				next = bp->list;
 				bp->list = nil;
 				if(waserror()){
@@ -364,21 +305,18 @@
 				}
 				ifc->m->bwrite(ifc, concatblock(bp), version, ip);
 				poperror();
-				bp = next;
 			}
-			runlock(ifc);
 			return 1;
 		}
 	}
 
 	if(refresh == 0){
-		a = newarp6(arp, ip, ifc, 0);
+		a = newarpent(arp, ip, ifc);
 		a->state = AOK;
-		a->ctime = NOW;
+		a->ctime = a->utime = NOW;
 		memmove(a->mac, mac, n);
 	}
 	qunlock(arp);
-	runlock(ifc);
 
 	return refresh == 0;
 }
@@ -390,6 +328,7 @@
 	Arp *arp;
 	Arpent *a, *x;
 	Medium *m;
+	Ipifc *ifc;
 	char *f[5], buf[256];
 	uchar ip[IPaddrlen], ia[IPaddrlen], mac[MAClen];
 
@@ -411,18 +350,20 @@
 			memset(a->ip, 0, sizeof(a->ip));
 			memset(a->mac, 0, sizeof(a->mac));
 			a->hash = nil;
-			a->state = 0;
-			a->utime = 0;
+			a->nextrxt = nil;
 			a->ifc = nil;
 			a->ifcid = 0;
+			a->state = 0;
+			a->rxtsrem = 0;
+			a->ctime = 0;
+			a->utime = 0;
 			freeblistchain(a->hold);
 			a->hold = a->last = nil;
 		}
 		memset(arp->hash, 0, sizeof(arp->hash));
-		/* clear all pkts on these lists (rxmt, dropf/l) */
-		arp->rxmt = nil;
 		freeblistchain(arp->dropf);
 		arp->dropf = arp->dropl = nil;
+		arp->rxmt = nil;
 		qunlock(arp);
 	} else if(strcmp(f[0], "add") == 0){
 		switch(n){
@@ -457,8 +398,14 @@
 				error(Ebadip);
 			break;
 		}
-		if(arpenter(fs, V6, ip, mac, n, ia, 0) <= 0)
+		if((ifc = findipifc(fs, ia, ia, Runi)) == nil)
+			error("no interface");
+		rlock(ifc);
+		if(arpenter(fs, V6, ip, mac, n, ia, ifc, 0) < 0){
+			runlock(ifc);
 			error("destination unreachable");
+		}
+		runlock(ifc);
 	} else if(strcmp(f[0], "del") == 0){
 		if (n != 2)
 			error(Ebadarg);
@@ -467,11 +414,8 @@
 		qlock(arp);
 		for(a = arp->hash[haship(ip)]; a != nil; a = x){
 			x = a->hash;
-			if(ipcmp(ip, a->ip) == 0){
+			if(ipcmp(ip, a->ip) == 0)
 				cleanarpent(arp, a);
-				memset(a->ip, 0, sizeof(a->ip));
-				memset(a->mac, 0, sizeof(a->mac));
-			}
 		}
 		qunlock(arp);
 	} else
@@ -535,9 +479,24 @@
 ndpsendsol(Fs *f, Ipifc *ifc, Arpent *a)
 {
 	uchar targ[IPaddrlen], src[IPaddrlen];
+	Arpent **l;
 
-	ipmove(targ, a->ip);
+	a->ctime = NOW;
+	if(a->rxtsrem == 0)
+		a->rxtsrem = MAX_MULTICAST_SOLICIT;
+	else
+		a->rxtsrem--;
 
+	/* put on end of re-transmit chain */
+	for(l = rxmtunchain(f->arp, a); *l != nil; l = &(*l)->nextrxt)
+		;
+	*l = a;
+
+	if(l == &f->arp->rxmt)
+		wakeup(&f->arp->rxmtq);
+
+	/* try to use source address of original packet */
+	ipmove(targ, a->ip);
 	if(a->last != nil){
 		ipmove(src, ((Ip6hdr*)a->last->rp)->src);
 		arprelease(f->arp, a);
@@ -547,7 +506,6 @@
 	} else {
 		arprelease(f->arp, a);
 	}
-
 	if(!ipv6local(ifc, src, targ))
 		return;
 send:
@@ -557,107 +515,50 @@
 	}
 }
 
-long
+static void
 rxmitsols(Arp *arp)
 {
-	Block *next, *xp;
-	Arpent *a, *b, **l;
+	Block *next, *bp;
+	Arpent *a;
 	Ipifc *ifc;
-	long nrxt;
-	Fs *f;
+	Route *r;
 
 	qlock(arp);
-	f = arp->f;
-
-	a = arp->rxmt;
-	if(a == nil){
-		nrxt = 0;
-		goto dodrops; 		/* return nrxt; */
-	}
-	nrxt = a->rtime - NOW;
-	if(nrxt > 3*ReTransTimer/4) 
-		goto dodrops; 		/* return nrxt; */
-
-	ifc = nil;
-	for(; a != nil; a = a->nextrxt){
-		ifc = a->ifc;
-		if(a->rxtsrem > 0 && ifc != nil && canrlock(ifc)){
-			if(a->ifcid == ifc->ifcid)
-				break;
+	while((a = arp->rxmt) != nil && NOW - a->ctime > 3*ReTransTimer/4){
+		if(a->rxtsrem > 0 && (ifc = a->ifc) != nil && canrlock(ifc)){
+			if(a->ifcid == ifc->ifcid){
+				ndpsendsol(arp->f, ifc, a);	/* unlocks arp */
+				runlock(ifc);
+				qlock(arp);
+				continue;
+			}
 			runlock(ifc);
 		}
-		xp = a->hold;
-		a->hold = nil;
-		if(xp != nil){
-			if(arp->dropf == nil) 
-				arp->dropf = xp;
-			else
-				arp->dropl->list = xp;
-			arp->dropl = a->last;
-		}
 		cleanarpent(arp, a);
 	}
-	if(a == nil)
-		goto dodrops;
-
-	ndpsendsol(f, ifc, a);	/* unlocks arp */
-
-	runlock(ifc);
-	qlock(arp);	
-
-	/* put to the end of re-transmit chain */
-	l = &arp->rxmt;
-	for(b = *l; b != nil; b = b->nextrxt){
-		if(b == a){
-			*l = a->nextrxt;
-			break;
-		}
-		l = &b->nextrxt;
-	}
-	for(b = *l; b != nil; b = b->nextrxt)
-		l = &b->nextrxt;
-
-	*l = a;
-	a->rxtsrem--;
-	a->nextrxt = nil;
-	a->rtime = NOW + ReTransTimer;
-
-	a = arp->rxmt;
-	if(a == nil)
-		nrxt = 0;
-	else 
-		nrxt = a->rtime - NOW;
-
-dodrops:
-	xp = arp->dropf;
+	bp = arp->dropf;
 	arp->dropf = arp->dropl = nil;
 	qunlock(arp);
 
-	for(; xp != nil; xp = next){
-		Ip6hdr *eh;
-		Route *r;
-
-		next = xp->list;
-		eh = (Ip6hdr*)xp->rp;
-		r = v6lookup(f, eh->src, eh->dst, nil);
+	for(; bp != nil; bp = next){
+		next = bp->list;
+		bp->list = nil;
+		r = v6lookup(arp->f, ((Ip6hdr*)bp->rp)->src, ((Ip6hdr*)bp->rp)->dst, nil);
 		if(r != nil && (ifc = r->ifc) != nil && canrlock(ifc)){
 			if(!waserror()){
-				icmphostunr6(f, ifc, xp, Icmp6_adr_unreach, (r->type & Runi) != 0);
+				icmphostunr6(arp->f, ifc, bp, Icmp6_adr_unreach, (r->type & Runi) != 0);
 				poperror();
 			}
 			runlock(ifc);
 		}
-		freeblist(xp);
+		freeblist(bp);
 	}
-
-	return nrxt;
-
 }
 
 static int
 rxready(void *v)
 {
-	Arp *arp = (Arp *) v;
+	Arp *arp = (Arp *)v;
 
 	return arp->rxmt != nil || arp->dropf != nil;
 }
@@ -666,7 +567,6 @@
 rxmitproc(void *v)
 {
 	Arp *arp = v;
-	long wakeupat;
 
 	arp->rxmitp = up;
 	if(waserror()){
@@ -674,11 +574,8 @@
 		pexit("hangup", 1);
 	}
 	for(;;){
-		wakeupat = rxmitsols(arp);
-		if(wakeupat == 0) 
-			sleep(&arp->rxmtq, rxready, v); 
-		else if(wakeupat > ReTransTimer/4) 
-			tsleep(&arp->rxmtq, return0, 0, wakeupat); 
+		sleep(&arp->rxmtq, rxready, v);
+		rxmitsols(arp);
+		tsleep(&arp->rxmtq, return0, nil, ReTransTimer/4);
 	}
 }
-
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -36,9 +36,9 @@
 static void	etherareg(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip);
 static Block*	multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
 static void	sendarp(Ipifc *ifc, Arpent *a);
+static void	sendndp(Ipifc *ifc, Arpent *a);
 static int	multicastea(uchar *ea, uchar *ip);
 static void	recvarpproc(void*);
-static void	resolveaddr6(Ipifc *ifc, Arpent *a);
 static void	etherpref2addr(uchar *pref, uchar *ea);
 
 Medium ethermedium =
@@ -272,13 +272,13 @@
 	if(a != nil){
 		/* check for broadcast or multicast */
 		bp = multicastarp(er->f, a, ifc->m, mac);
-		if(bp==nil){
+		if(bp == nil){
 			switch(version){
 			case V4:
 				sendarp(ifc, a);
 				break;
 			case V6:
-				resolveaddr6(ifc, a);
+				sendndp(ifc, a);
 				break;
 			default:
 				panic("etherbwrite: version %d", version);
@@ -492,7 +492,7 @@
 }
 
 static void
-resolveaddr6(Ipifc *ifc, Arpent *a)
+sendndp(Ipifc *ifc, Arpent *a)
 {
 	Block *bp;
 	Etherrock *er = ifc->arg;
@@ -511,15 +511,6 @@
 		freeblist(bp);
 	}
 
-	/* try to keep it around for a second more */
-	a->ctime = NOW;
-	a->rtime = NOW + ReTransTimer;
-	if(a->rxtsrem <= 0) {
-		arprelease(er->f->arp, a);
-		return;
-	}
-
-	a->rxtsrem--;
 	ndpsendsol(er->f, ifc, a);	/* unlocks arp */
 }
 
@@ -560,7 +551,7 @@
 static void
 recvarp(Ipifc *ifc)
 {
-	int n;
+	int n, forme;
 	Block *ebp, *rbp;
 	Etherarp *e, *r;
 	uchar ip[IPaddrlen];
@@ -582,6 +573,10 @@
 		break;
 
 	case ARPREPLY:
+		/* make sure not to enter multi/broadcat address */
+		if(e->sha[0] & 1)
+			break;
+
 		/* check for machine using my ip address */
 		v4tov6(ip, e->spa);
 		if(iplocalonifc(ifc, ip) != nil || ipproxyifc(er->f, ifc, ip)){
@@ -592,17 +587,15 @@
 			}
 		}
 
-		/* make sure we're not entering broadcast addresses */
-		if(ipcmp(ip, ipbroadcast) == 0 || memcmp(e->sha, etherbroadcast, sizeof(e->sha)) == 0){
-			print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
-				e->s, e->sha, e->spa);
-			break;
-		}
-
-		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), e->tpa, 0);
+		/* refresh what we know about sender */
+		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), e->tpa, ifc, 1);
 		break;
 
 	case ARPREQUEST:
+		/* don't reply to multi/broadcat addresses */
+		if(e->sha[0] & 1)
+			break;
+
 		/* don't answer arps till we know who we are */
 		if(ifc->lifc == nil)
 			break;
@@ -613,23 +606,28 @@
 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
 				if(memcmp(eprinted, e->spa, sizeof(e->spa)) != 0){
 					/* print only once */
-					print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
+					print("arpreq: 0x%E also has ip addr %V\n",
+						e->sha, e->spa);
 					memmove(eprinted, e->spa, sizeof(e->spa));
 				}
+				break;
 			}
 		} else {
 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
-				print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
+				print("arpreq: %V also has ether addr %E\n",
+					e->spa, e->sha);
 				break;
 			}
 		}
 
-		/* refresh what we know about sender */
-		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), e->tpa, 1);
-
-		/* answer only requests for our address or systems we're proxying for */
+		/*
+		 * when request is for our address or systems we're proxying for,
+		 * enter senders address into arp table and reply, otherwise just
+		 * refresh the senders address.
+		 */
 		v4tov6(ip, e->tpa);
-		if(iplocalonifc(ifc, ip) == nil && !ipproxyifc(er->f, ifc, ip))
+		forme = iplocalonifc(ifc, ip) != nil || ipproxyifc(er->f, ifc, ip);
+		if(arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), e->tpa, ifc, !forme) < 0 || !forme)
 			break;
 
 		n = sizeof(Etherarp);
@@ -761,7 +759,7 @@
 	static char tdad[] = "dad6";
 	uchar a[IPaddrlen];
 
-	if(ipcmp(ip, IPnoaddr) == 0)
+	if(ipcmp(ip, IPnoaddr) == 0 || ipcmp(ip, v4prefix) == 0)
 		return;
 
 	if(isv4(ip)){
--- a/sys/src/9/ip/icmp6.c
+++ b/sys/src/9/ip/icmp6.c
@@ -752,7 +752,7 @@
 		break;
 
 	case NbrSolicit:
-		np = (Ndpkt*) p;
+		np = (Ndpkt*)p;
 		pktflags = 0;
 		if(ifc->sendra6)
 			pktflags |= Rflag;
@@ -763,7 +763,8 @@
 
 		case Tuniproxy:
 			if(ipv6local(ifc, ia, np->src)) {
-				arpenter(icmp->f, V6, np->src, np->lnaddr, 8*np->olen-2, ia, 0);
+				if(arpenter(icmp->f, V6, np->src, np->lnaddr, 8*np->olen-2, ia, ifc, 0) < 0)
+					break;
 				pktflags |= Sflag;
 			} else
 				ipmove(ia, np->target);
@@ -781,7 +782,7 @@
 		break;
 
 	case NbrAdvert:
-		np = (Ndpkt*) p;
+		np = (Ndpkt*)p;
 
 		/*
 		 * if the target address matches one of the local interface
@@ -792,9 +793,9 @@
 		 */
 		lifc = iplocalonifc(ifc, np->target);
 		if(lifc != nil && lifc->tentative)
-			arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, np->target, 0);
+			arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, np->target, ifc, 0);
 		else if(ipv6local(ifc, ia, np->target))
-			arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, ia, 1);
+			arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, ia, ifc, 1);
 		freeblist(bp);
 		break;
 
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -589,17 +589,16 @@
 {
 	uchar	ip[IPaddrlen];
 	uchar	mac[MAClen];
-	Arpent*	hash;
-	Block*	hold;
-	Block*	last;
-	uint	ctime;			/* time entry was created or refreshed */
-	uint	utime;			/* time entry was last used */
-	uchar	state;
+	Arpent	*hash;
 	Arpent	*nextrxt;		/* re-transmit chain */
-	uint	rtime;			/* time for next retransmission */
-	uchar	rxtsrem;
+	Block	*hold;
+	Block	*last;
 	Ipifc	*ifc;
 	uchar	ifcid;			/* must match ifc->id */
+	uchar	state;
+	uchar	rxtsrem;		/* re-tranmissions remaining */
+	ulong	ctime;			/* time entry was created or refreshed */
+	ulong	utime;			/* time entry was last used */
 };
 
 extern void	arpinit(Fs*);
@@ -608,7 +607,7 @@
 extern Arpent*	arpget(Arp*, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *h);
 extern void	arprelease(Arp*, Arpent *a);
 extern Block*	arpresolve(Arp*, Arpent *a, Medium *type, uchar *mac);
-extern int	arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *ia, int norefresh);
+extern int	arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *ifc, int refresh);
 extern void	ndpsendsol(Fs*, Ipifc*, Arpent*);
 
 /*
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -1145,7 +1145,7 @@
 			return (Ipifc*)c->ptcl;
 	}
 	if(parseip(ip, s) != -1)
-		return findipifc(f, IPnoaddr, ip, Runi);
+		return findipifc(f, ip, ip, Runi);
 	return nil;
 }