xref: /plan9/sys/src/9/ip/arp.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "../port/error.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier #include "ip.h"
93ff48bf5SDavid du Colombier #include "ipv6.h"
107dd7cddfSDavid du Colombier 
117dd7cddfSDavid du Colombier /*
127dd7cddfSDavid du Colombier  *  address resolution tables
137dd7cddfSDavid du Colombier  */
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier enum
167dd7cddfSDavid du Colombier {
177dd7cddfSDavid du Colombier 	NHASH		= (1<<6),
187dd7cddfSDavid du Colombier 	NCACHE		= 256,
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier 	AOK		= 1,
217dd7cddfSDavid du Colombier 	AWAIT		= 2,
227dd7cddfSDavid du Colombier };
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier char *arpstate[] =
257dd7cddfSDavid du Colombier {
267dd7cddfSDavid du Colombier 	"UNUSED",
277dd7cddfSDavid du Colombier 	"OK",
287dd7cddfSDavid du Colombier 	"WAIT",
297dd7cddfSDavid du Colombier };
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier /*
327dd7cddfSDavid du Colombier  *  one per Fs
337dd7cddfSDavid du Colombier  */
347dd7cddfSDavid du Colombier struct Arp
357dd7cddfSDavid du Colombier {
367dd7cddfSDavid du Colombier 	QLock;
377dd7cddfSDavid du Colombier 	Fs	*f;
387dd7cddfSDavid du Colombier 	Arpent	*hash[NHASH];
397dd7cddfSDavid du Colombier 	Arpent	cache[NCACHE];
403ff48bf5SDavid du Colombier 	Arpent	*rxmt;
413ff48bf5SDavid du Colombier 	Proc	*rxmitp;	/* neib sol re-transmit proc */
423ff48bf5SDavid du Colombier 	Rendez	rxmtq;
433ff48bf5SDavid du Colombier 	Block 	*dropf, *dropl;
449a747e4fSDavid du Colombier };
459a747e4fSDavid du Colombier 
467dd7cddfSDavid du Colombier char *Ebadarp = "bad arp";
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier #define haship(s) ((s)[IPaddrlen-1]%NHASH)
497dd7cddfSDavid du Colombier 
503ff48bf5SDavid du Colombier extern int 	ReTransTimer = RETRANS_TIMER;
51ea58ad6fSDavid du Colombier 
523ff48bf5SDavid du Colombier static void 	rxmitproc(void *v);
533ff48bf5SDavid du Colombier 
547dd7cddfSDavid du Colombier void
arpinit(Fs * f)557dd7cddfSDavid du Colombier arpinit(Fs *f)
567dd7cddfSDavid du Colombier {
577dd7cddfSDavid du Colombier 	f->arp = smalloc(sizeof(Arp));
587dd7cddfSDavid du Colombier 	f->arp->f = f;
593ff48bf5SDavid du Colombier 	f->arp->rxmt = nil;
603ff48bf5SDavid du Colombier 	f->arp->dropf = f->arp->dropl = nil;
613ff48bf5SDavid du Colombier 	kproc("rxmitproc", rxmitproc, f->arp);
627dd7cddfSDavid du Colombier }
637dd7cddfSDavid du Colombier 
643ff48bf5SDavid du Colombier /*
653ff48bf5SDavid du Colombier  *  create a new arp entry for an ip address.
663ff48bf5SDavid du Colombier  */
677dd7cddfSDavid du Colombier static Arpent*
newarp6(Arp * arp,uchar * ip,Ipifc * ifc,int addrxt)683ff48bf5SDavid du Colombier newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier 	uint t;
717dd7cddfSDavid du Colombier 	Block *next, *xp;
727dd7cddfSDavid du Colombier 	Arpent *a, *e, *f, **l;
733ff48bf5SDavid du Colombier 	Medium *m = ifc->m;
743ff48bf5SDavid du Colombier 	int empty;
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier 	/* find oldest entry */
777dd7cddfSDavid du Colombier 	e = &arp->cache[NCACHE];
787dd7cddfSDavid du Colombier 	a = arp->cache;
79a6a9e072SDavid du Colombier 	t = a->utime;
807dd7cddfSDavid du Colombier 	for(f = a; f < e; f++){
81a6a9e072SDavid du Colombier 		if(f->utime < t){
82a6a9e072SDavid du Colombier 			t = f->utime;
837dd7cddfSDavid du Colombier 			a = f;
847dd7cddfSDavid du Colombier 		}
857dd7cddfSDavid du Colombier 	}
867dd7cddfSDavid du Colombier 
877dd7cddfSDavid du Colombier 	/* dump waiting packets */
887dd7cddfSDavid du Colombier 	xp = a->hold;
897dd7cddfSDavid du Colombier 	a->hold = nil;
903ff48bf5SDavid du Colombier 
913ff48bf5SDavid du Colombier 	if(isv4(a->ip)){
927dd7cddfSDavid du Colombier 		while(xp){
937dd7cddfSDavid du Colombier 			next = xp->list;
947dd7cddfSDavid du Colombier 			freeblist(xp);
957dd7cddfSDavid du Colombier 			xp = next;
967dd7cddfSDavid du Colombier 		}
973ff48bf5SDavid du Colombier 	}
9841dd6b47SDavid du Colombier 	else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
993ff48bf5SDavid du Colombier 		if(xp){
1003ff48bf5SDavid du Colombier 			if(arp->dropl == nil)
1013ff48bf5SDavid du Colombier 				arp->dropf = xp;
1023ff48bf5SDavid du Colombier 			else
1033ff48bf5SDavid du Colombier 				arp->dropl->list = xp;
1043ff48bf5SDavid du Colombier 
1053ff48bf5SDavid du Colombier 			for(next = xp->list; next; next = next->list)
1063ff48bf5SDavid du Colombier 				xp = next;
1073ff48bf5SDavid du Colombier 			arp->dropl = xp;
1083ff48bf5SDavid du Colombier 			wakeup(&arp->rxmtq);
1093ff48bf5SDavid du Colombier 		}
1103ff48bf5SDavid du Colombier 	}
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier 	/* take out of current chain */
1137dd7cddfSDavid du Colombier 	l = &arp->hash[haship(a->ip)];
1147dd7cddfSDavid du Colombier 	for(f = *l; f; f = f->hash){
1157dd7cddfSDavid du Colombier 		if(f == a){
1167dd7cddfSDavid du Colombier 			*l = a->hash;
1177dd7cddfSDavid du Colombier 			break;
1187dd7cddfSDavid du Colombier 		}
1197dd7cddfSDavid du Colombier 		l = &f->hash;
1207dd7cddfSDavid du Colombier 	}
1217dd7cddfSDavid du Colombier 
1227dd7cddfSDavid du Colombier 	/* insert into new chain */
1237dd7cddfSDavid du Colombier 	l = &arp->hash[haship(ip)];
1247dd7cddfSDavid du Colombier 	a->hash = *l;
1257dd7cddfSDavid du Colombier 	*l = a;
1263ff48bf5SDavid du Colombier 
1277dd7cddfSDavid du Colombier 	memmove(a->ip, ip, sizeof(a->ip));
128a6a9e072SDavid du Colombier 	a->utime = NOW;
12904b73bddSDavid du Colombier 	a->ctime = 0;
1307dd7cddfSDavid du Colombier 	a->type = m;
1317dd7cddfSDavid du Colombier 
132a6a9e072SDavid du Colombier 	a->rtime = NOW + ReTransTimer;
1333ff48bf5SDavid du Colombier 	a->rxtsrem = MAX_MULTICAST_SOLICIT;
1343ff48bf5SDavid du Colombier 	a->ifc = ifc;
1353ff48bf5SDavid du Colombier 	a->ifcid = ifc->ifcid;
1363ff48bf5SDavid du Colombier 
1373ff48bf5SDavid du Colombier 	/* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
1383ff48bf5SDavid du Colombier 	if(!ipismulticast(a->ip) && addrxt){
1393ff48bf5SDavid du Colombier 		l = &arp->rxmt;
1403ff48bf5SDavid du Colombier 		empty = (*l==nil);
1413ff48bf5SDavid du Colombier 
1423ff48bf5SDavid du Colombier 		for(f = *l; f; f = f->nextrxt){
1433ff48bf5SDavid du Colombier 			if(f == a){
1443ff48bf5SDavid du Colombier 				*l = a->nextrxt;
1453ff48bf5SDavid du Colombier 				break;
1463ff48bf5SDavid du Colombier 			}
1473ff48bf5SDavid du Colombier 			l = &f->nextrxt;
1483ff48bf5SDavid du Colombier 		}
1493ff48bf5SDavid du Colombier 		for(f = *l; f; f = f->nextrxt){
1503ff48bf5SDavid du Colombier 			l = &f->nextrxt;
1513ff48bf5SDavid du Colombier 		}
1523ff48bf5SDavid du Colombier 		*l = a;
1533ff48bf5SDavid du Colombier 		if(empty)
1543ff48bf5SDavid du Colombier 			wakeup(&arp->rxmtq);
1553ff48bf5SDavid du Colombier 	}
1563ff48bf5SDavid du Colombier 
1573ff48bf5SDavid du Colombier 	a->nextrxt = nil;
1583ff48bf5SDavid du Colombier 
1597dd7cddfSDavid du Colombier 	return a;
1607dd7cddfSDavid du Colombier }
1617dd7cddfSDavid du Colombier 
1623ff48bf5SDavid du Colombier /* called with arp qlocked */
1633ff48bf5SDavid du Colombier 
1643ff48bf5SDavid du Colombier void
cleanarpent(Arp * arp,Arpent * a)1653ff48bf5SDavid du Colombier cleanarpent(Arp *arp, Arpent *a)
1663ff48bf5SDavid du Colombier {
1673ff48bf5SDavid du Colombier 	Arpent *f, **l;
1683ff48bf5SDavid du Colombier 
169a6a9e072SDavid du Colombier 	a->utime = 0;
170a6a9e072SDavid du Colombier 	a->ctime = 0;
1713ff48bf5SDavid du Colombier 	a->type = 0;
1723ff48bf5SDavid du Colombier 	a->state = 0;
1733ff48bf5SDavid du Colombier 
1743ff48bf5SDavid du Colombier 	/* take out of current chain */
1753ff48bf5SDavid du Colombier 	l = &arp->hash[haship(a->ip)];
1763ff48bf5SDavid du Colombier 	for(f = *l; f; f = f->hash){
1773ff48bf5SDavid du Colombier 		if(f == a){
1783ff48bf5SDavid du Colombier 			*l = a->hash;
1793ff48bf5SDavid du Colombier 			break;
1803ff48bf5SDavid du Colombier 		}
1813ff48bf5SDavid du Colombier 		l = &f->hash;
1823ff48bf5SDavid du Colombier 	}
1833ff48bf5SDavid du Colombier 
1843ff48bf5SDavid du Colombier 	/* take out of re-transmit chain */
1853ff48bf5SDavid du Colombier 	l = &arp->rxmt;
1863ff48bf5SDavid du Colombier 	for(f = *l; f; f = f->nextrxt){
1873ff48bf5SDavid du Colombier 		if(f == a){
1883ff48bf5SDavid du Colombier 			*l = a->nextrxt;
1893ff48bf5SDavid du Colombier 			break;
1903ff48bf5SDavid du Colombier 		}
1913ff48bf5SDavid du Colombier 		l = &f->nextrxt;
1923ff48bf5SDavid du Colombier 	}
1933ff48bf5SDavid du Colombier 	a->nextrxt = nil;
1943ff48bf5SDavid du Colombier 	a->hash = nil;
1953ff48bf5SDavid du Colombier 	a->hold = nil;
1963ff48bf5SDavid du Colombier 	a->last = nil;
1973ff48bf5SDavid du Colombier 	a->ifc = nil;
1983ff48bf5SDavid du Colombier }
1993ff48bf5SDavid du Colombier 
2003ff48bf5SDavid du Colombier /*
2013ff48bf5SDavid du Colombier  *  fill in the media address if we have it.  Otherwise return an
2023ff48bf5SDavid du Colombier  *  Arpent that represents the state of the address resolution FSM
2033ff48bf5SDavid du Colombier  *  for ip.  Add the packet to be sent onto the list of packets
2043ff48bf5SDavid du Colombier  *  waiting for ip->mac to be resolved.
2053ff48bf5SDavid du Colombier  */
2067dd7cddfSDavid du Colombier Arpent*
arpget(Arp * arp,Block * bp,int version,Ipifc * ifc,uchar * ip,uchar * mac)2073ff48bf5SDavid du Colombier arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
2087dd7cddfSDavid du Colombier {
2097dd7cddfSDavid du Colombier 	int hash;
2107dd7cddfSDavid du Colombier 	Arpent *a;
2113ff48bf5SDavid du Colombier 	Medium *type = ifc->m;
2127dd7cddfSDavid du Colombier 	uchar v6ip[IPaddrlen];
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 	if(version == V4){
2157dd7cddfSDavid du Colombier 		v4tov6(v6ip, ip);
2167dd7cddfSDavid du Colombier 		ip = v6ip;
2177dd7cddfSDavid du Colombier 	}
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier 	qlock(arp);
2207dd7cddfSDavid du Colombier 	hash = haship(ip);
2217dd7cddfSDavid du Colombier 	for(a = arp->hash[hash]; a; a = a->hash){
2227dd7cddfSDavid du Colombier 		if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
2237dd7cddfSDavid du Colombier 		if(type == a->type)
2247dd7cddfSDavid du Colombier 			break;
2257dd7cddfSDavid du Colombier 	}
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier 	if(a == nil){
2283ff48bf5SDavid du Colombier 		a = newarp6(arp, ip, ifc, (version != V4));
2297dd7cddfSDavid du Colombier 		a->state = AWAIT;
2307dd7cddfSDavid du Colombier 	}
231a6a9e072SDavid du Colombier 	a->utime = NOW;
2327dd7cddfSDavid du Colombier 	if(a->state == AWAIT){
2337dd7cddfSDavid du Colombier 		if(bp != nil){
2347dd7cddfSDavid du Colombier 			if(a->hold)
2357dd7cddfSDavid du Colombier 				a->last->list = bp;
2367dd7cddfSDavid du Colombier 			else
2377dd7cddfSDavid du Colombier 				a->hold = bp;
2387dd7cddfSDavid du Colombier 			a->last = bp;
2397dd7cddfSDavid du Colombier 			bp->list = nil;
2407dd7cddfSDavid du Colombier 		}
2417dd7cddfSDavid du Colombier 		return a;		/* return with arp qlocked */
2427dd7cddfSDavid du Colombier 	}
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier 	memmove(mac, a->mac, a->type->maclen);
245a6a9e072SDavid du Colombier 
246a6a9e072SDavid du Colombier 	/* remove old entries */
247a6a9e072SDavid du Colombier 	if(NOW - a->ctime > 15*60*1000)
248a6a9e072SDavid du Colombier 		cleanarpent(arp, a);
249a6a9e072SDavid du Colombier 
2507dd7cddfSDavid du Colombier 	qunlock(arp);
2517dd7cddfSDavid du Colombier 	return nil;
2527dd7cddfSDavid du Colombier }
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier /*
2557dd7cddfSDavid du Colombier  * called with arp locked
2567dd7cddfSDavid du Colombier  */
2577dd7cddfSDavid du Colombier void
arprelease(Arp * arp,Arpent *)2587dd7cddfSDavid du Colombier arprelease(Arp *arp, Arpent*)
2597dd7cddfSDavid du Colombier {
2607dd7cddfSDavid du Colombier 	qunlock(arp);
2617dd7cddfSDavid du Colombier }
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier /*
2643ff48bf5SDavid du Colombier  * Copy out the mac address from the Arpent.  Return the
2653ff48bf5SDavid du Colombier  * block waiting to get sent to this mac address.
2663ff48bf5SDavid du Colombier  *
2677dd7cddfSDavid du Colombier  * called with arp locked
2687dd7cddfSDavid du Colombier  */
2697dd7cddfSDavid du Colombier Block*
arpresolve(Arp * arp,Arpent * a,Medium * type,uchar * mac)2707dd7cddfSDavid du Colombier arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
2717dd7cddfSDavid du Colombier {
2727dd7cddfSDavid du Colombier 	Block *bp;
2733ff48bf5SDavid du Colombier 	Arpent *f, **l;
2743ff48bf5SDavid du Colombier 
2753ff48bf5SDavid du Colombier 	if(!isv4(a->ip)){
2763ff48bf5SDavid du Colombier 		l = &arp->rxmt;
2773ff48bf5SDavid du Colombier 		for(f = *l; f; f = f->nextrxt){
2783ff48bf5SDavid du Colombier 			if(f == a){
2793ff48bf5SDavid du Colombier 				*l = a->nextrxt;
2803ff48bf5SDavid du Colombier 				break;
2813ff48bf5SDavid du Colombier 			}
2823ff48bf5SDavid du Colombier 			l = &f->nextrxt;
2833ff48bf5SDavid du Colombier 		}
2843ff48bf5SDavid du Colombier 	}
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier 	memmove(a->mac, mac, type->maclen);
2877dd7cddfSDavid du Colombier 	a->type = type;
2887dd7cddfSDavid du Colombier 	a->state = AOK;
289a6a9e072SDavid du Colombier 	a->utime = NOW;
2907dd7cddfSDavid du Colombier 	bp = a->hold;
2917dd7cddfSDavid du Colombier 	a->hold = nil;
2927dd7cddfSDavid du Colombier 	qunlock(arp);
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier 	return bp;
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier void
arpenter(Fs * fs,int version,uchar * ip,uchar * mac,int n,int refresh)2987dd7cddfSDavid du Colombier arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
2997dd7cddfSDavid du Colombier {
3007dd7cddfSDavid du Colombier 	Arp *arp;
3017dd7cddfSDavid du Colombier 	Route *r;
3023ff48bf5SDavid du Colombier 	Arpent *a, *f, **l;
3037dd7cddfSDavid du Colombier 	Ipifc *ifc;
3047dd7cddfSDavid du Colombier 	Medium *type;
3057dd7cddfSDavid du Colombier 	Block *bp, *next;
3067dd7cddfSDavid du Colombier 	uchar v6ip[IPaddrlen];
3077dd7cddfSDavid du Colombier 
3087dd7cddfSDavid du Colombier 	arp = fs->arp;
3097dd7cddfSDavid du Colombier 
3107dd7cddfSDavid du Colombier 	if(n != 6){
3117dd7cddfSDavid du Colombier //		print("arp: len = %d\n", n);
3127dd7cddfSDavid du Colombier 		return;
3137dd7cddfSDavid du Colombier 	}
3147dd7cddfSDavid du Colombier 
3153ff48bf5SDavid du Colombier 	switch(version){
3163ff48bf5SDavid du Colombier 	case V4:
317a6a9e072SDavid du Colombier 		r = v4lookup(fs, ip, nil);
3187dd7cddfSDavid du Colombier 		v4tov6(v6ip, ip);
3197dd7cddfSDavid du Colombier 		ip = v6ip;
3203ff48bf5SDavid du Colombier 		break;
3213ff48bf5SDavid du Colombier 	case V6:
322a6a9e072SDavid du Colombier 		r = v6lookup(fs, ip, nil);
3233ff48bf5SDavid du Colombier 		break;
3243ff48bf5SDavid du Colombier 	default:
3253ff48bf5SDavid du Colombier 		panic("arpenter: version %d", version);
3263ff48bf5SDavid du Colombier 		return;	/* to supress warnings */
3273ff48bf5SDavid du Colombier 	}
3287dd7cddfSDavid du Colombier 
3297dd7cddfSDavid du Colombier 	if(r == nil){
3307dd7cddfSDavid du Colombier //		print("arp: no route for entry\n");
3317dd7cddfSDavid du Colombier 		return;
3327dd7cddfSDavid du Colombier 	}
3337dd7cddfSDavid du Colombier 
3347dd7cddfSDavid du Colombier 	ifc = r->ifc;
3357dd7cddfSDavid du Colombier 	type = ifc->m;
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier 	qlock(arp);
3387dd7cddfSDavid du Colombier 	for(a = arp->hash[haship(ip)]; a; a = a->hash){
3397dd7cddfSDavid du Colombier 		if(a->type != type || (a->state != AWAIT && a->state != AOK))
3407dd7cddfSDavid du Colombier 			continue;
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier 		if(ipcmp(a->ip, ip) == 0){
3437dd7cddfSDavid du Colombier 			a->state = AOK;
3447dd7cddfSDavid du Colombier 			memmove(a->mac, mac, type->maclen);
3453ff48bf5SDavid du Colombier 
3463ff48bf5SDavid du Colombier 			if(version == V6){
3473ff48bf5SDavid du Colombier 				/* take out of re-transmit chain */
3483ff48bf5SDavid du Colombier 				l = &arp->rxmt;
3493ff48bf5SDavid du Colombier 				for(f = *l; f; f = f->nextrxt){
3503ff48bf5SDavid du Colombier 					if(f == a){
3513ff48bf5SDavid du Colombier 						*l = a->nextrxt;
3523ff48bf5SDavid du Colombier 						break;
3533ff48bf5SDavid du Colombier 					}
3543ff48bf5SDavid du Colombier 					l = &f->nextrxt;
3553ff48bf5SDavid du Colombier 				}
3563ff48bf5SDavid du Colombier 			}
3573ff48bf5SDavid du Colombier 
3583ff48bf5SDavid du Colombier 			a->ifc = ifc;
3593ff48bf5SDavid du Colombier 			a->ifcid = ifc->ifcid;
3607dd7cddfSDavid du Colombier 			bp = a->hold;
3617dd7cddfSDavid du Colombier 			a->hold = nil;
3627dd7cddfSDavid du Colombier 			if(version == V4)
3637dd7cddfSDavid du Colombier 				ip += IPv4off;
36404b73bddSDavid du Colombier 			a->utime = NOW;
36504b73bddSDavid du Colombier 			a->ctime = a->utime;
3667dd7cddfSDavid du Colombier 			qunlock(arp);
36704b73bddSDavid du Colombier 
3687dd7cddfSDavid du Colombier 			while(bp){
3697dd7cddfSDavid du Colombier 				next = bp->list;
3707dd7cddfSDavid du Colombier 				if(ifc != nil){
3717dd7cddfSDavid du Colombier 					if(waserror()){
3727dd7cddfSDavid du Colombier 						runlock(ifc);
3737dd7cddfSDavid du Colombier 						nexterror();
3747dd7cddfSDavid du Colombier 					}
3757dd7cddfSDavid du Colombier 					rlock(ifc);
3767dd7cddfSDavid du Colombier 					if(ifc->m != nil)
3777dd7cddfSDavid du Colombier 						ifc->m->bwrite(ifc, bp, version, ip);
3787dd7cddfSDavid du Colombier 					else
3797dd7cddfSDavid du Colombier 						freeb(bp);
3807dd7cddfSDavid du Colombier 					runlock(ifc);
3817dd7cddfSDavid du Colombier 					poperror();
3827dd7cddfSDavid du Colombier 				} else
3837dd7cddfSDavid du Colombier 					freeb(bp);
3847dd7cddfSDavid du Colombier 				bp = next;
3857dd7cddfSDavid du Colombier 			}
3867dd7cddfSDavid du Colombier 			return;
3877dd7cddfSDavid du Colombier 		}
3887dd7cddfSDavid du Colombier 	}
3897dd7cddfSDavid du Colombier 
3907dd7cddfSDavid du Colombier 	if(refresh == 0){
3913ff48bf5SDavid du Colombier 		a = newarp6(arp, ip, ifc, 0);
3927dd7cddfSDavid du Colombier 		a->state = AOK;
3937dd7cddfSDavid du Colombier 		a->type = type;
39404b73bddSDavid du Colombier 		a->ctime = NOW;
3957dd7cddfSDavid du Colombier 		memmove(a->mac, mac, type->maclen);
3967dd7cddfSDavid du Colombier 	}
3977dd7cddfSDavid du Colombier 
3987dd7cddfSDavid du Colombier 	qunlock(arp);
3997dd7cddfSDavid du Colombier }
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier int
arpwrite(Fs * fs,char * s,int len)4027dd7cddfSDavid du Colombier arpwrite(Fs *fs, char *s, int len)
4037dd7cddfSDavid du Colombier {
4047dd7cddfSDavid du Colombier 	int n;
4057dd7cddfSDavid du Colombier 	Route *r;
4067dd7cddfSDavid du Colombier 	Arp *arp;
4077dd7cddfSDavid du Colombier 	Block *bp;
4086d0d1481SDavid du Colombier 	Arpent *a, *fl, **l;
4097dd7cddfSDavid du Colombier 	Medium *m;
4103ff48bf5SDavid du Colombier 	char *f[4], buf[256];
4117dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen], mac[MAClen];
4127dd7cddfSDavid du Colombier 
4137dd7cddfSDavid du Colombier 	arp = fs->arp;
4147dd7cddfSDavid du Colombier 
4153ff48bf5SDavid du Colombier 	if(len == 0)
4169a747e4fSDavid du Colombier 		error(Ebadarp);
4173ff48bf5SDavid du Colombier 	if(len >= sizeof(buf))
4183ff48bf5SDavid du Colombier 		len = sizeof(buf)-1;
4193ff48bf5SDavid du Colombier 	strncpy(buf, s, len);
4203ff48bf5SDavid du Colombier 	buf[len] = 0;
4213ff48bf5SDavid du Colombier 	if(len > 0 && buf[len-1] == '\n')
4223ff48bf5SDavid du Colombier 		buf[len-1] = 0;
4239a747e4fSDavid du Colombier 
4243ff48bf5SDavid du Colombier 	n = getfields(buf, f, 4, 1, " ");
4253ff48bf5SDavid du Colombier 	if(strcmp(f[0], "flush") == 0){
4267dd7cddfSDavid du Colombier 		qlock(arp);
4277dd7cddfSDavid du Colombier 		for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
4287dd7cddfSDavid du Colombier 			memset(a->ip, 0, sizeof(a->ip));
4297dd7cddfSDavid du Colombier 			memset(a->mac, 0, sizeof(a->mac));
4307dd7cddfSDavid du Colombier 			a->hash = nil;
4317dd7cddfSDavid du Colombier 			a->state = 0;
432a6a9e072SDavid du Colombier 			a->utime = 0;
4337dd7cddfSDavid du Colombier 			while(a->hold != nil){
4347dd7cddfSDavid du Colombier 				bp = a->hold->list;
4357dd7cddfSDavid du Colombier 				freeblist(a->hold);
4367dd7cddfSDavid du Colombier 				a->hold = bp;
4377dd7cddfSDavid du Colombier 			}
4387dd7cddfSDavid du Colombier 		}
4397dd7cddfSDavid du Colombier 		memset(arp->hash, 0, sizeof(arp->hash));
44041dd6b47SDavid du Colombier 		/* clear all pkts on these lists (rxmt, dropf/l) */
4413ff48bf5SDavid du Colombier 		arp->rxmt = nil;
4423ff48bf5SDavid du Colombier 		arp->dropf = nil;
4433ff48bf5SDavid du Colombier 		arp->dropl = nil;
4447dd7cddfSDavid du Colombier 		qunlock(arp);
4453ff48bf5SDavid du Colombier 	} else if(strcmp(f[0], "add") == 0){
4463ff48bf5SDavid du Colombier 		switch(n){
4473ff48bf5SDavid du Colombier 		default:
4483ff48bf5SDavid du Colombier 			error(Ebadarg);
4493ff48bf5SDavid du Colombier 		case 3:
450ea58ad6fSDavid du Colombier 			if (parseip(ip, f[1]) == -1)
451ea58ad6fSDavid du Colombier 				error(Ebadip);
4523ff48bf5SDavid du Colombier 			if(isv4(ip))
453a6a9e072SDavid du Colombier 				r = v4lookup(fs, ip+IPv4off, nil);
4543ff48bf5SDavid du Colombier 			else
455a6a9e072SDavid du Colombier 				r = v6lookup(fs, ip, nil);
4563ff48bf5SDavid du Colombier 			if(r == nil)
4573ff48bf5SDavid du Colombier 				error("Destination unreachable");
4583ff48bf5SDavid du Colombier 			m = r->ifc->m;
4593ff48bf5SDavid du Colombier 			n = parsemac(mac, f[2], m->maclen);
4603ff48bf5SDavid du Colombier 			break;
4613ff48bf5SDavid du Colombier 		case 4:
4623ff48bf5SDavid du Colombier 			m = ipfindmedium(f[1]);
4633ff48bf5SDavid du Colombier 			if(m == nil)
4643ff48bf5SDavid du Colombier 				error(Ebadarp);
465ea58ad6fSDavid du Colombier 			if (parseip(ip, f[2]) == -1)
466ea58ad6fSDavid du Colombier 				error(Ebadip);
4673ff48bf5SDavid du Colombier 			n = parsemac(mac, f[3], m->maclen);
4687dd7cddfSDavid du Colombier 			break;
4697dd7cddfSDavid du Colombier 		}
4707dd7cddfSDavid du Colombier 
4713ff48bf5SDavid du Colombier 		if(m->ares == nil)
4723ff48bf5SDavid du Colombier 			error(Ebadarp);
4733ff48bf5SDavid du Colombier 
4743ff48bf5SDavid du Colombier 		m->ares(fs, V6, ip, mac, n, 0);
4756d0d1481SDavid du Colombier 	} else if(strcmp(f[0], "del") == 0){
4766d0d1481SDavid du Colombier 		if(n != 2)
4776d0d1481SDavid du Colombier 			error(Ebadarg);
4786d0d1481SDavid du Colombier 
479ea58ad6fSDavid du Colombier 		if (parseip(ip, f[1]) == -1)
480ea58ad6fSDavid du Colombier 			error(Ebadip);
4816d0d1481SDavid du Colombier 		qlock(arp);
4826d0d1481SDavid du Colombier 
4836d0d1481SDavid du Colombier 		l = &arp->hash[haship(ip)];
4846d0d1481SDavid du Colombier 		for(a = *l; a; a = a->hash){
4856d0d1481SDavid du Colombier 			if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){
4866d0d1481SDavid du Colombier 				*l = a->hash;
4876d0d1481SDavid du Colombier 				break;
4886d0d1481SDavid du Colombier 			}
4896d0d1481SDavid du Colombier 			l = &a->hash;
4906d0d1481SDavid du Colombier 		}
4916d0d1481SDavid du Colombier 
4926d0d1481SDavid du Colombier 		if(a){
4936d0d1481SDavid du Colombier 			/* take out of re-transmit chain */
4946d0d1481SDavid du Colombier 			l = &arp->rxmt;
4956d0d1481SDavid du Colombier 			for(fl = *l; fl; fl = fl->nextrxt){
4966d0d1481SDavid du Colombier 				if(fl == a){
4976d0d1481SDavid du Colombier 					*l = a->nextrxt;
4986d0d1481SDavid du Colombier 					break;
4996d0d1481SDavid du Colombier 				}
5006d0d1481SDavid du Colombier 				l = &fl->nextrxt;
5016d0d1481SDavid du Colombier 			}
5026d0d1481SDavid du Colombier 
5036d0d1481SDavid du Colombier 			a->nextrxt = nil;
5046d0d1481SDavid du Colombier 			a->hash = nil;
5056d0d1481SDavid du Colombier 			a->hold = nil;
5066d0d1481SDavid du Colombier 			a->last = nil;
5076d0d1481SDavid du Colombier 			a->ifc = nil;
5086d0d1481SDavid du Colombier 			memset(a->ip, 0, sizeof(a->ip));
5096d0d1481SDavid du Colombier 			memset(a->mac, 0, sizeof(a->mac));
5106d0d1481SDavid du Colombier 		}
5116d0d1481SDavid du Colombier 		qunlock(arp);
5123ff48bf5SDavid du Colombier 	} else
5133ff48bf5SDavid du Colombier 		error(Ebadarp);
5143ff48bf5SDavid du Colombier 
5157dd7cddfSDavid du Colombier 	return len;
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier 
5187dd7cddfSDavid du Colombier enum
5197dd7cddfSDavid du Colombier {
5203ff48bf5SDavid du Colombier 	Alinelen=	90,
5217dd7cddfSDavid du Colombier };
5227dd7cddfSDavid du Colombier 
5233ff48bf5SDavid du Colombier char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
5247dd7cddfSDavid du Colombier 
5257dd7cddfSDavid du Colombier static void
convmac(char * p,char * ep,uchar * mac,int n)526*4e3613abSDavid du Colombier convmac(char *p, char *ep, uchar *mac, int n)
5277dd7cddfSDavid du Colombier {
5287dd7cddfSDavid du Colombier 	while(n-- > 0)
529*4e3613abSDavid du Colombier 		p = seprint(p, ep, "%2.2ux", *mac++);
5307dd7cddfSDavid du Colombier }
5317dd7cddfSDavid du Colombier 
5327dd7cddfSDavid du Colombier int
arpread(Arp * arp,char * p,ulong offset,int len)5337dd7cddfSDavid du Colombier arpread(Arp *arp, char *p, ulong offset, int len)
5347dd7cddfSDavid du Colombier {
5357dd7cddfSDavid du Colombier 	Arpent *a;
5367dd7cddfSDavid du Colombier 	int n;
5377dd7cddfSDavid du Colombier 	char mac[2*MAClen+1];
5387dd7cddfSDavid du Colombier 
5397dd7cddfSDavid du Colombier 	if(offset % Alinelen)
5407dd7cddfSDavid du Colombier 		return 0;
5417dd7cddfSDavid du Colombier 
5427dd7cddfSDavid du Colombier 	offset = offset/Alinelen;
5437dd7cddfSDavid du Colombier 	len = len/Alinelen;
5447dd7cddfSDavid du Colombier 
5457dd7cddfSDavid du Colombier 	n = 0;
5467dd7cddfSDavid du Colombier 	for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
5477dd7cddfSDavid du Colombier 		if(a->state == 0)
5487dd7cddfSDavid du Colombier 			continue;
5497dd7cddfSDavid du Colombier 		if(offset > 0){
5507dd7cddfSDavid du Colombier 			offset--;
5517dd7cddfSDavid du Colombier 			continue;
5527dd7cddfSDavid du Colombier 		}
5537dd7cddfSDavid du Colombier 		len--;
5547dd7cddfSDavid du Colombier 		qlock(arp);
555*4e3613abSDavid du Colombier 		convmac(mac, &mac[sizeof mac], a->mac, a->type->maclen);
556*4e3613abSDavid du Colombier 		n += snprint(p+n, Alinelen+1, aformat, a->type->name,
557*4e3613abSDavid du Colombier 			arpstate[a->state], a->ip, mac);	/* +1 for NUL */
5587dd7cddfSDavid du Colombier 		qunlock(arp);
5597dd7cddfSDavid du Colombier 	}
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier 	return n;
5627dd7cddfSDavid du Colombier }
5633ff48bf5SDavid du Colombier 
5643ff48bf5SDavid du Colombier extern int
rxmitsols(Arp * arp)5653ff48bf5SDavid du Colombier rxmitsols(Arp *arp)
5663ff48bf5SDavid du Colombier {
5673ff48bf5SDavid du Colombier 	uint sflag;
5683ff48bf5SDavid du Colombier 	Block *next, *xp;
5693ff48bf5SDavid du Colombier 	Arpent *a, *b, **l;
5703ff48bf5SDavid du Colombier 	Fs *f;
5713ff48bf5SDavid du Colombier 	uchar ipsrc[IPaddrlen];
5723ff48bf5SDavid du Colombier 	Ipifc *ifc = nil;
5733ff48bf5SDavid du Colombier 	long nrxt;
5743ff48bf5SDavid du Colombier 
5753ff48bf5SDavid du Colombier 	qlock(arp);
5763ff48bf5SDavid du Colombier 	f = arp->f;
5773ff48bf5SDavid du Colombier 
5783ff48bf5SDavid du Colombier 	a = arp->rxmt;
5793ff48bf5SDavid du Colombier 	if(a==nil){
5803ff48bf5SDavid du Colombier 		nrxt = 0;
58141dd6b47SDavid du Colombier 		goto dodrops; 		/* return nrxt; */
5823ff48bf5SDavid du Colombier 	}
583a6a9e072SDavid du Colombier 	nrxt = a->rtime - NOW;
5843ff48bf5SDavid du Colombier 	if(nrxt > 3*ReTransTimer/4)
58541dd6b47SDavid du Colombier 		goto dodrops; 		/* return nrxt; */
5863ff48bf5SDavid du Colombier 
5873ff48bf5SDavid du Colombier 	for(; a; a = a->nextrxt){
5883ff48bf5SDavid du Colombier 		ifc = a->ifc;
5893ff48bf5SDavid du Colombier 		assert(ifc != nil);
5903ff48bf5SDavid du Colombier 		if((a->rxtsrem <= 0) || !(canrlock(ifc)) || (a->ifcid != ifc->ifcid)){
5913ff48bf5SDavid du Colombier 			xp = a->hold;
5923ff48bf5SDavid du Colombier 			a->hold = nil;
5933ff48bf5SDavid du Colombier 
5943ff48bf5SDavid du Colombier 			if(xp){
5953ff48bf5SDavid du Colombier 				if(arp->dropl == nil)
5963ff48bf5SDavid du Colombier 					arp->dropf = xp;
5973ff48bf5SDavid du Colombier 				else
5983ff48bf5SDavid du Colombier 					arp->dropl->list = xp;
5993ff48bf5SDavid du Colombier 			}
6003ff48bf5SDavid du Colombier 
6013ff48bf5SDavid du Colombier 			cleanarpent(arp, a);
6023ff48bf5SDavid du Colombier 		}
6033ff48bf5SDavid du Colombier 		else
6043ff48bf5SDavid du Colombier 			break;
6053ff48bf5SDavid du Colombier 	}
6063ff48bf5SDavid du Colombier 	if(a == nil)
6074b348146SDavid du Colombier 		goto dodrops;
6083ff48bf5SDavid du Colombier 
6094b348146SDavid du Colombier 
6104b348146SDavid du Colombier 	qunlock(arp);	/* for icmpns */
61108fd2d13SDavid du Colombier 	if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC)
6123ff48bf5SDavid du Colombier 		icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
6133ff48bf5SDavid du Colombier 
6143ff48bf5SDavid du Colombier 	runlock(ifc);
6153ff48bf5SDavid du Colombier 	qlock(arp);
6163ff48bf5SDavid du Colombier 
6173ff48bf5SDavid du Colombier 	/* put to the end of re-transmit chain */
6183ff48bf5SDavid du Colombier 	l = &arp->rxmt;
6193ff48bf5SDavid du Colombier 	for(b = *l; b; b = b->nextrxt){
6203ff48bf5SDavid du Colombier 		if(b == a){
6213ff48bf5SDavid du Colombier 			*l = a->nextrxt;
6223ff48bf5SDavid du Colombier 			break;
6233ff48bf5SDavid du Colombier 		}
6243ff48bf5SDavid du Colombier 		l = &b->nextrxt;
6253ff48bf5SDavid du Colombier 	}
6263ff48bf5SDavid du Colombier 	for(b = *l; b; b = b->nextrxt){
6273ff48bf5SDavid du Colombier 		l = &b->nextrxt;
6283ff48bf5SDavid du Colombier 	}
6293ff48bf5SDavid du Colombier 	*l = a;
6303ff48bf5SDavid du Colombier 	a->rxtsrem--;
6313ff48bf5SDavid du Colombier 	a->nextrxt = nil;
632a6a9e072SDavid du Colombier 	a->rtime = NOW + ReTransTimer;
6333ff48bf5SDavid du Colombier 
6343ff48bf5SDavid du Colombier 	a = arp->rxmt;
6353ff48bf5SDavid du Colombier 	if(a==nil)
6363ff48bf5SDavid du Colombier 		nrxt = 0;
6373ff48bf5SDavid du Colombier 	else
638a6a9e072SDavid du Colombier 		nrxt = a->rtime - NOW;
6393ff48bf5SDavid du Colombier 
6403ff48bf5SDavid du Colombier dodrops:
6413ff48bf5SDavid du Colombier 	xp = arp->dropf;
6423ff48bf5SDavid du Colombier 	arp->dropf = nil;
6433ff48bf5SDavid du Colombier 	arp->dropl = nil;
6443ff48bf5SDavid du Colombier 	qunlock(arp);
6453ff48bf5SDavid du Colombier 
6463ff48bf5SDavid du Colombier 	for(; xp; xp = next){
6473ff48bf5SDavid du Colombier 		next = xp->list;
648f2c197d9SDavid du Colombier 		icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
6493ff48bf5SDavid du Colombier 	}
6503ff48bf5SDavid du Colombier 
6513ff48bf5SDavid du Colombier 	return nrxt;
6523ff48bf5SDavid du Colombier 
6533ff48bf5SDavid du Colombier }
6543ff48bf5SDavid du Colombier 
6553ff48bf5SDavid du Colombier static int
rxready(void * v)6563ff48bf5SDavid du Colombier rxready(void *v)
6573ff48bf5SDavid du Colombier {
6583ff48bf5SDavid du Colombier 	Arp *arp = (Arp *) v;
6593ff48bf5SDavid du Colombier 	int x;
6603ff48bf5SDavid du Colombier 
6613ff48bf5SDavid du Colombier 	x = ((arp->rxmt != nil) || (arp->dropf != nil));
6623ff48bf5SDavid du Colombier 
6633ff48bf5SDavid du Colombier 	return x;
6643ff48bf5SDavid du Colombier }
6653ff48bf5SDavid du Colombier 
6663ff48bf5SDavid du Colombier static void
rxmitproc(void * v)6673ff48bf5SDavid du Colombier rxmitproc(void *v)
6683ff48bf5SDavid du Colombier {
6693ff48bf5SDavid du Colombier 	Arp *arp = v;
6703ff48bf5SDavid du Colombier 	long wakeupat;
6713ff48bf5SDavid du Colombier 
6723ff48bf5SDavid du Colombier 	arp->rxmitp = up;
6733ff48bf5SDavid du Colombier 	//print("arp rxmitproc started\n");
6743ff48bf5SDavid du Colombier 	if(waserror()){
6753ff48bf5SDavid du Colombier 		arp->rxmitp = 0;
6763ff48bf5SDavid du Colombier 		pexit("hangup", 1);
6773ff48bf5SDavid du Colombier 	}
6783ff48bf5SDavid du Colombier 	for(;;){
6793ff48bf5SDavid du Colombier 		wakeupat = rxmitsols(arp);
6803ff48bf5SDavid du Colombier 		if(wakeupat == 0)
6813ff48bf5SDavid du Colombier 			sleep(&arp->rxmtq, rxready, v);
6823ff48bf5SDavid du Colombier 		else if(wakeupat > ReTransTimer/4)
6833ff48bf5SDavid du Colombier 			tsleep(&arp->rxmtq, return0, 0, wakeupat);
6843ff48bf5SDavid du Colombier 	}
6853ff48bf5SDavid du Colombier }
6863ff48bf5SDavid du Colombier 
687