~kris/9p

9hist

63327bb38850af3de9dc588afc2b0a32b50c25bf — David du Colombier 34 years ago 452f66c
Plan 9 from Bell Labs 1992-02-19
9 files changed, 73 insertions(+), 1651 deletions(-)

M pc/devhard.c
M pc/main.c
A port/bootp.h
M port/devbit.c
M port/devdk.c
M port/devip.c
D port/devnonet.c
M port/devwren.c
M power/boot.c
M pc/devhard.c => pc/devhard.c +11 -15
@@ 623,23 623,19 @@ hardpart(Drive *dp)
	 *  parse partition table.
	 */
	n = getfields(cp->buf, line, Npart+1, '\n');
	if(strncmp(line[0], MAGIC, sizeof(MAGIC)-1) != 0){
		goto out;
	}
	for(i = 1; i < n; i++){
		pp++;
		if(getfields(line[i], field, 3, ' ') != 3){
			break;
		}
		strncpy(pp->name, field[0], NAMELEN);
		pp->start = strtoul(field[1], 0, 0);
		pp->end = strtoul(field[2], 0, 0);
		if(pp->start > pp->end || pp->start >= dp->p[0].end){
			break;
	if(strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
		for(i = 1; i < n; i++){
			pp++;
			if(getfields(line[i], field, 3, ' ') != 3)
				break;
			strncpy(pp->name, field[0], NAMELEN);
			pp->start = strtoul(field[1], 0, 0);
			pp->end = strtoul(field[2], 0, 0);
			if(pp->start > pp->end || pp->start >= dp->p[0].end)
				break;
			dp->npart++;
		}
		dp->npart++;
	}
out:
	qunlock(cp);
	poperror();
}

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

A port/bootp.h => port/bootp.h +29 -0
@@ 0,0 1,29 @@
/*
 *  this file used by (at least) snoopy, tboot and bootp
 */
enum
{
	Bootrequest = 1,
	Bootreply   = 2,
};

typedef struct Bootp Bootp;
struct Bootp
{
	uchar	op;		/* opcode */
	uchar	htype;		/* hardware type */
	uchar	hlen;		/* hardware address len */
	uchar	hops;		/* hops */
	uchar	xid[4];		/* a random number */
	uchar	secs[2];	/* elapsed snce client started booting */
	uchar	pad[2];
	uchar	ciaddr[4];	/* client IP address (client tells server) */
	uchar	yiaddr[4];	/* client IP address (server tells client) */
	uchar	siaddr[4];	/* server IP address */
	uchar	giaddr[4];	/* gateway IP address */
	uchar	chaddr[16];	/* client hardware address */
	char	sname[64];	/* server host name (optional) */
	char	file[128];	/* boot file name */
	char	vend[128];	/* vendor-specific goo */
};


M port/devbit.c => port/devbit.c +15 -2
@@ 1324,11 1324,19 @@ bitloadchar(GFont *f, int ci, GSubfont *subf, int si)
	GCacheinfo *c;
	Rectangle rect;
	Fontchar *fi;
	int y;

	c = &f->cache[ci];
	fi = &subf->info[si];
	c->top = fi->top + (f->ascent-subf->ascent);
	c->bottom = fi->bottom + (f->ascent-subf->ascent);
	/* careful about sign extension: top and bottom are uchars */
	y = fi->top + (f->ascent-subf->ascent);
	if(y < 0)
		y = 0;
	c->top = y;
	y = fi->bottom + (f->ascent-subf->ascent);
	if(y < 0)
		y = 0;
	c->bottom = y;
	c->width = fi->width;
	c->left = fi->left;
	c->x = ci*f->width;


@@ 1340,7 1348,12 @@ bitloadchar(GFont *f, int ci, GSubfont *subf, int si)
	gbitblt(f->b, rect.min, f->b, rect, 0);
	rect.min.x = fi->x;
	rect.max.x = (fi+1)->x;
	rect.max.y = subf->height;
	gbitblt(f->b, Pt(c->x, f->ascent-subf->ascent), subf->bits, rect, S);
/*
gbitblt(&gscreen, Pt(0,0), f->b, f->b->r, S);
gbitblt(&gscreen, Pt(0,30), f->b, Rect(c->x, 0, c->x+f->width,f->height), S);
*/
}

QLock	bitlock;

M port/devdk.c => port/devdk.c +3 -0
@@ 316,6 316,9 @@ dkmuxopen(Queue *q, Stream *s)
{
	RD(q)->ptr = s;
	WR(q)->ptr = 0;

	s->opens++;		/* Hold this queue in place */
	s->inuse++;
}

/*

M port/devip.c => port/devip.c +4 -0
@@ 100,6 100,10 @@ ipattach(char *spec)
	Chan *c;
	int i;

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

	for(i = 0; protocols[i]; i++) {
		if(strcmp(spec, protocols[i]->name) == 0) {
			c = devattach('I', spec);

D port/devnonet.c => port/devnonet.c +0 -1513
@@ 1,1513 0,0 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"
#include	"../port/nonet.h"

#define DPRINT if(pnonet)print
#define NOW (MACHP(0)->ticks*MS2HZ)
#define MSUCC(x) (((x)+1)%Nnomsg)

static Noifc *noifc;
int pnonet;

enum {
	/*
	 *  tuning parameters
	 */
	MSrexmit = 250,		/* retranmission interval in ms */

	/*
	 *  relative or immutable
	 */
	Nsubdir = 5,		/* entries in the nonet directory */
	Nmask = Nnomsg - 1,	/* mask for log(Nnomsg) bits */
};

/* predeclared */
static void	nohangup(Noconv*);
static void	noreset(Noconv*);
static Block*	nohdr(Noconv*, int);
static void	nolisten(Chan*, Noifc*);
static void	noannounce(Chan*, char*);
static void	noconnect(Chan*, char*);
static void	norack(Noconv*, int);
static void	nosendctl(Noconv*, int, int);
static void	nosend(Noconv*, Nomsg*);
static void	nostartconv(Noconv*, int, char*, int);
static void	noqack(Noconv*, int);
static void	nokproc(void*);
static void	noiput(Queue*, Block*);
static void	nooput(Queue*, Block*);
static void	noclose(Queue*);
static void	noopen(Queue*, Stream*);

extern Qinfo	noetherinfo;
extern Qinfo	nonetinfo;

/*
 *  nonet directory and subdirectory
 */
enum {
	/*
	 *  per conversation
	 */
	Naddrqid,
	Nlistenqid,
	Nraddrqid,
	Nruserqid,
	Nstatsqid,
	Nchanqid,

	/*
	 *  per noifc
	 */
	Ncloneqid,
};

Dirtab *nonetdir;
Dirtab nosubdir[]={
	"addr",		{Naddrqid},	0,	0666,
	"listen",	{Nlistenqid},	0,	0666,
	"raddr",	{Nraddrqid},	0,	0666,
	"ruser",	{Nruserqid},	0,	0666,
	"stats",	{Nstatsqid},	0,	0666,
};

/*
 *  Nonet conversation states (for Noconv.state)
 */
enum {
	Cclosed=	0,
	Copen=		1,
	Cannounced=	2,
	Cconnected=	3,
	Cconnecting=	4,
	Chungup=	5,
	Creset=		6,
};

/*
 *  nonet kproc
 */
static int kstarted;
static Rendez nonetkr;

/*
 *  nonet file system.  most of the calls use dev.c to access the nonet
 *  directory and stream.c to access the nonet devices.
 *  create the nonet directory.  the files are `clone' and stream
 *  directories '1' to '32' (or whatever conf.noconv is in decimal)
 */
void
nonetreset(void)
{
	int i;

	/*
	 *  allocate the interfaces
	 */
	noifc = (Noifc *)ialloc(sizeof(Noifc) * conf.nnoifc, 0);
	for(i = 0; i < conf.nnoifc; i++)
		noifc[i].conv = (Noconv *)ialloc(sizeof(Noconv) * conf.nnoconv, 0);

	/*
	 *  create the directory.
	 */
	nonetdir = (Dirtab *)ialloc(sizeof(Dirtab) * (conf.nnoconv+1), 0);

	/*
	 *  the circuits
	 */
	for(i = 0; i < conf.nnoconv; i++) {
		sprint(nonetdir[i].name, "%d", i);
		nonetdir[i].qid.path = CHDIR|STREAMQID(i, Nchanqid);
		nonetdir[i].qid.vers = 0;
		nonetdir[i].length = 0;
		nonetdir[i].perm = 0777;
	}

	/*
	 *  the clone device
	 */
	strcpy(nonetdir[i].name, "clone");
	nonetdir[i].qid.path = Ncloneqid;
	nonetdir[i].qid.vers = 0;
	nonetdir[i].length = 0;
	nonetdir[i].perm = 0666;
}

void
nonetinit(void)
{
}

/*
 *  find an noifc and increment its count
 */
Chan*
nonetattach(char *spec)
{
	Noifc *ifc;
	Chan *c;

	/*
	 *  find an noifc with the same name
	 */
	if(*spec == 0)
		spec = "nonet";
	for(ifc = noifc; ifc < &noifc[conf.nnoifc]; ifc++){
		lock(ifc);
		if(strcmp(spec, ifc->name)==0 && ifc->wq) {
			ifc->ref++;
			unlock(ifc);
			break;
		}
		unlock(ifc);
	}
	if(ifc == &noifc[conf.nnoifc])
		error(Enoifc);
	c = devattach('n', spec);
	c->dev = ifc - noifc;

	return c;
}

/*
 *  up the reference count to the noifc
 */
Chan*
nonetclone(Chan *c, Chan *nc)
{
	Noifc *ifc;

	c = devclone(c, nc);
	ifc = &noifc[c->dev];
	lock(ifc);
	ifc->ref++;
	unlock(ifc);
	return c;
}

int	 
nonetwalk(Chan *c, char *name)
{
	if(c->qid.path == CHDIR)
		return devwalk(c, name, nonetdir, conf.nnoconv+1, devgen);
	else
		return devwalk(c, name, nosubdir, Nsubdir, streamgen);
}

void	 
nonetstat(Chan *c, char *dp)
{
	if(c->qid.path == CHDIR)
		devstat(c, dp, nonetdir, conf.nnoconv+1, devgen);
	else if(c->qid.path == Ncloneqid)
		devstat(c, dp, &nonetdir[conf.nnoconv], 1, devgen);
	else
		devstat(c, dp, nosubdir, Nsubdir, streamgen);
}

/*
 *  opening a nonet device allocates a Noconv.  Opening the `clone'
 *  device is a ``macro'' for finding a free Noconv and opening
 *  it's ctl file.
 */
Noconv *
nonetopenclone(Chan *c, Noifc *ifc)
{
	Noconv *cp;
	Noconv *ep;

	ep = &ifc->conv[conf.nnoconv];
	for(cp = &ifc->conv[0]; cp < ep; cp++){
		if(cp->state == Cclosed && canqlock(cp)){
			if(cp->state != Cclosed){
				qunlock(cp);
				continue;
			}
			c->qid.path = CHDIR|STREAMQID(cp-ifc->conv, Nchanqid);
			devwalk(c, "ctl", 0, 0, streamgen);
			streamopen(c, &nonetinfo);
			qunlock(cp);
			break;
		}
	}
	if(cp == ep)
		error(Enodev);
	return cp;
}

Chan*
nonetopen(Chan *c, int omode)
{
	Stream *s;
	Noifc *ifc;
	int line;

	if(!kstarted){
		kproc("nonetack", nokproc, 0);
		kstarted = 1;
	}

	if(c->qid.path & CHDIR){
		/*
		 *  directories are read only
		 */
		if(omode != OREAD)
			error(Ebadarg);
	} else switch(STREAMTYPE(c->qid.path)){
	case Ncloneqid:
		/*
		 *  get an unused device and open it's control file
		 */
		ifc = &noifc[c->dev];
		nonetopenclone(c, ifc);
		break;
	case Nlistenqid:
		/*
		 *  listen for a call and open the control file for the
		 *  channel on which the call arrived.
		 */
		line = STREAMID(c->qid.path);
		ifc = &noifc[c->dev];
		if(ifc->conv[line].state != Cannounced)
			error(Enolisten);
		nolisten(c, ifc);
		break;
	case Nraddrqid:
		/*
		 *  read only files
		 */
		if(omode != OREAD)
			error(Ebadarg);
		break;
	default:
		/*
		 *  open whatever c points to
		 */
		streamopen(c, &nonetinfo);
		break;
	}

	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

void	 
nonetcreate(Chan *c, char *name, int omode, ulong perm)
{
	USED(c, name, omode, perm);
	error(Eperm);
}

void	 
nonetclose(Chan *c)
{
	Noifc *ifc;

	if(c->stream)
		streamclose(c);

	/*
	 *  let go of the multiplexor
	 */
	nonetfreeifc(&noifc[c->dev]);
}

long	 
nonetread(Chan *c, void *a, long n, ulong offset)
{
	int t;
	Noconv *cp;
	char stats[256];

	/*
	 *  pass data/ctl reads onto the stream code
	 */
	t = STREAMTYPE(c->qid.path);
	if(t >= Slowqid)
		return streamread(c, a, n);

	if(c->qid.path == CHDIR)
		return devdirread(c, a, n, nonetdir, conf.nnoconv+1, devgen);
	if(c->qid.path & CHDIR)
		return devdirread(c, a, n, nosubdir, Nsubdir, streamgen);

	cp = &noifc[c->dev].conv[STREAMID(c->qid.path)];
	switch(t){
	case Nraddrqid:
		return stringread(a, n, cp->raddr, offset);
	case Naddrqid:
		return stringread(a, n, cp->addr, offset);
	case Nruserqid:
		return stringread(a, n, cp->ruser, offset);
	case Nstatsqid:
		sprint(stats, "sent: %d\nrcved: %d\nrexmit: %d\nbad: %d\n",
			cp->sent, cp->rcvd, cp->rexmit, cp->bad);
		return stringread(a, n, stats, offset);
	}
	error(Eperm);
}

long	 
nonetwrite(Chan *c, void *a, long n, ulong offset)
{
	int t;
	int m;
	char buf[256];
	char *field[5];

	t = STREAMTYPE(c->qid.path);

	/*
	 *  get data dispatched as quickly as possible
	 */
	if(t == Sdataqid)
		return streamwrite(c, a, n, 0);

	/*
	 *  easier to do here than in nooput
	 */
	if(t == Sctlqid){
		if(n > sizeof buf - 1)
			n = sizeof buf - 1;
		strncpy(buf, a, n);
		buf[n] = '\0';
		m = getfields(buf, field, 5, ' ');
		if(strcmp(field[0], "connect")==0){
			if(m < 2)
				error(Ebadarg);
			noconnect(c, field[1]);
		} else if(strcmp(field[0], "announce")==0){
			noannounce(c, field[1]);
		} else if(strcmp(field[0], "accept")==0){
			/* ignore */;
		} else if(strcmp(field[0], "reject")==0){
			/* ignore */;
		} else
			return streamwrite(c, a, n, 0);
		return n;
	}
	
	error(Eperm);
}

void	 
nonetremove(Chan *c)
{
	USED(c);
	error(Eperm);
}

void	 
nonetwstat(Chan *c, char *dp)
{
	USED(c, dp);
	error(Eperm);
}

/*
 *  the device stream module definition
 */
Qinfo nonetinfo =
{
	noiput,
	nooput,
	noopen,
	noclose,
	"nonet"
};

/*
 *  store the device end of the stream so that the multiplexor can
 *  send blocks upstream.
 *
 *	State Transition:	Cclosed -> Copen
 */
static void
noopen(Queue *q, Stream *s)
{
	Noifc *ifc;
	Noconv *cp;

	ifc = &noifc[s->dev];
	cp = &ifc->conv[s->id];
	cp->s = s;
	cp->ifc = ifc;
	cp->rq = RD(q);
	cp->state = Copen;
	RD(q)->ptr = WR(q)->ptr = (void *)cp;
}

/*
 *  wait until a hangup is received.
 *  then send a hangup message (until one is received).
 *
 *	State Transitions:	* -> Cclosed
 */
static int
ishungup(void *a)
{
	Noconv *cp;

	cp = (Noconv *)a;
	switch(cp->state){
	case Chungup:
	case Creset:
	case Cclosed:
		return 1;
	}
	return 0;
}
static int
isempty(void *a)
{
	Noconv *cp;

	cp = (Noconv *)a;
	switch(cp->state){
	case Cconnecting:
	case Cconnected:
		return cp->first == cp->next;
	default:
		return 1;
	}
}
static void
noclose(Queue *q)
{
	Noconv *cp;
	Nomsg *mp;
	int i;

	cp = (Noconv *)q->ptr;

	if(!waserror()){
		/*
		 *  wait till we have nothing to transmit
		 */
		while(!isempty(cp))
			tsleep(&cp->r, isempty, cp, MSrexmit);

		/*
		 *  send hangup messages to the other side
		 *  until it hangs up or we get tired.
		 */
		switch(cp->state){
		case Cconnecting:
		case Cconnected:
			/*
			 *  send close till we get one back
			 */
			nosendctl(cp, NO_HANGUP, 1);
			for(i=0; i<10 && !ishungup(cp); i++){
				nosendctl(cp, NO_HANGUP, 0);
				tsleep(&cp->r, ishungup, cp, MSrexmit);
			}
			break;
		case Chungup:
			/*
			 *  ack any close
			 */
			nosendctl(cp, NO_HANGUP, 1);
			break;
		}
		poperror();
	}

	/*
	 *  we give up, ack any unacked messages
	 */
	qlock(cp);
	for(i = cp->first; i != cp->next; i = MSUCC(i))
		norack(cp, cp->out[i].mid);
	cp->rcvcircuit = -1;
	cp->state = Cclosed;
	if(cp->media){
		freeb(cp->media);
		cp->media = 0;
	}
	qunlock(cp);
}

/*
 *  send all messages up stream.  this should only be control messages
 *
 *	State Transition:	(on M_HANGUP) * -> Chungup
 */
static void
noiput(Queue *q, Block *bp)
{
	Noconv *cp;

	if(bp->type == M_HANGUP){
		cp = (Noconv *)q->ptr;
		cp->state = Chungup;
	}
	PUTNEXT(q, bp);
}

/*
 *  queue a block
 */
enum {
	Window=	1,
};

static int
windowopen(void *a)
{
	Noconv *cp;
	int i;

	cp = (Noconv *)a;
	i = cp->next - cp->first;
	if(i>=0 && i<Window)	
		return 1;
	if(i<0 && Nnomsg+i<Window)
		return 1;
	return 0;	
}
static void
nooput(Queue *q, Block *bp)
{
	Noconv *cp;
	int next;
	Nomsg *mp;
	Block *first, *last;
	int len;

	cp = (Noconv *)(q->ptr);

	/*
	 *  do all control functions
	 */
	if(bp->type != M_DATA){
		freeb(bp);
		error(Ebadctl);
	}

	/*
	 *  collect till we see a delim
	 */
	qlock(&cp->mlock);
	if(!putb(q, bp)){
		qunlock(&cp->mlock);
		return;
	}

	/*
	 *  take the collected message out of the queue
	 */
	first = q->first;
	last = q->last;
	len = q->len;
	q->len = q->nb = 0;
	q->first = q->last = 0;
	if(len == 0){
		freeb(first);
		qunlock(&cp->mlock);
		return;
	}

	/*
	 *  block till we get an output buffer
	 */
	if(waserror()){
		freeb(first);
		qunlock(&cp->mlock);
		nexterror();
	}
	while(!windowopen(cp))
		sleep(&cp->r, windowopen, cp);
	mp = &cp->out[cp->next];
	cp->next = MSUCC(cp->next);
	qlock(cp);
	qunlock(&cp->mlock);
	poperror();

	/*
	 *  point the output buffer to the message
	 */
	mp->time = NOW + MSrexmit;
	mp->first = first;
	mp->last = last;
	mp->len = len;
	mp->mid ^= Nnomsg;
	mp->acked = 0;

	cp->sent++;

	/*
	 *  send the message, the kproc will retry
	 */
	if(!waserror()){
		nosend(cp, mp);
		poperror();
	}
	qunlock(cp);
}

/*
 *  start a new conversation.  start an ack/retransmit process if
 *  none already exists for this circuit.
 */
void
nostartconv(Noconv *cp, int circuit, char *raddr, int state)
{
	int i;
	char name[32];
	Noifc *ifc;

	ifc = cp->ifc;

	/*
	 *  allocate the prototype header
	 */
	cp->media = allocb(ifc->hsize + NO_HDRSIZE);
	cp->media->wptr += ifc->hsize + NO_HDRSIZE;
	cp->hdr = (Nohdr *)(cp->media->rptr + ifc->hsize);

	/*
	 *  fill in the circuit number
	 */
	cp->hdr->flag = NO_NEWCALL|NO_ACKME;
	cp->hdr->circuit[2] = circuit>>16;
	cp->hdr->circuit[1] = circuit>>8;
	cp->hdr->circuit[0] = circuit;

	/*
	 *  set the state variables
	 */
	cp->state = state;
	for(i = 1; i < Nnomsg; i++){
		cp->in[i].mid = i;
		cp->in[i].acked = 0;
		cp->in[i].rem = 0;
		cp->out[i].mid = i | Nnomsg;
		cp->out[i].acked = 1;
		cp->out[i].rem = 0;
	}
	cp->in[0].mid = Nnomsg;
	cp->in[0].acked = 0;
	cp->in[0].rem = 0;
	cp->out[0].mid = 0;
	cp->out[0].acked = 1;
	cp->out[0].rem = 0;
	cp->ack = 0;
	cp->sendack = 0;
	cp->first = cp->next = 1;
	cp->rexmit = cp->bad = cp->sent = cp->rcvd = 0;
	cp->lastacked = Nnomsg|(Nnomsg-1);

	/*
	 *  used for demultiplexing
	 */
	cp->rcvcircuit = circuit ^ 1;

	/*
	 *  media dependent header
	 */
	(*ifc->connect)(cp, raddr);

	/*
	 *  status files
	 */
	strncpy(cp->raddr, raddr, sizeof(cp->raddr));
	strcpy(cp->ruser, "none");
}

/*
 *  announce willingness to take calls
 *
 *	State Transition:	Copen -> Chungup
 */
static void
noannounce(Chan *c, char *addr)
{
	Noconv *cp;

	cp = (Noconv *)(c->stream->devq->ptr);
	if(cp->state != Copen)
		error(Einuse);
	cp->state = Cannounced;
}

/*
 *  connect to the destination whose name is pointed to by bp->rptr.
 *
 *  a service is separated from the destination system by a '!'
 *
 *	State Transition:	Copen -> Cconnecting
 */
static void
noconnect(Chan *c, char *addr)
{
	Noifc *ifc;
	Noconv *cp;
	char *service;
	char buf[2*NAMELEN+2];

	cp = (Noconv *)(c->stream->devq->ptr);
	if(cp->state != Copen)
		error(Einuse);
	ifc = cp->ifc;
	service = strchr(addr, '!');
	if(service){
		*service++ = 0;
		if(strchr(service, ' '))
			error(Ebadctl);
		if(strlen(service) > NAMELEN)
			error(Ebadctl);
	}

	nostartconv(cp, 2*(cp - ifc->conv), addr, Cconnecting);

	if(service){
		/*
		 *  send service name and user name
		 */
		cp->hdr->flag |= NO_SERVICE;
		sprint(buf, "%s %s", service, u->p->user);
		c->qid.path = STREAMQID(STREAMID(c->qid.path), Sdataqid);
		streamwrite(c, buf, strlen(buf), 1);
		c->qid.path = STREAMQID(STREAMID(c->qid.path), Sctlqid);
	}
}

/*
 *  listen for a call.  There can be many listeners, but only one can sleep
 *  on the circular queue at a time.  ifc->listenl lets only one at a time into
 *  the sleep.
 *
 *	State Transition:	Cclosed -> Copen -> Cconnecting
 */
static int
iscall(void *a)
{
	Noifc *ifc;

	ifc = (Noifc *)a;
	return ifc->rptr != ifc->wptr;
}
static void
nolisten(Chan *c, Noifc *ifc)
{
	Noconv *cp, *ep;
	Nocall call;
	int f;
	char buf[2*NAMELEN+4];
	char *user;
	long n;
	Block *bp;

	call.msg = 0;

	if(waserror()){
		if(call.msg)
			freeb(call.msg);
		qunlock(&ifc->listenl);
		nexterror();
	}

	for(;;){
		/*
		 *  one listener at a time
		 */
		qlock(&ifc->listenl);

		/*
		 *  wait for a call
		 */
		sleep(&ifc->listenr, iscall, ifc);
		call = ifc->call[ifc->rptr];
		ifc->rptr = (ifc->rptr+1) % Nnocalls;
		qunlock(&ifc->listenl);

		/*
		 *  make sure we aren't already using this circuit
		 */
		ep = &ifc->conv[conf.nnoconv];
		for(cp = &ifc->conv[0]; cp < ep; cp++){
			if(cp->state>Cannounced && (call.circuit^1)==cp->rcvcircuit
			&& strcmp(call.raddr, cp->raddr)==0)
				break;
		}
		if(cp != ep){
			freeb(call.msg);
			call.msg = 0;
			continue;
		}

		/*
		 *  get a free channel
		 */
		cp = nonetopenclone(c, ifc);
		c->qid.path = STREAMQID(cp - ifc->conv, Sctlqid);

		/*
		 *  start the protocol and
		 *  stuff the connect message into it
		 */
		f = ((Nohdr *)(call.msg->rptr))->flag;
		nostartconv(cp, call.circuit, call.raddr, Cconnecting);
		bp = call.msg;
		call.msg = 0;
		switch(nonetrcvmsg(cp, bp)){
		case -1:
			print("bad call message");
			streamclose(c);
			continue;
		case 0:
			if(f & NO_SERVICE){
				streamclose(c);
				print("bad call message");
				continue;
			}
			break;
		default:
			if(f & NO_SERVICE){
				c->qid.path = STREAMQID(cp - ifc->conv, Sdataqid);
				n = streamread(c, buf, sizeof(buf));
				c->qid.path = STREAMQID(cp - ifc->conv, Sctlqid);
				if(n <= 0)
					error(Ebadctl);
				buf[n] = 0;
				user = strchr(buf, ' ');
				if(user){
					*user++ = 0;
					strncpy(cp->ruser, user, NAMELEN);
				} else
					strcpy(cp->ruser, "none");
				strncpy(cp->addr, buf, NAMELEN);
			}
			break;
		}
		break;
	}
	poperror();
}

/*
 *  send a hangup signal up the stream to get all line disciplines
 *  to cease and desist
 *
 *	State Transition:	{Cconnected, Cconnecting} -> Chungup
 */
static void
nohangup(Noconv *cp)
{
	Block *bp;
	Queue *q;

	switch(cp->state){
	case Cconnected:
	case Cconnecting:
		cp->state = Chungup;
		bp = allocb(0);
		bp->type = M_HANGUP;
		q = cp->rq;
		PUTNEXT(q, bp);
		break;
	}
	wakeup(&cp->r);
}

/*
 *  Send a hangup signal up the stream to get all line disciplines
 *  to cease and desist.  Disassociate this conversation from a circuit
 *  number.  Any subsequent close of the conversation will
 *  not send hangup messages.
 *
 *	State Transition:	{Cconnected, Cconnecting, Chungup} -> Creset
 */
static void
noreset(Noconv *cp)
{
	Block *bp;
	Queue *q;

	switch(cp->state){
	case Cconnected:
	case Cconnecting:
	case Chungup:
		cp->state = Creset;
		cp->rcvcircuit = -1;
 		bp = allocb(0);
		bp->type = M_HANGUP;
		q = cp->rq;
		PUTNEXT(q, bp);
		break;
	}
	wakeup(&cp->r);
}

/*
 *  process a message acknowledgement.  if the message
 *  has any xmit buffers queued, free them.
 */
static void
norack(Noconv *cp, int mid)
{
	Nomsg *mp;
	Block *bp;
	int i;

	mp = &cp->out[mid & Nmask];

	/*
	 *  if already acked, ignore
	 */
	if(mp->acked || mp->mid != mid)
		return;

	/*
 	 *  free it
	 */
	cp->rexmit = 0;
	cp->lastacked = mid;
	mp->acked = 1;
	if(mp->first)
		freeb(mp->first);
	mp->first = 0;

	/*
	 *  advance first if this is the first
	 */
	if((mid&Nmask) == cp->first){
		while(cp->first != cp->next){
			if(cp->out[cp->first].acked == 0)
				break;
			cp->first = MSUCC(cp->first);
		}
		wakeup(&cp->r);
	}
}

/*
 *  queue an acknowledgement to be sent.  ignore it if we already have Nnomsg
 *  acknowledgements queued.
 */
static void
noqack(Noconv *cp, int mid)
{
	cp->ack = mid;
	cp->sendack = 1;
}

/*
 *  make a packet header
 */
Block *
nohdr(Noconv *cp, int rem)
{
	Block *bp;
	Nohdr *hp;

	bp = allocb(cp->ifc->hsize + NO_HDRSIZE + cp->ifc->mintu);
	memmove(bp->wptr, cp->media->rptr, cp->ifc->hsize + NO_HDRSIZE);
	bp->wptr += cp->ifc->hsize + NO_HDRSIZE;
	hp = (Nohdr *)(bp->rptr + cp->ifc->hsize);
	hp->remain[1] = rem>>8;
	hp->remain[0] = rem;
	hp->sum[0] = hp->sum[1] = 0;

	return bp;
}

/*
 *  transmit a message.  this involves breaking a possibly multi-block message into
 *  a train of packets on the media.
 *
 *  called by nooput().  the qlock(mp) synchronizes these two
 *  processes.
 */
static void
nosend(Noconv *cp, Nomsg *mp)
{
	Noifc *ifc;
	Queue *wq;
	int msgrem;
	int pktrem;
	int n;
	Block *bp, *pkt, *last;
	uchar *rptr;

	ifc = cp->ifc;
	if(ifc == 0)
		return;
	wq = ifc->wq->next;

	/*
	 *  get the next acknowledge to use if the next queue up
	 *  is not full.
	 */
	cp->sendack = 0;
	cp->hdr->ack = cp->ack;
	cp->hdr->mid = mp->mid;

	/*
	 *  package n blocks into m packets.  make sure
	 *  no packet is < mintu or > maxtu in length.
	 */
	if(ifc->mintu > mp->len) {
		/*
		 *  short message:
		 *  copy the whole message into the header block
		 */
		last = pkt = nohdr(cp, mp->len);
		for(bp = mp->first; bp; bp = bp->next){
			memmove(pkt->wptr, bp->rptr, n = BLEN(bp));
			pkt->wptr += n;
		}
		/*
		 *  round up to mintu
		 */
		memset(pkt->wptr, 0, n = ifc->mintu-mp->len);
		pkt->wptr += n;
	} else {
		/*
		 *  long message:
		 *  break up the message into noifc packets and send them.
		 *  once around this loop for each non-header block generated.
		 */
		msgrem = mp->len;
		pktrem = msgrem > ifc->maxtu ? ifc->maxtu : msgrem;
		bp = mp->first;
		SET(rptr);
		if(bp)
			rptr = bp->rptr;
		last = pkt = nohdr(cp, msgrem);
		n = 0;
		while(bp){
			/*
			 *  if pkt full, send and create new header block
			 */
			if(pktrem == 0){
				nonetcksum(pkt, ifc->hsize);
				last->flags |= S_DELIM;
				(*wq->put)(wq, pkt);
				last = pkt = nohdr(cp, -msgrem);
				pktrem = msgrem > ifc->maxtu ? ifc->maxtu : msgrem;
			}
			n = bp->wptr - rptr;
			if(n > pktrem)
				n = pktrem;
			last = last->next = allocb(0);
			last->rptr = rptr;
			last->wptr = rptr = rptr + n;
			msgrem -= n;
			pktrem -= n;
			if(rptr >= bp->wptr){
				bp = bp->next;
				if(bp)
					rptr = bp->rptr;
			}
		}
		/*
		 *  round up last packet to mintu
		 */
		if(n < ifc->mintu){
			n = ifc->mintu - n;
			last = last->next = allocb(n);
			memset(last->wptr, 0, n);
			last->wptr += n;
		}
	}
	nonetcksum(pkt, ifc->hsize);
	last->flags |= S_DELIM;
	if(cp->rexmit > 10)
		mp->time = NOW + 10*MSrexmit;
	else
		mp->time = NOW + (cp->rexmit+1)*MSrexmit;

	(*wq->put)(wq, pkt);
}

/*
 *  send a control message (hangup or acknowledgement).
 */
static void
nosendctl(Noconv *cp, int flag, int new)
{
	Nomsg ctl;

	ctl.len = 0;
	ctl.first = 0;
	ctl.acked = 0;
	if(new)
		ctl.mid = Nnomsg^cp->out[cp->next].mid;
	else
		ctl.mid = cp->lastacked;
	cp->hdr->flag |= flag;
	nosend(cp, &ctl);
}

/*
 *  receive a message (called by the multiplexor; noetheriput, nofddiiput, ...)
 *
 *	State Transition:	(no NO_NEWCALL in msg) Cconnecting -> Cconnected
 */
int
nonetrcvmsg(Noconv *cp, Block *bp)
{
	Block *nbp;
	Nohdr *h;
	short r;
	int c;
	Nomsg *mp;
	int f;
	Queue *q;

	q = cp->rq;

	/*
	 *  grab the packet header, push the pointer past the nonet header
	 */
	h = (Nohdr *)bp->rptr;
	bp->rptr += NO_HDRSIZE;
	mp = &cp->in[h->mid & Nmask];
	r = (h->remain[1]<<8) | h->remain[0];
	f = h->flag;

	/*
	 *  Obey reset even if the message id is bogus
	 */
	if(f & NO_RESET){
		DPRINT("reset received\n");
		noreset(cp);
		freeb(bp);
		return -1;
	}

	/*
	 *  A new call request (maybe), treat it as a reset if seen on a
	 *  connected, hungup, or reset channel.
	 *
 	 *  On a connecting channel, treat as a reset if this is an
	 *  invalid message ID.
	 */
	if(f & NO_NEWCALL){
		switch(cp->state){
		case Cclosed:
		case Copen:
		case Cannounced:
		case Creset:
			DPRINT("nonetrcvmsg %d %d\n", cp->rcvcircuit, cp - cp->ifc->conv);
			freeb(bp);
			return -1;
		case Chungup:
		case Cconnected:
			DPRINT("Nonet call on connected/hanging-up circ %d conv %d\n",
				cp->rcvcircuit, cp - cp->ifc->conv); 
			freeb(bp);
			noreset(cp);
			return -1;
		case Cconnecting:
			break;
		}
	}

	/*
	 *  ignore old messages and process the acknowledgement
	 */
	if(h->mid!=mp->mid || (f&NO_NULL)){
		DPRINT("old msg %d instead of %d r==%d\n", h->mid, mp->mid, r);
		if(r == 0){
			norack(cp, h->ack);
			if(f & NO_HANGUP)
				nohangup(cp);
		} else {
			if(r>0){
				norack(cp, h->ack);
				noqack(cp, h->mid);
			}
			cp->bad++;
		}
		freeb(bp);
		return -1;
	}

	if(r>=0){
		/*
		 *  start of message packet
		 */
		if(mp->first){
			DPRINT("mp->mid==%d mp->rem==%d r==%d\n", mp->mid, mp->rem, r);
			freeb(mp->first);
			mp->first = mp->last = 0;
			mp->len = 0;
		}
		mp->rem = r;
	} else {
		/*
		 *  a continuation
		 */
		if(-r != mp->rem) {
			DPRINT("mp->mid==%d mp->rem==%d r==%d\n", mp->mid, mp->rem, r);
			cp->bad++;
			freeb(bp);
			return -1;
		}
	}

	/*
	 *  take care of packets that were padded up
	 */
	mp->rem -= BLEN(bp);
	if(mp->rem < 0){
		if(-mp->rem <= BLEN(bp)){
			bp->wptr += mp->rem;
			mp->rem = 0;
		} else
			panic("nonetrcvmsg: short packet");
	}
	putb(mp, bp);

	/*
	 *  if the last chunk - pass it up the stream and wake any
	 *  waiting process.
	 *
	 *  if not, strip off the delimiter.
	 */
	if(mp->rem == 0){
		cp->hdr->flag &= ~(NO_NEWCALL|NO_SERVICE);
		norack(cp, h->ack);
		if(f & NO_ACKME)
			noqack(cp, h->mid);
		mp->last->flags |= S_DELIM;
		PUTNEXT(q, mp->first);
		r = mp->len;
		mp->first = mp->last = 0;
		mp->len = 0;
		cp->rcvd++;

		/*
		 *  cycle bufffer to next expected mid
		 */
		mp->mid ^= Nnomsg;

		/*
		 *  any NO_NEWCALL after this is another call
		 */
		if(cp->state==Cconnecting && !(f&NO_NEWCALL))
			cp->state = Cconnected;

		/*
		 *  hangup (after processing message)
		 */
		if(f & NO_HANGUP){
			DPRINT("hangup with message\n");
			nohangup(cp);
			return -1;
		}
		return r;
	} else {
		mp->last->flags &= ~S_DELIM;
		return 0;
	}
}


/*
 *  noifc
 */
/*
 *  Create an ifc.
 */
Noifc *
nonetnewifc(Queue *q, Stream *s, int maxtu, int mintu, int hsize,
	void (*connect)(Noconv *, char *))
{
	Noifc *ifc;
	int i;

	for(ifc = noifc; ifc < &noifc[conf.nnoifc]; ifc++){
		if(ifc->ref == 0){
			lock(ifc);
			if(ifc->ref) {
				/* someone was faster than us */
				unlock(ifc);
				continue;
			}
			RD(q)->ptr = WR(q)->ptr = (void *)ifc;
			for(i = 0; i < conf.nnoconv; i++)
				ifc->conv[i].rcvcircuit = -1;
			ifc->maxtu = maxtu - hsize - NO_HDRSIZE;
			ifc->mintu = mintu - hsize - NO_HDRSIZE;
			ifc->hsize = hsize;
			ifc->connect = connect;
			ifc->name[0] = 0;
			ifc->wq = WR(q);
			ifc->ref = 1;
			unlock(ifc);
			return ifc;
		}
	}
	error(Enoifc);
}

/*
 *  Free an noifc.
 */
void
nonetfreeifc(Noifc *ifc)
{
	lock(ifc);
	ifc->ref--;
	if(ifc->ref == 0)
		ifc->wq = 0;
	unlock(ifc);
}

/*
 *  calculate the checksum of a list of blocks.  ignore the first `offset' bytes.
 */
int
nonetcksum(Block *bp, int offset)
{
	uchar *ep, *p;
	int n;
	ulong s;
	Nohdr *hp;
	Block *first;

	s = 0;
	p = bp->rptr + offset;
	n = bp->wptr - p;
	hp = (Nohdr *)p;
	hp->sum[0] = hp->sum[1] = 0;
	for(;;){
		ep = p+(n&~0x7);
		while(p < ep) {
			s = s + s + p[0];
			s = s + s + p[1];
			s = s + s + p[2];
			s = s + s + p[3];
			s = s + s + p[4];
			s = s + s + p[5];
			s = s + s + p[6];
			s = s + s + p[7];
			s = (s&0xffff) + (s>>16);
			p += 8;
		}
		ep = p+(n&0x7);
		while(p < ep) {
			s = s + s + *p;
			p++;
		}
		s = (s&0xffff) + (s>>16);
		bp = bp->next;
		if(bp == 0)
			break;
		p = bp->rptr;
		n = BLEN(bp);
	}
	s = (s&0xffff) + (s>>16);
	hp->sum[1] = s>>8;
	hp->sum[0] = s;
	s &= 0xffff;
if(0)
	switch(s){
	case 0xac9f:
	case 0xc1a4:
	case 0xc41c:
	case 0xc46d:
		{ int i;
		print("%lux s,", s);
		for(bp = first; bp; bp = bp->next)
			for(i = 0; i < BLEN(bp); i++)
				print(" %ux", bp->rptr[i]);
		}
	}
	return s;
}

/*
 *  send acknowledges that need to be sent.  this happens at 1/2
 *  the retransmission interval.
 */
static void
nokproc(void *arg)
{
	Noifc *ifc;
	Noconv *cp, *ep;
	Nomsg *mp;

	USED(arg);
	cp = 0;
	ifc = 0;
	if(waserror()){
		if(ifc)
			unlock(ifc);
		if(cp)
			qunlock(cp);
	}

	for(;;){
		/*
		 *  loop through all active interfaces
		 */
		for(ifc = noifc; ifc < &noifc[conf.nnoifc]; ifc++){
			if(ifc->wq==0)
				continue;
			lock(ifc);
			if(ifc->wq==0){
				unlock(ifc);
				continue;
			}
			ifc->ref++;
			unlock(ifc);
	
			/*
			 *  loop through all active conversations
			 */
			ep = ifc->conv + conf.nnoconv;
			for(cp = ifc->conv; cp < ep; cp++){
				if(cp->state<=Copen || !canqlock(cp))
					continue;
				if(cp->state != Cconnected && cp->state != Cconnecting){
					qunlock(cp);
					continue;
				}
	
				/*
				 *  resend the first message
				 */
				if(cp->first!=cp->next && NOW>=cp->out[cp->first].time){
					mp = &(cp->out[cp->first]);
					if(cp->rexmit++ > 15){
						norack(cp, mp->mid);
						noreset(cp);
					} else
						nosend(cp, mp);
				}
	
				/*
				 *  get the acknowledges out
				 */
				if(cp->sendack){
					DPRINT("sending ack %d\n", cp->ack);
					nosendctl(cp, /*NO_NULL*/0, 0);
				}
				qunlock(cp);
			}
			nonetfreeifc(ifc);
		}
		tsleep(&nonetkr, return0, 0, MSrexmit);
	}
}

void
nonettoggle(void)
{
	pnonet ^= 1;
}


M port/devwren.c => port/devwren.c +10 -8
@@ 263,9 263,13 @@ wrenpart(int dev)
	ulong n;
	int i;

	scsiready(dev);
	scsisense(dev, buf);
	if (scsicap(dev, buf))
	if(scsiready(dev)){
		scsisense(dev, buf);
		if(scsiready(dev))
			print("scsi %d.%d not ready: sense 0x%2.2ux, code 0x%2.2ux\n",
				dev>>3, dev&7, buf[2], buf[12]);
	}
	if(scsicap(dev, buf))
		error(Eio);
	dp = &wren[dev];
	dp->drive = dev;


@@ 301,18 305,16 @@ wrenpart(int dev)
	 *  parse partition table.
	 */
	n = getfields(rawpart, line, Npart+1, '\n');
	if(n > 0 && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
	if(strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
		for(i = 1; i < n; i++){
			pp++;
			if(getfields(line[i], field, 3, ' ') != 3){
			if(getfields(line[i], field, 3, ' ') != 3)
				break;
			}
			strncpy(pp->name, field[0], NAMELEN);
			pp->start = strtoul(field[1], 0, 0);
			pp->end = strtoul(field[2], 0, 0);
			if(pp->start > pp->end || pp->start >= dp->p[0].end){
			if(pp->start > pp->end || pp->start >= dp->p[0].end)
				break;
			}
			dp->npart++;
		}
	}

M power/boot.c => power/boot.c +0 -112
@@ 5,9 5,6 @@
#define DEFSYS "bit!bootes"
#define DEFFILE "/mips/9"

char	*net;
char	*netdev;

Fcall	hdr;
char	*scmd;



@@ 22,21 19,6 @@ int cfd;
int efd;
int setkey;

typedef
struct address {
	char *name;
	char *cmd;
} Address;

Address addr[] = {
	{ "bootes", "connect 0800690203f3" },
	{ "helix", "connect 080069020427" },
	{ "spindle", "connect 0800690202df" },
	{ "r70", "connect 08002b04265d" },
	{ "fornax", "connect 00007701d2ba" },
	{ 0 }
};

/*
 *  predeclared
 */


@@ 45,7 27,6 @@ void	prerror(char *);
void	error(char *);
void	boot(int);
int	dkdial(char *);
int	nonetdial(char *);
int	bitdial(char *);
int	preamble(int);
void	srvcreate(char*, int);


@@ 116,75 97,6 @@ bitdial(char *arg)
}

int
nonetdial(char *arg)
{
	int efd, cfd, fd;
	Address *a;
	static int mounted;

	for(a = addr; a->name; a++){
		if(strcmp(a->name, arg) == 0)
			break;
	}
	if(a->name == 0){
		print("can't convert nonet address to ether address\n");
		return -1;
	}

	if(!mounted){
		/*
		 *  grab a lance channel, make it recognize ether type 0x900,
		 *  and push the nonet ethernet multiplexor onto it.
		 */
		efd = open("#l/ether/0/ctl", ORDWR);
		if(efd < 0){
			prerror("opening #l/ether/0/ctl");
			return -1;
		}
		if(write(efd, "connect 0x900", sizeof("connect 0x900")-1)<0){
			close(efd);
			prerror("connect 0x900");
			return -1;
		}
		if(write(efd, "push noether", sizeof("push noether")-1)<0){
			close(efd);
			prerror("push noether");
			return -1;
		}
		if(write(efd, "config nonet", sizeof("config nonet")-1)<0){
			close(efd);
			prerror("config nonet");
			return -1;
		}
		mounted = 1;
	}

	/*
	 *  grab a nonet channel and call up the file server
	 */
	fd = open("#nnonet/2/data", ORDWR);
	if(fd < 0) {
		prerror("opening #nnonet/2/data");
		return -1;
	}
	cfd = open("#nnonet/2/ctl", ORDWR);
	if(cfd < 0){
		close(fd);
		prerror("opening #nnonet/2/ctl");
		return -1;
	}
	if(write(cfd, a->cmd, strlen(a->cmd))<0){
		close(cfd);
		close(fd);
		prerror(a->cmd);
		return -1;
	}
	net = "nonet";
	netdev = "#nnonet";
	return fd;
}

int
dkdial(char *arg)
{
	int fd;


@@ 235,8 147,6 @@ dkdial(char *arg)
		prerror(cmd);
		return -1;
	}
	net = "dk";
	netdev = "#k";
	return fd;
}



@@ 370,10 280,6 @@ boot(int ask)
			fd = hotdial(&sys[4]);
		else if(strncmp(sys, "dk!", 3) == 0)
			fd = dkdial(&sys[3]);
		else if(strncmp(sys, "nonet!", 6) == 0)
			fd = nonetdial(&sys[6]);
		else
			fd = nonetdial(sys);
		if(fd >= 0)
			break;
		print("can't connect, retrying...\n");


@@ 391,8 297,6 @@ boot(int ask)
	srvcreate("bootes", fd);

	print("mount...");
	if(bind("/", "/", MREPL) < 0)
		error("bind");
	if(mount(fd, "/", MAFTER|MCREATE, "", "") < 0)
		error("mount");



@@ 400,22 304,6 @@ boot(int ask)

	print("success\n");

	if(netdev){
		char buf[64];
		sprint(buf, "/net/%s", net);
		if(strcmp(netdev, "#k")==0)
			bind(netdev, "/net", MBEFORE);
		else
			bind(netdev, buf, MREPL);
		bind(buf, "/net/net", MREPL);
	}
	if(net){
		char buf[64];
		sprint(buf, "/lib/netaddr.%s", net);
		print("binding %s onto /lib/netaddr.net\n", buf);
		bind(buf, "/lib/netaddr.net", MREPL);
	}

	if(ask){
		execl("/mips/init", "init", "-mc", 0);
	} else {