~kris/9p

9hist

8588febad778f6ef4c28fbbd12ee72803fb47684 — David du Colombier 34 years ago f92bbf2
Plan 9 from Bell Labs 1991-11-07
M gnot/dat.h => gnot/dat.h +1 -0
@@ 105,6 105,7 @@ struct Conf
	int	copymode;	/* 0 is copy on write, 1 is copy on reference */
	int	portispaged;	/* ??? */
	int	cntrlp;		/* panic on ^P */
	int	dkif;		/* number of datakit interfaces */
};

#include "../port/portdat.h"

M gnot/main.c => gnot/main.c +1 -0
@@ 278,6 278,7 @@ confinit(void)
	conf.copymode = 0;		/* copy on write */
	conf.portispaged = 0;
	conf.cntrlp = 0;
	conf.dkif = 2;
}

/*

M pc/dat.h => pc/dat.h +1 -0
@@ 93,6 93,7 @@ struct Conf
	ulong	cntrlp;		/* panic on ^P */
	ulong	nfloppy;	/* number of floppy drives */
	ulong	nhard;		/* number of hard drives */
	int	dkif;		/* number of datakit interfaces */
};

/*

M pc/main.c => pc/main.c +2 -0
@@ 19,6 19,7 @@ main(void)
	confinit();
	screeninit();
	printinit();
crdump();
	print("%ludK bytes of physical memory\n", (conf.base1 + conf.npage1*BY2PG)/1024);
	mmuinit();
	trapinit();


@@ 225,6 226,7 @@ confinit(void)
	conf.cntrlp = 0;
	conf.nfloppy = 1;
	conf.nhard = 1;
	conf.dkif = 1;
}

char *mathmsg[] =

M pc/vga.c => pc/vga.c +11 -0
@@ 89,6 89,17 @@ crout(int reg, int val)
	outb(CRX, reg);
	outb(CR, val);
}
crdump(void)
{
	uchar x;
	int i;

	for(i = 0; i < 0x16; i++){
		outb(CRX, i);
		x = inb(CR);
		print("cr[0x%lux] = %ux\n", i, x);
	}
}

/*
 *  m is a bit mask of planes to be affected by CPU writes

M port/chan.c => port/chan.c +5 -0
@@ 647,10 647,15 @@ char isfrog[]={
void
nameok(char *elem)
{
	char *eelem;

	eelem = elem+NAMELEN;
	while(*elem) {
		if((*elem&0x80) || isfrog[*elem])
			error(Ebadchar);
		elem++;
		if(elem >= eelem)
			error(Efilename);
	}
}


M port/devdk.c => port/devdk.c +73 -47
@@ 12,11 12,6 @@

enum {
	/*
	 *  configuration parameters
	 */
	Ndk = 2,		/* max dks */

	/*
	 *  relative or immutable
	 */
	Nline = 256,		/* max lines per dk */


@@ 97,6 92,7 @@ struct Dkmsg {
 */
struct Line {
	QLock;
	int	lineno;
	Rendez	r;		/* wait here for dial */
	int	state;		/* dial state */
	int	err;		/* dialing error (if non zero) */


@@ 107,7 103,6 @@ struct Line {
	char	addr[64];
	char	raddr[64];
	char	ruser[32];
	char	other[64];
	Dk *dp;			/* interface contianing this line */
};



@@ 124,14 119,16 @@ struct Dk {
	int	lines;		/* number of lines */
	int	ncsc;		/* csc line number */
	Chan	*csc;
	Line	line[Nline];
	Line	**linep;
	int	restart;
	int	urpwindow;
	Rendez	timer;
	int	closeall;	/* set when we receive a closeall message */
	Rendez	closeallr;	/* wait here for a closeall */

	Block	*alloc;
};
static Dk dk[Ndk];
static Dk *dk;
static Lock dklock;

/*


@@ 217,14 214,16 @@ Qinfo dkmuxinfo =
 *  Look for a dk struct with a name.  If none exists,  create one.
 */ 
static Dk *
dkalloc(char *name)
dkalloc(char *name, int ncsc, int lines)
{
	Dk *dp;
	Dk *freep;
	Block *bp;
	int i, n;

	lock(&dklock);
	freep = 0;
	for(dp = dk; dp < &dk[Ndk]; dp++){
	for(dp = dk; dp < &dk[conf.dkif]; dp++){
		if(strcmp(name, dp->name) == 0){
			unlock(&dklock);
			return dp;


@@ 236,11 235,42 @@ dkalloc(char *name)
		unlock(&dklock);
		error(Enoifc);
	}
	if(lines == 0)
		errors("unknown dk interface");

	/*
 	 *  init the structures
	 */
	dp = freep;
	dp->opened = 0;
	dp->s = 0;
	dp->ncsc = 1;
	dp->ncsc = ncsc;
	dp->lines = lines;
	strncpy(dp->name, name, sizeof(freep->name));

	/*
	 *  allocate memory for line structures
	 */
	n = sizeof(Line*)*dp->lines;
	bp = allocb(n);
	if(bp->lim - bp->base < n){
		unlock(&dklock);
		errors("too many lines");
	}
	dp->linep = (Line **)bp->base;
	bp->wptr += n;
	dp->alloc = bp;
	for(i = 0; i < n; i++){
		if(bp->lim - bp->wptr < sizeof(Line)){
			bp = allocb(sizeof(Line)*n);
			bp->next = dp->alloc;
			dp->alloc = bp;
		}
		dp->linep[i] = (Line*)bp->wptr;
		dp->linep[i]->lineno = i;
		bp->wptr += sizeof(Line);
	}
		
	unlock(&dklock);
	return dp;
}


@@ 281,7 311,7 @@ dkmuxclose(Queue *q)
	 *  hang up all datakit connections
	 */
	for(i=dp->ncsc; i < dp->lines; i++)
		dkhangup(&dp->line[i]);
		dkhangup(dp->linep[i]);

	/*
	 *  wakeup the timer so it can die


@@ 344,7 374,7 @@ dkmuxiput(Queue *q, Block *bp)
		return;
	}

	lp = &dp->line[line];
	lp = dp->linep[line];
	if(canqlock(lp)){
		if(lp->rq)
			PUTNEXT(lp->rq, bp);


@@ 385,7 415,7 @@ dkstopen(Queue *q, Stream *s)
	Line *lp;

	dp = &dk[s->dev];
	q->other->ptr = q->ptr = lp = &dp->line[s->id];
	q->other->ptr = q->ptr = lp = dp->linep[s->id];
	lp->dp = dp;
	lock(dp);
	if(dp->opened==0 || streamenter(dp->s)<0){


@@ 449,22 479,22 @@ dkstclose(Queue *q)
	 */
	switch(lp->state){
	case Lrclose:
		dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0);
		dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
		lp->state = Lclosed;
		break;

	case Lackwait:
		dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0);
		dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
		lp->state = Llclose;
		break;

	case Llistening:
		dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0);
		dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
		lp->state = Llclose;
		break;

	case Lconnected:
		dkmesg(c, T_CHG, D_CLOSE, lp - dp->line, 0);
		dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
		lp->state = Llclose;
		break;
	}


@@ 506,7 536,7 @@ dkoput(Queue *q, Block *bp)

	lp = (Line *)q->ptr;
	dp = lp->dp;
	line = lp - dp->line;
	line = lp->lineno;

	bp = padb(bp, 2);
	bp->rptr[0] = line;


@@ 590,14 620,12 @@ dkmuxconfig(Queue *q, Block *bp)
	/*
	 *  set up
	 */
	dp = dkalloc(name);
	dp = dkalloc(name, ncsc, lines);
	lock(dp);
	if(dp->opened){
		unlock(dp);
		error(Ebadarg);
	}
	dp->ncsc = ncsc;
	dp->lines = lines;
	dp->restart = restart;
	dp->urpwindow = window;
	dp->s = RD(q)->ptr;


@@ 649,7 677,6 @@ enum {
	Dlistenqid,
	Draddrqid,
	Duserqid,
	Dotherqid,
	Dlineqid,

	/*


@@ 669,7 696,6 @@ Dirtab dkdir[Ndir];
Dirtab dksubdir[]={
	"addr",		{Daddrqid},	0,	0600,
	"listen",	{Dlistenqid},	0,	0600,
	"other",	{Dotherqid},	0,	0600,
	"raddr",	{Draddrqid},	0, 	0600,
	"ruser",	{Duserqid},	0, 	0600,
};


@@ 681,6 707,7 @@ Dirtab dksubdir[]={
void
dkreset(void)
{
	dk = (Dk*)ialloc(conf.dkif*sizeof(Dk), 0);
	newqinfo(&dkmuxinfo);
}



@@ 728,7 755,7 @@ dkattach(char *spec)
	 */
	if(*spec == 0)
		spec = "dk";
	dp = dkalloc(spec);
	dp = dkalloc(spec, 0, 0);

	/*
	 *  return the new channel


@@ 778,7 805,7 @@ dkopen(Chan *c, int omode)
{
	extern Qinfo dkinfo;
	Stream *s;
	Line *lp, *end;
	Line *lp;
	Dk *dp;
	int line;



@@ 794,21 821,21 @@ dkopen(Chan *c, int omode)
		/*
		 *  get an unused device and open its control file
		 */
		end = &dp->line[dp->lines];
		for(lp = &dp->line[dp->ncsc+1]; lp < end; lp++){
		for(line = dp->ncsc+1; line < dp->lines; line++){
			lp = dp->linep[line];
			if(lp->state == Lclosed && canqlock(lp)){
				if(lp->state != Lclosed){
					qunlock(lp);
					continue;
				}
				c->qid.path = STREAMQID(lp-dp->line, Sctlqid);
				c->qid.path = STREAMQID(line, Sctlqid);
				lp->state = Lopened;
				qunlock(lp);
				break;
			}
		}
		if(lp == end)
		if(line == dp->lines)
			error(Enodev);
		lp->state = Lopened;
		qunlock(lp);
		streamopen(c, &dkinfo);
		pushq(c->stream, &urpinfo);
		break;


@@ 826,7 853,6 @@ dkopen(Chan *c, int omode)
	case Daddrqid:
	case Draddrqid:
	case Duserqid:
	case Dotherqid:
		/*
		 *  read only files
		 */


@@ 877,7 903,7 @@ dkread(Chan *c, void *a, long n, ulong offset)
			return devdirread(c, a, n, dksubdir, Nsubdir, streamgen);
	}

	lp = &dk[c->dev].line[STREAMID(c->qid.path)];
	lp = dk[c->dev].linep[STREAMID(c->qid.path)];
	switch(STREAMTYPE(c->qid.path)){
	case Daddrqid:
		return stringread(c, a, n, lp->addr, offset);


@@ 1028,7 1054,7 @@ dkcall(int type, Chan *c, char *addr, char *nuser, char *machine)
	
	line = STREAMID(c->qid.path);
	dp = &dk[c->dev];
	lp = &dp->line[line];
	lp = dp->linep[line];

	/*
	 *  only dial on virgin lines


@@ 1272,7 1298,7 @@ dklisten(Chan *c)
			print("dklisten: illegal line %d\n", lineno);
			continue;
		}
		lp = &dp->line[lineno];
		lp = dp->linep[lineno];
		ts = strtoul(field[1], 0, 0);

		/*


@@ 1338,9 1364,8 @@ dklisten(Chan *c)
			error(Ebadarg);
		}

		sprint(lp->other, "w(%d)", W_TRAF(lp->window));
		DPRINT("src(%s)user(%s)dest(%s)other(%s)\n", lp->raddr, lp->ruser,
			lp->addr, lp->other);
		DPRINT("src(%s)user(%s)dest(%s)w(%d)\n", lp->raddr, lp->ruser,
			lp->addr, W_TRAF(lp->window));

		lp->timestamp = ts;
		lp->state = Lconnected;


@@ 1365,7 1390,7 @@ dkanswer(Chan *c, int line, int code)
	Line *lp;

	dp = &dk[c->dev];
	lp = &dp->line[line];
	lp = dp->linep[line];

	/*
	 *  open the data file (c is a control file)


@@ 1398,7 1423,7 @@ dkwindow(Chan *c)
	long wins;
	Line *lp;

	lp = &dk[c->dev].line[STREAMID(c->qid.path)];
	lp = dk[c->dev].linep[STREAMID(c->qid.path)];
	if(lp->window == 0)
		lp->window = 64;
	sprint(buf, "init %d %d", lp->window, Streamhi);


@@ 1496,7 1521,7 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
			dkmesg(c, T_CHG, D_CLOSE, line, 0);
			return;
		}
		lp = &dp->line[line];
		lp = dp->linep[line];
		switch (lp->state) {

		case Ldialing:


@@ 1532,7 1557,7 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
			dkmesg(c, T_CHG, D_CLOSE, line, 0);
			return;
		}
		lp = &dp->line[line];
		lp = dp->linep[line];
		switch (lp->state) {
		case Llclose:
		case Lclosed:


@@ 1552,7 1577,7 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
		 *  datakit wants us to close all lines
		 */
		for(line = dp->ncsc+1; line < dp->lines; line++){
			lp = &dp->line[line];
			lp = dp->linep[line];
			switch (lp->state) {
	
			case Ldialing:


@@ 1601,7 1626,7 @@ dkreplymesg(Dk *dp, Dkmsg *dialp, int line)
	if(line < 0 || line >= dp->lines)
		return;

	lp=&dp->line[line];
	lp = dp->linep[line];
	if(lp->state != Ldialing)
		return;



@@ 1646,7 1671,7 @@ dktimer(void *a)
		 *  hang up any calls waiting for the dk
		 */
		for (i=dp->ncsc+1; i<dp->lines; i++){
			lp = &dp->line[i];
			lp = dp->linep[i];
			switch(lp->state){
			case Llclose:
				lp->state = Lclosed;


@@ 1659,6 1684,7 @@ dktimer(void *a)
		}
		if(c)
			close(c);
		freeb(dp->alloc);
		return;
	}



@@ 1682,7 1708,7 @@ dktimer(void *a)
		 *  timeout calls that take to long
		 */
		for (i=dp->ncsc+1; i<dp->lines; i++){
			lp = &dp->line[i];
			lp = dp->linep[i];
			switch(lp->state){
			case Llclose:
				dkmesg(c, T_CHG, D_CLOSE, i, 0);

M port/devlance.c => port/devlance.c +6 -53
@@ 186,7 186,6 @@ static SoftLance l;
 */
static void lancekproc(void *);
static void lancestart(int, int);
static void lancedump(void);
static void lanceup(Etherpkt*, int);

/*


@@ 244,45 243,6 @@ lancestclose(Queue *q)
}

/*
 *  expand a block list to be one byte, len bytes long
 */
static Block*
expandb(Block *bp, int len)
{
	Block *nbp, *new;
	int i;

	new = allocb(len);
	if(new == 0){
		freeb(bp);
		return 0;
	}

	/*
	 *  copy bytes into new block
	 */
	for(nbp = bp; len>0 && nbp; nbp = nbp->next){
		i = BLEN(bp);
		if(i > len) {
			memmove(new->wptr, nbp->rptr, len);
			new->wptr += len;
			break;
		} else {
			memmove(new->wptr, nbp->rptr, i);
			new->wptr += i;
			len -= i;
		}
	}
	if(len){
		memset(new->wptr, 0, len);
		new->wptr += len;
	}
	freeb(bp);
	return new;

}

/*
 *  the ``connect'' control message specifyies the type
 */
Proc *lanceout;


@@ 329,7 289,7 @@ lanceoput(Queue *q, Block *bp )
	memmove(p->s, l.ea, sizeof(l.ea));
	if(memcmp(l.ea, p->d, sizeof(l.ea)) == 0){
		len = blen(bp);
		bp = expandb(bp, len >= 60 ? len : 60);
		bp = expandb(bp, len >= ETHERMINTU ? len : ETHERMINTU);
		if(bp){
			putq(&l.self, bp);
			wakeup(&l.rr);


@@ 370,9 330,9 @@ lanceoput(Queue *q, Block *bp )
	/*
	 *  pad the packet (zero the pad)
	 */
	if(len < 60){
		memset(((char*)p)+len, 0, 60-len);
		len = 60;
	if(len < ETHERMINTU){
		memset(((char*)p)+len, 0, ETHERMINTU-len);
		len = ETHERMINTU;
	}

	/*


@@ 695,9 655,8 @@ lanceintr(void)
	 *  see if an error occurred
	 */
	if(csr & (BABL|MISS|MERR)){
		print("lance err %ux\n", csr);
		if(csr & MISS)
			lancedump();
		if(misses++ < 4)
			print("lance err %ux\n", csr);
	}

	if(csr & IDON){


@@ 838,9 797,3 @@ stage:
		sleep(&l.rr, isinput, 0);
	}
}

static void
lancedump(void)
{
	print("l.rl %d l.rc %d l.tl %d l.tc %d\n", l.rl, l.rc, l.tl, l.tc);
}

M port/devproc.c => port/devproc.c +0 -2
@@ 166,9 166,7 @@ procopen(Chan *c, int omode)
		if(p->pid != PID(c->qid))
			goto Close;

		qlock(&tc->rdl);
		tc->offset = 0;
		qunlock(&tc->rdl);
		return tc;
	case Qctl:
	case Qnote:

M port/ipdat.h => port/ipdat.h +1 -1
@@ 101,7 101,7 @@ struct Ilcb				/* Control block */
	Block	*unacked;
	Block	*unackedtail;
	Block	*outoforder;
	ulong	sent;
	ulong	next;
	ulong	recvd;
	ulong	start;
	ulong	rstart;

A port/net.c => port/net.c +143 -0
@@ 0,0 1,143 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"

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

/*
 *  generate a 3 level directory
 */
int
netgen(Chan *c, void *vp, int ntab, int i, Dir *dp)
{
	Qid q;
	char buf[32];
	Network *np = vp;

	q.vers = 0;

	/* top level directory contains the name of the network */
	if(c->qid.path == CHDIR){
		switch(i){
		case 0:
			q.path = CHDIR | Q2nd;
			strcpy(buf, np->name);
			devdir(c, q, buf, 0, 0666, dp);
			break;
		default:
			return -1;
		}
		return 1;
	}

	/* second level contains clone plus all the conversations */
	if(c->qid.path == (CHDIR | Q2nd)){
		if(i == 0){
			q.path = Qclone;
			devdir(c, q, "clone", 0, 0666, dp);
		}else if(i < np->nconv){
			q.path = CHDIR|STREAMQID(i, Q3rd);
			sprint(buf, "%d", i);
			devdir(c, q, buf, 0, 0666, dp);
		}else
			return -1;
		return 1;
	}

	if((c->qid.path & CHDIR) == 0)
		return -1;

	/* third level depends on the number of info files */
	switch(i){
	case 0:
		q.path = STREAMQID(STREAMID(c->qid.path), Sdataqid);
		devdir(c, q, "data", 0, 0666, dp);
		break;
	case 1:
		q.path = STREAMQID(STREAMID(c->qid.path), Sctlqid);
		devdir(c, q, "ctl", 0, 0666, dp);
		break;
	case 2:
		if(np->listen == 0)
			return 0;
		q.path = STREAMQID(STREAMID(c->qid.path), Qlisten);
		devdir(c, q, "listen", 0, 0666, dp);
		break;
	default:
		if(i >= 3 + np->ninfo)
			return -1;
		i -= 3;
		q.path = Qlisten + i + 1;
		devdir(c, q, np->info[i].name, 0, 0666, dp);
	}
	return 1;
}

Chan *
netopen(Chan *c, int omode, Network *np)
{
	int conv;

	if(c->qid.path & CHDIR){
		if(omode != OREAD)
			error(Eperm);
	} else {
		switch(STREAMTYPE(c->qid.path)){
		case Sdataqid:
		case Sctlqid:
			break;
		case Qlisten:
			conv = (*np->listen)(c);
			c->qid.path = STREAMQID(conv, Sctlqid);
			break;
		case Qclone:
			conv = (*np->clone)(c);
			c->qid.path = STREAMQID(conv, Sctlqid);
			break;
		default:
			if(omode != OREAD)
				error(Ebadarg);
		}
		switch(STREAMTYPE(c->qid.path)){
		case Sdataqid:
		case Sctlqid:
			streamopen(c, np->devp);
			if(np->protop && c->stream->devq->next->info != np->protop)
				pushq(c->stream, np->protop);
			break;
		}
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

long
netread(Chan *c, void *a, long n, ulong offset, Network *np)
{
	int i;
	char buf[256];

	if(c->stream)
		return streamread(c, a, n);

	if(c->qid.path&CHDIR)
		return devdirread(c, a, n, (Dirtab*)np, 0, netgen);

	if(c->qid.path <= Qlisten || c->qid.path > Qlisten + np->ninfo)
		error(Ebadusefd);

	i = c->qid.path - Qlisten - 1;
	(*np->info[i].fill)(c, buf, sizeof(buf));
	return stringread(c, a, n, buf, offset);
}

M port/portdat.h => port/portdat.h +0 -3
@@ 624,14 624,11 @@ struct Ifile
struct Network
{
	char	*name;
	int	nif;			/* max # of interfaces */
	int	nconv;			/* max # of conversations */
	Qinfo	*devp;			/* device end line disc */
	Qinfo	*protop;		/* protocol line disc */
	int	(*listen)(Chan*);
	int	(*clone)(Chan*);
	void	(*connect)(Chan*, char*);
	void	(*announce)(Chan*, char*);
	int	ninfo;
	Ifile	info[5];
};

M port/portfns.h => port/portfns.h +4 -0
@@ 64,6 64,7 @@ void	error(int);
void	errors(char*);
void	execpc(ulong);
void	exit(void);
Block*	expandb(Block *, int);
int	fault(ulong, int);
void	fdclose(int, int);
Chan*	fdtochan(int, int, int);


@@ 120,6 121,9 @@ void	mouseclock(void);
int	mouseputc(IOQ*, int);
Chan*	namec(char*, int, int, ulong);
void	nameok(char*);
int	netgen(Chan*, void*, int, int, Dir*);
Chan*	netopen(Chan*, int, Network*);
long	netread(Chan*, void*, long, ulong, Network*);
Alarm*	newalarm(void);
Chan*	newchan(void);
Egrp*	newegrp(void);

M port/stil.c => port/stil.c +42 -40
@@ 31,6 31,7 @@ void	ilackq(Ilcb*, Block*);
void	ilprocess(Ipconv*, Ilhdr*, Block*);
void	ilpullup(Ipconv*);
void	ilhangup(Ipconv*);
void	ilfreeq(Ilcb*);

void
ilopen(Queue *q, Stream *s)


@@ 83,18 84,8 @@ ilclose(Queue *q)
	case Ilsyncer:
	case Ilsyncee:
	case Ilestablished:
		for(bp = ic->unacked; bp; bp = next) {
			next = bp->list;
			freeb(bp);
		}
		for(bp = ic->outoforder; bp; bp = next) {
			next = bp->list;
			freeb(bp);
		}
		ic->unacked = 0;
		ic->outoforder = 0;
		ilfreeq(ic);
		ic->state = Ilclosing;
		ic->sent++;
		ilsendctl(s, 0, Ilclose);
		break;
	Illistening:


@@ 156,7 147,7 @@ iloput(Queue *q, Block *bp)
	hnputs(ih->illen, dlen+IL_HDRSIZE);
	hnputs(ih->ilsrc, ipc->psrc);
	hnputs(ih->ildst, ipc->pdst);
	hnputl(ih->ilid, ic->sent++);
	hnputl(ih->ilid, ic->next++);
	hnputl(ih->ilack, ic->recvd);
	ih->iltype = Ildata;
	ih->ilspec = 0;


@@ 275,8 266,8 @@ ilrcvmsg(Ipconv *ipc, Block *bp)
			ic = &new->ilctl;
			ic->state = Ilsyncee;
			initseq += TK2MS(MACHP(0)->ticks);
			ic->sent = initseq;
			ic->start = ic->sent;
			ic->next = initseq;
			ic->start = ic->next;
			ic->recvd = 0;
			ic->rstart = nhgetl(ih->ilid);
			ilprocess(new, ih, bp);


@@ 413,22 404,11 @@ _ilprocess(Ipconv *s, Ilhdr *h, Block *bp)
			break;
		case Ilclose:
			freeb(bp);
			if(ic->start >= ack || ack < ic->sent)
			if(id != ic->recvd)
				break;
			ic->sent++;
			ic->recvd = ack;
			ilsendctl(s, 0, Ilclose);
			ic->state = Ilclosing;
			for(nb = ic->unacked; nb; nb = next) {
				next = nb->list;
				freeb(nb);
			}
			for(nb = ic->outoforder; nb; nb = next) {
				next = nb->list;
				freeb(nb);
			}
			ic->unacked = 0;
			ic->outoforder = 0;
			ilfreeq(ic);
			break;
		}
		break;


@@ 438,15 418,16 @@ _ilprocess(Ipconv *s, Ilhdr *h, Block *bp)
	case Ilclosing:
		switch(h->iltype) {
		case Ilclose:
			if(ack == ic->sent) {
			if(ack == ic->next) {
				ic->state = Ilclosed;
				ilhangup(s);
			}
			ic->recvd = id;
			ilsendctl(s, 0, Ilclose);
			else {
				ic->recvd = id;
				ilsendctl(s, 0, Ilclose);
			}
			break;
		default:
			ic->state = Ilclosed;
			ilsendctl(s, 0, Ilclose);
			ilhangup(s);
			break;


@@ 462,14 443,14 @@ ilprocess(Ipconv *s, Ilhdr *h, Block *bp)
{
	Ilcb *ic = &s->ilctl;

	print("%s start %d rstart %d recvd %d sent %d\n",
		ilstate[ic->state], ic->start, ic->rstart, ic->recvd, ic->sent);
	print("pkt(%s id %d ack %d)\n", iltype[h->iltype], nhgetl(h->ilid), nhgetl(h->ilack));
	print("%s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ",
		ilstate[ic->state],  ic->rstart, ic->recvd, ic->start, ic->next,
		iltype[h->iltype], nhgetl(h->ilid), nhgetl(h->ilack), 
		nhgets(h->ilsrc), nhgets(h->ildst));

	_ilprocess(s, h, bp);

	print("%s start %d rstart %d recvd %d sent %d\n",
		ilstate[ic->state], ic->start, ic->rstart, ic->recvd, ic->sent);
	print("%s rcv %d snt %d\n", ilstate[ic->state], ic->recvd, ic->next);
}

void


@@ 578,7 559,7 @@ ilsendctl(Ipconv *ipc, Ilhdr *inih, int type)
		hnputl(ih->dst, ipc->dst);
		hnputs(ih->ilsrc, ipc->psrc);
		hnputs(ih->ildst, ipc->pdst);
		id = ic->sent;
		id = ic->next;
		if(type == Ilsync)
			id = ic->start;
		hnputl(ih->ilid, id);


@@ 592,6 573,10 @@ ilsendctl(Ipconv *ipc, Ilhdr *inih, int type)
	if(ilcksum)
		hnputs(ih->ilsum, ptcl_csum(bp, IL_EHSIZE, IL_HDRSIZE));

	print("ctl(%s id %d ack %d %d->%d) ",
		iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack), 
		nhgets(ih->ilsrc), nhgets(ih->ildst));

	PUTNEXT(Ipoutput, bp);
}



@@ 638,10 623,10 @@ ilstart(Ipconv *ipc, int type, int window)
	ic->unacked = 0;
	ic->outoforder = 0;
	initseq += TK2MS(MACHP(0)->ticks);
	ic->sent = initseq;
	ic->start = ic->sent;
	ic->next = initseq;
	ic->start = ic->next;
	ic->recvd = 0;
	ic->lastack = ic->sent;
	ic->lastack = ic->next;
	ic->window = window;

	switch(type) {


@@ 654,3 639,20 @@ ilstart(Ipconv *ipc, int type, int window)
		break;
	}
}

void
ilfreeq(Ilcb *ic)
{
	Block *bp, *next;

	for(bp = ic->unacked; bp; bp = next) {
		next = bp->list;
		freeb(bp);
	}
	for(bp = ic->outoforder; bp; bp = next) {
		next = bp->list;
		freeb(bp);
	}
	ic->unacked = 0;
	ic->outoforder = 0;
}

M port/stnoether.c => port/stnoether.c +12 -5
@@ 196,11 196,18 @@ noetheriput(Queue *q, Block *bp)
	 */
	ep = &ifc->conv[conf.nnoconv];
	for(cp = &ifc->conv[0]; cp < ep; cp++){
		if(circuit==cp->rcvcircuit){
			qlock(cp);
			peh = (Etherpkt*)cp->media->rptr;
			if(circuit == cp->rcvcircuit
			&& memcmp(peh->d, eh->s, sizeof(eh->s)) == 0){
		nbp = cp->media;
		if(nbp == 0)
			continue;
		peh = (Etherpkt*)nbp->rptr;
		if(circuit==cp->rcvcircuit && memcmp(peh->d, eh->s, sizeof(eh->s))==0){
			if(!canqlock(cp)){
				freeb(bp);
				return;
			}
			peh = (Etherpkt*)nbp->rptr;
			if(circuit==cp->rcvcircuit
			&& memcmp(peh->d, eh->s, sizeof(eh->s))==0){
				bp->rptr += ifc->hsize;
				nonetrcvmsg(cp, bp);
				qunlock(cp);

M port/stream.c => port/stream.c +49 -9
@@ 44,6 44,7 @@ static Lock garbagelock;
typedef struct {
	int	size;
	int	made;
	QLock;
	Blist;
} Bclass;
Bclass bclass[Nclass]={


@@ 145,11 146,11 @@ newblock(Bclass *bcp)
			 *  upgrade a level 0 block
			 */
			bp = allocb(0);
			lock(bclass);
			qlock(bclass);
			bclass->made--;
			bcp->made++;
			bp->flags = bcp - bclass;
			unlock(bclass);
			qunlock(bclass);

			/*
			 *  tack on the data area


@@ 193,10 194,10 @@ allocb(ulong size)
	/*
	 *  look for a free block
	 */
	lock(bcp);
	qlock(bcp);
	while(bcp->first == 0){
		if(waserror()){
			unlock(bcp);
			qunlock(bcp);
			nexterror();
		}
		newblock(bcp);


@@ 206,7 207,7 @@ allocb(ulong size)
	bcp->first = bp->next;
	if(bcp->first == 0)
		bcp->last = 0;
	unlock(bcp);
	qunlock(bcp);

	/*
	 *  return an empty block


@@ 240,7 241,7 @@ freeb(Block *bp)
	for(; bp; bp = nbp){
		bcp = &bclass[bp->flags & S_CLASS];
		bp->flags = bp->flags|S_CLASS;		/* Check for double free */
		lock(bcp);
		qlock(bcp);
		bp->rptr = bp->wptr = 0;
		if(bcp->first)
			bcp->last->next = bp;


@@ 249,7 250,7 @@ freeb(Block *bp)
		bcp->last = bp;
		nbp = bp->next;
		bp->next = 0;
		unlock(bcp);
		qunlock(bcp);
	}
}



@@ 617,6 618,45 @@ pullup(Block *bp, int n)
}

/*
 *  expand a block list to be one byte, len bytes long
 */
Block*
expandb(Block *bp, int len)
{
	Block *nbp, *new;
	int i;

	new = allocb(len);
	if(new == 0){
		freeb(bp);
		return 0;
	}

	/*
	 *  copy bytes into new block
	 */
	for(nbp = bp; len>0 && nbp; nbp = nbp->next){
		i = BLEN(bp);
		if(i > len) {
			memmove(new->wptr, nbp->rptr, len);
			new->wptr += len;
			break;
		} else {
			memmove(new->wptr, nbp->rptr, i);
			new->wptr += i;
			len -= i;
		}
	}
	if(len){
		memset(new->wptr, 0, len);
		new->wptr += len;
	}
	freeb(bp);
	return new;

}

/*
 *  grow the front of a list of blocks by n bytes
 */
Block *


@@ 1414,10 1454,10 @@ dumpqueues(void)
	}
	print("%d queues\n", qcount);
	for(bcp=bclass; bcp<&bclass[Nclass]; bcp++){
		lock(bcp);
		qlock(bcp);
		for(count = 0, bp = bcp->first; bp; count++, bp = bp->next)
			;
		unlock(bcp);
		qunlock(bcp);
		print("%d byte blocks: %d made %d free\n", bcp->size,
			bcp->made, count);
	}

M port/sysfile.c => port/sysfile.c +2 -2
@@ 535,7 535,7 @@ syswstat(ulong *arg)
	long n;

	validaddr(arg[1], DIRLEN, 0);
	evenaddr(arg[1]);
	nameok((char*)arg[1]);
	validaddr(arg[0], 1, 0);
	c = namec((char*)arg[0], Aaccess, 0, 0);
	if(waserror()){


@@ 555,7 555,7 @@ sysfwstat(ulong *arg)
	long n;

	validaddr(arg[1], DIRLEN, 0);
	evenaddr(arg[1]);
	nameok((char*)arg[1]);
	c = fdtochan(arg[0], -1, 1);
	(*devtab[c->type].wstat)(c, (char*)arg[1]);
	return 0;

M power/conf.h => power/conf.h +1 -0
@@ 37,6 37,7 @@ Conftab conftab[] = {
	{"arp", &conf.arp },
	{"frag", &conf.frag },
	{"cntrlp", &conf.cntrlp },
	{"dkif", &conf.dkif },
	{ 0, 0 },
};


M power/dat.h => power/dat.h +1 -0
@@ 74,6 74,7 @@ struct Conf
	ulong	arp;		/* Arp table size */
	ulong	frag;		/* Ip fragment assemble queue size */
	ulong	cntrlp;		/* panic on ^P */
	ulong	dkif;		/* number of datakit interfaces */
};

/*

M power/main.c => power/main.c +1 -0
@@ 595,6 595,7 @@ confinit(void)

	conf.copymode = 1;		/* copy on reference */
	conf.cntrlp = 1;
	conf.dkif = 2;
}

/*

M ss/dat.h => ss/dat.h +1 -0
@@ 99,6 99,7 @@ struct Conf
	ulong	arp;		/* Arp table size */
	ulong	frag;		/* Ip fragment assemble queue size */
	int	cntrlp;		/* panic on ^P */
	int	dkif;		/* number of datakit interfaces */
};

/*

M ss/main.c => ss/main.c +1 -0
@@ 243,6 243,7 @@ confinit(void)
	conf.arp = 32;
	conf.frag = 32;
	conf.cntrlp = 0;
	conf.dkif = 1;
}

/*