xref: /plan9-contrib/sys/src/9k/ip/arp.c (revision a3323688dee1e9a0fcc1d7d933e3ce101170952d)
19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier #include "ip.h"
99ef1f84bSDavid du Colombier #include "ipv6.h"
109ef1f84bSDavid du Colombier 
119ef1f84bSDavid du Colombier /*
129ef1f84bSDavid du Colombier  *  address resolution tables
139ef1f84bSDavid du Colombier  */
149ef1f84bSDavid du Colombier 
159ef1f84bSDavid du Colombier enum
169ef1f84bSDavid du Colombier {
179ef1f84bSDavid du Colombier 	NHASH		= (1<<6),
189ef1f84bSDavid du Colombier 	NCACHE		= 256,
199ef1f84bSDavid du Colombier 
209ef1f84bSDavid du Colombier 	AOK		= 1,
219ef1f84bSDavid du Colombier 	AWAIT		= 2,
229ef1f84bSDavid du Colombier };
239ef1f84bSDavid du Colombier 
249ef1f84bSDavid du Colombier char *arpstate[] =
259ef1f84bSDavid du Colombier {
269ef1f84bSDavid du Colombier 	"UNUSED",
279ef1f84bSDavid du Colombier 	"OK",
289ef1f84bSDavid du Colombier 	"WAIT",
299ef1f84bSDavid du Colombier };
309ef1f84bSDavid du Colombier 
319ef1f84bSDavid du Colombier /*
329ef1f84bSDavid du Colombier  *  one per Fs
339ef1f84bSDavid du Colombier  */
349ef1f84bSDavid du Colombier struct Arp
359ef1f84bSDavid du Colombier {
369ef1f84bSDavid du Colombier 	QLock;
379ef1f84bSDavid du Colombier 	Fs	*f;
389ef1f84bSDavid du Colombier 	Arpent	*hash[NHASH];
399ef1f84bSDavid du Colombier 	Arpent	cache[NCACHE];
409ef1f84bSDavid du Colombier 	Arpent	*rxmt;
419ef1f84bSDavid du Colombier 	Proc	*rxmitp;	/* neib sol re-transmit proc */
429ef1f84bSDavid du Colombier 	Rendez	rxmtq;
439ef1f84bSDavid du Colombier 	Block	*dropf, *dropl;
449ef1f84bSDavid du Colombier };
459ef1f84bSDavid du Colombier 
469ef1f84bSDavid du Colombier char *Ebadarp = "bad arp";
479ef1f84bSDavid du Colombier 
489ef1f84bSDavid du Colombier #define haship(s) ((s)[IPaddrlen-1]%NHASH)
499ef1f84bSDavid du Colombier 
509ef1f84bSDavid du Colombier extern int	ReTransTimer = RETRANS_TIMER;
519ef1f84bSDavid du Colombier 
529ef1f84bSDavid du Colombier static void	rxmitproc(void *v);
539ef1f84bSDavid du Colombier 
549ef1f84bSDavid du Colombier void
arpinit(Fs * f)559ef1f84bSDavid du Colombier arpinit(Fs *f)
569ef1f84bSDavid du Colombier {
579ef1f84bSDavid du Colombier 	f->arp = smalloc(sizeof(Arp));
589ef1f84bSDavid du Colombier 	f->arp->f = f;
599ef1f84bSDavid du Colombier 	f->arp->rxmt = nil;
609ef1f84bSDavid du Colombier 	f->arp->dropf = f->arp->dropl = nil;
619ef1f84bSDavid du Colombier 	kproc("rxmitproc", rxmitproc, f->arp);
629ef1f84bSDavid du Colombier }
639ef1f84bSDavid du Colombier 
649ef1f84bSDavid du Colombier /*
659ef1f84bSDavid du Colombier  *  create a new arp entry for an ip address.
669ef1f84bSDavid du Colombier  */
679ef1f84bSDavid du Colombier static Arpent*
newarp6(Arp * arp,uchar * ip,Ipifc * ifc,int addrxt)689ef1f84bSDavid du Colombier newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
699ef1f84bSDavid du Colombier {
709ef1f84bSDavid du Colombier 	uint t;
719ef1f84bSDavid du Colombier 	Block *next, *xp;
729ef1f84bSDavid du Colombier 	Arpent *a, *e, *f, **l;
739ef1f84bSDavid du Colombier 	int empty;
749ef1f84bSDavid du Colombier 
759ef1f84bSDavid du Colombier 	/* find oldest entry */
769ef1f84bSDavid du Colombier 	e = &arp->cache[NCACHE];
779ef1f84bSDavid du Colombier 	a = arp->cache;
789ef1f84bSDavid du Colombier 	t = a->utime;
799ef1f84bSDavid du Colombier 	for(f = a; f < e; f++){
809ef1f84bSDavid du Colombier 		if(f->utime < t){
819ef1f84bSDavid du Colombier 			t = f->utime;
829ef1f84bSDavid du Colombier 			a = f;
839ef1f84bSDavid du Colombier 		}
849ef1f84bSDavid du Colombier 	}
859ef1f84bSDavid du Colombier 
869ef1f84bSDavid du Colombier 	/* dump waiting packets */
879ef1f84bSDavid du Colombier 	xp = a->hold;
889ef1f84bSDavid du Colombier 	a->hold = nil;
899ef1f84bSDavid du Colombier 
909ef1f84bSDavid du Colombier 	if(isv4(a->ip)){
919ef1f84bSDavid du Colombier 		while(xp){
929ef1f84bSDavid du Colombier 			next = xp->list;
939ef1f84bSDavid du Colombier 			freeblist(xp);
949ef1f84bSDavid du Colombier 			xp = next;
959ef1f84bSDavid du Colombier 		}
969ef1f84bSDavid du Colombier 	}
979ef1f84bSDavid du Colombier 	else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
989ef1f84bSDavid du Colombier 		if(xp){
999ef1f84bSDavid du Colombier 			if(arp->dropl == nil)
1009ef1f84bSDavid du Colombier 				arp->dropf = xp;
1019ef1f84bSDavid du Colombier 			else
1029ef1f84bSDavid du Colombier 				arp->dropl->list = xp;
1039ef1f84bSDavid du Colombier 
1049ef1f84bSDavid du Colombier 			for(next = xp->list; next; next = next->list)
1059ef1f84bSDavid du Colombier 				xp = next;
1069ef1f84bSDavid du Colombier 			arp->dropl = xp;
1079ef1f84bSDavid du Colombier 			wakeup(&arp->rxmtq);
1089ef1f84bSDavid du Colombier 		}
1099ef1f84bSDavid du Colombier 	}
1109ef1f84bSDavid du Colombier 
1119ef1f84bSDavid du Colombier 	/* take out of current chain */
1129ef1f84bSDavid du Colombier 	l = &arp->hash[haship(a->ip)];
1139ef1f84bSDavid du Colombier 	for(f = *l; f; f = f->hash){
1149ef1f84bSDavid du Colombier 		if(f == a){
1159ef1f84bSDavid du Colombier 			*l = a->hash;
1169ef1f84bSDavid du Colombier 			break;
1179ef1f84bSDavid du Colombier 		}
1189ef1f84bSDavid du Colombier 		l = &f->hash;
1199ef1f84bSDavid du Colombier 	}
1209ef1f84bSDavid du Colombier 
1219ef1f84bSDavid du Colombier 	/* insert into new chain */
1229ef1f84bSDavid du Colombier 	l = &arp->hash[haship(ip)];
1239ef1f84bSDavid du Colombier 	a->hash = *l;
1249ef1f84bSDavid du Colombier 	*l = a;
1259ef1f84bSDavid du Colombier 
1269ef1f84bSDavid du Colombier 	memmove(a->ip, ip, sizeof(a->ip));
1279ef1f84bSDavid du Colombier 	a->utime = NOW;
1289ef1f84bSDavid du Colombier 	a->ctime = 0;
1299ef1f84bSDavid du Colombier 	a->type = ifc->medium;
1309ef1f84bSDavid du Colombier 
1319ef1f84bSDavid du Colombier 	a->rtime = NOW + ReTransTimer;
1329ef1f84bSDavid du Colombier 	a->rxtsrem = MAX_MULTICAST_SOLICIT;
1339ef1f84bSDavid du Colombier 	a->ifc = ifc;
1349ef1f84bSDavid du Colombier 	a->ifcid = ifc->ifcid;
1359ef1f84bSDavid du Colombier 
1369ef1f84bSDavid du Colombier 	/* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
1379ef1f84bSDavid du Colombier 	if(!ipismulticast(a->ip) && addrxt){
1389ef1f84bSDavid du Colombier 		l = &arp->rxmt;
1399ef1f84bSDavid du Colombier 		empty = (*l==nil);
1409ef1f84bSDavid du Colombier 
1419ef1f84bSDavid du Colombier 		for(f = *l; f; f = f->nextrxt){
1429ef1f84bSDavid du Colombier 			if(f == a){
1439ef1f84bSDavid du Colombier 				*l = a->nextrxt;
1449ef1f84bSDavid du Colombier 				break;
1459ef1f84bSDavid du Colombier 			}
1469ef1f84bSDavid du Colombier 			l = &f->nextrxt;
1479ef1f84bSDavid du Colombier 		}
1489ef1f84bSDavid du Colombier 		for(f = *l; f; f = f->nextrxt){
1499ef1f84bSDavid du Colombier 			l = &f->nextrxt;
1509ef1f84bSDavid du Colombier 		}
1519ef1f84bSDavid du Colombier 		*l = a;
1529ef1f84bSDavid du Colombier 		if(empty)
1539ef1f84bSDavid du Colombier 			wakeup(&arp->rxmtq);
1549ef1f84bSDavid du Colombier 	}
1559ef1f84bSDavid du Colombier 
1569ef1f84bSDavid du Colombier 	a->nextrxt = nil;
1579ef1f84bSDavid du Colombier 
1589ef1f84bSDavid du Colombier 	return a;
1599ef1f84bSDavid du Colombier }
1609ef1f84bSDavid du Colombier 
1619ef1f84bSDavid du Colombier /* called with arp qlocked */
1629ef1f84bSDavid du Colombier 
1639ef1f84bSDavid du Colombier void
cleanarpent(Arp * arp,Arpent * a)1649ef1f84bSDavid du Colombier cleanarpent(Arp *arp, Arpent *a)
1659ef1f84bSDavid du Colombier {
1669ef1f84bSDavid du Colombier 	Arpent *f, **l;
1679ef1f84bSDavid du Colombier 
1689ef1f84bSDavid du Colombier 	a->utime = 0;
1699ef1f84bSDavid du Colombier 	a->ctime = 0;
1709ef1f84bSDavid du Colombier 	a->type = 0;
1719ef1f84bSDavid du Colombier 	a->state = 0;
1729ef1f84bSDavid du Colombier 
1739ef1f84bSDavid du Colombier 	/* take out of current chain */
1749ef1f84bSDavid du Colombier 	l = &arp->hash[haship(a->ip)];
1759ef1f84bSDavid du Colombier 	for(f = *l; f; f = f->hash){
1769ef1f84bSDavid du Colombier 		if(f == a){
1779ef1f84bSDavid du Colombier 			*l = a->hash;
1789ef1f84bSDavid du Colombier 			break;
1799ef1f84bSDavid du Colombier 		}
1809ef1f84bSDavid du Colombier 		l = &f->hash;
1819ef1f84bSDavid du Colombier 	}
1829ef1f84bSDavid du Colombier 
1839ef1f84bSDavid du Colombier 	/* take out of re-transmit chain */
1849ef1f84bSDavid du Colombier 	l = &arp->rxmt;
1859ef1f84bSDavid du Colombier 	for(f = *l; f; f = f->nextrxt){
1869ef1f84bSDavid du Colombier 		if(f == a){
1879ef1f84bSDavid du Colombier 			*l = a->nextrxt;
1889ef1f84bSDavid du Colombier 			break;
1899ef1f84bSDavid du Colombier 		}
1909ef1f84bSDavid du Colombier 		l = &f->nextrxt;
1919ef1f84bSDavid du Colombier 	}
1929ef1f84bSDavid du Colombier 	a->nextrxt = nil;
1939ef1f84bSDavid du Colombier 	a->hash = nil;
1949ef1f84bSDavid du Colombier 	a->hold = nil;
1959ef1f84bSDavid du Colombier 	a->last = nil;
1969ef1f84bSDavid du Colombier 	a->ifc = nil;
1979ef1f84bSDavid du Colombier }
1989ef1f84bSDavid du Colombier 
1999ef1f84bSDavid du Colombier /*
2009ef1f84bSDavid du Colombier  *  fill in the media address if we have it.  Otherwise return an
2019ef1f84bSDavid du Colombier  *  Arpent that represents the state of the address resolution FSM
2029ef1f84bSDavid du Colombier  *  for ip.  Add the packet to be sent onto the list of packets
2039ef1f84bSDavid du Colombier  *  waiting for ip->mac to be resolved.
2049ef1f84bSDavid du Colombier  */
2059ef1f84bSDavid du Colombier Arpent*
arpget(Arp * arp,Block * bp,int version,Ipifc * ifc,uchar * ip,uchar * mac)2069ef1f84bSDavid du Colombier arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
2079ef1f84bSDavid du Colombier {
2089ef1f84bSDavid du Colombier 	int hash;
2099ef1f84bSDavid du Colombier 	Arpent *a;
2109ef1f84bSDavid du Colombier 	Medium *type;
2119ef1f84bSDavid du Colombier 	uchar v6ip[IPaddrlen];
2129ef1f84bSDavid du Colombier 
2139ef1f84bSDavid du Colombier 	if(version == V4){
2149ef1f84bSDavid du Colombier 		v4tov6(v6ip, ip);
2159ef1f84bSDavid du Colombier 		ip = v6ip;
2169ef1f84bSDavid du Colombier 	}
2179ef1f84bSDavid du Colombier 
2189ef1f84bSDavid du Colombier 	qlock(arp);
2199ef1f84bSDavid du Colombier 	hash = haship(ip);
2209ef1f84bSDavid du Colombier 	type = ifc->medium;
2219ef1f84bSDavid du Colombier 	for(a = arp->hash[hash]; a; a = a->hash){
2229ef1f84bSDavid du Colombier 		if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
2239ef1f84bSDavid du Colombier 		if(type == a->type)
2249ef1f84bSDavid du Colombier 			break;
2259ef1f84bSDavid du Colombier 	}
2269ef1f84bSDavid du Colombier 
2279ef1f84bSDavid du Colombier 	if(a == nil){
2289ef1f84bSDavid du Colombier 		a = newarp6(arp, ip, ifc, (version != V4));
2299ef1f84bSDavid du Colombier 		a->state = AWAIT;
2309ef1f84bSDavid du Colombier 	}
2319ef1f84bSDavid du Colombier 	a->utime = NOW;
2329ef1f84bSDavid du Colombier 	if(a->state == AWAIT){
2339ef1f84bSDavid du Colombier 		if(bp != nil){
2349ef1f84bSDavid du Colombier 			if(a->hold)
2359ef1f84bSDavid du Colombier 				a->last->list = bp;
2369ef1f84bSDavid du Colombier 			else
2379ef1f84bSDavid du Colombier 				a->hold = bp;
2389ef1f84bSDavid du Colombier 			a->last = bp;
2399ef1f84bSDavid du Colombier 			bp->list = nil;
2409ef1f84bSDavid du Colombier 		}
2419ef1f84bSDavid du Colombier 		return a;		/* return with arp qlocked */
2429ef1f84bSDavid du Colombier 	}
2439ef1f84bSDavid du Colombier 
2449ef1f84bSDavid du Colombier 	memmove(mac, a->mac, a->type->maclen);
2459ef1f84bSDavid du Colombier 
2469ef1f84bSDavid du Colombier 	/* remove old entries */
2479ef1f84bSDavid du Colombier 	if(NOW - a->ctime > 15*60*1000)
2489ef1f84bSDavid du Colombier 		cleanarpent(arp, a);
2499ef1f84bSDavid du Colombier 
2509ef1f84bSDavid du Colombier 	qunlock(arp);
2519ef1f84bSDavid du Colombier 	return nil;
2529ef1f84bSDavid du Colombier }
2539ef1f84bSDavid du Colombier 
2549ef1f84bSDavid du Colombier /*
2559ef1f84bSDavid du Colombier  * called with arp locked
2569ef1f84bSDavid du Colombier  */
2579ef1f84bSDavid du Colombier void
arprelease(Arp * arp,Arpent *)2589ef1f84bSDavid du Colombier arprelease(Arp *arp, Arpent*)
2599ef1f84bSDavid du Colombier {
2609ef1f84bSDavid du Colombier 	qunlock(arp);
2619ef1f84bSDavid du Colombier }
2629ef1f84bSDavid du Colombier 
2639ef1f84bSDavid du Colombier /*
2649ef1f84bSDavid du Colombier  * Copy out the mac address from the Arpent.  Return the
2659ef1f84bSDavid du Colombier  * block waiting to get sent to this mac address.
2669ef1f84bSDavid du Colombier  *
2679ef1f84bSDavid du Colombier  * called with arp locked
2689ef1f84bSDavid du Colombier  */
2699ef1f84bSDavid du Colombier Block*
arpresolve(Arp * arp,Arpent * a,Medium * type,uchar * mac)2709ef1f84bSDavid du Colombier arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
2719ef1f84bSDavid du Colombier {
2729ef1f84bSDavid du Colombier 	Block *bp;
2739ef1f84bSDavid du Colombier 	Arpent *f, **l;
2749ef1f84bSDavid du Colombier 
2759ef1f84bSDavid du Colombier 	if(!isv4(a->ip)){
2769ef1f84bSDavid du Colombier 		l = &arp->rxmt;
2779ef1f84bSDavid du Colombier 		for(f = *l; f; f = f->nextrxt){
2789ef1f84bSDavid du Colombier 			if(f == a){
2799ef1f84bSDavid du Colombier 				*l = a->nextrxt;
2809ef1f84bSDavid du Colombier 				break;
2819ef1f84bSDavid du Colombier 			}
2829ef1f84bSDavid du Colombier 			l = &f->nextrxt;
2839ef1f84bSDavid du Colombier 		}
2849ef1f84bSDavid du Colombier 	}
2859ef1f84bSDavid du Colombier 
2869ef1f84bSDavid du Colombier 	memmove(a->mac, mac, type->maclen);
2879ef1f84bSDavid du Colombier 	a->type = type;
2889ef1f84bSDavid du Colombier 	a->state = AOK;
2899ef1f84bSDavid du Colombier 	a->utime = NOW;
2909ef1f84bSDavid du Colombier 	bp = a->hold;
2919ef1f84bSDavid du Colombier 	a->hold = nil;
2929ef1f84bSDavid du Colombier 	qunlock(arp);
2939ef1f84bSDavid du Colombier 
2949ef1f84bSDavid du Colombier 	return bp;
2959ef1f84bSDavid du Colombier }
2969ef1f84bSDavid du Colombier 
2979ef1f84bSDavid du Colombier void
arpenter(Fs * fs,int version,uchar * ip,uchar * mac,int n,int refresh)2989ef1f84bSDavid du Colombier arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
2999ef1f84bSDavid du Colombier {
3009ef1f84bSDavid du Colombier 	Arp *arp;
3019ef1f84bSDavid du Colombier 	Route *r;
3029ef1f84bSDavid du Colombier 	Arpent *a, *f, **l;
3039ef1f84bSDavid du Colombier 	Ipifc *ifc;
3049ef1f84bSDavid du Colombier 	Medium *type;
3059ef1f84bSDavid du Colombier 	Block *bp, *next;
3069ef1f84bSDavid du Colombier 	uchar v6ip[IPaddrlen];
3079ef1f84bSDavid du Colombier 
3089ef1f84bSDavid du Colombier 	arp = fs->arp;
3099ef1f84bSDavid du Colombier 
3109ef1f84bSDavid du Colombier 	if(n != 6){
3119ef1f84bSDavid du Colombier //		print("arp: len = %d\n", n);
3129ef1f84bSDavid du Colombier 		return;
3139ef1f84bSDavid du Colombier 	}
3149ef1f84bSDavid du Colombier 
3159ef1f84bSDavid du Colombier 	switch(version){
3169ef1f84bSDavid du Colombier 	case V4:
3179ef1f84bSDavid du Colombier 		r = v4lookup(fs, ip, nil);
3189ef1f84bSDavid du Colombier 		v4tov6(v6ip, ip);
3199ef1f84bSDavid du Colombier 		ip = v6ip;
3209ef1f84bSDavid du Colombier 		break;
3219ef1f84bSDavid du Colombier 	case V6:
3229ef1f84bSDavid du Colombier 		r = v6lookup(fs, ip, nil);
3239ef1f84bSDavid du Colombier 		break;
3249ef1f84bSDavid du Colombier 	default:
3259ef1f84bSDavid du Colombier 		panic("arpenter: version %d", version);
3269ef1f84bSDavid du Colombier 		return;	/* to supress warnings */
3279ef1f84bSDavid du Colombier 	}
3289ef1f84bSDavid du Colombier 
3299ef1f84bSDavid du Colombier 	if(r == nil){
3309ef1f84bSDavid du Colombier //		print("arp: no route for entry\n");
3319ef1f84bSDavid du Colombier 		return;
3329ef1f84bSDavid du Colombier 	}
3339ef1f84bSDavid du Colombier 
3349ef1f84bSDavid du Colombier 	ifc = r->ifc;
3359ef1f84bSDavid du Colombier 	type = ifc->medium;
3369ef1f84bSDavid du Colombier 
3379ef1f84bSDavid du Colombier 	qlock(arp);
3389ef1f84bSDavid du Colombier 	for(a = arp->hash[haship(ip)]; a; a = a->hash){
3399ef1f84bSDavid du Colombier 		if(a->type != type || (a->state != AWAIT && a->state != AOK))
3409ef1f84bSDavid du Colombier 			continue;
3419ef1f84bSDavid du Colombier 
3429ef1f84bSDavid du Colombier 		if(ipcmp(a->ip, ip) == 0){
3439ef1f84bSDavid du Colombier 			a->state = AOK;
3449ef1f84bSDavid du Colombier 			memmove(a->mac, mac, type->maclen);
3459ef1f84bSDavid du Colombier 
3469ef1f84bSDavid du Colombier 			if(version == V6){
3479ef1f84bSDavid du Colombier 				/* take out of re-transmit chain */
3489ef1f84bSDavid du Colombier 				l = &arp->rxmt;
3499ef1f84bSDavid du Colombier 				for(f = *l; f; f = f->nextrxt){
3509ef1f84bSDavid du Colombier 					if(f == a){
3519ef1f84bSDavid du Colombier 						*l = a->nextrxt;
3529ef1f84bSDavid du Colombier 						break;
3539ef1f84bSDavid du Colombier 					}
3549ef1f84bSDavid du Colombier 					l = &f->nextrxt;
3559ef1f84bSDavid du Colombier 				}
3569ef1f84bSDavid du Colombier 			}
3579ef1f84bSDavid du Colombier 
3589ef1f84bSDavid du Colombier 			a->ifc = ifc;
3599ef1f84bSDavid du Colombier 			a->ifcid = ifc->ifcid;
3609ef1f84bSDavid du Colombier 			bp = a->hold;
3619ef1f84bSDavid du Colombier 			a->hold = nil;
3629ef1f84bSDavid du Colombier 			if(version == V4)
3639ef1f84bSDavid du Colombier 				ip += IPv4off;
3649ef1f84bSDavid du Colombier 			a->utime = NOW;
3659ef1f84bSDavid du Colombier 			a->ctime = a->utime;
3669ef1f84bSDavid du Colombier 			qunlock(arp);
3679ef1f84bSDavid du Colombier 
3689ef1f84bSDavid du Colombier 			while(bp){
3699ef1f84bSDavid du Colombier 				next = bp->list;
3709ef1f84bSDavid du Colombier 				if(ifc != nil){
3719ef1f84bSDavid du Colombier 					if(waserror()){
3729ef1f84bSDavid du Colombier 						runlock(ifc);
3739ef1f84bSDavid du Colombier 						nexterror();
3749ef1f84bSDavid du Colombier 					}
3759ef1f84bSDavid du Colombier 					rlock(ifc);
3769ef1f84bSDavid du Colombier 					if(ifc->medium != nil)
3779ef1f84bSDavid du Colombier 						ifc->medium->bwrite(ifc, bp, version, ip);
3789ef1f84bSDavid du Colombier 					else
3799ef1f84bSDavid du Colombier 						freeb(bp);
3809ef1f84bSDavid du Colombier 					runlock(ifc);
3819ef1f84bSDavid du Colombier 					poperror();
3829ef1f84bSDavid du Colombier 				} else
3839ef1f84bSDavid du Colombier 					freeb(bp);
3849ef1f84bSDavid du Colombier 				bp = next;
3859ef1f84bSDavid du Colombier 			}
3869ef1f84bSDavid du Colombier 			return;
3879ef1f84bSDavid du Colombier 		}
3889ef1f84bSDavid du Colombier 	}
3899ef1f84bSDavid du Colombier 
3909ef1f84bSDavid du Colombier 	if(refresh == 0){
3919ef1f84bSDavid du Colombier 		a = newarp6(arp, ip, ifc, 0);
3929ef1f84bSDavid du Colombier 		a->state = AOK;
3939ef1f84bSDavid du Colombier 		a->type = type;
3949ef1f84bSDavid du Colombier 		a->ctime = NOW;
3959ef1f84bSDavid du Colombier 		memmove(a->mac, mac, type->maclen);
3969ef1f84bSDavid du Colombier 	}
3979ef1f84bSDavid du Colombier 
3989ef1f84bSDavid du Colombier 	qunlock(arp);
3999ef1f84bSDavid du Colombier }
4009ef1f84bSDavid du Colombier 
4019ef1f84bSDavid du Colombier int
arpwrite(Fs * fs,char * s,int len)4029ef1f84bSDavid du Colombier arpwrite(Fs *fs, char *s, int len)
4039ef1f84bSDavid du Colombier {
4049ef1f84bSDavid du Colombier 	int n;
4059ef1f84bSDavid du Colombier 	Route *r;
4069ef1f84bSDavid du Colombier 	Arp *arp;
4079ef1f84bSDavid du Colombier 	Block *bp;
4089ef1f84bSDavid du Colombier 	Arpent *a, *fl, **l;
4099ef1f84bSDavid du Colombier 	Medium *type;
4109ef1f84bSDavid du Colombier 	char *f[4], buf[256];
4119ef1f84bSDavid du Colombier 	uchar ip[IPaddrlen], mac[MAClen];
4129ef1f84bSDavid du Colombier 
4139ef1f84bSDavid du Colombier 	arp = fs->arp;
4149ef1f84bSDavid du Colombier 
4159ef1f84bSDavid du Colombier 	if(len == 0)
4169ef1f84bSDavid du Colombier 		error(Ebadarp);
4179ef1f84bSDavid du Colombier 	if(len >= sizeof(buf))
4189ef1f84bSDavid du Colombier 		len = sizeof(buf)-1;
4199ef1f84bSDavid du Colombier 	strncpy(buf, s, len);
4209ef1f84bSDavid du Colombier 	buf[len] = 0;
4219ef1f84bSDavid du Colombier 	if(len > 0 && buf[len-1] == '\n')
4229ef1f84bSDavid du Colombier 		buf[len-1] = 0;
4239ef1f84bSDavid du Colombier 
4249ef1f84bSDavid du Colombier 	n = getfields(buf, f, 4, 1, " ");
4259ef1f84bSDavid du Colombier 	if(strcmp(f[0], "flush") == 0){
4269ef1f84bSDavid du Colombier 		qlock(arp);
4279ef1f84bSDavid du Colombier 		for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
4289ef1f84bSDavid du Colombier 			memset(a->ip, 0, sizeof(a->ip));
4299ef1f84bSDavid du Colombier 			memset(a->mac, 0, sizeof(a->mac));
4309ef1f84bSDavid du Colombier 			a->hash = nil;
4319ef1f84bSDavid du Colombier 			a->state = 0;
4329ef1f84bSDavid du Colombier 			a->utime = 0;
4339ef1f84bSDavid du Colombier 			while(a->hold != nil){
4349ef1f84bSDavid du Colombier 				bp = a->hold->list;
4359ef1f84bSDavid du Colombier 				freeblist(a->hold);
4369ef1f84bSDavid du Colombier 				a->hold = bp;
4379ef1f84bSDavid du Colombier 			}
4389ef1f84bSDavid du Colombier 		}
4399ef1f84bSDavid du Colombier 		memset(arp->hash, 0, sizeof(arp->hash));
4409ef1f84bSDavid du Colombier 		/* clear all pkts on these lists (rxmt, dropf/l) */
4419ef1f84bSDavid du Colombier 		arp->rxmt = nil;
4429ef1f84bSDavid du Colombier 		arp->dropf = nil;
4439ef1f84bSDavid du Colombier 		arp->dropl = nil;
4449ef1f84bSDavid du Colombier 		qunlock(arp);
4459ef1f84bSDavid du Colombier 	} else if(strcmp(f[0], "add") == 0){
4469ef1f84bSDavid du Colombier 		switch(n){
4479ef1f84bSDavid du Colombier 		default:
4489ef1f84bSDavid du Colombier 			error(Ebadarg);
4499ef1f84bSDavid du Colombier 		case 3:
4509ef1f84bSDavid du Colombier 			if (parseip(ip, f[1]) == -1)
4519ef1f84bSDavid du Colombier 				error(Ebadip);
4529ef1f84bSDavid du Colombier 			if(isv4(ip))
4539ef1f84bSDavid du Colombier 				r = v4lookup(fs, ip+IPv4off, nil);
4549ef1f84bSDavid du Colombier 			else
4559ef1f84bSDavid du Colombier 				r = v6lookup(fs, ip, nil);
4569ef1f84bSDavid du Colombier 			if(r == nil)
4579ef1f84bSDavid du Colombier 				error("Destination unreachable");
4589ef1f84bSDavid du Colombier 			type = r->ifc->medium;
4599ef1f84bSDavid du Colombier 			n = parsemac(mac, f[2], type->maclen);
4609ef1f84bSDavid du Colombier 			break;
4619ef1f84bSDavid du Colombier 		case 4:
4629ef1f84bSDavid du Colombier 			type = ipfindmedium(f[1]);
4639ef1f84bSDavid du Colombier 			if(type == nil)
4649ef1f84bSDavid du Colombier 				error(Ebadarp);
4659ef1f84bSDavid du Colombier 			if (parseip(ip, f[2]) == -1)
4669ef1f84bSDavid du Colombier 				error(Ebadip);
4679ef1f84bSDavid du Colombier 			n = parsemac(mac, f[3], type->maclen);
4689ef1f84bSDavid du Colombier 			break;
4699ef1f84bSDavid du Colombier 		}
4709ef1f84bSDavid du Colombier 
4719ef1f84bSDavid du Colombier 		if(type->ares == nil)
4729ef1f84bSDavid du Colombier 			error(Ebadarp);
4739ef1f84bSDavid du Colombier 
4749ef1f84bSDavid du Colombier 		type->ares(fs, V6, ip, mac, n, 0);
4759ef1f84bSDavid du Colombier 	} else if(strcmp(f[0], "del") == 0){
4769ef1f84bSDavid du Colombier 		if(n != 2)
4779ef1f84bSDavid du Colombier 			error(Ebadarg);
4789ef1f84bSDavid du Colombier 
4799ef1f84bSDavid du Colombier 		if (parseip(ip, f[1]) == -1)
4809ef1f84bSDavid du Colombier 			error(Ebadip);
4819ef1f84bSDavid du Colombier 		qlock(arp);
4829ef1f84bSDavid du Colombier 
4839ef1f84bSDavid du Colombier 		l = &arp->hash[haship(ip)];
4849ef1f84bSDavid du Colombier 		for(a = *l; a; a = a->hash){
4859ef1f84bSDavid du Colombier 			if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){
4869ef1f84bSDavid du Colombier 				*l = a->hash;
4879ef1f84bSDavid du Colombier 				break;
4889ef1f84bSDavid du Colombier 			}
4899ef1f84bSDavid du Colombier 			l = &a->hash;
4909ef1f84bSDavid du Colombier 		}
4919ef1f84bSDavid du Colombier 
4929ef1f84bSDavid du Colombier 		if(a){
4939ef1f84bSDavid du Colombier 			/* take out of re-transmit chain */
4949ef1f84bSDavid du Colombier 			l = &arp->rxmt;
4959ef1f84bSDavid du Colombier 			for(fl = *l; fl; fl = fl->nextrxt){
4969ef1f84bSDavid du Colombier 				if(fl == a){
4979ef1f84bSDavid du Colombier 					*l = a->nextrxt;
4989ef1f84bSDavid du Colombier 					break;
4999ef1f84bSDavid du Colombier 				}
5009ef1f84bSDavid du Colombier 				l = &fl->nextrxt;
5019ef1f84bSDavid du Colombier 			}
5029ef1f84bSDavid du Colombier 
5039ef1f84bSDavid du Colombier 			a->nextrxt = nil;
5049ef1f84bSDavid du Colombier 			a->hash = nil;
5059ef1f84bSDavid du Colombier 			a->hold = nil;
5069ef1f84bSDavid du Colombier 			a->last = nil;
5079ef1f84bSDavid du Colombier 			a->ifc = nil;
5089ef1f84bSDavid du Colombier 			memset(a->ip, 0, sizeof(a->ip));
5099ef1f84bSDavid du Colombier 			memset(a->mac, 0, sizeof(a->mac));
5109ef1f84bSDavid du Colombier 		}
5119ef1f84bSDavid du Colombier 		qunlock(arp);
5129ef1f84bSDavid du Colombier 	} else
5139ef1f84bSDavid du Colombier 		error(Ebadarp);
5149ef1f84bSDavid du Colombier 
5159ef1f84bSDavid du Colombier 	return len;
5169ef1f84bSDavid du Colombier }
5179ef1f84bSDavid du Colombier 
5189ef1f84bSDavid du Colombier enum
5199ef1f84bSDavid du Colombier {
5209ef1f84bSDavid du Colombier 	Alinelen=	90,
5219ef1f84bSDavid du Colombier };
5229ef1f84bSDavid du Colombier 
5239ef1f84bSDavid du Colombier char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
5249ef1f84bSDavid du Colombier 
5259ef1f84bSDavid du Colombier static void
convmac(char * p,char * ep,uchar * mac,int n)526*a3323688SDavid du Colombier convmac(char *p, char *ep, uchar *mac, int n)
5279ef1f84bSDavid du Colombier {
5289ef1f84bSDavid du Colombier 	while(n-- > 0)
529*a3323688SDavid du Colombier 		p = seprint(p, ep, "%2.2ux", *mac++);
5309ef1f84bSDavid du Colombier }
5319ef1f84bSDavid du Colombier 
5329ef1f84bSDavid du Colombier int
arpread(Arp * arp,char * p,ulong offset,int len)5339ef1f84bSDavid du Colombier arpread(Arp *arp, char *p, ulong offset, int len)
5349ef1f84bSDavid du Colombier {
5359ef1f84bSDavid du Colombier 	Arpent *a;
5369ef1f84bSDavid du Colombier 	int n;
5379ef1f84bSDavid du Colombier 	char mac[2*MAClen+1];
5389ef1f84bSDavid du Colombier 
5399ef1f84bSDavid du Colombier 	if(offset % Alinelen)
5409ef1f84bSDavid du Colombier 		return 0;
5419ef1f84bSDavid du Colombier 
5429ef1f84bSDavid du Colombier 	offset = offset/Alinelen;
5439ef1f84bSDavid du Colombier 	len = len/Alinelen;
5449ef1f84bSDavid du Colombier 
5459ef1f84bSDavid du Colombier 	n = 0;
5469ef1f84bSDavid du Colombier 	for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
5479ef1f84bSDavid du Colombier 		if(a->state == 0)
5489ef1f84bSDavid du Colombier 			continue;
5499ef1f84bSDavid du Colombier 		if(offset > 0){
5509ef1f84bSDavid du Colombier 			offset--;
5519ef1f84bSDavid du Colombier 			continue;
5529ef1f84bSDavid du Colombier 		}
5539ef1f84bSDavid du Colombier 		len--;
5549ef1f84bSDavid du Colombier 		qlock(arp);
555*a3323688SDavid du Colombier 		convmac(mac, &mac[sizeof mac], a->mac, a->type->maclen);
556*a3323688SDavid du Colombier 		n += snprint(p+n, Alinelen+1, aformat, a->type->name,
557*a3323688SDavid du Colombier 			arpstate[a->state], a->ip, mac);	/* +1 for NUL */
5589ef1f84bSDavid du Colombier 		qunlock(arp);
5599ef1f84bSDavid du Colombier 	}
5609ef1f84bSDavid du Colombier 
5619ef1f84bSDavid du Colombier 	return n;
5629ef1f84bSDavid du Colombier }
5639ef1f84bSDavid du Colombier 
5649ef1f84bSDavid du Colombier extern int
rxmitsols(Arp * arp)5659ef1f84bSDavid du Colombier rxmitsols(Arp *arp)
5669ef1f84bSDavid du Colombier {
5679ef1f84bSDavid du Colombier 	uint sflag;
5689ef1f84bSDavid du Colombier 	Block *next, *xp;
5699ef1f84bSDavid du Colombier 	Arpent *a, *b, **l;
5709ef1f84bSDavid du Colombier 	Fs *f;
5719ef1f84bSDavid du Colombier 	uchar ipsrc[IPaddrlen];
5729ef1f84bSDavid du Colombier 	Ipifc *ifc = nil;
5739ef1f84bSDavid du Colombier 	long nrxt;
5749ef1f84bSDavid du Colombier 
5759ef1f84bSDavid du Colombier 	qlock(arp);
5769ef1f84bSDavid du Colombier 	f = arp->f;
5779ef1f84bSDavid du Colombier 
5789ef1f84bSDavid du Colombier 	a = arp->rxmt;
5799ef1f84bSDavid du Colombier 	if(a==nil){
5809ef1f84bSDavid du Colombier 		nrxt = 0;
5819ef1f84bSDavid du Colombier 		goto dodrops;		/* return nrxt; */
5829ef1f84bSDavid du Colombier 	}
5839ef1f84bSDavid du Colombier 	nrxt = a->rtime - NOW;
5849ef1f84bSDavid du Colombier 	if(nrxt > 3*ReTransTimer/4)
5859ef1f84bSDavid du Colombier 		goto dodrops;		/* return nrxt; */
5869ef1f84bSDavid du Colombier 
5879ef1f84bSDavid du Colombier 	for(; a; a = a->nextrxt){
5889ef1f84bSDavid du Colombier 		ifc = a->ifc;
5899ef1f84bSDavid du Colombier 		assert(ifc != nil);
5909ef1f84bSDavid du Colombier 		if((a->rxtsrem <= 0) || !(canrlock(ifc)) || (a->ifcid != ifc->ifcid)){
5919ef1f84bSDavid du Colombier 			xp = a->hold;
5929ef1f84bSDavid du Colombier 			a->hold = nil;
5939ef1f84bSDavid du Colombier 
5949ef1f84bSDavid du Colombier 			if(xp){
5959ef1f84bSDavid du Colombier 				if(arp->dropl == nil)
5969ef1f84bSDavid du Colombier 					arp->dropf = xp;
5979ef1f84bSDavid du Colombier 				else
5989ef1f84bSDavid du Colombier 					arp->dropl->list = xp;
5999ef1f84bSDavid du Colombier 			}
6009ef1f84bSDavid du Colombier 
6019ef1f84bSDavid du Colombier 			cleanarpent(arp, a);
6029ef1f84bSDavid du Colombier 		}
6039ef1f84bSDavid du Colombier 		else
6049ef1f84bSDavid du Colombier 			break;
6059ef1f84bSDavid du Colombier 	}
6069ef1f84bSDavid du Colombier 	if(a == nil)
6079ef1f84bSDavid du Colombier 		goto dodrops;
6089ef1f84bSDavid du Colombier 
6099ef1f84bSDavid du Colombier 
6109ef1f84bSDavid du Colombier 	qunlock(arp);	/* for icmpns */
6119ef1f84bSDavid du Colombier 	if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC)
6129ef1f84bSDavid du Colombier 		icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
6139ef1f84bSDavid du Colombier 
6149ef1f84bSDavid du Colombier 	runlock(ifc);
6159ef1f84bSDavid du Colombier 	qlock(arp);
6169ef1f84bSDavid du Colombier 
6179ef1f84bSDavid du Colombier 	/* put to the end of re-transmit chain */
6189ef1f84bSDavid du Colombier 	l = &arp->rxmt;
6199ef1f84bSDavid du Colombier 	for(b = *l; b; b = b->nextrxt){
6209ef1f84bSDavid du Colombier 		if(b == a){
6219ef1f84bSDavid du Colombier 			*l = a->nextrxt;
6229ef1f84bSDavid du Colombier 			break;
6239ef1f84bSDavid du Colombier 		}
6249ef1f84bSDavid du Colombier 		l = &b->nextrxt;
6259ef1f84bSDavid du Colombier 	}
6269ef1f84bSDavid du Colombier 	for(b = *l; b; b = b->nextrxt){
6279ef1f84bSDavid du Colombier 		l = &b->nextrxt;
6289ef1f84bSDavid du Colombier 	}
6299ef1f84bSDavid du Colombier 	*l = a;
6309ef1f84bSDavid du Colombier 	a->rxtsrem--;
6319ef1f84bSDavid du Colombier 	a->nextrxt = nil;
6329ef1f84bSDavid du Colombier 	a->rtime = NOW + ReTransTimer;
6339ef1f84bSDavid du Colombier 
6349ef1f84bSDavid du Colombier 	a = arp->rxmt;
6359ef1f84bSDavid du Colombier 	if(a==nil)
6369ef1f84bSDavid du Colombier 		nrxt = 0;
6379ef1f84bSDavid du Colombier 	else
6389ef1f84bSDavid du Colombier 		nrxt = a->rtime - NOW;
6399ef1f84bSDavid du Colombier 
6409ef1f84bSDavid du Colombier dodrops:
6419ef1f84bSDavid du Colombier 	xp = arp->dropf;
6429ef1f84bSDavid du Colombier 	arp->dropf = nil;
6439ef1f84bSDavid du Colombier 	arp->dropl = nil;
6449ef1f84bSDavid du Colombier 	qunlock(arp);
6459ef1f84bSDavid du Colombier 
6469ef1f84bSDavid du Colombier 	for(; xp; xp = next){
6479ef1f84bSDavid du Colombier 		next = xp->list;
6489ef1f84bSDavid du Colombier 		icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
6499ef1f84bSDavid du Colombier 	}
6509ef1f84bSDavid du Colombier 
6519ef1f84bSDavid du Colombier 	return nrxt;
6529ef1f84bSDavid du Colombier 
6539ef1f84bSDavid du Colombier }
6549ef1f84bSDavid du Colombier 
6559ef1f84bSDavid du Colombier static int
rxready(void * v)6569ef1f84bSDavid du Colombier rxready(void *v)
6579ef1f84bSDavid du Colombier {
6589ef1f84bSDavid du Colombier 	Arp *arp = (Arp *) v;
6599ef1f84bSDavid du Colombier 	int x;
6609ef1f84bSDavid du Colombier 
6619ef1f84bSDavid du Colombier 	x = ((arp->rxmt != nil) || (arp->dropf != nil));
6629ef1f84bSDavid du Colombier 
6639ef1f84bSDavid du Colombier 	return x;
6649ef1f84bSDavid du Colombier }
6659ef1f84bSDavid du Colombier 
6669ef1f84bSDavid du Colombier static void
rxmitproc(void * v)6679ef1f84bSDavid du Colombier rxmitproc(void *v)
6689ef1f84bSDavid du Colombier {
6699ef1f84bSDavid du Colombier 	Arp *arp = v;
6709ef1f84bSDavid du Colombier 	long wakeupat;
6719ef1f84bSDavid du Colombier 
6729ef1f84bSDavid du Colombier 	arp->rxmitp = up;
6739ef1f84bSDavid du Colombier 	//print("arp rxmitproc started\n");
6749ef1f84bSDavid du Colombier 	if(waserror()){
6759ef1f84bSDavid du Colombier 		arp->rxmitp = 0;
6769ef1f84bSDavid du Colombier 		pexit("hangup", 1);
6779ef1f84bSDavid du Colombier 	}
6789ef1f84bSDavid du Colombier 	for(;;){
6799ef1f84bSDavid du Colombier 		wakeupat = rxmitsols(arp);
6809ef1f84bSDavid du Colombier 		if(wakeupat == 0)
6819ef1f84bSDavid du Colombier 			sleep(&arp->rxmtq, rxready, v);
6829ef1f84bSDavid du Colombier 		else if(wakeupat > ReTransTimer/4)
6839ef1f84bSDavid du Colombier 			tsleep(&arp->rxmtq, return0, 0, wakeupat);
6849ef1f84bSDavid du Colombier 	}
6859ef1f84bSDavid du Colombier }
6869ef1f84bSDavid du Colombier 
687