~kris/9p

9hist

3b4bfba9c73b08a8490c4749c254445fdadc6b1c — David du Colombier 26 years ago deed979
Plan 9 from Bell Labs 2000-03-17
2 files changed, 120 insertions(+), 20 deletions(-)

M ip/rudp.c
M pc/ether82557.c
M ip/rudp.c => ip/rudp.c +83 -18
@@ 37,8 37,11 @@ enum
	Rudptickms	= 50,
	Rudpmaxxmit	= 10,
	Maxunacked	= 100,

};

#define Hangupgen	0xffffffff	/* used only in hangup messages */

typedef struct Udphdr Udphdr;
struct Udphdr
{


@@ 100,6 103,8 @@ struct Rudphdr
typedef struct Reliable Reliable;
struct Reliable
{
	Ref;

	Reliable *next;

	uchar	addr[IPaddrlen];	/* always V6 when put here */


@@ 121,7 126,6 @@ struct Reliable
	ulong	ackrcvd;	/* last msg for which ack was rcvd */

	/* flow control */
	QLock	lock;
	Rendez	vous;
	int	blocked;
};


@@ 176,9 180,11 @@ struct Rudpcb
/*
 * local functions 
 */
void	relsendack(Conv *, Reliable *);
void	relsendack(Conv *, Reliable *, int);
int	reliput(Conv *, Block *, uchar *, ushort);
Reliable *relstate(Rudpcb *, uchar *, ushort, char *from);
void	relput(Reliable *);
void	relforget(Conv *, uchar *, int, int);
void	relackproc(void *);
void	relackq(Reliable *, Block *);
void	relhangup(Conv *, Reliable *);


@@ 263,7 269,7 @@ rudpclose(Conv *c)
	qlock(ucb);
	for(r = ucb->r; r; r = r->next){
		if(r->acksent != r->rcvseq)
			relsendack(c, r);
			relsendack(c, r, 0);
	}
	qunlock(ucb);



@@ 280,7 286,7 @@ rudpclose(Conv *c)
	qlock(ucb);
	for(r = ucb->r; r; r = nr){
		if(r->acksent != r->rcvseq)
			relsendack(c, r);
			relsendack(c, r, 0);
		nr = r->next;
		relhangup(c, r);
		free(r);


@@ 429,7 435,6 @@ rudpkick(Conv *c, int)
	hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_RHDRSIZE));

	relackq(r, bp);
	qunlock(ucb);

	upriv->ustats.rudpOutDatagrams++;



@@ 439,13 444,13 @@ rudpkick(Conv *c, int)
	doipoput(c, f, bp, 0, c->ttl, c->tos);

	/* flow control of sorts */
	qlock(&r->lock);
	if(UNACKED(r) > Maxunacked){
		r->blocked = 1;
		sleep(&r->vous, flow, r);
		r->blocked = 0;
	}
	qunlock(&r->lock);
	relput(r);
	qunlock(ucb);
}

void


@@ 615,6 620,7 @@ char*
rudpctl(Conv *c, char **f, int n)
{
	Rudpcb *ucb;
	uchar ip[IPaddrlen];
	int x;

	ucb = (Rudpcb*)c->ptcl;


@@ 627,6 633,15 @@ rudpctl(Conv *c, char **f, int n)
	} else if(strcmp(f[0], "headers") == 0){
		ucb->headers = 6;
		return nil;
	} else if(strcmp(f[0], "hangup") == 0){
		if(n < 3)
			return "bad syntax";
		parseip(ip, f[1]);
		x = atoi(f[2]);
		qlock(ucb);
		relforget(c, ip, x, 1);
		qunlock(ucb);
		return nil;
	} else if(strcmp(f[0], "randdrop") == 0){
		x = 10;		/* default is 10% */
		if(n > 1)


@@ 764,7 779,7 @@ loop:
					relrexmit(c, r);
			}
			if(r->acksent != r->rcvseq)
				relsendack(c, r);
				relsendack(c, r, 0);
		}
		qunlock(ucb);
	}


@@ 798,6 813,8 @@ relstate(Rudpcb *ucb, uchar *addr, ushort port, char *from)
		memmove(r->addr, addr, IPaddrlen);
		r->port = port;
		r->unacked = 0;
		if(generation == Hangupgen)
			generation++;
		r->sndgen = generation++;
		r->sndseq = 0;
		r->ackrcvd = 0;


@@ 806,11 823,41 @@ relstate(Rudpcb *ucb, uchar *addr, ushort port, char *from)
		r->acksent = 0;
		r->xmits = 0;
		r->timeout = 0;
		r->ref = 0;
		incref(r);	/* one reference for being in the list */
	}

	incref(r);
	return r;
}

void
relput(Reliable *r)
{
	if(decref(r) == 0)
		free(r);
}

void
relforget(Conv *c, uchar *ip, int port, int originator)
{
	Rudpcb *ucb;
	Reliable *r, **l;

	ucb = (Rudpcb*)c->ptcl;

	l = &ucb->r;
	for(r = *l; r; r = *l){
		if(ipcmp(ip, r->addr) == 0 && port == r->port){
			*l = r->next;
			if(originator)
				relsendack(c, r, 1);
			relhangup(c, r);
			relput(r);	/* remove from the list */
			break;
		}
		l = &r->next;
	}
}

/* 
 *  process a rcvd reliable packet. return -1 if not to be passed to user process,


@@ 826,6 873,7 @@ reliput(Conv *c, Block *bp, uchar *addr, ushort port)
	Reliable *r;
	Rudphdr *rh;
	ulong seq, ack, sgen, agen, ackreal;
	int rv = -1;

	/* get fields */
	uh = (Udphdr*)(bp->rp);


@@ 837,20 885,27 @@ reliput(Conv *c, Block *bp, uchar *addr, ushort port)

	upriv = c->p->priv;
	ucb = (Rudpcb*)c->ptcl;
	qlock(ucb);
	r = relstate(ucb, addr, port, "input");
	

	DPRINT("rcvd %lud/%lud, %lud/%lud, r->sndgen = %lud\n", 
		seq, sgen, ack, agen, r->sndgen);

	/* if acking an incorrect generation, ignore */
	if(ack && agen != r->sndgen)
		return -1;
		goto out;

	/* Look for a hangup */
	if(sgen == Hangupgen) {
		if(agen == r->sndgen)
			relforget(c, addr, port, 0);
		goto out;
	}

	/* make sure we're not talking to a new remote side */
	if(r->rcvgen != sgen){
		if(seq != 0 && seq != 1)
			return -1;
			goto out;

		/* new connection */
		if(r->rcvgen != 0){


@@ 893,22 948,26 @@ reliput(Conv *c, Block *bp, uchar *addr, ushort port)

	/* no message or input queue full */
	if(seq == 0 || qfull(c->rq))
		return -1;
		goto out;

	/* refuse out of order delivery */
	if(seq != NEXTSEQ(r->rcvseq)){
		relsendack(c, r);	/* tell him we got it already */
		relsendack(c, r, 0);	/* tell him we got it already */
		upriv->orders++;
		DPRINT("out of sequence %lud not %lud\n", seq, NEXTSEQ(r->rcvseq));
		return -1;
		goto out;
	}
	r->rcvseq = seq;

	return 0;
	rv = 0;
out:
	relput(r);
	qunlock(ucb);
	return rv;
}

void
relsendack(Conv *c, Reliable *r)
relsendack(Conv *c, Reliable *r, int hangup)
{
	Udphdr *uh;
	Block *bp;


@@ 939,7 998,10 @@ relsendack(Conv *c, Reliable *r)
	v6tov4(uh->udpsrc, c->laddr);
	hnputs(uh->udplen, ptcllen);

	hnputl(rh->relsgen, r->sndgen);
	if(hangup)
		hnputl(rh->relsgen, Hangupgen);
	else
		hnputl(rh->relsgen, r->sndgen);
	hnputl(rh->relseq, 0);
	hnputl(rh->relagen, r->rcvgen);
	hnputl(rh->relack, r->rcvseq);


@@ 955,6 1017,7 @@ relsendack(Conv *c, Reliable *r)
	doipoput(c, f, bp, 0, c->ttl, c->tos);
}


/*
 *  called with ucb locked (and c locked if user initiated close)
 */


@@ 980,6 1043,8 @@ relhangup(Conv *c, Reliable *r)
	r->rcvgen = 0;
	r->rcvseq = 0;
	r->acksent = 0;
	if(generation == Hangupgen)
		generation++;
	r->sndgen = generation++;
	r->sndseq = 0;
	r->ackrcvd = 0;

M pc/ether82557.c => pc/ether82557.c +37 -2
@@ 929,6 929,33 @@ static char* mediatable[9] = {
};

static int
scanphy(Ctlr* ctlr)
{
	int i, oui, x;

	for(i = 0; i < 32; i++){
		if((oui = miir(ctlr, i, 2)) == -1 || oui == 0 || oui == 0xFFFF)
			continue;
		oui <<= 6;
		x = miir(ctlr, i, 3);
		oui |= x>>10;
		//print("phy%d: oui %uX reg1 %uX\n", i, oui, miir(ctlr, i, 1));

		ctlr->eeprom[6] = i;
		if(oui == 0xAA00)
			ctlr->eeprom[6] |= 0x07<<8;
		else if(oui == 0x80017){
			if(x & 0x01)
				ctlr->eeprom[6] |= 0x0A<<8;
			else
				ctlr->eeprom[6] |= 0x04<<8;
		}
		return i;
	}
	return -1;
}

static int
reset(Ether* ether)
{
	int anar, anlpar, bmcr, bmsr, i, k, medium, phyaddr, port, x;


@@ 1009,11 1036,19 @@ reset(Ether* ether)
	 * Eeprom[6] indicates whether there is a PHY and whether
	 * it's not 10Mb-only, in which case use the given PHY address
	 * to set any PHY specific options and determine the speed.
	 * Unfortunately, sometimes the EEPROM is blank except for
	 * the ether address and checksum; in this case look at the
	 * controller type and if 0 scan for the first PHY and try to
	 * use that.
	 * If no PHY, assume 82503 (serial) operation.
	 */
	if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){
	if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000))
		phyaddr = ctlr->eeprom[6] & 0x00FF;

	else if(!(ctlr->eeprom[5] & 0xFF00))
		phyaddr = scanphy(ctlr);
	else
		phyaddr = -1;
	if(phyaddr >= 0){
		/*
		 * Resolve the highest common ability of the two
		 * link partners. In descending order: