~kris/9p

9hist

0cce6ce90069d8914d160dfb6511736eb61f2dfc — David du Colombier 34 years ago ace215e
Plan 9 from Bell Labs 1992-09-03
10 files changed, 400 insertions(+), 340 deletions(-)

M pc/dat.h
M pc/devhard.c
M pc/main.c
M port/devbit.c
M port/devip.c
M port/ipdat.h
M port/tcpif.c
M port/tcpinput.c
M port/tcpoutput.c
M port/tcptimer.c
M pc/dat.h => pc/dat.h +22 -6
@@ 182,14 182,30 @@ extern User	*u;

extern int	flipD[];	/* for flipping bitblt destination polarity */

/*
 *  bootline passed by boot program
 */
#define BOOTLINE ((char *)0x80000100)

/*
 *  configuration info
 */
enum
{
	PMUnsx20=	0,
	PMUother=	1,

	Mouseserial=	0,
	MousePS2=	1,
	Mouseother=	2,
	/* what kind of power management */
	PMUother=	0,
	PMUnsx20=	1,

	/* what kind of mouse */
	Mouseother=	0,
	Mouseserial=	1,
	MousePS2=	2,

	/* how to reset the processor */
	Resetother=	0,
	Reset8042=	1,
	Resetheadland=	2,
};
extern int mousetype;
extern int pmutype;
extern int resettype;

M pc/devhard.c => pc/devhard.c +149 -126
@@ 6,7 6,7 @@
#include	"io.h"
#include	"../port/error.h"

#define DPRINT if(0)print
#define DPRINT if(1)print

typedef	struct Drive		Drive;
typedef	struct Ident		Ident;


@@ 53,44 53,6 @@ enum
#define DRIVE(x)	(((x)>>4)&0x7)
#define MKQID(d,p)	(((d)<<4) | (p))

/*
 *  ident sector from drive
 */
struct Ident
{
	ushort	magic;		/* drive type magic */
	ushort	lcyls;		/* logical number of cylinders */
	ushort	rcyl;		/* number of removable cylinders */
	ushort	lheads;		/* logical number of heads */
	ushort	b2t;		/* unformatted bytes/track */
	ushort	b2s;		/* unformated bytes/sector */
	ushort	ls2t;		/* logical sectors/track */
	ushort	gap;		/* bytes in inter-sector gaps */
	ushort	sync;		/* bytes in sync fields */
	ushort	magic2;		/* must be 0x0000 */
	ushort	serial[10];	/* serial number */
	ushort	type;		/* controller type (0x0003) */
	ushort	bsize;		/* buffer size/512 */
	ushort	ecc;		/* ecc bytes returned by read long */
	ushort	firm[4];	/* firmware revision */
	ushort	model[20];	/* model number */
	ushort	s2i;		/* number of sectors/interrupt */
	ushort	dwtf;		/* double word transfer flag */
	ushort	alernate;
	ushort	piomode;
	ushort	dmamode;
	ushort	reserved[76];
	ushort	ncyls;		/* native number of cylinders */
	ushort	nheads;		/* native number of heads, sectors */
	ushort	dlcyls;		/* default logical number of cyinders */
	ushort	dlheads;	/* default logical number of heads, sectors */
	ushort	interface;
	ushort	power;		/* 0xFFFF if power commands supported */
	ushort	flags;
	ushort	ageprog;	/* MSB = age, LSB = program */
	ushort	reserved2[120];
};

struct Partition
{
	ulong	start;


@@ 126,8 88,6 @@ struct Drive
	int	sectors;	/* sectors/track */
	int	heads;		/* heads/cyl */
	long	cyl;		/* cylinders/drive */

	Ident	id;		/* disk properties */
};

/*


@@ 161,8 121,9 @@ static void	hardintr(Ureg*);
static long	hardxfer(Drive*, Partition*, int, long, long, char*);
static void	hardident(Drive*);
static void	hardsetbuf(Drive*, int);
static void	hardinitparam(Drive*);
static void	hardparams(Drive*);
static void	hardpart(Drive*);
static int	hardprobe(Drive*, int, int, int);

static int
hardgen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp)


@@ 237,66 198,24 @@ Chan*
hardattach(char *spec)
{
	Drive *dp;
	static int drivecomment=1;

	for(dp = hard; dp < &hard[conf.nhard]; dp++){
		if(!waserror()){
			/*
			 *  the following is magic to determine the parameters
			 *  (number of cylinders/sectors/heads) on an IDE drive.
			 *  I haven't found a method that is guaranteed to work.
			 *  For some drives, it may be necessary to compile the
			 *  numbers into this driver and circumvent this code.
			 *  The BIOS disk type & tables doesn't help since the
			 *  types are inconsistent from one BIOS to the next.
			 */
			dp->bytes = 512;	/* until we know better */
			hardsetbuf(dp, 0);	/* turned off during ident */
			hardident(dp);
			hardsetbuf(dp, 1);
			/*
			 *  for now use the configuration word to identify the
			 *  wayward 6386 disk.  BUG!!!  This word isn't
			 *  meant to identify disks, but we have nothing
			 *  better.
			 */
			switch(dp->id.magic){
			case 0x324A:	/* hard drive on the AT&T 6386, it lies */
				dp->cyl = dp->id.lcyls - 4;
				dp->heads = dp->id.lheads;
				dp->sectors = dp->id.ls2t - 1;
				break;
			default:	/* others: we hope this works */
				dp->cyl = dp->id.lcyls;
				dp->heads = dp->id.lheads;
				dp->sectors = dp->id.ls2t;
				break;
			}
			dp->bytes = 512;
			dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
			dp->online = 1;
			/*
			 *  Try reading the partition table (last disk sector).
			 *  If an error occurs set the drive parameters and try
			 *  again.  This works if the parameters reported
			 *  by the disk are the physical parameters rather than
			 *  the current logical ones (as they are on the NCR 3170).
			 *
			 *  We don't routinely set the parameters since it confuses
			 *  some disks (on the Gateway and AT&T Safari for example).
			 */
			if(waserror()){
				hardinitparam(dp);	/* set drive parameters */
				hardpart();
			} else {
				hardpart();
				poperror();
			}
			poperror();
		} else
		if(waserror()){
			dp->online = 0;
			continue;
		}
		if(!dp->online){
			hardparams(dp);
			dp->online = 1;
			hardsetbuf(dp, 1);
		}

		/*
		 *  read Plan 9 partition table
		 */
		hardpart(dp);
		poperror();
	}
	drivecomment=0;	/* only the first time */
	return devattach('w', spec);
}



@@ 629,35 548,42 @@ hardsetbuf(Drive *dp, int on)
}

/*
 *  set the drive parameters
 *  ident sector from drive
 */
static void
hardinitparam(Drive *dp)
struct Ident
{
	Controller *cp = dp->cp;

	qlock(cp);
	if(waserror()){
		qunlock(cp);
		nexterror();
	}

	cmdreadywait(cp);

	cp->cmd = Cinitparam;
	outb(cp->pbase+Psector, dp->sectors);
	outb(cp->pbase+Pdh, 0x20 | (dp->heads-1) | (dp->drive<<4));
	outb(cp->pbase+Pcmd, Cinitparam);

	sleep(&cp->r, cmddone, cp);

	if(cp->status & Serr)
		DPRINT("hd%d initparam err: status %lux, err %lux\n",
			dp-hard, cp->status, cp->error);

	poperror();
	qunlock(cp);
}
	ushort	magic;		/* drive type magic */
	ushort	lcyls;		/* logical number of cylinders */
	ushort	rcyl;		/* number of removable cylinders */
	ushort	lheads;		/* logical number of heads */
	ushort	b2t;		/* unformatted bytes/track */
	ushort	b2s;		/* unformated bytes/sector */
	ushort	ls2t;		/* logical sectors/track */
	ushort	gap;		/* bytes in inter-sector gaps */
	ushort	sync;		/* bytes in sync fields */
	ushort	magic2;		/* must be 0x0000 */
	ushort	serial[10];	/* serial number */
	ushort	type;		/* controller type (0x0003) */
	ushort	bsize;		/* buffer size/512 */
	ushort	ecc;		/* ecc bytes returned by read long */
	ushort	firm[4];	/* firmware revision */
	ushort	model[20];	/* model number */
	ushort	s2i;		/* number of sectors/interrupt */
	ushort	dwtf;		/* double word transfer flag */
	ushort	alernate;
	ushort	piomode;
	ushort	dmamode;
	ushort	reserved[76];
	ushort	ncyls;		/* native number of cylinders */
	ushort	nheads;		/* native number of heads, sectors */
	ushort	dlcyls;		/* default logical number of cyinders */
	ushort	dlheads;	/* default logical number of heads, sectors */
	ushort	interface;
	ushort	power;		/* 0xFFFF if power commands supported */
	ushort	flags;
	ushort	ageprog;	/* MSB = age, LSB = program */
	ushort	reserved2[120];
};

/*
 *  get parameters from the drive


@@ 667,6 593,7 @@ hardident(Drive *dp)
{
	Controller *cp;
	char *buf;
	Ident *ip;

	cp = dp->cp;
	buf = smalloc(Maxxfer);


@@ 690,7 617,8 @@ hardident(Drive *dp)
		DPRINT("bad disk ident status\n");
		error(Eio);
	}
	memmove(&dp->id, buf, dp->bytes);
	ip = (Ident*)buf;

	/*
	 * this function appears to respond with an extra interrupt after
	 * the ident information is read, except on the safari.  The following


@@ 700,6 628,11 @@ hardident(Drive *dp)
	 */
	if (cp->cmd == Cident2)
		tsleep(&cp->r, return0, 0, 10);

	dp->cyl = ip->lcyls;
	dp->heads = ip->lheads;
	dp->sectors = ip->ls2t;
	dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
	cp->cmd = 0;
	cp->buf = 0;
	free(buf);


@@ 707,6 640,96 @@ hardident(Drive *dp)
	qunlock(cp);
}

/*
 *  probe the given sector to see if it exists
 */
static int
hardprobe(Drive *dp, int cyl, int sec, int head)
{
	Controller *cp;
	char *buf;
	int rv;

	cp = dp->cp;
	buf = smalloc(Maxxfer);
	qlock(cp);
	if(waserror()){
		qunlock(cp);
		nexterror();
	}

	cmdreadywait(cp);

	cp->cmd = Cread;
	cp->dp = dp;
	cp->status = 0;
	cp->nsecs = 1;

	outb(cp->pbase+Pcount, 1);
	outb(cp->pbase+Psector, sec+1);
	outb(cp->pbase+Pdh, 0x20 | head);
	outb(cp->pbase+Pcyllsb, cyl);
	outb(cp->pbase+Pcylmsb, cyl>>8);
	outb(cp->pbase+Pcmd, Cread);

	sleep(&cp->r, cmddone, cp);

	if(cp->status & Serr)
		rv = -1;
	else
		rv = 0;

	cp->buf = 0;
	free(buf);
	poperror();
	qunlock(cp);
	return rv;
}

/*
 *  figure out the drive parameters
 */
static void
hardparams(Drive *dp)
{
	int i, hi, lo;

	/*
	 *  first try the easy way, ask the drive and make sure it
	 *  isn't lying.
	 */
	dp->bytes = 512;
	hardident(dp);
	if(hardprobe(dp, dp->cyl-1, dp->sectors-1, dp->heads-1) == 0)
		return;

	/*
	 *  the drive lied, determine parameters by seeing which ones
	 *  work to read sectors.
	 */
	for(i = 0; i < 32; i++)
		if(hardprobe(dp, 0, 0, i) < 0)
			break;
	dp->heads = i;
	for(i = 0; i < 128; i++)
		if(hardprobe(dp, 0, i, 0) < 0)
			break;
	dp->sectors = i;
	for(i = 512; ; i += 512)
		if(hardprobe(dp, i, dp->sectors-1, dp->heads-1) < 0)
			break;
	lo = i - 512;
	hi = i;
	for(; hi-lo > 1;){
		i = lo + (hi - lo)/2;
		if(hardprobe(dp, i, dp->sectors-1, dp->heads-1) < 0)
			hi = i;
		else
			lo = i;
	}
	dp->cyl = lo + 1;
	dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors;
}

/*
 *  Read block replacement table.

M pc/main.c => pc/main.c +29 -9
@@ 7,9 7,12 @@
#include	"ureg.h"
#include	"init.h"

/* configuration parameters */
int mousetype;
int pmutype;
uchar	*sp;	/* stack pointer for /boot */
int resettype;

uchar *sp;	/* stack pointer for /boot */

void
main(void)


@@ 41,24 44,24 @@ main(void)
}

/*
 *  this should be changed to describe architecture dependencies outside the
 *  PC model
 *  This tries to capture architecture dependencies since things
 *  like power management/reseting/mouse are outside the hardware
 *  model.
 */
void
ident(void)
{
	char *id = (char*)(ROMBIOS + 0xFF40);

	/* check for a safari (tres special) */
	if(strncmp(id, "AT&TNSX", 7) == 0){
		mousetype = MousePS2;
		pmutype = PMUnsx20;
		resettype = Resetheadland;
	}else if(strncmp(id, "NCRD.0", 6) == 0){
		mousetype = MousePS2;
		pmutype = PMUother;
		resettype = Reset8042;
	}else{
		mousetype = Mouseserial;
		pmutype = PMUother;
	}
}



@@ 184,12 187,22 @@ bootargs(ulong base)
 	int i, ac;
	uchar *av[32];
	uchar **lsp;
	char *cp = BOOTLINE;
	char buf[64];

	sp = (uchar*)base + BY2PG - MAXSYSARG*BY2WD;

	ac = 0;
	av[ac++] = pusharg("/386/9safari");
	av[ac++] = pusharg("-p");
	cp[64] = 0;
	if(strncmp(cp, "fd!", 3) == 0){
		sprint(buf, "local!#f/fd%ddisk", atoi(cp+3));
		av[ac++] = pusharg(buf);
	} else if(strncmp(cp, "hd!", 3) == 0){
		sprint(buf, "local!#w/hd%ddisk", atoi(cp+3));
		av[ac++] = pusharg(buf);
	}

	/* 4 byte word align stack */
	sp = (uchar*)((ulong)sp & ~3);


@@ 413,9 426,16 @@ exit(int ispanic)
	print("exiting\n");
	if(ispanic)
		for(;;);
	i8042reset();		/* via keyboard controller */
	print("can't reset via software, do something drastic!\n");
	for(;;);

	switch(resettype){
	case Resetheadland:
		headreset();
	case Reset8042:
		i8042reset();		/* via keyboard controller */
	default:
		print("Reset the machine!\n");
		for(;;);
	}
}

/*

M port/devbit.c => port/devbit.c +19 -5
@@ 1661,11 1661,18 @@ bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc)
	Rectangle rect;
	ushort r;
	GCacheinfo *c;
	int x;
	Fcode clr;

	full = (fc==S || fc==notS);	/* for reverse-video */
	clr = 0;
	full = (fc&~S)^(D&~S);	/* result involves source */
	if(full){
		rect.min.y = 0;
		rect.max.y = f->height;
		/* set clr to result under fc if source pixel is zero */
		/* hard to do without knowing layout of bits, so we cheat */
		clr = (fc&3);	/* fc&3 is result if source is zero */
		clr |= clr<<2;	/* fc&(3<<2) is result if source is one */
	}

	while(l > 0){


@@ 1678,10 1685,17 @@ bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc)
		if(!full){
			rect.min.y = c->top;
			rect.max.y = c->bottom;
		}else if(c->left > 0)
			gbitblt(bp, pt, f->b,
				Rect(pt.x, pt.y, pt.x+c->left, pt.y+f->height),
				fc==S? 0 : F);
		}else{
			if(c->left > 0)
				gbitblt(bp, pt, bp,
					Rect(pt.x, pt.y, pt.x+c->left, pt.y+f->height),
					clr);
			x = c->left+(c->xright-c->x);
			if(x < c->width)
				gbitblt(bp, Pt(pt.x+x, pt.y), bp,
					Rect(pt.x+x, pt.y, pt.x+c->width, pt.y+f->height),
					clr);
		}
		rect.min.x = c->x;
		rect.max.x = c->xright;
		gbitblt(bp, Pt(pt.x+c->left, pt.y+rect.min.y), f->b, rect, fc);

M port/devip.c => port/devip.c +21 -16
@@ 23,9 23,10 @@ Ipifc	*ipifc[Nrprotocol+1];
QLock	ipalloc;			/* Protocol port allocation lock */
Ipconv	**tcpbase;

Streamput   udpstiput, udpstoput, tcpstiput, tcpstoput, iliput, iloput, bsdiput, bsdoput;
Streamopen  udpstopen, tcpstopen, ilopen, bsdopen;
Streamclose udpstclose, tcpstclose, ilclose, bsdclose;
Streamput	udpstiput, udpstoput, tcpstiput, tcpstoput;
Streamput	iliput, iloput, bsdiput, bsdoput;
Streamopen	udpstopen, tcpstopen, ilopen, bsdopen;
Streamclose	udpstclose, tcpstclose, ilclose, bsdclose;

Qinfo tcpinfo = { tcpstiput, tcpstoput, tcpstopen, tcpstclose, "tcp", 0, 1 };
Qinfo udpinfo = { udpstiput, udpstoput, udpstopen, udpstclose, "udp" };


@@ 76,8 77,8 @@ ipinit(void)
Chan *
ipattach(char *spec)
{
	Chan *c;
	int i;
	Chan *c;

	/* fail if ip is not yet configured */
	if(Ipoutput == 0)


@@ 169,8 170,8 @@ ipcreateconv(Ipifc *ifc, int id)
Ipconv*
ipincoming(Ipifc *ifc, Ipconv *from)
{
	Ipconv **p, **etab;
	Ipconv *new;
	Ipconv **p, **etab;

	/* look for an unused existing conversation */
	etab = &ifc->conv[Nipconv];


@@ 554,10 555,11 @@ udpstoput(Queue *q, Block *bp)
	hnputs(uh->udpplen, ptcllen);
	hnputl(uh->udpsrc, Myip[Myself]);
	hnputs(uh->udpsport, cp->psrc);
	if(cp->headers){
	if(cp->headers) {
		hnputl(uh->udpdst, addr);
		hnputs(uh->udpdport, port);
	} else {
	}
	else {
		hnputl(uh->udpdst, cp->dst);
		hnputs(uh->udpdport, cp->pdst);
	}


@@ 627,14 629,17 @@ tcpstoput(Queue *q, Block *bp)
	switch(tcb->state) {
	case Listen:
		tcb->flags |= ACTIVE;
		send_syn(tcb);
		setstate(s, Syn_sent);
		tcpsndsyn(tcb);
		tcpsetstate(s, Syn_sent);

		/* No break */
	case Syn_sent:
	case Syn_received:
	case Established:
	case Close_wait:
		/*
		 * Push data
		 */
		qlock(tcb);
		if(waserror()) {
			qunlock(tcb);


@@ 649,7 654,7 @@ tcpstoput(Queue *q, Block *bp)
			f->next = bp;
		}
		tcprcvwin(s);
		tcp_output(s);
		tcpoutput(s);
		poperror();
		qunlock(tcb);
		break;


@@ 686,7 691,7 @@ tcpstopen(Queue *q, Stream *s)
	if(tcpbase == 0)
		tcpbase = ipifc[s->dev]->conv;
	ifc = ipifc[s->dev];
	initipifc(ifc, IP_TCPPROTO, tcp_input, 1500, 512, ETHER_HDR);
	initipifc(ifc, IP_TCPPROTO, tcpinput, 1500, 512, ETHER_HDR);
	ipc = ipcreateconv(ifc, s->id);

	ipc->readq = RD(q);


@@ 730,8 735,8 @@ iplocalfill(Chan *c, char *buf, int len)
void
ipstatusfill(Chan *c, char *buf, int len)
{
	int connection;
	Ipconv *cp;
	int connection;

	if(len < 64)
		error(Ebadarg);


@@ 759,9 764,9 @@ iphavecon(Ipconv *s)
int
iplisten(Chan *c)
{
	Ipconv **p, **etab, *new;
	Ipconv *s;
	int connection;
	Ipconv **p, **etab, *new;

	connection = STREAMID(c->qid.path);
	s = ipcreateconv(ipifc[c->dev], connection);


@@ 850,20 855,20 @@ tcpstclose(Queue *q)
	case Established:
		tcb->sndcnt++;
		tcb->snd.nxt++;
		setstate(s, Finwait1);
		tcpsetstate(s, Finwait1);
		goto output;

	case Close_wait:
		tcb->sndcnt++;
		tcb->snd.nxt++;
		setstate(s, Last_ack);
		tcpsetstate(s, Last_ack);
	output:
		qlock(tcb);
		if(waserror()) {
			qunlock(tcb);
			nexterror();
		}
		tcp_output(s);
		tcpoutput(s);
		poperror();
		qunlock(tcb);
		break;

M port/ipdat.h => port/ipdat.h +9 -9
@@ 472,7 472,7 @@ void	proc_syn(Ipconv*, char, Tcp*);
ushort	ptcl_csum(Block*bp, int, int);
int	pullb(Block **, int);
void	reset(Ipaddr, Ipaddr, char, ushort, Tcp*);
void	send_syn(Tcpctl*);
void	tcpsndsyn(Tcpctl*);
int	seq_ge(int, int);
int	seq_gt(int, int);
int	seq_gt(int, int);


@@ 480,14 480,14 @@ int	seq_le(int, int);
int	seq_lt(int, int);
int	seq_within(int, int, int);
int	seq_within(int, int, int);
void	setstate(Ipconv *, char);
void	start_timer(Timer *);
void	state_upcall(Ipconv*, char oldstate, char newstate);
void	stop_timer(Timer *);
void	tcp_acktimer(void *);
void	tcp_input(Ipifc*, Block *);
void	tcp_output(Ipconv*);
void	tcp_timeout(void *);
void	tcpsetstate(Ipconv *, char);
void	tcpgo(Timer *);
void	tcphalt(Timer *);
void	tcpxstate(Ipconv*, char oldstate, char newstate);
void	tcpacktimer(void *);
void	tcpinput(Ipifc*, Block *);
void	tcpoutput(Ipconv*);
void	tcptimeout(void *);
void	tcpackproc(void*);
void	tcpflow(void*);
void	tcpflushincoming(Ipconv*);

M port/tcpif.c => port/tcpif.c +9 -12
@@ 11,24 11,21 @@ extern int tcpdbg;
#define DPRINT	if(tcpdbg) print

void
state_upcall(Ipconv *s, char oldstate, char newstate)
tcpxstate(Ipconv *s, char oldstate, char newstate)
{
	Block *bp;
	int len;
	Block *bp;
	Tcpctl *tcb = &s->tcpctl;

	DPRINT("state_upcall: %s -> %s err %s\n", 
	      tcpstate[oldstate], tcpstate[newstate], s->err);

	if(oldstate == newstate)
		return;

	switch(newstate) {
	case Closed:
		s->psrc = 0;
		s->psrc = 0;		/* This connection is toast */
		s->pdst = 0;
		s->dst = 0;
		/* NO break */

	case Close_wait:		/* Remote closes */
		if(s->err) {
			len = strlen(s->err);


@@ 46,7 43,7 @@ state_upcall(Ipconv *s, char oldstate, char newstate)
			qunlock(s);
			nexterror();
		}
		if(s->readq == 0){
		if(s->readq == 0) {
			if(newstate == Close_wait)
				putb(&tcb->rcvq, bp);
			else


@@ 84,7 81,7 @@ tcpstart(Ipconv *s, int mode, ushort window, char tos)
	switch(mode){
	case TCP_PASSIVE:
		tcb->flags |= CLONE;
		setstate(s, Listen);
		tcpsetstate(s, Listen);
		break;

	case TCP_ACTIVE:


@@ 95,9 92,9 @@ tcpstart(Ipconv *s, int mode, ushort window, char tos)
			qunlock(tcb);
			nexterror();
		}
		send_syn(tcb);
		setstate(s, Syn_sent);
		tcp_output(s);
		tcpsndsyn(tcb);
		tcpsetstate(s, Syn_sent);
		tcpoutput(s);
		poperror();
		qunlock(tcb);
		sleep(&tcb->syner, notsyner, tcb);

M port/tcpinput.c => port/tcpinput.c +61 -66
@@ 19,15 19,13 @@ char *tcpstate[] =
};

void
sndrst(Ipaddr source, Ipaddr dest, char tos, ushort length, Tcp *seg)
sndrst(Ipaddr source, Ipaddr dest, ushort length, Tcp *seg)
{
	Block *hbp;
	Port tmp;
	char rflags;
	Tcphdr ph;

	USED(tos);		/* is this right??? */

	if(seg->flags & RST)
		return;



@@ 85,7 83,7 @@ tcpflushincoming(Ipconv *s)
	seg.seq = tcb->snd.ptr;
	seg.ack = tcb->last_ack = tcb->rcv.nxt;

	sndrst(s->dst, Myip[Myself], 0, 0, &seg);
	sndrst(s->dst, Myip[Myself], 0, &seg);
	localclose(s, 0);
}



@@ 130,7 128,7 @@ tcpincoming(Ipifc *ifc, Ipconv *s, Tcp *segp, Ipaddr source)
}

void
tcp_input(Ipifc *ifc, Block *bp)
tcpinput(Ipifc *ifc, Block *bp)
{
	Ipconv *s, **p, **etab;
	Ipconv *spec, *gen;


@@ 198,7 196,7 @@ tcp_input(Ipifc *ifc, Block *bp)
		}
		if(s == 0){
			freeb(bp);   
			sndrst(source, dest, tos, length, &seg);
			sndrst(source, dest, length, &seg);
			return;
		}
	}


@@ 212,7 210,7 @@ tcp_input(Ipifc *ifc, Block *bp)
	switch(tcb->state) {
	case Closed:
		freeb(bp);
		sndrst(source, dest, tos, length, &seg);
		sndrst(source, dest, length, &seg);
		goto done;
	case Listen:
		if(seg.flags & RST) {


@@ 221,13 219,13 @@ tcp_input(Ipifc *ifc, Block *bp)
		} 
		if(seg.flags & ACK) {
			freeb(bp);
			sndrst(source, dest, tos, length, &seg);
			sndrst(source, dest, length, &seg);
			goto done;
		}
		if(seg.flags & SYN) {
			proc_syn(s, tos, &seg);
			send_syn(tcb);
			setstate(s, Syn_received);		
			tcpsndsyn(tcb);
			tcpsetstate(s, Syn_received);		
			if(length != 0 || (seg.flags & FIN)) 
				break;
			freeb(bp);


@@ 239,7 237,7 @@ tcp_input(Ipifc *ifc, Block *bp)
		if(seg.flags & ACK) {
			if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) {
				freeb(bp);
				sndrst(source, dest, tos, length, &seg);
				sndrst(source, dest, length, &seg);
				goto done;
			}
		}


@@ 253,7 251,7 @@ tcp_input(Ipifc *ifc, Block *bp)
		if(seg.flags & ACK)
		if(PREC(tos) != PREC(tcb->tos)){
			freeb(bp);
			sndrst(source, dest, tos, length, &seg);
			sndrst(source, dest, length, &seg);
			goto done;
		}



@@ 261,10 259,10 @@ tcp_input(Ipifc *ifc, Block *bp)
			proc_syn(s, tos, &seg);
			if(seg.flags & ACK){
				update(s, &seg);
				setstate(s, Established);
				tcpsetstate(s, Established);
			}
			else 
				setstate(s, Syn_received);
				tcpsetstate(s, Syn_received);

			if(length != 0 || (seg.flags & FIN))
				break;


@@ 291,7 289,7 @@ tcp_input(Ipifc *ifc, Block *bp)
	if(s->readq == 0)
	if(tcb->state == Closed) {
		freeb(bp);
		sndrst(source, dest, tos, length, &seg);
		sndrst(source, dest, length, &seg);
		goto done;
	}



@@ 309,7 307,7 @@ tcp_input(Ipifc *ifc, Block *bp)
		if(seg.flags & RST) {
			if(tcb->state == Syn_received
			   && !(tcb->flags & (CLONE|ACTIVE))) 
				setstate(s, Listen);
				tcpsetstate(s, Listen);
			else
				localclose(s, Econrefused);



@@ 317,9 315,10 @@ tcp_input(Ipifc *ifc, Block *bp)
			goto done;
		}

		/* This tos stuff should be removed */
		if(PREC(tos) != PREC(tcb->tos) || (seg.flags & SYN)){
			freeb(bp);
			sndrst(source, dest, tos, length, &seg);
			sndrst(source, dest, length, &seg);
			goto done;
		}



@@ 330,16 329,13 @@ tcp_input(Ipifc *ifc, Block *bp)

		switch(tcb->state) {
		case Syn_received:
			if(seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){
				update(s, &seg);
				setstate(s, Established);
			}
			else {
			if(!seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){
				freeb(bp);
				sndrst(source, dest, tos, length, &seg);
				sndrst(source, dest, length, &seg);
				goto done;
			}
			break;
			update(s, &seg);
			tcpsetstate(s, Established);
		case Established:
		case Close_wait:
			update(s, &seg);


@@ 347,7 343,7 @@ tcp_input(Ipifc *ifc, Block *bp)
		case Finwait1:
			update(s, &seg);
			if(tcb->sndcnt == 0)
				setstate(s, Finwait2);
				tcpsetstate(s, Finwait2);
			break;
		case Finwait2:
			update(s, &seg);


@@ 355,9 351,9 @@ tcp_input(Ipifc *ifc, Block *bp)
		case Closing:
			update(s, &seg);
			if(tcb->sndcnt == 0) {
				setstate(s, Time_wait);
				tcpsetstate(s, Time_wait);
				tcb->timer.start = MSL2 * (1000 / MSPTICK);
				start_timer(&tcb->timer);
				tcpgo(&tcb->timer);
			}
			break;
		case Last_ack:


@@ 369,7 365,7 @@ tcp_input(Ipifc *ifc, Block *bp)
			}			
		case Time_wait:
			tcb->flags |= FORCE;
			start_timer(&tcb->timer);
			tcpgo(&tcb->timer);
		}

		if((seg.flags&URG) && seg.up) {


@@ 409,7 405,7 @@ tcp_input(Ipifc *ifc, Block *bp)

				tcprcvwin(s);
	
				start_timer(&tcb->acktimer);
				tcpgo(&tcb->acktimer);

				if(tcb->max_snd <= tcb->rcv.nxt-tcb->last_ack)
					tcb->flags |= FORCE;


@@ 418,7 414,7 @@ tcp_input(Ipifc *ifc, Block *bp)
				/* no process to read the data, send a reset */
				if(bp)
					freeb(bp);
				sndrst(source, dest, tos, length, &seg);
				sndrst(source, dest, length, &seg);
				goto done;
			}
		}


@@ 430,35 426,35 @@ tcp_input(Ipifc *ifc, Block *bp)
			case Syn_received:
			case Established:
				tcb->rcv.nxt++;
				setstate(s, Close_wait);
				tcpsetstate(s, Close_wait);
				break;
			case Finwait1:
				tcb->rcv.nxt++;
				if(tcb->sndcnt == 0) {
					setstate(s, Time_wait);
					tcpsetstate(s, Time_wait);
					tcb->timer.start = MSL2 * (1000/MSPTICK);
					start_timer(&tcb->timer);
					tcpgo(&tcb->timer);
				}
				else 
					setstate(s, Closing);
					tcpsetstate(s, Closing);
				break;
			case Finwait2:
				tcb->rcv.nxt++;
				setstate(s, Time_wait);
				tcpsetstate(s, Time_wait);
				tcb->timer.start = MSL2 * (1000/MSPTICK);
				start_timer(&tcb->timer);
				tcpgo(&tcb->timer);
				break;
			case Close_wait:
			case Closing:
			case Last_ack:
				break;
			case Time_wait:
				start_timer(&tcb->timer);
				tcpgo(&tcb->timer);
				break;
			}
		}

		while(tcb->reseq != 0) {
		while(tcb->reseq) {
			if(seq_ge(tcb->rcv.nxt, tcb->reseq->seg.seq) == 0)
				break;



@@ 470,7 466,7 @@ tcp_input(Ipifc *ifc, Block *bp)
		break;
	}
output:
	tcp_output(s);
	tcpoutput(s);
done:
	qunlock(tcb);
}


@@ 521,7 517,7 @@ update(Ipconv *s, Tcp *seg)
	/* Adjust the timers acorrding to the round trip time */
	if(run_timer(&tcb->rtt_timer))
	if(seq_ge(seg->ack, tcb->rttseq)) {
		stop_timer(&tcb->rtt_timer);
		tcphalt(&tcb->rtt_timer);
		if((tcb->flags&RETRAN) == 0) {
			tcb->backoff = 0;
			rtt = tcb->rtt_timer.start - tcb->rtt_timer.count;


@@ 550,9 546,9 @@ update(Ipconv *s, Tcp *seg)
	if(seq_gt(seg->ack, tcb->snd.up))
		tcb->snd.up = seg->ack;

	stop_timer(&tcb->timer);
	tcphalt(&tcb->timer);
	if(tcb->snd.una != tcb->snd.nxt)
		start_timer(&tcb->timer);
		tcpgo(&tcb->timer);

	if(seq_lt(tcb->snd.ptr, tcb->snd.una))
		tcb->snd.ptr = tcb->snd.una;


@@ 595,7 591,7 @@ proc_syn(Ipconv *s, char tos, Tcp *seg)

/* Generate an initial sequence number and put a SYN on the send queue */
void
send_syn(Tcpctl *tcb)
tcpsndsyn(Tcpctl *tcb)
{
	static int start;



@@ 630,16 626,16 @@ add_reseq(Tcpctl *tcb, char tos, Tcp *seg, Block *bp, ushort length)
	if(rp1 == 0 || seq_lt(seg->seq, rp1->seg.seq)) {
		rp->next = rp1;
		tcb->reseq = rp;
	} 
	else {
		for(;;){
			if(rp1->next == 0 || seq_lt(seg->seq, rp1->next->seg.seq)) {
				rp->next = rp1->next;
				rp1->next = rp;
				break;
			}
			rp1 = rp1->next;
		return;
	}

	for(;;) {
		if(rp1->next == 0 || seq_lt(seg->seq, rp1->next->seg.seq)) {
			rp->next = rp1->next;
			rp1->next = rp;
			break;
		}
		rp1 = rp1->next;
	}
}



@@ 648,7 644,8 @@ get_reseq(Tcpctl *tcb, char *tos, Tcp *seg, Block **bp, ushort *length)
{
	Reseq *rp;

	if((rp = tcb->reseq) == 0)
	rp = tcb->reseq;
	if(rp == 0)
		return;

	tcb->reseq = rp->next;


@@ 818,16 815,13 @@ init_tcpctl(Ipconv *s)
	tcb->ssthresh = 65535;
	tcb->srtt = tcp_irtt;

	/* Initialize timer intervals */
	tcb->timer.start = tcb->srtt / MSPTICK;
	tcb->timer.func = (void(*)(void*))tcp_timeout;
	tcb->timer.arg = (void *)s;
	tcb->timer.func = tcptimeout;
	tcb->timer.arg = s;
	tcb->rtt_timer.start = MAX_TIME; 

	/* Initialise ack timer */
	tcb->acktimer.start = TCP_ACK / MSPTICK;
	tcb->acktimer.func = (void(*)(void*))tcp_acktimer;
	tcb->acktimer.arg = (void *)s;
	tcb->acktimer.func = tcpacktimer;
	tcb->acktimer.arg = s;
}

/*


@@ 840,8 834,8 @@ localclose(Ipconv *s, char reason[])
	Tcpctl *tcb = &s->tcpctl;
	Block *bp;

	stop_timer(&tcb->timer);
	stop_timer(&tcb->rtt_timer);
	tcphalt(&tcb->timer);
	tcphalt(&tcb->rtt_timer);
	s->err = reason;

	/* flush receive queue */


@@ 857,7 851,7 @@ localclose(Ipconv *s, char reason[])

	tcb->reseq = 0;
	s->err = reason;
	setstate(s, Closed);
	tcpsetstate(s, Closed);
}

int


@@ 899,14 893,14 @@ seq_ge(int x, int y)
}

void
setstate(Ipconv *s, char newstate)
tcpsetstate(Ipconv *s, char newstate)
{
	char oldstate;
	Tcpctl *tcb = &s->tcpctl;

	oldstate = tcb->state;
	tcb->state = newstate;
	state_upcall(s, oldstate, newstate);
	tcpxstate(s, oldstate, newstate);
}

Block *


@@ 1004,7 998,8 @@ ntohtcp(Tcp *tcph, Block **bpp)
	if(!*bpp)
		return -1;

	for(optr = h->tcpopt, i = TCP_HDRSIZE; i < hdrlen;) {
	optr = h->tcpopt;
	for(i = TCP_HDRSIZE; i < hdrlen;) {
		switch(*optr++){
		case EOL_KIND:
			return hdrlen;

M port/tcpoutput.c => port/tcpoutput.c +23 -24
@@ 7,13 7,14 @@
#include 	"arp.h"
#include 	"ipdat.h"

extern int tcpdbg;
#define DPRINT if(tcpdbg) print
extern ushort tcp_mss;
int tcptimertype = 0;

extern	int tcpdbg;
extern	ushort tcp_mss;
	int tcptimertype;

void
tcp_output(Ipconv *s)
tcpoutput(Ipconv *s)
{
	Block *hbp,*dbp, *sndq;
	ushort ssize, dsize, usable, sent;


@@ 30,7 31,7 @@ tcp_output(Ipconv *s)
		return;
	}

	for(;;){
	for(;;) {
		qlen = tcb->sndcnt;
		sent = tcb->snd.ptr - tcb->snd.una;
		sndq = tcb->sndq;


@@ 40,16 41,15 @@ tcp_output(Ipconv *s)
		if((tcb->flags & SYNACK) == 0)
			break;

		/* Compute usable segment based on offered window and limit
		 * window probes to one
		 */
		if(tcb->snd.wnd == 0){
			/* Allow only one closed-window probe at a time */
			if(sent != 0)
				break;
			/* Force a closed-window probe */
			usable = 1;
		} else {
			/* usable window = offered window - unacked bytes in transit
			 * limited by the congestion window
			 */
		}
		else {
			usable = MIN(tcb->snd.wnd,tcb->cwind) - sent;
			if(sent != 0)
			if(qlen - sent < tcb->mss) 


@@ 61,20 61,18 @@ tcp_output(Ipconv *s)
		dsize = ssize;
		seg.up = 0;

		DPRINT("tcp_out: ssize = %lux\n", ssize);
		if(ssize == 0)
		if((tcb->flags&FORCE) == 0)
			break;

		/* Stop ack timer if one will be piggy backed on data */
		stop_timer(&tcb->acktimer);
		tcphalt(&tcb->acktimer);

		tcb->flags &= ~FORCE;
		tcprcvwin(s);

		/* By default we will generate an ack */
		seg.source = s->psrc;
		seg.dest = s->pdst;
		/* Every state except SYN_SENT */
		seg.flags = ACK; 	
		seg.mss = 0;



@@ 137,11 135,11 @@ tcp_output(Ipconv *s)
			tcb->timer.start = backoff(tcb->backoff) *
			 (2 * tcb->mdev + tcb->srtt + MSPTICK) / MSPTICK;
			if(!run_timer(&tcb->timer))
				start_timer(&tcb->timer);
				tcpgo(&tcb->timer);

			/* If round trip timer isn't running, start it */
			if(!run_timer(&tcb->rtt_timer)){
				start_timer(&tcb->rtt_timer);
				tcpgo(&tcb->rtt_timer);
				tcb->rttseq = tcb->snd.ptr;
			}
		}


@@ 165,12 163,12 @@ tcprxmit(Ipconv *s)

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

void
tcp_timeout(void *arg)
tcptimeout(void *arg)
{
	Tcpctl *tcb;
	Ipconv *s;


@@ 181,10 179,11 @@ tcp_timeout(void *arg)
	switch(tcb->state){
	default:
		tcb->backoff++;
		if (tcb->backoff >= MAXBACKOFF)
		if (tcb->backoff >= MAXBACKOFF) {
			localclose(s, Etimedout);
		else 
			tcprxmit(s);
			break;
		}
		tcprxmit(s);
		break;

	case Time_wait:


@@ 207,14 206,14 @@ backoff(int n)
}

void
tcp_acktimer(Ipconv *s)
tcpacktimer(Ipconv *s)
{
	Tcpctl *tcb = &s->tcpctl;

	qlock(tcb);
	tcb->flags |= FORCE;
	tcprcvwin(s);
	tcp_output(s);
	tcpoutput(s);
	qunlock(tcb);
}


M port/tcptimer.c => port/tcptimer.c +58 -67
@@ 7,12 7,53 @@
#include 	"arp.h"
#include 	"ipdat.h"

/* Head of running timer chain */
Timer 	*timers;
QLock 	timerlock;
Rendez	Tcpack;
static	Timer 	*timers;	/* List of active timers */
static	QLock 	tl;		/* Protect timer list */
static	Rendez	Tcpack;
Rendez	tcpflowr;

static void
deltimer(Timer *t)
{
	if(timers == t)
		timers = t->next;

	if(t->next)
		t->next->prev = t->prev;

	if(t->prev)
		t->prev->next = t->next;
}

/*
 * Poke each tcp connection to recompute window size and
 * acknowledgement timer
 */

void
tcpflow(void *x)
{
	Ipifc *ifc;
	Ipconv *cp, **p, **etab;

	ifc = x;
	etab = &ifc->conv[Nipconv];

	for(;;) {
		sleep(&tcpflowr, return0, 0);

		for(p = ifc->conv; p < etab; p++) {
			cp = *p;
			if(cp == 0)
				break;
			if(cp->readq && cp->ref != 0 && !QFULL(cp->readq->next)) {
				tcprcvwin(cp);
				tcpacktimer(cp);
			}
		}
	}
}

void
tcpackproc(void *junk)
{


@@ 23,30 64,18 @@ tcpackproc(void *junk)
	for(;;) {
		expired = 0;

		qlock(&timerlock);
		qlock(&tl);
		for(t = timers;t != 0; t = tp) {
			tp = t->next;
			if(tp == t)
				panic("Timer loop at %lux\n",(long)tp);
	
 			if(t->state == TIMER_RUN)
			if(--(t->count) == 0){

				/* Delete from active timer list */
				if(timers == t)
					timers = t->next;
				if(t->next != 0)
					t->next->prev = t->prev;
				if(t->prev != 0)
					t->prev->next = t->next;

				deltimer(t);
				t->state = TIMER_EXPIRE;
				/* Put on head of expired timer list */
				t->next = expired;
				expired = t;
			}
		}
		qunlock(&timerlock);
		qunlock(&tl);

		for(;;) {
			t = expired;


@@ 58,76 87,38 @@ tcpackproc(void *junk)
			if(t->func)
				(*t->func)(t->arg);
		}

		tsleep(&Tcpack, return0, 0, MSPTICK);
	}
}

void
start_timer(Timer *t)
tcpgo(Timer *t)
{

	if(t == 0 || t->start == 0)
		return;

	qlock(&timerlock);

	qlock(&tl);
	t->count = t->start;
	if(t->state != TIMER_RUN){
	if(t->state != TIMER_RUN) {
		t->state = TIMER_RUN;
		/* Put on head of active timer list */
		t->prev = 0;
		t->next = timers;
		if(t->next != 0)
		if(t->next)
			t->next->prev = t;
		timers = t;
	}
	qunlock(&timerlock);
	qunlock(&tl);
}

void
stop_timer(Timer *t)
tcphalt(Timer *t)
{
	if(t == 0)
		return;

	qlock(&timerlock);

	if(t->state == TIMER_RUN){
		/* Delete from active timer list */
		if(timers == t)
			timers = t->next;
		if(t->next != 0)
			t->next->prev = t->prev;
		if(t->prev != 0)
			t->prev->next = t->next;
	}
	qlock(&tl);
	if(t->state == TIMER_RUN)
		deltimer(t);
	t->state = TIMER_STOP;

	qunlock(&timerlock);
}

void
tcpflow(void *x)
{
	Ipifc *ifc;
	Ipconv *cp, **p, **etab;

	ifc = x;
	etab = &ifc->conv[Nipconv];

	for(;;) {
		sleep(&tcpflowr, return0, 0);

		for(p = ifc->conv; p < etab; p++) {
			cp = *p;
			if(cp == 0)
				break;
			if(cp->readq && cp->ref != 0 && !QFULL(cp->readq->next)) {
				tcprcvwin(cp);
				tcp_acktimer(cp);
			}
		}
	}
	qunlock(&tl);
}