~kris/9p

9hist

0b8779b500b4f282d896ab42441e2e8dd3a59178 — David du Colombier 25 years ago 99355eb
Plan 9 from Bell Labs 2001-03-01
9 files changed, 371 insertions(+), 295 deletions(-)

M boot/boot.c
M ip/devip.c
M ip/il.c
M ip/ip.h
M ip/ipaux.c
M ip/rudp.c
M ip/tcp.c
M ip/udp.c
M pc/ether82557.c
M boot/boot.c => boot/boot.c +0 -1
@@ 40,7 40,6 @@ boot(int argc, char *argv[])
	Method *mp;
	char *cmd, cmdbuf[64], *iargv[16];
	char rootbuf[64];
	char flags[6];
	int islocal, ishybrid, iargc;
	char *rp;


M ip/devip.c => ip/devip.c +18 -20
@@ 754,29 754,27 @@ setladdrport(Conv* c, char* str, int announcing)
	}

	c->lport = 0;
	if(announcing){
		if(p == nil){
	if(p == nil){
		if(announcing)
			ipmove(c->laddr, IPnoaddr);
			lport = atoi(str);
		} else {
			if(strcmp(str, "*") == 0)
				ipmove(c->laddr, IPnoaddr);
			else
				parseip(c->laddr, str);
			lport = atoi(p);
		}
	} else {
		if(p == nil){
		else
			setladdr(c);
			lport = atoi(str);
		} else {
			if(strcmp(str, "*") == 0)
				setladdr(c);
			else
				parseip(c->laddr, str);
			lport = atoi(p);
		}
		p = str;
	} else {
		if(strcmp(str, "*") == 0)
			ipmove(c->laddr, IPnoaddr);
		else
			parseip(c->laddr, str);
	}

	/* one process can get all connections */
	if(announcing && strcmp(p, "*") == 0){
		if(!iseve())
			error(Eperm);
		return setluniqueport(c, 0);
	}

	lport = atoi(p);
	if(lport <= 0)
		setlport(c);
	else

M ip/il.c => ip/il.c +67 -91
@@ 183,17 183,19 @@ static char *statnames[] =
typedef struct Ilpriv Ilpriv;
struct Ilpriv
{
	Ipht	ht;

	ulong	stats[Nstats];

	ulong		csumerr;		/* checksum errors */
	ulong		hlenerr;		/* header length error */
	ulong		lenerr;			/* short packet */
	ulong		order;			/* out of order */
	ulong		rexmit;			/* retransmissions */
	ulong		dup;
	ulong		dupb;
	ulong	csumerr;		/* checksum errors */
	ulong	hlenerr;		/* header length error */
	ulong	lenerr;			/* short packet */
	ulong	order;			/* out of order */
	ulong	rexmit;			/* retransmissions */
	ulong	dup;
	ulong	dupb;

	Rendez		ilr;
	Rendez	ilr;

	/* keeping track of the ack kproc */
	int	ackprocstarted;


@@ 222,7 224,7 @@ int	ilnextqt(Ilcb*);
void	ilcbinit(Ilcb*);
int	later(ulong, ulong, char*);
void	ilreject(Fs*, Ilhdr*);

void	illocalclose(Conv *c);
	int 	ilcksum = 1;
static 	int 	initseq = 25001;
static	ulong	scalediv, scalemul;


@@ 280,6 282,20 @@ ilannounce(Conv *c, char **argv, int argc)
	return nil;
}

void
illocalclose(Conv *c)
{
	Ilcb *ic;
	Ilpriv *ipriv;

	ipriv = c->p->priv;
	ic = (Ilcb*)c->ptcl;
	ic->state = Ilclosed;
	iphtrem(&ipriv->ht, c);
	ipmove(c->laddr, IPnoaddr);
	c->lport = 0;
}

static void
ilclose(Conv *c)
{


@@ 303,9 319,7 @@ ilclose(Conv *c)
		ilsendctl(c, nil, Ilclose, ic->next, ic->recvd, 0);
		break;
	case Illistening:
		ic->state = Ilclosed;
		ipmove(c->laddr, IPnoaddr);
		c->lport = 0;
		illocalclose(c);
		break;
	}
	ilfreeq(ic);


@@ 516,7 530,7 @@ iliput(Proto *il, uchar*, Block *bp)
	uchar laddr[IPaddrlen];
	ushort sp, dp, csum;
	int plen, illen;
	Conv *s, **p, *new, *spec, *gen;
	Conv *s;
	Ilpriv *ipriv;

	ipriv = il->priv;


@@ 539,6 553,7 @@ iliput(Proto *il, uchar*, Block *bp)
	sp = nhgets(ih->ildst);
	dp = nhgets(ih->ilsrc);
	v4tov6(raddr, ih->src);
	v4tov6(laddr, ih->dst);

	if((csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) {
		if(ih->iltype < 0 || ih->iltype > Ilclose)


@@ 552,96 567,55 @@ iliput(Proto *il, uchar*, Block *bp)
	}

	qlock(il);

	for(p = il->conv; *p; p++) {
		s = *p;
		if(s->lport == sp)
		if(s->rport == dp)
		if(ipcmp(s->raddr, raddr) == 0) {
			qlock(s);
			qunlock(il);
			if(waserror()){
				qunlock(s);
				nexterror();
			}
			ilprocess(s, ih, bp);
			qunlock(s);
			poperror();
			return;
		}
	}

	if(ih->iltype != Ilsync){
	s = iphtlook(&ipriv->ht, raddr, dp, laddr, sp);
	if(s == nil){
		qunlock(il);
		if(ih->iltype < 0 || ih->iltype > Ilclose)
			st = "?";
		else
			st = iltype[ih->iltype];
		ilreject(il->f, ih);		/* no channel and not sync */
		netlog(il->f, Logil, "il: no channel, pkt(%s id %lud ack %lud %I/%ud->%ud)\n",
			st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); 
		goto raise;
	}

	gen = nil;
	spec = nil;
	for(p = il->conv; *p; p++) {
		s = *p;
		ic = (Ilcb*)s->ptcl;
		if(ic->state != Illistening)
			continue;

		if(s->rport == 0 && ipcmp(s->raddr, IPnoaddr) == 0) {
			if(s->lport == sp) {
				spec = s;
				break;
			}
			if(s->lport == 0)
				gen = s;
	ic = (Ilcb*)s->ptcl;
	if(ic->state == Illistening){
		if(ih->iltype != Ilsync){
			qunlock(il);
			if(ih->iltype < 0 || ih->iltype > Ilclose)
				st = "?";
			else
				st = iltype[ih->iltype];
			ilreject(il->f, ih);		/* no channel and not sync */
			netlog(il->f, Logil, "il: no channel, pkt(%s id %lud ack %lud %I/%ud->%ud)\n",
				st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); 
			goto raise;
		}
	}

	if(spec)
		s = spec;
	else
	if(gen)
		s = gen;
	else {
		qunlock(il);
		ilreject(il->f, ih);		/* no listener */
		goto raise;
	}

	v4tov6(laddr, ih->dst);
	new = Fsnewcall(s, raddr, dp, laddr, sp);
	if(new == nil){
		qunlock(il);
		netlog(il->f, Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp);
		ilsendctl(s, ih, Ilclose, 0, nhgetl(ih->ilid), 0);
		goto raise;
		s = Fsnewcall(s, raddr, dp, laddr, sp);
		if(s == nil){
			qunlock(il);
			netlog(il->f, Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp);
			ilsendctl(s, ih, Ilclose, 0, nhgetl(ih->ilid), 0);
			goto raise;
		}
	
		ic = (Ilcb*)s->ptcl;
	
		ic->conv = s;
		ic->state = Ilsyncee;
		ilcbinit(ic);
		ic->rstart = nhgetl(ih->ilid);
		iphtadd(&ipriv->ht, s);
	}

	ic = (Ilcb*)new->ptcl;

	ic->conv = new;
	ic->state = Ilsyncee;
	ilcbinit(ic);
	ic->rstart = nhgetl(ih->ilid);

	qlock(new);
	qlock(s);
	qunlock(il);
	if(waserror()){
		qunlock(new);
		qunlock(s);
		nexterror();
	}
	ilprocess(new, ih, bp);
	qunlock(new);
	ilprocess(s, ih, bp);
	qunlock(s);
	poperror();
	return;

raise:
	freeblist(bp);
	return;
}

void


@@ 695,9 669,9 @@ _ilprocess(Conv *s, Ilhdr *h, Block *bp)
		default:
			break;
		case Ilsync:
			if(id != ic->rstart || ack != 0)
				ic->state = Ilclosed;
			else {
			if(id != ic->rstart || ack != 0){
				illocalclose(s);
			} else {
				ic->recvd = id;
				ilsendctl(s, nil, Ilsync, ic->start, ic->recvd, 0);
			}


@@ 867,7 841,7 @@ ilhangup(Conv *s, char *msg)

	ic = (Ilcb*)s->ptcl;
	callout = ic->state == Ilsyncer;
	ic->state = Ilclosed;
	illocalclose(s);

	qhangup(s->rq, msg);
	qhangup(s->wq, msg);


@@ 1264,9 1238,11 @@ ilstart(Conv *c, int type, int fasttimeout)
		break;
	case IL_LISTEN:
		ic->state = Illistening;
		iphtadd(&ipriv->ht, c);
		break;
	case IL_CONNECT:
		ic->state = Ilsyncer;
		iphtadd(&ipriv->ht, c);
		ilsendctl(c, nil, Ilsync, ic->start, ic->recvd, 0);
		break;
	}

M ip/ip.h => ip/ip.h +30 -0
@@ 11,6 11,8 @@ typedef struct	Ipmulti	Ipmulti;
typedef struct	Ipmux	Ipmux;
typedef struct	IProuter IProuter;
typedef struct	Ipifc	Ipifc;
typedef struct	Iphash	Iphash;
typedef struct	Ipht	Ipht;
typedef struct	Netlog	Netlog;
typedef struct	Ifclog	Ifclog;
typedef struct	Medium	Medium;


@@ 196,6 198,34 @@ struct Ipmulti
};

/*
 *  hash table for 2 ip addresses + 2 ports
 */
enum
{
	Nipht=		521,	/* convenient prime */

	IPmatchexact=	0,	/* match on 4 tuple */
	IPmatchany,		/* *!* */
	IPmatchport,		/* *!port */
	IPmatchaddr,		/* addr!* */
	IPmatchpa,		/* addr!port */
};
struct Iphash
{
	Iphash	*next;
	Conv	*c;
	int	match;
};
struct Ipht
{
	Lock;
	Iphash	*tab[Nipht];
};
void iphtadd(Ipht*, Conv*);
void iphtrem(Ipht*, Conv*);
Conv* iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp);

/*
 *  one per multiplexed protocol
 */
struct Proto

M ip/ipaux.c => ip/ipaux.c +148 -6
@@ 249,15 249,23 @@ isv4(uchar *ip)
	return memcmp(ip, v4prefix, IPv4off) == 0;
}

/* 
 *  since we call v4tov6 so often (per packet in), avoiding the memmove's is
 *  useful.  However, we need to check allignment for processors
 *  without unalligned moves.
 */
void
v4tov6(uchar *v6, uchar *v4)
{
//	memmove(v6, v4prefix, IPv4off);
//	memmove(v6 + IPv4off, v4, IPv4addrlen);
	*(ulong*)v6 = *(ulong*)v4prefix;
	*(ulong*)(v6+4) = *(ulong*)(v4prefix+4);
	*(ulong*)(v6+8) = *(ulong*)(v4prefix+8);
	*(ulong*)(v6+12) = *(ulong*)v4;
	if((((ulong)v6) & 0x3) != 0 || (((ulong)v4) & 0x3) != 0){
		memmove(v6, v4prefix, IPv4off);
		memmove(v6 + IPv4off, v4, IPv4addrlen);
	} else {
		*(ulong*)v6 = *(ulong*)v4prefix;
		*(ulong*)(v6+4) = *(ulong*)(v4prefix+4);
		*(ulong*)(v6+8) = *(ulong*)(v4prefix+8);
		*(ulong*)(v6+12) = *(ulong*)v4;
	}
}

int


@@ 392,3 400,137 @@ parsemac(uchar *to, char *from, int len)
	}
	return i;
}

/*
 *  hashing tcp, udp, ... connections
 */
ulong
iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
{
	return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nhash;
}

void
iphtadd(Ipht *ht, Conv *c)
{
	ulong hv;
	Iphash *h;

	hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
	h = smalloc(sizeof(*h));
	if(ipcmp(c->raddr, IPnoaddr) != 0)
		h->match = IPmatchexact;
	else {
		if(ipcmp(c->laddr, IPnoaddr) != 0){
			if(c->lport == 0)
				h->match = IPmatchaddr;
			else
				h->match = IPmatchpa;
		} else {
			if(c->lport == 0)
				h->match = IPmatchany;
			else
				h->match = IPmatchport;
		}
	}
	h->c = c;
	lock(ht);
	h->next = ht->tab[hv];
	ht->tab[hv] = h;
	unlock(ht);
}

void
iphtrem(Ipht *ht, Conv *c)
{
	ulong hv;
	Iphash **l, *h;

	hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
	lock(ht);
	for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
		if((*l)->c == c){
			h = *l;
			(*l) = h->next;
			free(h);
			break;
		}
	unlock(ht);
}

/* look for a matching conversation with the following precedence
 *	connected && raddr,rport,laddr,lport
 *	announced && laddr,lport
 *	announced && *,lport
 *	announced && laddr,*
 *	announced && *,*
 */
Conv*
iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
{
	ulong hv;
	Iphash *h;
	Conv *c;

	/* exact 4 pair match (connection) */
	hv = iphash(sa, sp, da, dp);
	lock(ht);
	for(h = ht->tab[hv]; h != nil; h = h->next){
		if(h->match != IPmatchexact)
			continue;
		c = h->c;
		if(sp == c->rport && dp == c->lport
		&& ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
			unlock(ht);
			return c;
		}
	}
	
	/* match local address and port */
	hv = iphash(IPnoaddr, 0, da, dp);
	for(h = ht->tab[hv]; h != nil; h = h->next){
		if(h->match != IPmatchpa)
			continue;
		c = h->c;
		if(dp == c->lport && ipcmp(da, c->laddr) == 0){
			unlock(ht);
			return c;
		}
	}
	
	/* match just port */
	hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
	for(h = ht->tab[hv]; h != nil; h = h->next){
		if(h->match != IPmatchport)
			continue;
		c = h->c;
		if(dp == c->lport){
			unlock(ht);
			return c;
		}
	}
	
	/* match local address */
	hv = iphash(IPnoaddr, 0, da, 0);
	for(h = ht->tab[hv]; h != nil; h = h->next){
		if(h->match != IPmatchaddr)
			continue;
		c = h->c;
		if(ipcmp(da, c->laddr) == 0){
			unlock(ht);
			return c;
		}
	}
	
	/* look for something that matches anything */
	hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
	for(h = ht->tab[hv]; h != nil; h = h->next){
		if(h->match != IPmatchany)
			continue;
		c = h->c;
		unlock(ht);
		return c;
	}
	unlock(ht);
	return nil;
}

M ip/rudp.c => ip/rudp.c +17 -28
@@ 147,6 147,7 @@ typedef struct Rudppriv Rudppriv;
struct Rudppriv
{
	Rendez	vous;
	Ipht	ht;

	/* MIB counters */
	Rudpstats	ustats;


@@ 214,10 215,13 @@ static char*
rudpconnect(Conv *c, char **argv, int argc)
{
	char *e;
	Rudppriv *upriv;

	upriv = c->p->priv;
	rudpstartackproc(c->p);
	e = Fsstdconnect(c, argv, argc);
	Fsconnected(c, e);
	iphtadd(&upriv->ht, c);

	return e;
}


@@ 243,12 247,15 @@ static char*
rudpannounce(Conv *c, char** argv, int argc)
{
	char *e;
	Rudppriv *upriv;

	upriv = c->p->priv;
	rudpstartackproc(c->p);
	e = Fsstdannounce(c, argv, argc);
	if(e != nil)
		return e;
	Fsconnected(c, nil);
	iphtadd(&upriv->ht, c);

	return nil;
}


@@ 265,6 272,10 @@ rudpclose(Conv *c)
{
	Rudpcb *ucb;
	Reliable *r, *nr;
	Rudppriv *upriv;

	upriv = c->p->priv;
	iphtrem(&upriv->ht, c);

	/* force out any delayed acks */
	ucb = (Rudpcb*)c->ptcl;


@@ 468,7 479,7 @@ rudpiput(Proto *rudp, uchar *ia, Block *bp)
{
	int len, olen, ottl;
	Udphdr *uh;
	Conv *c, **p;
	Conv *c;
	Rudpcb *ucb;
	uchar raddr[IPaddrlen], laddr[IPaddrlen];
	ushort rport, lport;


@@ 509,33 520,12 @@ rudpiput(Proto *rudp, uchar *ia, Block *bp)

	qlock(rudp);

	/* Look for a conversation structure for this port */
	c = nil;
	for(p = rudp->conv; *p; p++) {
		c = *p;
		if(c->inuse == 0)
			continue;
		if(c->lport == lport){
			ucb = (Rudpcb*)c->ptcl;

			/* with headers turned on, descriminate only on local port */
			if(ucb->headers)
				break;

			/* otherwise discriminate on lport, rport, and raddr */
			if(c->rport == 0 || c->rport == rport)
			if(ipisbm(c->raddr) || ipcmp(c->raddr, IPnoaddr) == 0
			   || ipcmp(c->raddr, raddr) == 0)
				break;
		}
	}

	if(*p == nil) {
		qunlock(rudp);
	c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
	if(c == nil){
		/* no converstation found */
		upriv->ustats.rudpNoPorts++;
		netlog(f, Logrudp, "rudp: no conv %I!%d -> %I!%d\n", raddr, rport,
			laddr, lport);
		DPRINT("rudp: no conv %I!%d -> %I!%d\n", raddr, rport,
		qunlock(rudp);
		netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
			laddr, lport);
		uh->Unused = ottl;
		hnputs(uh->udpplen, olen);


@@ 543,7 533,6 @@ rudpiput(Proto *rudp, uchar *ia, Block *bp)
		freeblist(bp);
		return;
	}

	ucb = (Rudpcb*)c->ptcl;
	qlock(ucb);
	qunlock(rudp);

M ip/tcp.c => ip/tcp.c +29 -66
@@ 245,6 245,9 @@ struct Tcppriv
	QLock 	tl;			/* Protect timer list */
	Rendez	tcpr;			/* used by tcpackproc */

	/* hash table for matching conversations */
	Ipht	ht;

	ulong	stats[Nstats];

	/* for keeping track of tcpackproc */


@@ 604,6 607,8 @@ localclose(Conv *s, char *reason)	 /*  called with tcb locked */
	tpriv = s->p->priv;
	tcb = (Tcpctl*)s->ptcl;

	iphtrem(&tpriv->ht, s);

	tcphalt(tpriv, &tcb->timer);
	tcphalt(tpriv, &tcb->rtt_timer);
	tcphalt(tpriv, &tcb->acktimer);


@@ 711,6 716,7 @@ tcpstart(Conv *s, int mode, ushort window)
	tcb->window = window;
	tcb->rcv.wnd = window;

	iphtadd(&tpriv->ht, s);
	switch(mode) {
	case TCP_LISTEN:
		tpriv->stats[PassiveOpens]++;


@@ 983,6 989,7 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst)
	Conv *new;
	Tcpctl *tcb;
	Tcphdr *h;
	Tcppriv *tpriv;

	new = Fsnewcall(s, src, segp->source, dst, segp->dest);
	if(new == nil)


@@ 1008,6 1015,9 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst)
	v6tov4(h->tcpsrc, dst);
	v6tov4(h->tcpdst, src);

	tpriv = new->p->priv;
	iphtadd(&tpriv->ht, new);

	return new;
}



@@ 1218,7 1228,7 @@ tcpiput(Proto *tcp, uchar*, Block *bp)
	Tcpctl *tcb;
	ushort length;
	uchar source[IPaddrlen], dest[IPaddrlen];
	Conv *spec, *gen, *s, **p;
	Conv *s;
	Fs *f;
	Tcppriv *tpriv;



@@ 1229,9 1239,9 @@ tcpiput(Proto *tcp, uchar*, Block *bp)

	h = (Tcphdr*)(bp->rp);

	length = nhgets(h->length);
	v4tov6(dest, h->tcpdst);
	v4tov6(source, h->tcpsrc);
	length = nhgets(h->length);

	h->Unused = 0;
	hnputs(h->tcplen, length-TCP_PKT);


@@ 1265,77 1275,30 @@ tcpiput(Proto *tcp, uchar*, Block *bp)
	/* lock protocol while searching for a conversation */
	qlock(tcp);

	/* Look for a connection. failing that look for a listener. */
	for(p = tcp->conv; *p; p++) {
		s = *p;
		tcb = (Tcpctl*)s->ptcl;
		if(s->rport == seg.source)
		if(s->lport == seg.dest)
		if(tcb->state != Closed)
		if(ipcmp(s->raddr, source) == 0)
			break;
	}
	s = *p;
	if(s){
		/* can't send packets to a listener */
		tcb = (Tcpctl*)s->ptcl;
		if(tcb->state == Listen){
			qunlock(tcp);
			freeblist(bp);
			return;
		}
	/* Look for a matching conversation */
	s = iphtlook(&tpriv->ht, source, seg.source, dest, seg.dest);
	if(s == nil){
reset:
		qunlock(tcp);
		sndrst(tcp, source, dest, length, &seg);
		freeblist(bp);
		return;
	}
	if(s == nil && (seg.flags & SYN)) {
		/*
		 *  dump packets with bogus flags
		 */
		if(seg.flags & RST){
			qunlock(tcp);
			freeblist(bp);
			return;
		}

		if(seg.flags & ACK) {
	/* if it's a listener, look for the right flags and get a new conv */
	tcb = (Tcpctl*)s->ptcl;
	if(tcb->state == Listen){
		if(seg.flags & RST){
			qunlock(tcp);
			sndrst(tcp, source, dest, length, &seg);
			freeblist(bp);
			return;
		}
		if((seg.flags & SYN) == 0 || (seg.flags & ACK) != 0)
			goto reset;

		/*
		 *  find a listener specific to this port (spec) or,
		 *  failing that, a general one (gen)
		 */
		gen = nil;
		spec = nil;
		for(p = tcp->conv; *p; p++) {
			s = *p;
			tcb = (Tcpctl*)s->ptcl;
			if((tcb->flags & CLONE) == 0)
				continue;
			if(tcb->state != Listen)
				continue;
			if(s->rport == 0 && ipcmp(s->raddr, IPnoaddr) == 0) {
				if(s->lport == seg.dest){
					spec = s;
					break;
				}
				if(s->lport == 0)
					gen = s;
			}
		}
		s = nil;
		if(spec != nil)
			s = tcpincoming(spec, &seg, source, dest);
		else
		if(gen != nil)
			s = tcpincoming(gen, &seg, source, dest);
	}
	if(s == nil) {
		qunlock(tcp);
		sndrst(tcp, source, dest, length, &seg);
		freeblist(bp);
		return;
		s = tcpincoming(s, &seg, source, dest);
		if(s == nil)
			goto reset;
	}

	/* The rest of the input state machine is run with the control block

M ip/udp.c => ip/udp.c +39 -75
@@ 58,6 58,8 @@ struct Udpstats
typedef struct Udppriv Udppriv;
struct Udppriv
{
	Ipht		ht;

	/* MIB counters */
	Udpstats	ustats;



@@ 80,9 82,12 @@ static char*
udpconnect(Conv *c, char **argv, int argc)
{
	char *e;
	Udppriv *upriv;

	upriv = c->p->priv;
	e = Fsstdconnect(c, argv, argc);
	Fsconnected(c, e);
	iphtadd(&upriv->ht, c);

	return e;
}


@@ 98,11 103,14 @@ static char*
udpannounce(Conv *c, char** argv, int argc)
{
	char *e;
	Udppriv *upriv;

	upriv = c->p->priv;
	e = Fsstdannounce(c, argv, argc);
	if(e != nil)
		return e;
	Fsconnected(c, nil);
	iphtadd(&upriv->ht, c);

	return nil;
}


@@ 118,6 126,10 @@ static void
udpclose(Conv *c)
{
	Udpcb *ucb;
	Udppriv *upriv;

	upriv = c->p->priv;
	iphtrem(&upriv->ht, c);

	c->state = 0;
	qclose(c->rq);


@@ 245,7 257,7 @@ udpiput(Proto *udp, uchar *ia, Block *bp)
{
	int len, olen, ottl;
	Udphdr *uh;
	Conv *c, **p, *gen;
	Conv *c;
	Udpcb *ucb;
	uchar raddr[IPaddrlen], laddr[IPaddrlen];
	ushort rport, lport;


@@ 283,85 295,37 @@ udpiput(Proto *udp, uchar *ia, Block *bp)

	qlock(udp);

	gen = nil;

	/* look for an announced port with headers (most likely) */
	for(p = udp->conv; *p; p++){
		c = *p;
		ucb = (Udpcb*)c->ptcl;
		if(c->inuse == 0 || c->state != Announced || ucb->headers == 0)
			continue;
		
		if(c->lport != lport)
			continue;

		if(ipcmp(c->laddr, laddr) == 0)
			goto found;

		if(ipcmp(c->laddr, IPnoaddr) == 0 || ipcmp(c->laddr, v4prefix) == 0)
			gen = c;
	}
	if(gen != nil){
		c = gen;
		goto found;
	}

	/* look for a connected port */
	for(p = udp->conv; *p; p++){
		c = *p;
		if(c->inuse == 0 || c->state != Connected)
			continue;
		if(c->lport == lport
		&& c->rport == rport
		&& (ipcmp(c->laddr, laddr) == 0)
		&& ipcmp(c->raddr, raddr) == 0 || ipisbm(c->raddr))
			goto found;
	c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
	if(c == nil){
		/* no converstation found */
		upriv->ustats.udpNoPorts++;
		qunlock(udp);
		netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
			laddr, lport);
		uh->Unused = ottl;
		hnputs(uh->udpplen, olen);
		icmpnoconv(f, bp);
		freeblist(bp);
		return;
	}
	ucb = (Udpcb*)c->ptcl;

	/* finally, look for a listener */
	for(p = udp->conv; *p; p++){
		c = *p;
		ucb = (Udpcb*)c->ptcl;
		if(c->inuse == 0 || c->state != Announced || ucb->headers != 0)
			continue;
		
		if(c->lport != lport)
			continue;

		if(ipcmp(c->laddr, laddr) == 0)
			break;

		if(ipcmp(c->laddr, IPnoaddr) == 0)
			gen = c;
	}
	c = *p;
	if(c == nil)
		c = gen;
	if(c != nil){
		if(ipforme(f, laddr) != Runi)
			v4tov6(laddr, ia);
		c = Fsnewcall(gen, raddr, rport, laddr, lport);
		if(c == nil){
			freeblist(bp);
			return;
	if(c->state == Announced){
		if(ucb->headers == 0){
			/* create a new conversation */
			if(ipforme(f, laddr) != Runi)
				v4tov6(laddr, ia);
			c = Fsnewcall(c, raddr, rport, laddr, lport);
			if(c == nil){
				qunlock(udp);
				freeblist(bp);
				return;
			}
			iphtadd(&upriv->ht, c);
			ucb = (Udpcb*)c->ptcl;
		}
		c->state = Connected;
		goto found;
	}

	/* no converstation found */
	upriv->ustats.udpNoPorts++;
	qunlock(udp);
	netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
		laddr, lport);
	uh->Unused = ottl;
	hnputs(uh->udpplen, olen);
	icmpnoconv(f, bp);
	freeblist(bp);
	return;

found:
	ucb = (Udpcb*)c->ptcl;
	qlock(c);
	qunlock(udp);


M pc/ether82557.c => pc/ether82557.c +23 -8
@@ 90,8 90,6 @@ enum {					/* Ecr */

	EEstart		= 0x04,		/* start bit */
	EEread		= 0x02,		/* read opcode */

	EEaddrsz	= 6,		/* bits of address */
};

enum {					/* Mcr */


@@ 190,7 188,8 @@ typedef struct Ctlr {
	int	state;

	int	port;
	ushort	eeprom[0x40];
	int	eepromsz;		/* address size in bits */
	ushort*	eeprom;

	Lock	miilock;



@@ 440,7 439,7 @@ ifstat(Ether* ether, void* a, long n, ulong offset)
	len += snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold);

	len += snprint(p+len, READSTR-len, "eeprom:");
	for(i = 0; i < 0x40; i++){
	for(i = 0; i < (1<<ctlr->eepromsz); i++){
		if(i && ((i & 0x07) == 0))
			len += snprint(p+len, READSTR-len, "\n       ");
		len += snprint(p+len, READSTR-len, " %4.4uX", ctlr->eeprom[i]);


@@ 825,7 824,7 @@ miiw(Ctlr* ctlr, int phyadd, int regadd, int data)
static int
hy93c46r(Ctlr* ctlr, int r)
{
	int i, op, data;
	int data, i, op, size;

	/*
	 * Hyundai HY93C46 or equivalent serial EEPROM.


@@ 833,6 832,7 @@ hy93c46r(Ctlr* ctlr, int r)
	 * in the EEPROM is taken straight from Section
	 * 3.3.4.2 of the Intel 82557 User's Guide.
	 */
reread:
	csr16w(ctlr, Ecr, EEcs);
	op = EEstart|EEread;
	for(i = 2; i >= 0; i--){


@@ 844,8 844,14 @@ hy93c46r(Ctlr* ctlr, int r)
		microdelay(1);
	}

	for(i = EEaddrsz-1; i >= 0; i--){
		data = (((r>>i) & 0x01)<<2)|EEcs;
	/*
	 * First time through must work out the EEPROM size.
	 */
	if((size = ctlr->eepromsz) == 0)
		size = 8;

	for(size = size-1; size >= 0; size--){
		data = (((r>>size) & 0x01)<<2)|EEcs;
		csr16w(ctlr, Ecr, data);
		csr16w(ctlr, Ecr, data|EEsk);
		delay(1);


@@ 867,6 873,12 @@ hy93c46r(Ctlr* ctlr, int r)

	csr16w(ctlr, Ecr, 0);

	if(ctlr->eepromsz == 0){
		ctlr->eepromsz = 8-size;
		ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort));
		goto reread;
	}

	return data;
}



@@ 1022,9 1034,12 @@ reset(Ether* ether)

	/*
	 * Read the EEPROM.
	 * Do a dummy read first to get the size
	 * and allocate ctlr->eeprom.
	 */
	hy93c46r(ctlr, 0);
	sum = 0;
	for(i = 0; i < 0x40; i++){
	for(i = 0; i < (1<<ctlr->eepromsz); i++){
		x = hy93c46r(ctlr, i);
		ctlr->eeprom[i] = x;
		sum += x;