~kris/9p

9hist

87045a95d062cbe60db5153bfc18bed71910b838 — David du Colombier 34 years ago 169cd74
Plan 9 from Bell Labs 1992-09-06
8 files changed, 203 insertions(+), 171 deletions(-)

M pc/devether.c
M pc/devhard.c
M port/ipdat.h
M port/net.c
M port/tcpif.c
M port/tcpinput.c
M port/tcpoutput.c
M port/tcptimer.c
M pc/devether.c => pc/devether.c +59 -33
@@ 15,6 15,8 @@ typedef struct Ctlr Ctlr;
struct Hw {
	int	addr;			/* interface address */
	uchar	*ram;			/* interface shared memory address */
	int	bt16;			/* true if a 16 bit interface */
	int	lvl;			/* interrupt level */
	int	size;
	uchar	tstart;
	uchar	pstart;


@@ 639,7 641,14 @@ wd8013dumpregs(Hw *hw)
	print("id=#%2.2ux\n", IN(hw, id));
}

/* mapping from configuration bits to interrupt level */
int intrmap[] =
{
	9, 3, 5, 7, 10, 11, 15, 4,
};

/*
 *  get configuration parameters, enable memory
 */
static void
wd8013reset(Ctlr *cp)


@@ 647,6 656,9 @@ wd8013reset(Ctlr *cp)
	Hw *hw = cp->hw;
	int i;
	uchar msr;
	uchar icr;
	uchar laar;
	uchar irr;
	ulong ram;

	cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0);


@@ 655,19 667,47 @@ wd8013reset(Ctlr *cp)
	cp->ntb = Ntb;

	msr = IN(hw, msr);
	OUT(hw, msr, MENB|msr);
	icr = IN(hw, icr);
	irr = IN(hw, irr);
	laar = IN(hw, laar);

	/* ethernet address */
	for(i = 0; i < sizeof(cp->ea); i++)
		cp->ea[i] = IN(hw, lan[i]);

	/* get configuration info from card */
	ram = (IN(hw, msr) & 0x3f) << 13;
	ram |= KZERO|0x80000;
	/* 16 bit operation? */
	hw->bt16 = icr & 0x1;

	/* address of interface RAM */
	ram = KZERO | ((msr & 0x3f) << 13);
	if(hw->bt16)
		ram |= (laar & 0x3f)<<19;
	else
		ram |= 0x80000;
	hw->ram = (uchar*)ram;
print("ether ram is at %lux\n", ram);

	/* interrupt level */
	hw->lvl = intrmap[((irr>>5) & 0x3) | (icr & 0x4)];

	/* ram size */
	if(icr&(1<<3))
		hw->size = 32*1024;
	else
		hw->size = 8*1024;
	if(hw->bt16)
		hw->size <<= 1;
	hw->pstop = HOWMANY(hw->size, 256);

print("ether width %d addr %lux size %d lvl %d\n", hw->bt16?16:8,
	hw->ram, hw->size, hw->lvl);

	/* enable interface RAM, set interface width */
	OUT(hw, msr, MENB|msr);
	if(hw->bt16)
		OUT(hw, laar, laar|L16EN|M16EN);

	(*hw->init)(cp);
	setvec(Ethervec, hw->intr);
	setvec(Int0vec + hw->lvl, hw->intr);
}

static void


@@ 693,7 733,10 @@ wd8013init(Ctlr *cp)
	int i;

	OUT(hw, w.cr, 0x21);			/* Page0|RD2|STP */
	OUT(hw, w.dcr, 0x48);			/* FT1|LS */
	if(hw->bt16)
		OUT(hw, w.dcr, 0x49);		/* 16 bit interface, DMA burst size 8 */
	else
		OUT(hw, w.dcr, 0x48);		/* FT1|LS */
	OUT(hw, w.rbcr0, 0);
	OUT(hw, w.rbcr1, 0);
	OUT(hw, w.rcr, 0x04);			/* AB */


@@ 739,17 782,6 @@ wd8013online(Ctlr *cp, int on)
}

static void
bmemmove(void *a, void *b, int n)
{
	uchar *to, *from;

	to = a;
	from = b;
	while(n-- > 0)
		*to++ = *from++;
}

static void
wd8013receive(Ctlr *cp)
{
	Hw *hw = cp->hw;


@@ 769,16 801,11 @@ wd8013receive(Ctlr *cp)
		if(next == curr)
			break;
		cp->inpackets++;
print("*");
OUT(hw, laar, 0xC1);
print("!");
		p = &((Ring*)hw->ram)[next];
{ int ii; for(ii = 0; ii < 30; ii++) print("%2.2ux ", p->data[ii]); for(;;); }
		len = ((p->len1<<8)|p->len0)-4;
		if(p->next < hw->pstart || p->next >= hw->pstop || len < 60){
			print("%d/%d : #%2.2ux #%2.2ux  #%2.2ux #%2.2ux\n", next, len,
				p->status, p->next, p->len0, p->len1);
OUT(hw, laar, 0x01);
			dp8390rinit(cp);
			break;
		}


@@ 788,25 815,22 @@ OUT(hw, laar, 0x01);
			rb->len = len;
			if((p->data+len) >= (hw->ram+hw->size)){
				len = (hw->ram+hw->size) - p->data;
				bmemmove(rb->pkt+len,
				memmove(rb->pkt+len,
					&((Ring*)hw->ram)[hw->pstart],
					(p->data+rb->len) - (hw->ram+hw->size));
			}
			bmemmove(rb->pkt, p->data, len);
			memmove(rb->pkt, p->data, len);
			rb->owner = Host;
			cp->ri = NEXT(cp->ri, cp->nrb);
		}

		p->status = 0;
		next = p->next;
OUT(hw, laar, 0x01);
print("?");
		bnry = next-1;
		if(bnry < hw->pstart)
			bnry = hw->pstop-1;
		OUT(hw, w.bnry, bnry);
	}
print(">");
}

static void


@@ 817,10 841,10 @@ wd8013transmit(Ctlr *cp)
	int s;

	s = splhi();
	hw = cp->hw;
	tb = &cp->tb[cp->ti];
	if(tb->busy == 0 && tb->owner == Interface){
		hw = cp->hw;
		bmemmove(hw->ram, tb->pkt, tb->len);
		memmove(hw->ram, tb->pkt, tb->len);
		OUT(hw, w.tbcr0, tb->len & 0xFF);
		OUT(hw, w.tbcr1, (tb->len>>8) & 0xFF);
		OUT(hw, w.cr, 0x26);		/* Page0|RD2|TXP|STA */


@@ 876,11 900,13 @@ wd8013intr(Ureg *ur)

static Hw wd8013 = {
	0x360,					/* I/O base address */
	KZERO|0xF0000,				/* shared memory address */
	8*1024,
	0,
	0,
	0,
	0,
	0,
	HOWMANY(sizeof(Etherpkt), 256),
	HOWMANY(8*1024, 256),
	0,
	wd8013reset,
	wd8013init,
	wd8013mode,

M pc/devhard.c => pc/devhard.c +1 -1
@@ 831,7 831,7 @@ hardpart(Drive *dp)
	 *  parse partition table.
	 */
	n = getfields(buf, line, Npart+1, '\n');
	if(strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){
	if(n && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){
		for(i = 1; i < n; i++){
			pp++;
			if(getfields(line[i], field, 3, ' ') != 3)

M port/ipdat.h => port/ipdat.h +79 -79
@@ 38,7 38,6 @@ struct Etherhdr
/* Ethernet packet types */
#define ET_IP	0x0800

/* A userlevel data gram */
struct Udphdr
{
#define UDP_EHSIZE	22


@@ 185,7 184,12 @@ struct Tcphdr
	uchar	tcpmss[2];
};


enum
{
	TimerOFF	= 0,
	TimerON		= 1,
	TimerDONE	= 2,
};

struct Timer
{


@@ 200,50 204,50 @@ struct Timer

struct Tctl
{
	uchar	state;		/* Connection state */
	uchar	type;		/* Listening or active connection */
	uchar	code;		/* Icmp code */		
	uchar	state;			/* Connection state */
	uchar	type;			/* Listening or active connection */
	uchar	code;			/* Icmp code */		
	struct {
		int	una;	/* Unacked data pointer */
		int	nxt;	/* Next sequence expected */
		int	ptr;	/* Data pointer */
		ushort	wnd;	/* Tcp send window */
		int	up;	/* Urgent data pointer */
		int	una;		/* Unacked data pointer */
		int	nxt;		/* Next sequence expected */
		int	ptr;		/* Data pointer */
		ushort	wnd;		/* Tcp send window */
		int	up;		/* Urgent data pointer */
		int	wl1;
		int	wl2;
	} snd;
	struct {
		int	nxt;
		ushort	wnd;
		int	up;
		int	nxt;		/* Receive pointer to next byte slot */
		ushort	wnd;		/* Receive window incoming */
		int	up;		/* Urgent pointer */
	} rcv;
	int	iss;
	ushort	cwind;
	ushort	ssthresh;
	int	resent;
	int	irs;
	ushort	mss;
	int	rerecv;
	ushort	window;
	int	max_snd;
	int	last_ack;	/* Last acknowledege received */
	char	backoff;
	char	flags;		/* State flags */
	char	tos;		/* Type of service */

	Blist	rcvq;		/* Received data */
	ulong	rcvcnt;

	Block	*sndq;		/* List of data going out */
	ulong	sndcnt;		/* Amount of data in send queue */

	Reseq	*reseq;		/* Resequencing queue */
	Timer	timer;			 
	Timer	acktimer;	/* Acknoledge timer */
	Timer	rtt_timer;	/* Round trip timer */
	int	rttseq;		/* Round trip sequence */
	int	srtt;		/* Shortened round trip */
	int	mdev;		/* Mean deviation of round trip */
	int	iss;			/* Initial sequence number */
	ushort	cwind;			/* Congestion window */
	ushort	ssthresh;		/* Slow start threshold */
	int	resent;			/* Bytes just resent */
	int	irs;			/* Initial received squence */
	ushort	mss;			/* Mean segment size */
	int	rerecv;			/* Overlap of data rerecevived */
	ushort	window;			/* Recevive window */
	int	max_snd;		/* Max send */
	int	last_ack;		/* Last acknowledege received */
	char	backoff;		/* Exponential backoff counter */
	char	flags;			/* State flags */
	char	tos;			/* Type of service */

	Blist	rcvq;			/* Received data */
	ulong	rcvcnt;			/* Bytes queued for upstream */

	Block	*sndq;			/* List of data going out */
	ulong	sndcnt;			/* Amount of data in send queue */

	Reseq	*reseq;			/* Resequencing queue */
	Timer	timer;			/* Activity timer */
	Timer	acktimer;		/* Acknoledge timer */
	Timer	rtt_timer;		/* Round trip timer */
	int	rttseq;			/* Round trip sequence */
	int	srtt;			/* Shortened round trip */
	int	mdev;			/* Mean deviation of round trip */
};

struct Tcpctl


@@ 277,53 281,54 @@ struct Reseq
/* An ip interface used for UDP/TCP/IL */
struct Ipconv
{
	QLock;			/* Ref count lock */
	Netprot;		/* stat info */
	QLock;				/* Ref count lock */
	Netprot;			/* stat info */
	int 	ref;
	Ipaddr	dst;		/* Destination from connect */
	Port	psrc;		/* Source port */
	Port	pdst;		/* Destination port */

	Ipifc	*ifc;	/* Ip protocol interface */
	Queue	*readq;		/* Pointer to upstream read q */
	QLock	listenq;	/* List of people waiting incoming cons */
	Rendez	listenr;	/* Some where to sleep while waiting */
	Ipaddr	dst;			/* Destination from connect */
	Port	psrc;			/* Source port */
	Port	pdst;			/* Destination port */

	Ipifc	*ifc;			/* Ip protocol interface */
	Queue	*readq;			/* Pointer to upstream read q */
	QLock	listenq;		/* List of people waiting incoming cons */
	Rendez	listenr;		/* Some where to sleep while waiting */
		
	char	*err;		/* Async protocol error */
	int	backlog;	/* Maximum number of waiting connections */
	int	headers;	/* include header in packet */
	int	curlog;		/* Number of waiting connections */
	Ipconv 	*newcon;	/* This is the start of a connection */
	char	*err;			/* Async protocol error */
	int	backlog;		/* Maximum number of waiting connections */
	int	headers;		/* include header in packet */
	int	curlog;			/* Number of waiting connections */
	Ipconv 	*newcon;		/* This is the start of a connection */

	union {
		Tcpctl	tcpctl;	/* Tcp control block */
		Ilcb	ilctl;	/* Il control block */
		Tcpctl	tcpctl;		/* Tcp control block */
		Ilcb	ilctl;		/* Il control block */
	};
};

enum {
	MAX_TIME 	= (1<<20),/* Forever */
	TCP_ACK		= 200,	/* Timed ack sequence every 200ms */
enum
{
	MAX_TIME 	= (1<<20),	/* Forever */
	TCP_ACK		= 200,		/* Timed ack sequence every 200ms */

	URG		= 0x20,	/* Data marked urgent */
	ACK		= 0x10,	/* Aknowledge is valid */
	PSH		= 0x08,	/* Whole data pipe is pushed */
	RST		= 0x04,	/* Reset connection */
	SYN		= 0x02,	/* Pkt. is synchronise */
	FIN		= 0x01,	/* Start close down */
	URG		= 0x20,		/* Data marked urgent */
	ACK		= 0x10,		/* Aknowledge is valid */
	PSH		= 0x08,		/* Whole data pipe is pushed */
	RST		= 0x04,		/* Reset connection */
	SYN		= 0x02,		/* Pkt. is synchronise */
	FIN		= 0x01,		/* Start close down */

	EOL_KIND	= 0,
	NOOP_KIND	= 1,
	MSS_KIND	= 2,

	MSS_LENGTH	= 4,	/* Mean segment size */
	MSS_LENGTH	= 4,		/* Mean segment size */
	MSL2		= 10,
	MSPTICK		= 100,	/* Milliseconds per timer tick */
	DEF_MSS		= 1024,	/* Default mean segment */
	DEF_RTT		= 1000,	/* Default round trip */
	MSPTICK		= 100,		/* Milliseconds per timer tick */
	DEF_MSS		= 1024,		/* Default mean segment */
	DEF_RTT		= 1000,		/* Default round trip */

	TCP_PASSIVE	= 0,	/* Listen connection */
	TCP_ACTIVE	= 1,	/* Outgoing connection */
	TCP_PASSIVE	= 0,		/* Listen connection */
	TCP_ACTIVE	= 1,		/* Outgoing connection */
	IL_PASSIVE	= 0,
	IL_ACTIVE	= 1,



@@ 335,16 340,12 @@ enum {
	SYNACK		= 16,
	AGAIN		= 8,
	DGAIN		= 4,

	TIMER_STOP	= 0,
	TIMER_RUN	= 1,
	TIMER_EXPIRE	= 2,
};

#define	set_timer(t,x)	(((t)->start) = (x)/MSPTICK)
#define	run_timer(t)	((t)->state == TIMER_RUN)
#define	run_timer(t)	((t)->state == TimerON)

enum				/* Tcp connection states */
enum					/* Tcp connection states */
{
	Closed		= 0,
	Listen,


@@ 380,7 381,6 @@ struct Ipifc
	int		minmtu;			/* Minumum tranfer unit */
	int		hsize;			/* Media header size */	
	ulong		chkerrs;		/* checksum errors */
	Lock;
	Ipconv		**conv;			/* conversations */
};


M port/net.c => port/net.c +5 -5
@@ 7,11 7,11 @@

enum
{
	Qlisten=	1,
	Qclone=		2,
	Q2nd=		3,
	Q3rd=		4,
	Qinf=		5,
	Qlisten	= 1,
	Qclone	= 2,
	Q2nd	= 3,
	Q3rd	= 4,
	Qinf	= 5,
};

/*

M port/tcpif.c => port/tcpif.c +6 -3
@@ 15,11 15,12 @@ tcpxstate(Ipconv *s, char oldstate, char newstate)
{
	int len;
	Block *bp;
	Tcpctl *tcb = &s->tcpctl;
	Tcpctl *tcb;

	if(oldstate == newstate)
		return;

	tcb = &s->tcpctl;
	switch(newstate) {
	case Closed:
		s->psrc = 0;		/* This connection is toast */


@@ 68,14 69,16 @@ notsyner(void *ic)
void
tcpstart(Ipconv *s, int mode, ushort window, char tos)
{
	Tcpctl *tcb = &s->tcpctl;
	Tcpctl *tcb;

	tcb = &s->tcpctl;
	if(tcb->state != Closed)
		return;

	init_tcpctl(s);

	tcb->window = tcb->rcv.wnd = window;
	tcb->window = window;
	tcb->rcv.wnd = window;
	tcb->tos = tos;

	switch(mode){

M port/tcpinput.c => port/tcpinput.c +22 -19
@@ 7,7 7,10 @@
#include 	"arp.h"
#include 	"ipdat.h"

int tcpdbg = 0;
int	tcpdbg = 0;
ushort	tcp_mss = DEF_MSS;	/* Maximum segment size to be sent with SYN */
int	tcp_irtt = DEF_RTT;	/* Initial guess at round trip time */

#define DPRINT	if(tcpdbg) print
#define LPRINT  if(tcpdbg) print



@@ 118,9 121,9 @@ tcpincoming(Ipifc *ifc, Ipconv *s, Tcp *segp, Ipaddr source)
	tcpmove(&new->tcpctl, &s->tcpctl);
	new->tcpctl.flags &= ~CLONE;
	new->tcpctl.timer.arg = new;
	new->tcpctl.timer.state = TIMER_STOP;
	new->tcpctl.timer.state = TimerOFF;
	new->tcpctl.acktimer.arg = new;
	new->tcpctl.acktimer.state = TIMER_STOP;
	new->tcpctl.acktimer.state = TimerOFF;
	new->newcon = s;

	wakeup(&s->listenr);


@@ 130,15 133,15 @@ tcpincoming(Ipifc *ifc, Ipconv *s, Tcp *segp, Ipaddr source)
void
tcpinput(Ipifc *ifc, Block *bp)
{
	Ipconv *s, **p, **etab;
	Ipconv *spec, *gen;
	Tcpctl *tcb;		
	Tcphdr *h;
	Tcp seg;
	int hdrlen;	
	Ipaddr source, dest;
	char tos;
	Tcphdr *h;
	int hdrlen;	
	Tcpctl *tcb;		
	ushort length;
	Ipconv *spec, *gen;
	Ipaddr source, dest;
	Ipconv *s, **p, **etab;

	h = (Tcphdr *)(bp->rptr);
	dest = nhgetl(h->tcpdst);


@@ 202,7 205,8 @@ tcpinput(Ipifc *ifc, Block *bp)
	}

	/* The rest of the input state machine is run with the control block
	 * locked
	 * locked and implements the state machine directly out of the RFC
	 * Out-of-band data is ignored - it was always a bad idea.
	 */
	tcb = &s->tcpctl;
	qlock(tcb);


@@ 681,10 685,10 @@ trim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
	}
	else {
		/* Some part of the segment should be in the window */
		if(in_window(tcb,seg->seq)) {
		if(in_window(tcb,seg->seq))
			accept++;
		}
		else if(len != 0) {
		else
		if(len != 0) {
			if(in_window(tcb, (int)(seg->seq+len-1)) || 
			seq_within(tcb->rcv.nxt, seg->seq,(int)(seg->seq+len-1)))
				accept++;


@@ 794,9 798,6 @@ dupb(Block **hp, Block *bp, int offset, int count)
	return bytes;
}

ushort tcp_mss = DEF_MSS;	/* Maximum segment size to be sent with SYN */
int tcp_irtt = DEF_RTT;		/* Initial guess at round trip time */

static void
cleartcp(struct Tctl *a)
{


@@ 895,8 896,10 @@ seq_ge(int x, int y)
void
tcpsetstate(Ipconv *s, char newstate)
{
	Tcpctl *tcb;
	char oldstate;
	Tcpctl *tcb = &s->tcpctl;

	tcb = &s->tcpctl;

	oldstate = tcb->state;
	tcb->state = newstate;


@@ 906,11 909,11 @@ tcpsetstate(Ipconv *s, char newstate)
Block *
htontcp(Tcp *tcph, Block *data, Tcphdr *ph)
{
	ushort hdrlen;
	int dlen;
	ushort csum;
	Tcphdr *h;
	Block *bp;
	ushort csum;
	ushort hdrlen;

	hdrlen = TCP_HDRSIZE;
	if(tcph->mss)

M port/tcpoutput.c => port/tcpoutput.c +14 -15
@@ 16,12 16,12 @@ extern	ushort tcp_mss;
void
tcpoutput(Ipconv *s)
{
	Block *hbp,*dbp, *sndq;
	ushort ssize, dsize, usable, sent;
	Tcp seg;
	int qlen;
	Tcphdr ph;
	Tcp seg;
	Tcpctl *tcb;
	Block *hbp,*dbp, *sndq;
	ushort ssize, dsize, usable, sent;

	tcb = &s->tcpctl;



@@ 157,11 157,12 @@ tcprxmit(Ipconv *s)
	tcb->flags |= RETRAN|FORCE;
	tcb->snd.ptr = tcb->snd.una;

	/* Reduce slowstart threshold to half current window */
	/* Pull window down to a single packet and halve the slow
	 * start threshold
	 */
	tcb->ssthresh = tcb->cwind / 2;
	tcb->ssthresh = MAX(tcb->ssthresh,tcb->mss);
	tcb->ssthresh = MAX(tcb->ssthresh, tcb->mss);

	/* Shrink congestion window to 1 packet */
	tcb->cwind = tcb->mss;
	tcpoutput(s);
	qunlock(tcb);


@@ 197,12 198,11 @@ backoff(int n)
{
	if(tcptimertype == 1) 
		return n+1;
	else {
		if(n <= 4)
			return 1 << n;
		else
			return n * n;
	}

	if(n <= 4)
		return 1 << n;

	return n*n;
}

void


@@ 220,13 220,12 @@ tcpacktimer(Ipconv *s)
void
tcprcvwin(Ipconv *s)				/* Call with tcb locked */
{
	Tcpctl *tcb = &s->tcpctl;
	int w;
	Tcpctl *tcb;

	/* Calculate new window */
	tcb = &s->tcpctl;
	qlock(s);
	if(s->readq) {
		/* use w because rcv.wnd is unsigned */
		w = Streamhi - s->readq->next->len;
		if(w < 0)
			tcb->rcv.wnd = 0;

M port/tcptimer.c => port/tcptimer.c +17 -16
@@ 57,33 57,34 @@ tcpflow(void *x)
void
tcpackproc(void *junk)
{
	Timer *t,*tp;
	Timer *expired;
	Timer *t, *tp, *timeo;

	USED(junk);
	for(;;) {
		expired = 0;
		timeo = 0;

		qlock(&tl);
		for(t = timers;t != 0; t = tp) {
			tp = t->next;
 			if(t->state == TIMER_RUN)
			if(--(t->count) == 0){
				deltimer(t);
				t->state = TIMER_EXPIRE;
				t->next = expired;
				expired = t;
 			if(t->state == TimerON) {
				t->count--;
				if(t->count == 0) {
					deltimer(t);
					t->state = TimerDONE;
					t->next = timeo;
					timeo = t;
				}
			}
		}
		qunlock(&tl);

		for(;;) {
			t = expired;
			t = timeo;
			if(t == 0)
				break;

			expired = t->next;
			if(t->state == TIMER_EXPIRE)
			timeo = t->next;
			if(t->state == TimerDONE)
			if(t->func)
				(*t->func)(t->arg);
		}


@@ 99,8 100,8 @@ tcpgo(Timer *t)

	qlock(&tl);
	t->count = t->start;
	if(t->state != TIMER_RUN) {
		t->state = TIMER_RUN;
	if(t->state != TimerON) {
		t->state = TimerON;
		t->prev = 0;
		t->next = timers;
		if(t->next)


@@ 117,8 118,8 @@ tcphalt(Timer *t)
		return;

	qlock(&tl);
	if(t->state == TIMER_RUN)
	if(t->state == TimerON)
		deltimer(t);
	t->state = TIMER_STOP;
	t->state = TimerOFF;
	qunlock(&tl);
}