~kris/9p

9hist

b8fff571df27ab7bc2301267b4de0cc4b9c6a3cd — David du Colombier 34 years ago d0087ac
Plan 9 from Bell Labs 1991-10-27
5 files changed, 284 insertions(+), 31 deletions(-)

M port/devarp.c
M port/devlance.c
M port/ipdat.h
M port/stip.c
M port/stream.c
M port/devarp.c => port/devarp.c +275 -8
@@ 9,17 9,41 @@

#include	"devtab.h"

Arpcache 	*arp;
Arpcache	**arphash;
Arpstats	arpstats;
Arpcache 	*arplruhead, *arplrutail;
Arpcache 	*arp, **arphash;
Queue		*Servq;

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" };

#define ARP_ENTRYLEN	50
char *padstr = "                                           ";

extern Arpcache *arplruhead;
extern Arpcache *arplrutail;

enum{
	arpdirqid,
	arpstatqid,


@@ 55,6 79,7 @@ arpreset(void)
	ap = &arp[conf.arp-1];
	ap->frwd = 0;
	arplrutail = ap;
	newqinfo(&arpinfo);
}

void


@@ 203,19 228,19 @@ arpwrite(Chan *c, char *a, long n, ulong offset)
		m = getfields(buf, field, 5, ' ');

		if(strncmp(field[0], "flush", 5) == 0)
			arp_flush();
			arpflush();
		else if(strcmp(field[0], "delete") == 0) {
			if(m != 2)
				error(Ebadarg);

			if(arp_delete(field[1]) < 0)
			if(arpdelete(field[1]) < 0)
				error(Eaddrnotfound);
		}
	case arpdataqid:
		if(n != sizeof(Arpentry))
			error(Emsgsize);
		memmove(&entry, a, sizeof(Arpentry));
		arp_enter(&entry, ARP_TEMP);
		arpenter(&entry, ARP_TEMP);
		break;
	default:
		error(Ebadusefd);


@@ 224,3 249,245 @@ arpwrite(Chan *c, char *a, long n, ulong offset)
	return n;
}


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;
	}
}

M port/devlance.c => port/devlance.c +1 -3
@@ 684,7 684,6 @@ lanceup(Ethertype *e, Etherpkt *p, int len)

	if(waserror())
		return;

	if(e->q && e->q->next->len<=Streamhi){
		bp = allocb(len);
		memmove(bp->rptr, (uchar *)p, len);


@@ 704,6 703,7 @@ isinput(void *arg)
	Lancemem *lm = LANCEMEM;
	return l.rl!=l.rc && (MPus(lm->rmr[l.rl].flags) & OWN)==0;
}

static void
lancekproc(void *arg)
{


@@ 740,7 740,6 @@ lancekproc(void *arg)
			len = MPus(m->cntflags) - 4;
			for(e = &l.e[0]; e < &l.e[Ntypes]; e++){
				if(e->q!=0 && (t==e->type||e->type==-1) && canqlock(e)){
if(p->type[0] == 0x80 || p->type[0] == 0x8) print("*");
					if(t==e->type||e->type==-1)
						lanceup(e, p, len);
					qunlock(e);


@@ 761,7 760,6 @@ stage:
		}
		qunlock(&l.rlock);
		sleep(&l.rr, isinput, 0);
print("!");
	}
}


M port/ipdat.h => port/ipdat.h +5 -3
@@ 453,9 453,10 @@ Block	*btrim(Block*, int, int);
Block	*ip_reassemble(int, Block*, Etherhdr*);
Ipconv	*portused(Ipconv *, Port);
Port	nextport(Ipconv *, Port);
void	arp_enter(Arpentry*, int);
void	arp_flush(void);
int	arp_delete(char*);
void	arpenter(Arpentry*, int);
void	arpflush(void);
int	arpdelete(char*);
void	pusharpq(void);
void	arplinkhead(Arpcache*);
Fragq   *ipfragallo(void);
void	ipfragfree(Fragq*);


@@ 509,6 510,7 @@ void	tcp_acktimer(void *);
Ipconv  *ipclonecon(Chan *);
void	iplisten(Chan *, Ipconv *, Ipconv *);
void	iloutoforder(Ipconv*, Ilhdr*, Block*);
void	arpsendpkt(uchar*, uchar*, Queue*, Block*);

#define	fmtaddr(xx)	(xx>>24)&0xff,(xx>>16)&0xff,(xx>>8)&0xff,xx&0xff
#define	MIN(a, b)	((a) < (b) ? (a) : (b))

M port/stip.c => port/stip.c +2 -12
@@ 200,12 200,7 @@ ipetheroput(Queue *q, Block *bp)

		/* Finally put in the ethernet level information */
		hnputs(eh->type, ET_IP);
		if(!arp_lookup(eh->dst, eh->d)) {
			freeb(bp);
			return;
		}

		PUTNEXT(Etherq, bp);
		arpsendpkt(eh->dst, eh->d, Etherq, bp);
		return;
	}



@@ 218,10 213,6 @@ ipetheroput(Queue *q, Block *bp)

	/* Make prototype output header */
	hnputs(eh->type, ET_IP);
	if(!arp_lookup(eh->dst, eh->d)) {
		freeb(bp);
		return;
	}
	
	dlen = len - (ETHER_HDR+ETHER_IPHDR);
	xp = bp;


@@ 271,9 262,8 @@ ipetheroput(Queue *q, Block *bp)
		feh->cksum[0] = 0;
		feh->cksum[1] = 0;
		hnputs(feh->cksum, ip_csum(&feh->vihl));

		nb->flags |= S_DELIM;
		PUTNEXT(Etherq, nb);
		arpsendpkt(feh->dst, feh->d, Etherq, nb);
	}

drop:

M port/stream.c => port/stream.c +1 -5
@@ 1324,11 1324,7 @@ streamwrite(Chan *c, void *a, long n, int docopy)
 *  like andrew's getmfields but no hidden state
 */
int
getfields(char *lp,	/* to be parsed */
	char **fields,	/* where to put pointers */
	int n,		/* number of pointers */
	char sep	/* separator */
)
getfields(char *lp, char **fields, int n, char sep)
{
	int i;