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

1992/0319/port/devarp.c (diff list | history)

port/devarp.c on 1991/0424
1991/0424    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1991/0424    
#include	"arp.h" 
#include 	"ipdat.h" 
 
#include	"devtab.h" 
 
1991/1029    
#define ARP_FREE	0 
#define ARP_OK		1 
#define ARP_ASKED	2 
#define ARP_TEMP	0 
#define ARP_PERM	1 
#define Arphashsize	32 
#define ARPHASH(p)	arphash[((p[2]^p[3])%Arphashsize)] 
 
typedef struct Arpcache Arpcache; 
1991/1203    
struct Arpcache 
{ 
1991/1029    
	uchar	status; 
	uchar	type; 
	uchar	eip[4]; 
	uchar	et[6]; 
	Arpcache *hash; 
	Arpcache **hashhd; 
	Arpcache *frwd; 
	Arpcache *prev; 
}; 
 
1991/0424    
Arpstats	arpstats; 
1991/1027    
Arpcache 	*arplruhead, *arplrutail; 
Arpcache 	*arp, **arphash; 
1991/0424    
Queue		*Servq; 
1991/1029    
Lock		larphash; 
1991/0424    
 
1991/1029    
void	arpiput(Queue *, Block *); 
void	arpoput(Queue *, Block *); 
void	arpopn(Queue *, Stream *); 
void	arpcls(Queue *); 
void	arpenter(Arpentry*, int); 
void	arpflush(void); 
int	arpdelete(char*); 
void	arplinkhead(Arpcache*); 
int	arplookup(uchar*, uchar*); 
1991/1027    
 
Qinfo arpinfo = { arpiput, arpoput, arpopn, arpcls, "arp" }; 
 
1991/0424    
#define ARP_ENTRYLEN	50 
char *padstr = "                                           "; 
 
enum{ 
	arpdirqid, 
1992/0213    
	arpdir2qid, 
1991/0424    
	arpstatqid, 
	arpctlqid, 
	arpdataqid, 
}; 
 
Dirtab arptab[]={ 
1992/0213    
	"stats",	{arpstatqid},		0,	0444, 
	"ctl",		{arpctlqid},		0,	0664, 
	"data",		{arpdataqid},		0,	0664, 
1991/0424    
}; 
#define Narptab (sizeof(arptab)/sizeof(Dirtab)) 
 
1992/0213    
/* 
 *  create a 2-level directory 
 */ 
int 
arpgen(Chan *c, void *vp, int ntab, int i, Dir *dp) 
{ 
	Qid q; 
 
	q.vers = 0; 
 
	/* top level directory contains the directory arp */ 
	if(c->qid.path == CHDIR){ 
		if(i) 
			return -1; 
		q.path = CHDIR | arpdir2qid; 
		devdir(c, q, "arp", 0, eve, 0555, dp); 
		return 1; 
	} 
 
	/* next level uses table */ 
	return devgen(c, arptab, Narptab, i, dp); 
} 
 
1991/0424    
void 
arpreset(void) 
{ 
	Arpcache *ap, *ep; 
 
	arp = (Arpcache *)ialloc(sizeof(Arpcache) * conf.arp, 0); 
	arphash = (Arpcache **)ialloc(sizeof(Arpcache *) * Arphashsize, 0); 
 
	ep = &arp[conf.arp]; 
	for(ap = arp; ap < ep; ap++) { 
		ap->frwd = ap+1; 
		ap->prev = ap-1; 
		ap->type = ARP_FREE; 
		ap->status = ARP_TEMP; 
	} 
 
	arp[0].prev = 0; 
	arplruhead = arp; 
	ap = &arp[conf.arp-1]; 
	ap->frwd = 0; 
	arplrutail = ap; 
1991/1027    
	newqinfo(&arpinfo); 
1991/0424    
} 
 
void 
arpinit(void) 
{ 
} 
 
Chan * 
arpattach(char *spec) 
{ 
	return devattach('a', spec); 
} 
 
Chan * 
arpclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
 
int 
arpwalk(Chan *c, char *name) 
{ 
1992/0213    
	return devwalk(c, name, 0, 0, arpgen); 
1991/0424    
} 
 
void 
arpstat(Chan *c, char *db) 
{ 
1992/0213    
	devstat(c, db, 0, 0, arpgen); 
1991/0424    
} 
 
Chan * 
arpopen(Chan *c, int omode) 
{ 
 
	if(c->qid.path == CHDIR){ 
		if(omode != OREAD) 
			error(Eperm); 
	} 
 
	switch(STREAMTYPE(c->qid.path)) { 
	case arpdataqid: 
		break; 
	case arpstatqid: 
		if(omode != OREAD) 
			error(Ebadarg); 
		break; 
	case arpctlqid: 
		break; 
	} 
 
 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
void 
arpcreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1991/1115    
	USED(c, name, omode, perm); 
1991/0424    
	error(Eperm); 
} 
 
void 
arpremove(Chan *c) 
{ 
1991/1115    
	USED(c); 
1991/0424    
	error(Eperm); 
} 
 
void 
arpwstat(Chan *c, char *dp) 
{ 
1991/1115    
	USED(c, dp); 
1991/0424    
	error(Eperm); 
} 
 
void 
arpclose(Chan *c) 
{ 
	streamclose(c); 
} 
 
long 
arpread(Chan *c, void *a, long n, ulong offset) 
{ 
	char	 buf[100]; 
	Arpcache *ap, *ep; 
	int	 part, bytes, size; 
	char	 *ptr, *ststr; 
 
	switch((int)(c->qid.path&~CHDIR)){ 
	case arpdirqid: 
1992/0213    
		return devdirread(c, a, n, 0, 0, arpgen); 
1991/0424    
	case arpdataqid: 
		bytes = c->offset; 
		while(bytes < conf.arp*ARP_ENTRYLEN && n) { 
			ap = &arp[bytes/ARP_ENTRYLEN]; 
			part = bytes%ARP_ENTRYLEN; 
 
			if(ap->status != ARP_OK) 
				ststr = "invalid"; 
			else 
				ststr = (ap->type == ARP_TEMP ? "temp" : "perm"); 
 
			sprint(buf,"%d.%d.%d.%d to %.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s%s", 
				ap->eip[0], ap->eip[1], ap->eip[2], ap->eip[3], 
				ap->et[0], ap->et[1], ap->et[2], ap->et[3], 
				ap->et[4], ap->et[5], 
				ststr, padstr);  
			 
			buf[ARP_ENTRYLEN-1] = '\n'; 
 
			size = ARP_ENTRYLEN - part; 
			size = MIN(n, size); 
			memmove(a, buf+part, size); 
 
			a = (void *)((int)a + size); 
			n -= size; 
			bytes += size; 
		} 
		return bytes - c->offset; 
		break; 
	case arpstatqid: 
		sprint(buf, "hits: %d miss: %d failed: %d\n", 
			arpstats.hit, arpstats.miss, arpstats.failed); 
 
1991/1115    
		return stringread(a, n, buf, offset); 
1991/0424    
	default: 
		n=0; 
		break; 
	} 
	return n; 
} 
 
long 
arpwrite(Chan *c, char *a, long n, ulong offset) 
{ 
	Arpentry entry; 
	char	 buf[20], *field[5]; 
	int 	 m; 
 
	switch(STREAMTYPE(c->qid.path)) { 
	case arpctlqid: 
 
		strncpy(buf, a, sizeof buf); 
		m = getfields(buf, field, 5, ' '); 
 
		if(strncmp(field[0], "flush", 5) == 0) 
1991/1027    
			arpflush(); 
1991/0424    
		else if(strcmp(field[0], "delete") == 0) { 
			if(m != 2) 
				error(Ebadarg); 
 
1991/1027    
			if(arpdelete(field[1]) < 0) 
1992/0114    
				error(Enetaddr); 
1991/0424    
		} 
	case arpdataqid: 
		if(n != sizeof(Arpentry)) 
			error(Emsgsize); 
		memmove(&entry, a, sizeof(Arpentry)); 
1991/1027    
		arpenter(&entry, ARP_TEMP); 
1991/0424    
		break; 
	default: 
		error(Ebadusefd); 
	} 
 
	return n; 
} 
 
1991/1027    
void 
arpopn(Queue *q, Stream *s) 
{ 
1992/0319    
	if(Myip[Myself]) 
		error(Einuse); 
1991/1115    
	USED(q, s); 
1991/1027    
} 
 
void 
arpcls(Queue *q) 
{ 
	if(q == Servq) 
		Servq = 0; 
} 
 
void 
arpiput(Queue *q, Block *bp) 
{ 
	PUTNEXT(q, bp); 
} 
 
void 
arpoput(Queue *q, Block *bp) 
{ 
1991/1029    
	uchar ip[4]; 
	Etherhdr *eh; 
1992/0213    
	Ipaddr addr; 
	static int dropped; 
1991/1029    
 
	if(bp->type != M_DATA) { 
		if(Servq == 0 && streamparse("arpd", bp)) { 
			Servq = RD(q); 
			freeb(bp); 
		} 
		else 
			PUTNEXT(q, bp); 
		return; 
	} 
 
	eh = (Etherhdr *)bp->rptr; 
1991/1030    
	if(nhgets(eh->type) != ET_IP) { 
		PUTNEXT(q, bp);	 
		return; 
	} 
 
1992/0214    
	/* if ip broadcast, use ether bcast address */ 
	addr = nhgetl(eh->dst); 
1992/0304    
	if(addr == Myip[Mybcast] || addr == Myip[Mynet] 
	|| ((addr & Mymask) == Myip[Mynet+1] && (addr & ~Mynetmask) == ~Mynetmask)){ 
1992/0214    
		memset(eh->d, 0xff, sizeof(eh->d)); 
		PUTNEXT(q, bp); 
		return; 
	} 
 
1991/1029    
	iproute(eh->dst, ip); 
 
1992/0213    
	/* if a known ip addr, send downstream to the ethernet */ 
1991/1029    
	if(arplookup(ip, eh->d)) { 
		PUTNEXT(q, bp); 
		return; 
	} 
 
1992/0214    
	/* Push the packet up to the arp server for address resolution */ 
	if(!Servq) { 
		if((dropped++ % 1000) == 0) 
			print("arp: No server, packet dropped %d.%d.%d.%d\n", 
				eh->dst[0], eh->dst[1], eh->dst[2], eh->dst[3]); 
		freeb(bp); 
1992/0213    
		return; 
	} 
1991/1029    
	memmove(eh->d, ip, sizeof(ip)); 
	PUTNEXT(Servq, bp); 
1991/1027    
} 
 
int 
arplookup(uchar *ip, uchar *et) 
{ 
	Arpcache *ap; 
 
1991/1029    
	lock(&larphash); 
1991/1027    
	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); 
1991/1029    
			unlock(&larphash); 
1991/1027    
			arpstats.hit++; 
			return 1; 
		} 
	} 
1991/1029    
	arpstats.miss++; 
	unlock(&larphash); 
1991/1027    
	return 0; 
} 
 
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); 
1991/1029    
	lock(&larphash); 
1991/1027    
	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; 
			} 
1991/1029    
			unlock(&larphash); 
1991/1027    
			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"); 
1991/1029    
		unlock(&larphash); 
1991/1027    
		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->hashhd = l; 
	ap->hash = *l; 
	*l = ap; 
	arplinkhead(ap); 
1991/1029    
	unlock(&larphash); 
1991/1027    
} 
 
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; 
	} 
 
1991/1029    
	lock(&larphash); 
1991/1027    
	for(ap = arplruhead; ap; ap = ap->frwd) { 
		if(memcmp(ap->et, ptr, sizeof(ap->et)) == 0) { 
			ap->status = ARP_FREE; 
			break; 
		} 
	} 
1991/1029    
	unlock(&larphash); 
1991/1027    
} 
 
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; 
1992/0213    
 
1991/1027    
		arplruhead = ap; 
	} 
} 


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