plan 9 kernel history: overview | file list | diff list

1991/1027/port/devarp.c (diff list | history)

1991/1026/sys/src/9/port/devarp.c:9,251991/1027/sys/src/9/port/devarp.c:9,49 (short | long | prev | next)
1991/0424    
 
#include	"devtab.h" 
 
Arpcache 	*arp; 
Arpcache	**arphash; 
Arpstats	arpstats; 
1991/1027    
Arpcache 	*arplruhead, *arplrutail; 
Arpcache 	*arp, **arphash; 
1991/0424    
Queue		*Servq; 
 
1991/1027    
typedef struct Arpq Arpq; 
struct Arpq 
{ 
	uchar	ip[4]; 
	uchar	*etheraddr; 
	Block	*bp; 
	Queue	*put; 
	ulong	time; 
	Arpq	*next; 
}; 
 
struct arpalloc 
{ 
	Lock; 
	Lock	list; 
	Lock	hash; 
	Arpq	*free; 
	Arpq	*head; 
	Arpq	*tail; 
}arpalloc; 
 
void		arpiput(Queue *, Block *); 
void		arpoput(Queue *, Block *); 
void		arpopn(Queue *, Stream *); 
void		arpcls(Queue *); 
Qinfo arpinfo = { arpiput, arpoput, arpopn, arpcls, "arp" }; 
 
1991/0424    
#define ARP_ENTRYLEN	50 
char *padstr = "                                           "; 
 
extern Arpcache *arplruhead; 
extern Arpcache *arplrutail; 
                 
enum{ 
	arpdirqid, 
	arpstatqid, 
1991/1026/sys/src/9/port/devarp.c:55,601991/1027/sys/src/9/port/devarp.c:79,85
1991/0424    
	ap = &arp[conf.arp-1]; 
	ap->frwd = 0; 
	arplrutail = ap; 
1991/1027    
	newqinfo(&arpinfo); 
1991/0424    
} 
 
void 
1991/1026/sys/src/9/port/devarp.c:203,2141991/1027/sys/src/9/port/devarp.c:228,239
1991/0424    
		m = getfields(buf, field, 5, ' '); 
 
		if(strncmp(field[0], "flush", 5) == 0) 
			arp_flush(); 
1991/1027    
			arpflush(); 
1991/0424    
		else if(strcmp(field[0], "delete") == 0) { 
			if(m != 2) 
				error(Ebadarg); 
 
			if(arp_delete(field[1]) < 0) 
1991/1027    
			if(arpdelete(field[1]) < 0) 
1991/0424    
				error(Eaddrnotfound); 
		} 
	case arpdataqid: 
1991/1026/sys/src/9/port/devarp.c:215,2211991/1027/sys/src/9/port/devarp.c:240,246
1991/0424    
		if(n != sizeof(Arpentry)) 
			error(Emsgsize); 
		memmove(&entry, a, sizeof(Arpentry)); 
		arp_enter(&entry, ARP_TEMP); 
1991/1027    
		arpenter(&entry, ARP_TEMP); 
1991/0424    
		break; 
	default: 
		error(Ebadusefd); 
1991/1026/sys/src/9/port/devarp.c:224,2261991/1027/sys/src/9/port/devarp.c:249,493
1991/0424    
	return n; 
} 
 
1991/1027    
 
void 
arpopn(Queue *q, Stream *s) 
{ 
	if(!Servq) 
		Servq = RD(q); 
} 
 
void 
arpcls(Queue *q) 
{ 
	if(q == Servq) 
		Servq = 0; 
} 
 
void 
arpiput(Queue *q, Block *bp) 
{ 
	PUTNEXT(q, bp); 
} 
 
void 
arpoput(Queue *q, Block *bp) 
{ 
	PUTNEXT(q, bp); 
} 
 
int 
arplookup(uchar *ip, uchar *et) 
{ 
	Arpcache *ap; 
 
	lock(&arpalloc.hash); 
	for(ap = ARPHASH(ip); ap; ap = ap->hash) { 
		if(ap->status == ARP_OK && memcmp(ap->eip, ip, sizeof(ap->eip)) == 0) { 
			memmove(et, ap->et, sizeof(ap->et)); 
			arplinkhead(ap); 
			unlock(&arpalloc.hash); 
			arpstats.hit++; 
			return 1; 
		} 
	} 
	unlock(&arpalloc.hash); 
	return 0; 
} 
 
void 
arpsendpkt(uchar *unroutedip, uchar *ether, Queue *put, Block *bp) 
{ 
	Arpq *aq; 
	Block *nbp; 
	uchar ip[4]; 
 
	if(!Servq) { 
		print("arp: No server\n"); 
		freeb(bp); 
		return; 
	} 
 
	iproute(unroutedip, ip); 
	if(arplookup(ip, ether)) { 
		PUTNEXT(put, bp); 
		return; 
	} 
 
	/* Send the request out to the user level arp daemon */ 
	nbp = allocb(sizeof(ip)); 
	memmove(nbp->rptr, ip, sizeof(ip)); 
	nbp->wptr += sizeof(ip); 
	nbp->flags |= S_DELIM; 
	PUTNEXT(Servq, nbp); 
	arpstats.miss++; 
 
	lock(&arpalloc); 
	if(aq = arpalloc.free) 
		arpalloc.free = aq->next; 
	unlock(&arpalloc); 
 
	if(aq == 0) { 
		freeb(bp); 
		return; 
	} 
 
	/* Stash the work away until the arp completes or times out */ 
	memmove(aq->ip, ip, sizeof(aq->ip)); 
	aq->etheraddr = ether; 
	aq->bp = bp; 
	aq->put = put; 
	aq->time = MACHP(0)->ticks; 
 
	lock(&arpalloc.list); 
	if(arpalloc.head)  { 
		arpalloc.tail->next = aq; 
		arpalloc.tail = aq; 
	} 
	else { 
		arpalloc.tail = aq; 
		arpalloc.head = aq; 
	} 
	aq->next = 0; 
	unlock(&arpalloc.list); 
} 
 
void 
arpflush(void) 
{ 
	Arpcache *ap; 
 
	for(ap = arplruhead; ap; ap = ap->frwd) 
		ap->status = ARP_FREE; 
} 
 
void 
arpenter(Arpentry *ape, int type) 
{ 
	Arpcache *ap, **l, *d; 
 
 
	/* Update an entry if we have one already */ 
	l = &ARPHASH(ape->ipaddr); 
	lock(&arpalloc.hash); 
	for(ap = *l; ap; ap = ap->hash) { 
		if(ap->status == ARP_OK && memcmp(ap->eip, ape->ipaddr, sizeof(ap->eip)) == 0) { 
			if(ap->type != ARP_PERM) { 
				ap->type = type; 
				memmove(ap->et, ape->etaddr, sizeof(ap->et)); 
				ap->status = ARP_OK; 
			} 
			unlock(&arpalloc.hash); 
			return; 
		} 
	} 
 
	/* Find an entry to replace */ 
	for(ap = arplrutail; ap && ap->type == ARP_PERM; ap = ap->prev) 
		; 
 
	if(!ap) { 
		print("arp: too many permanent entries\n"); 
		unlock(&arpalloc.hash); 
		return; 
	} 
 
	if(ap->hashhd) { 
		for(d = *ap->hashhd; d; d = d->hash) { 
			if(d == ap) { 
				*(ap->hashhd) = ap->hash; 
				break; 
			} 
			ap->hashhd = &d->hash; 
		} 
	} 
 
	ap->type = type; 
	ap->status = ARP_OK; 
	memmove(ap->eip, ape->ipaddr, sizeof(ape->ipaddr)); 
	memmove(ap->et, ape->etaddr, sizeof(ape->etaddr)); 
	ap->ip = nhgetl(ap->eip); 
	ap->hashhd = l; 
	ap->hash = *l; 
	*l = ap; 
	arplinkhead(ap); 
	unlock(&arpalloc.hash); 
	pusharpq(); 
} 
 
void 
pusharpq(void) 
{ 
	int sent; 
	Arpq *aq, *prev; 
 
loop:	prev = 0; 
	lock(&arpalloc.list); 
	for(aq = arpalloc.head; aq; aq = aq->next) { 
		if(arplookup(aq->ip, aq->etheraddr)) { 
			if(prev) 
				prev->next = aq->next; 
			else 
				arpalloc.head = 0; 
			if(aq->next == 0) 
				arpalloc.tail = prev; 
			unlock(&arpalloc.list); 
			PUTNEXT(aq->put, aq->bp); 
 
			lock(&arpalloc); 
			aq->next = arpalloc.free; 
			arpalloc.free = aq; 
			unlock(&arpalloc); 
			goto loop; 
		} 
		prev = aq; 
	} 
	unlock(&arpalloc.list); 
} 
 
int 
arpdelete(char *addr) 
{ 
	Arpcache *ap; 
	char enetaddr[6], buf[20], *ptr; 
	int i; 
 
	ptr = buf + 2; 
	strncpy(ptr, addr, (sizeof buf) - 2); 
 
	for(i = 0; i < 6 && addr != (char *)1; i++) { 
		ptr[-2] = '0'; 
		ptr[-1] = 'x'; 
		enetaddr[i] = atoi(ptr-2); 
		ptr = strchr(ptr, ':')+1; 
	} 
 
	lock(&arpalloc.hash); 
	for(ap = arplruhead; ap; ap = ap->frwd) { 
		if(memcmp(ap->et, ptr, sizeof(ap->et)) == 0) { 
			ap->status = ARP_FREE; 
			break; 
		} 
	} 
	unlock(&arpalloc.hash); 
} 
 
void 
arplinkhead(Arpcache *ap) 
{ 
	if(ap != arplruhead) { 
		if(ap->prev) 
			ap->prev->frwd = ap->frwd; 
		else 
			arplruhead = ap->frwd; 
	 
		if(ap->frwd) 
			ap->frwd->prev = ap->prev; 
		else 
			arplrutail = ap->prev; 
		 
		ap->frwd = arplruhead; 
		ap->prev = 0; 
		arplruhead = ap; 
	} 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)