Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/devnonet.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/devnonet.c 1990/1210
## diff -e /dev/null /n/bootesdump/1990/1210/sys/src/9/port/devnonet.c
0a
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"errno.h"

#define DPRINT if(0)
#define NOW (MACHP(0)->ticks*MS2HZ)

static Noifc *noifc;

enum {
	/*
	 *  tuning parameters
	 */
	MSrexmit = 500,	/* retranmission interval in ms */
	MSack = 50,		/* ms to sit on an ack */

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

/* predeclared */
static void	hangup(Noconv*);
static Block*	mkhdr(Noconv*, int);
static void	listen(Chan*, Noifc*);
static void	announce(Chan*, char*);
static void	connect(Chan*, char*);
static void	rcvack(Noconv*, int);
static void	sendctlmsg(Noconv*, int, int);
static void	sendmsg(Noconv*, Nomsg*);
static void	startconv(Noconv*, int, char*, int);
static void	queueack(Noconv*, int);

static void	nonetiput(Queue*, Block*);
static void	nonetoput(Queue*, Block*);
static void	nonetstclose(Queue*);
static void	nonetstopen(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,	0600,
	"listen",	{Nlistenqid},	0,	0600,
	"raddr",	{Nraddrqid},	0,	0600,
	"ruser",	{Nruserqid},	0,	0600,
	"stats",	{Nstatsqid},	0,	0600,
};

/*
 *  Nonet conversation states (for Noconv.state)
 */
enum {
	Cclosed,
	Copen,
	Cannounced,
	Cconnected,
	Cconnecting,
	Chungup,
	Cclosing,
};

/*
 *  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.nnoconv; 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 = 0600;
	}

	/*
	 *  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 = 0600;
}

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, 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;
	Noconv *cp;
	Noifc *ifc;
	int line;

	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];
		cp = 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(Enoannounce);
		listen(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)
{
	error(Eperm);
}

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

	/*
	 *  real closing happens in nonetstclose
	 */
	if(c->qid.path != CHDIR)
		streamclose(c);

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

long	 
nonetread(Chan *c, void *a, long n)
{
	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(c, a, n, cp->raddr);
	case Naddrqid:
		return stringread(c, a, n, cp->addr);
	case Nruserqid:
		return stringread(c, a, n, cp->ruser);
	case Nstatsqid:
		sprint(stats, "sent: %d\nrcved: %d\nrexmit: %d\nbad: %d\n",
			cp->sent, cp->rcvd, cp->rexmit, cp->bad);
		return stringread(c, a, n, stats);
	}
	error(Eperm);
}

long	 
nonetwrite(Chan *c, void *a, long n)
{
	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 nonetoput
	 */
	if(t == Sctlqid){
		strncpy(buf, a, sizeof buf);
		m = getfields(buf, field, 5, ' ');
		if(strcmp(field[0], "connect")==0){
			if(m < 2)
				error(Ebadarg);
			connect(c, field[1]);
		} else if(strcmp(field[0], "announce")==0){
			announce(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)
{
	error(Eperm);
}

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

/*
 *  the device stream module definition
 */
Qinfo nonetinfo =
{
	nonetiput,
	nonetoput,
	nonetstopen,
	nonetstclose,
	"nonet"
};

/*
 *  store the device end of the stream so that the multiplexor can
 *  send blocks upstream.
 */
static void
nonetstopen(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).
 */
static int
ishungup(void *a)
{
	Noconv *cp;

	cp = (Noconv *)a;
	return cp->state == Chungup;
}
static void
nonetstclose(Queue *q)
{
	Noconv *cp;
	Nomsg *mp;
	int i;

	cp = (Noconv *)q->ptr;

	if(waserror()){
		cp->rcvcircuit = -1;
		cp->state = Cclosed;
		nexterror();
	}

	/*
	 *  send hangup messages to the other side
	 *  until it hangs up or we get tired.
	 */
	if(cp->state >= Cconnected){
		sendctlmsg(cp, NO_HANGUP, 1);
		for(i=0; i<10 && !ishungup(cp); i++){
			sendctlmsg(cp, NO_HANGUP, 1);
			tsleep(&cp->r, ishungup, cp, MSrexmit);
		}
	}

	cp->rcvcircuit = -1;
	cp->state = Cclosed;
	poperror();
}

/*
 *  send all messages up stream.  this should only be control messages
 */
static void
nonetiput(Queue *q, Block *bp)
{
	Noconv *cp;

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

/*
 *  queue a block
 */
static int
windowopen(void *a)
{
	Noconv *cp;

	cp = (Noconv *)a;
	return cp->out[cp->next].inuse == 0;	
}
static int
acked(void *a)
{
	Nomsg *mp;

	mp = (Nomsg *)a;
	return mp->acked;
}
static void
nonetoput(Queue *q, Block *bp)
{
	Noconv *cp;
	int next;
	Nomsg *mp;

	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;
	}

	mp = 0;
	if(waserror()){
		if(mp){
			if(mp->first){
				freeb(mp->first);
				mp->first = 0;
			}
			mp->inuse = 0;
		} else
			qunlock(&cp->mlock);
	}

	/*
	 *  block till we get a buffer
	 */
	while(cp->out[cp->next].inuse)
		sleep(&cp->r, windowopen, cp);
	mp = &cp->out[cp->next];
	mp->inuse = 1;
	cp->next = (cp->next+1)%Nnomsg;

	/*
	 *  stick the message in a Nomsg structure
	 */
	mp->time = NOW + MSrexmit;
	mp->first = q->first;
	mp->last = q->last;
	mp->len = q->len;
	mp->mid ^= Nnomsg;
	mp->acked = 0;

	/*
	 *  init the queue for new messages
	 */
	q->len = 0;
	q->first = q->last = 0;
	cp->sent++;
	qunlock(&cp->mlock);

	/*
	 *  wait for acknowledgement
	 */
	while(!mp->acked && cp->state!=Chungup){
		sendmsg(cp, mp);
		tsleep(&mp->r, acked, mp, MSrexmit);
	}

	/*
	 *  free buffer
	 */
	freeb(mp->first);
	mp->first = 0;
	mp->inuse = 0;
	wakeup(&cp->r);
	poperror();
}

/*
 *  start a new conversation.  start an ack/retransmit process if
 *  none already exists for this circuit.
 */
void
startconv(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->out[i].inuse = 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->first = cp->next = 1;
	cp->rexmit = cp->bad = cp->sent = cp->rcvd = cp->lastacked = 0;

	/*
	 *  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
 */
static void
announce(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 '!'
 */
static void
connect(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);
	}

	startconv(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->pgrp->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.
 */
static int
iscall(void *a)
{
	Noifc *ifc;

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

	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==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;
		startconv(cp, call.circuit, call.raddr, Cconnecting);
		print("rcving %d byte message\n", call.msg->wptr - call.msg->rptr);
		nonetrcvmsg(cp, call.msg);
		call.msg = 0;

		/*
		 *  if a service and remote user were specified,
		 *  grab them
		 */
		if(f & NO_SERVICE){
			print("reading service\n");
			c->qid.path = STREAMQID(cp - ifc->conv, Sdataqid);
			n = streamread(c, buf, sizeof(buf));
			c->qid.path = STREAMQID(cp - ifc->conv, Sctlqid);
			print("read %d bytes\n", n);
			if(n <= 0)
				error(Ebadctl);
			buf[n] = 0;
			print("read %s\n", buf);
			user = strchr(buf, ' ');
			if(user){
				*user++ = 0;
				strncpy(cp->ruser, user, NAMELEN);
			} else
				strcpy(cp->ruser, "none");
			strncpy(cp->addr, buf, NAMELEN);
		}
		break;
	}
	poperror();
}

/*
 *  send a hangup signal up the stream to get all line disciplines
 *  to cease and desist
 */
static void
hangup(Noconv *cp)
{
	Block *bp;
	Queue *q;

	cp->state = Chungup;
	bp = allocb(0);
	bp->type = M_HANGUP;
	q = cp->rq;
	PUTNEXT(q, bp);
	wakeup(&cp->r);
}

/*
 *  process a message acknowledgement.  if the message
 *  has any xmit buffers queued, free them.
 */
static void
rcvack(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;

	/*
	 *  wakeup the sender
	 */
	mp->acked = 1;
	wakeup(&mp->r);
	cp->lastacked = mid;
}

/*
 *  queue an acknowledgement to be sent.  ignore it if we already have Nnomsg
 *  acknowledgements queued.
 */
static void
queueack(Noconv *cp, int mid)
{
	int next;
	ulong now;

	now = NOW;
	next = (cp->anext + 1)&Nmask;
	if(next != cp->afirst){
		cp->ack[cp->anext] = mid;
		cp->anext = next;
	}
}

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

	bp = allocb(cp->ifc->hsize + NO_HDRSIZE + cp->ifc->mintu);
	memcpy(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 nonetoput().  the qlock(mp) synchronizes these two
 *  processes.
 */
static void
sendmsg(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;

	/*
	 *  one transmitter at a time
	 */
	qlock(&cp->xlock);

	if(waserror()){
		qunlock(&cp->xlock);
		return;
	}

	/*
	 *  get the next acknowledge to use if the next queue up
	 *  is not full.
	 */
	if(cp->afirst != cp->anext && cp->rq->next->len < 16*1024){
		cp->hdr->ack = cp->ack[cp->afirst];
		cp->afirst = (cp->afirst+1)&Nmask;
	}
	cp->hdr->mid = mp->mid;

	if(ifc->mintu > mp->len) {
		/*
		 *  short message:
		 *  copy the whole message into the header block
		 */
		last = pkt = mkhdr(cp, mp->len);
		for(bp = mp->first; bp; bp = bp->next){
			memcpy(pkt->wptr, bp->rptr, n = BLEN(bp));
			pkt->wptr += n;
		}
		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;
		if(bp)
			rptr = bp->rptr;
		last = pkt = mkhdr(cp, msgrem);
		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 = mkhdr(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;
			}
		}
	}
	nonetcksum(pkt, ifc->hsize);
	last->flags |= S_DELIM;
	(*wq->put)(wq, pkt);
	mp->time = NOW + MSrexmit;
	qunlock(&cp->xlock);
	poperror();
}

/*
 *  send a control message (hangup or acknowledgement).
 */
static void
sendctlmsg(Noconv *cp, int flag, int new)
{
	cp->ctl.len = 0;
	cp->ctl.first = 0;
	cp->ctl.acked = 0;
	if(new)
		cp->ctl.mid = Nnomsg^cp->out[cp->next].mid;
	else
		cp->ctl.mid = cp->lastacked;
	cp->hdr->flag |= flag;
	sendmsg(cp, &cp->ctl);
}

/*
 *  receive a message (called by the multiplexor; noetheriput, nofddiiput, ...)
 */
void
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;

	/*
	 *  if a new call request comes in on a connected channel, hang up the call
	 */
	if(h->mid==0 && (f & NO_NEWCALL) && cp->state==Cconnected){
		freeb(bp);
		hangup(cp);
		return;
	}

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

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

	/*
	 *  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){
		rcvack(cp, h->ack);
		if(f & NO_ACKME)
			queueack(cp, h->mid);
		mp->last->flags |= S_DELIM;
		PUTNEXT(q, mp->first);
		mp->first = mp->last = 0;
		mp->len = 0;
		cp->rcvd++;

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

		/*
		 *  stop xmitting the NO_NEWCALL flag
		 */
		if(cp->state==Cconnecting && !(f & NO_NEWCALL))
			cp->state = Cconnected;
	} else
		mp->last->flags &= ~S_DELIM;

}

/*
 *  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)
{
	Block *nbp = bp;
	uchar *ep, *p;
	int n;
	ulong s;
	Nohdr *hp;

	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;
	return s & 0xffff;
}
.
## diffname port/devnonet.c 1990/1214
## diff -e /n/bootesdump/1990/1210/sys/src/9/port/devnonet.c /n/bootesdump/1990/1214/sys/src/9/port/devnonet.c
1192d
961a
		SET(rptr);
.
871d
869d
255c
		nonetopenclone(c, ifc);
.
239d
## diffname port/devnonet.c 1990/1229
## diff -e /n/bootesdump/1990/1214/sys/src/9/port/devnonet.c /n/bootesdump/1990/1229/sys/src/9/port/devnonet.c
1229a
}

nonettoggle()
{
	pnonet ^= 1;
.
1042a
		DPRINT("new call on connected channel\n"); 
.
105c
	for(i = 0; i < conf.nnoifc; i++)
.
18c
	MSrexmit = 500,		/* retranmission interval in ms */
.
12a
int pnonet;
.
9c
#define DPRINT if(pnonet)print
.
## diffname port/devnonet.c 1990/1231
## diff -e /n/bootesdump/1990/1229/sys/src/9/port/devnonet.c /n/bootesdump/1990/1231/sys/src/9/port/devnonet.c
1061c
				sendack(cp, h->mid);
.
1015a
 *  send an acknowledgement
 */
static void
sendack(Noconv *cp, int ack)
{
	cp->ackmsg.len = 0;
	cp->ackmsg.first = 0;
	cp->ackmsg.acked = ack;
	cp->ackmsg.mid = cp->lastacked;
	sendmsg(cp, &cp->ctl);
}

/*
.
783a
		print("call from %d %s\n", call.circuit, call.raddr);
.
707a
		print("request sent\n");
.
706a
		print("sending request\n");
.
39a
static void	sendack(Noconv*, int);
.
## diffname port/devnonet.c 1991/0102
## diff -e /n/bootesdump/1990/1231/sys/src/9/port/devnonet.c /n/bootesdump/1991/0102/sys/src/9/port/devnonet.c
1077,1078c
			if(r>0){
				queueack(cp, h->mid);
				sendctlmsg(cp, 0, 0);
			}
.
1020,1032d
1016c
	sendmsg(cp, &ctl);
.
1014c
		ctl.mid = cp->lastacked;
.
1012c
		ctl.mid = Nnomsg^cp->out[cp->next].mid;
.
1008,1010c
	Nomsg ctl;

	ctl.len = 0;
	ctl.first = 0;
	ctl.acked = 0;
.
924c
	 *  one transmitter at a time for this connection
.
40d
## diffname port/devnonet.c 1991/0108
## diff -e /n/bootesdump/1991/0102/sys/src/9/port/devnonet.c /n/bootesdump/1991/0108/sys/src/9/port/devnonet.c
1244a

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

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

loop:
	for(ifc = noifc; ifc < &noifc[conf.nnoifc]; ifc++){
		if(ifc->wq==0 || !canlock(ifc))
			continue;
		ep = ifc->conv + conf.nnoconv;
		for(cp = ifc->conv; cp < ep; cp++){
			if(cp->state==Cclosed || !canqlock(cp))
				continue;
			if(cp->afirst != cp->anext){
				DPRINT("sending ack %d\n", cp->ack[cp->afirst]);
				sendctlmsg(cp, 0, 0);
			}
			qunlock(cp);
		}
		unlock(ifc);
	}
	tsleep(&nonetkr, return0, 0, MSrexmit/2);
	goto loop;
}

.
1067d
1065a
				rcvack(cp, h->ack);
.
1059c
		DPRINT("old msg %d instead of %d r==%d\n", h->mid, mp->mid, r);
.
805d
801d
797c
			DPRINT("reading service\n");
.
788c
		DPRINT("rcving %d byte message\n", call.msg->wptr - call.msg->rptr);
.
786c
		DPRINT("call from %d %s\n", call.circuit, call.raddr);
.
709c
		DPRINT("request sent\n");
.
707c
		DPRINT("sending request\n");
.
578a
		if(retries++ > 100)
			errors("to many nonet rexmits");
.
575a
	retries = 0;
.
513a
	int retries;
.
470a
	qunlock(cp);
.
468a
	qlock(cp);
.
242a
	if(!kstarted){
		kproc("nonetack", nonetkproc, 0);
		kstarted = 1;
	}

.
166a

.
91a
 *  nonet kproc
 */
static int kstarted;
static Rendez nonetkr;

/*
.
40c
static void	nonetkproc(void*);
.
19c
	MSrexmit = 250,		/* retranmission interval in ms */
.
## diffname port/devnonet.c 1991/0109
## diff -e /n/bootesdump/1991/0108/sys/src/9/port/devnonet.c /n/bootesdump/1991/0109/sys/src/9/port/devnonet.c
606d
597a
	poperror();
.
596c
			errors("too many nonet rexmits");
.
557,558c
		}
		qunlock(&cp->mlock);
		nexterror();
.
## diffname port/devnonet.c 1991/0112
## diff -e /n/bootesdump/1991/0109/sys/src/9/port/devnonet.c /n/bootesdump/1991/0112/sys/src/9/port/devnonet.c
784c
			if(cp->state>Cannounced && (call.circuit^1)==cp->rcvcircuit
.
## diffname port/devnonet.c 1991/01151
## diff -e /n/bootesdump/1991/0112/sys/src/9/port/devnonet.c /n/bootesdump/1991/01151/sys/src/9/port/devnonet.c
1297c
void
nonettoggle(void)
.
1284a
			if(cp->state == Cclosed){
				qunlock(cp);
				continue;
			}

			/*
			 *  resend the first message
			 */
			if(cp->first!=cp->next && cp->out[cp->first].time>=NOW){
				if(cp->rexmit++ > 100){
					print("hanging up\n");
					hangup(cp);
				} else
					sendmsg(cp, &(cp->out[cp->first]));
			}

			/*
			 *  resend an acknowledge
			 */
.
1280a

		/*
		 *  loop through all active conversations
		 */
.
1277a
	/*
	 *  loop through all active interfaces
	 */
.
1108c
			DPRINT("mp->mid==%d mp->rem==%d r==%d\n", mp->mid, mp->rem, r);
.
1097,1100c
			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;
.
878a
	freeb(mp->first);
	mp->first = 0;
	mp->inuse = 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 = (cp->first+1) % Nnomsg;
		}
	}
.
877d
875a
	cp->rexmit = 0;
.
874c
 	 *  free it
.
600,607d
592,598c
	sendmsg(cp, mp);
	qunlock(&cp->mlock);
.
590c
	 *  send the message, the kproc will retry
.
587d
556a
			mp->acked = 0;
			if(((cp->first+1)%Nnomsg) == cp->next)
				cp->first = cp->next;
.
551a
			q->len = 0;
			q->first = q->last = 0;
.
520c
	return mp->inuse;
.
## diffname port/devnonet.c 1991/0118
## diff -e /n/bootesdump/1991/01151/sys/src/9/port/devnonet.c /n/bootesdump/1991/0118/sys/src/9/port/devnonet.c
1309,1310c
				} else {
					mp = &(cp->out[cp->first]);
					sendmsg(cp, mp);
				}
.
1305,1306c
			if(cp->first!=cp->next && NOW>=cp->out[cp->first].time){
				if(cp->rexmit++ > 60){
.
1271a
	Nomsg *mp;
.
1073c
		if(cp->state != Csuperceded){
			cp->state = Csuperceded;
			hangup(cp);
		}
.
1070c
	if(h->mid==0 && (f & NO_NEWCALL)
	&& (cp->state==Cconnected || cp->state==Csuperceded)){
.
1018d
1016a
	if(cp->rexmit > 10)
		mp->time = NOW + 10*MSrexmit;
	else
		mp->time = NOW + (cp->rexmit+1)*MSrexmit;
	DPRINT("xmit %d %lud %lud\n", cp->rexmit, NOW, mp->time);
.
1013a
		/*
		 *  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;
		}
.
988a
		n = 0;
.
974c
		/*
		 *  round up to mintu
		 */
		memset(pkt->wptr, 0, n = ifc->mintu-mp->len);
.
963a
	/*
	 *  package n blocks into m packets.  make sure
	 *  no packet is < mintu or > maxtu in length.
	 */
.
473c
	if(cp->state>=Cconnected && cp->state!=Csuperceded){
.
88a
	Csuperceded,
.
## diffname port/devnonet.c 1991/0119
## diff -e /n/bootesdump/1991/0118/sys/src/9/port/devnonet.c /n/bootesdump/1991/0119/sys/src/9/port/devnonet.c
1347c
				nosendctl(cp, 0, 0);
.
1338c
					nosend(cp, mp);
.
1335c
					nohangup(cp);
.
1294c
nokproc(void *arg)
.
1189a

.
1184a

		/*
		 *  hangup (after processing message)
		 */
		if(f & NO_RESET){
			DPRINT("reset with message\n");
			noreset(cp);
		} else if(f & NO_HANGUP){
			DPRINT("hangup with message\n");
			nohangup(cp);
		}
.
1183c
		if(cp->state==Cconnecting && !(f&NO_NEWCALL))
.
1181c
		 *  any NO_NEWCALL after this is another call
.
1168c
			noqack(cp, h->mid);
.
1166c
		cp->hdr->flag &= ~(NO_NEWCALL|NO_SERVICE);
		norack(cp, h->ack);
.
1114,1115c
				norack(cp, h->ack);
				noqack(cp, h->mid);
.
1109,1111c
			norack(cp, h->ack);
			if(f & NO_RESET)
				noreset(cp);
			else if(f & NO_HANGUP)
				nohangup(cp);
.
1096,1099c
		noreset(cp);
.
1092,1093c
	if((f&NO_NEWCALL) && cp->state==Cconnected){
.
1065a
 *
 *	State Transition:	(no NO_NEWCALL in msg) Cconnecting -> Cconnected
.
1061c
	nosend(cp, &ctl);
.
1049c
nosendctl(Noconv *cp, int flag, int new)
.
1039d
1006c
				last = pkt = nohdr(cp, -msgrem);
.
996c
		last = pkt = nohdr(cp, msgrem);
.
974c
		last = pkt = nohdr(cp, mp->len);
.
930c
nosend(Noconv *cp, Nomsg *mp)
.
926c
 *  called by nooput().  the qlock(mp) synchronizes these two
.
907c
nohdr(Noconv *cp, int rem)
.
892c
noqack(Noconv *cp, int mid)
.
851c
norack(Noconv *cp, int mid)
.
846a
 *  send a hangup signal up the stream to get all line disciplines
 *  to cease and desist.  The Creset state makes any subsequent close not
 *  send hangup messages.
 *
 *	State Transition:	{Cconnected, Cconnecting} -> Creset
 */
static void
noreset(Noconv *cp)
{
	Block *bp;
	Queue *q;

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

/*
.
838,842c
	switch(cp->state){
	case Cconnected:
	case Cconnecting:
		cp->state = Chungup;
		bp = allocb(0);
		bp->type = M_HANGUP;
		q = cp->rq;
		PUTNEXT(q, bp);
		break;
	}
.
833c
nohangup(Noconv *cp)
.
830a
 *
 *	State Transition:	{Cconnected, Cconnecting} -> Chungup
.
798c
		nostartconv(cp, call.circuit, call.raddr, Cconnecting);
.
739c
nolisten(Chan *c, Noifc *ifc)
.
728a
 *
 *	State Transition:	Cclosed -> Copen -> Cconnecting
.
720d
718d
709c
	nostartconv(cp, 2*(cp - ifc->conv), addr, Cconnecting);
.
689c
noconnect(Chan *c, char *addr)
.
686a
 *
 *	State Transition:	Copen -> Cconnecting
.
673c
noannounce(Chan *c, char *addr)
.
670a
 *
 *	State Transition:	Copen -> Chungup
.
650c
	cp->rexmit = cp->bad = cp->sent = cp->rcvd = 0;
	cp->lastacked = Nnomsg|(Nnomsg-1);
.
607c
nostartconv(Noconv *cp, int circuit, char *raddr, int state)
.
597c
	nosend(cp, mp);
.
524c
nooput(Queue *q, Block *bp)
.
493c
noiput(Queue *q, Block *bp)
.
490a
 *
 *	State Transition:	(on M_HANGUP) * -> Chungup
.
479a
		break;
	case Chungup:
		/*
		 *  ack any close
		 */
		nosendctl(cp, NO_HANGUP, 1);
		break;
.
477c
			nosendctl(cp, NO_HANGUP, 1);
.
474,475c
	switch(cp->state){
	case Cconnected:
		/*
		 *  send close till we get one back
		 */
		nosendctl(cp, NO_HANGUP, 1);
.
456c
noclose(Queue *q)
.
453c
	switch(cp->state){
	case Chungup:
	case Creset:
	case Cclosed:
		return 1;
	}
	return 0;
.
445a
 *
 *	State Transitions:	* -> Cclosed
.
429c
noopen(Queue *q, Stream *s)
.
426a
 *
 *	State Transition:	Cclosed -> Copen
.
417,420c
	noiput,
	nooput,
	noopen,
	noclose,
.
387c
			noannounce(c, field[1]);
.
385c
			noconnect(c, field[1]);
.
377c
	 *  easier to do here than in nooput
.
314c
	 *  real closing happens in noclose
.
279c
		nolisten(c, ifc);
.
252c
		kproc("nonetack", nokproc, 0);
.
88,89c
	Creset,
.
30,44c
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*);
.
## diffname port/devnonet.c 1991/0206
## diff -e /n/bootesdump/1991/0119/sys/src/9/port/devnonet.c /n/bootesdump/1991/0206/sys/src/9/port/devnonet.c
1418c
			while(cp->afirst != cp->anext){
.
1416c
			 *  get the acknowledges out
.
1412d
1409,1410c
				} else
.
1407c
					norack(cp, mp->mid);
.
1405a
				mp = &(cp->out[cp->first]);
.
944a
		wakeup(&cp->r);
.
943c
			cp->first = MSUCC(cp->first);
.
934d
931a
	mp->acked = 1;
.
930d
664d
621c
	qunlock(cp);
.
619a
	if(waserror()){
		/* throw out the message */
		freeb(mp->first);
		mp->first = 0;
		mp->acked = 0;
		if(MSUCC(cp->first) == cp->next)
			cp->first = cp->next;
		qunlock(cp);
		nexterror();
	}
.
613c
	q->len = q->nb = 0;
.
611c
	 *  take the message out of the queue
.
601c
	 *  point the output buffer to the message
.
597,598c
	cp->next = MSUCC(cp->next);
	qlock(cp);
	qunlock(&cp->mlock);
	poperror();
.
590,594c
	while(!windowopen(cp))
.
575,586c
		/* throw out the message */
		while(bp = getb(q))
			freeb(bp);
.
573c
	/*
	 *  block till we get an output buffer
	 */
.
538,545d
536c
	return MSUCC(cp->next) != cp->first;	
.
506a

.
503a
	/*
	 *  we give up, ack any unacked messages
	 */
	for(i = cp->first; i != cp->next; i = MSUCC(i))
		norack(cp, cp->out[i].mid);
.
10a
#define MSUCC(x) (((x)+1)%Nnomsg)
.
## diffname port/devnonet.c 1991/0207
## diff -e /n/bootesdump/1991/0206/sys/src/9/port/devnonet.c /n/bootesdump/1991/0207/sys/src/9/port/devnonet.c
1416c
			while(cp->afirst!=cp->anext && cp->rq->next->len<16*1024){
.
543c
	i = cp->next - cp->first;
	if(i>=0 && i<32)	
		return 1;
	if(i<0 && Nnomsg+i<32)
		return 1;
	return 0;	
.
540a
	int i;
.
## diffname port/devnonet.c 1991/0209
## diff -e /n/bootesdump/1991/0207/sys/src/9/port/devnonet.c /n/bootesdump/1991/0209/sys/src/9/port/devnonet.c
1414c
					noreset(cp);
.
1412c
				if(cp->rexmit++ > 15){
.
1106,1107d
1025c
	if(cp->afirst!=cp->anext && cp->rq->next->len<16*1024){
.
1012,1021d
492c
			nosendctl(cp, NO_HANGUP, 0);
.
## diffname port/devnonet.c 1991/0316
## diff -e /n/bootesdump/1991/0209/sys/src/9/port/devnonet.c /n/bootesdump/1991/0316/sys/src/9/port/devnonet.c
279c
			errors("channel not announced");
.
## diffname port/devnonet.c 1991/0318
## diff -e /n/bootesdump/1991/0316/sys/src/9/port/devnonet.c /n/bootesdump/1991/0318/sys/src/9/port/devnonet.c
1094a

.
1032c
			memmove(pkt->wptr, bp->rptr, n = BLEN(bp));
.
984a

.
979c
	memmove(bp->wptr, cp->media->rptr, cp->ifc->hsize + NO_HDRSIZE);
.
## diffname port/devnonet.c 1991/0320
## diff -e /n/bootesdump/1991/0318/sys/src/9/port/devnonet.c /n/bootesdump/1991/0320/sys/src/9/port/devnonet.c
1150c
		print("new call on connected channel\n"); 
.
465a
/*
 *  wait until a hangup is received.
 *  then send a hangup message (until one is received).
 *
 *	State Transitions:	* -> Cclosed
 */
.
446,451c

.
## diffname port/devnonet.c 1991/0328
## diff -e /n/bootesdump/1991/0320/sys/src/9/port/devnonet.c /n/bootesdump/1991/0328/sys/src/9/port/devnonet.c
1246,1249c
		if(f & NO_HANGUP){
.
1164,1166c
			if(f & NO_HANGUP)
.
1157a
	 *  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:
			panic("nonetrcvmsg %d %d\n", cp->rcvcircuit, cp - cp->ifc->conv);
		case Chungup:
		case Cconnected:
			print("Nonet call on connected/hanging-up circ %d conv %d\n",
				cp->rcvcircuit, cp - cp->ifc->conv); 
			freeb(bp);
			noreset(cp);
			return;
		case Cconnecting:
			if(h->mid != mp->mid){
				print("Nonet call on connecting circ %d conv %d\n",
					cp->rcvcircuit, cp - cp->ifc->conv); 
				freeb(bp);
				noreset(cp);
				return;
			}
			break;
		}
	}

	/*
.
1153a
		freeb(bp);
.
1150,1152c
	if(f & NO_RESET){
		print("reset received\n");
.
1148c
	 *  Obey reset even if the message id is bogus
.
904c
		cp->rcvcircuit = -1;
 		bp = allocb(0);
.
902a
	case Chungup:
		print("resetting connection\n");
.
892c
 *	State Transition:	{Cconnected, Cconnecting, Chungup} -> Creset
.
888,890c
 *  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.
.
512a
	if(cp->media){
		freeb(cp->media);
		cp->media = 0;
	}
.
7a
#include	"../port/nonet.h"
.
## diffname port/devnonet.c 1991/0411
## diff -e /n/bootesdump/1991/0328/sys/src/9/port/devnonet.c /n/bootesdump/1991/0411/sys/src/9/port/devnonet.c
363c
nonetwrite(Chan *c, void *a, long n, ulong offset)
.
357c
		return stringread(c, a, n, stats, offset);
.
353c
		return stringread(c, a, n, cp->ruser, offset);
.
351c
		return stringread(c, a, n, cp->addr, offset);
.
349c
		return stringread(c, a, n, cp->raddr, offset);
.
328c
nonetread(Chan *c, void *a, long n, ulong offset)
.
## diffname port/devnonet.c 1991/0412
## diff -e /n/bootesdump/1991/0411/sys/src/9/port/devnonet.c /n/bootesdump/1991/0412/sys/src/9/port/devnonet.c
211c
		devstat(c, dp, &nonetdir[conf.nnoconv], 1, devgen);
.
## diffname port/devnonet.c 1991/0413
## diff -e /n/bootesdump/1991/0412/sys/src/9/port/devnonet.c /n/bootesdump/1991/0413/sys/src/9/port/devnonet.c
1430c
			if(cp->state <= Copen){
.
1428c
			if(cp->state<=Copen || !canqlock(cp))
.
682a
	cp->afirst = cp->anext = 0;
.
85,91c
	Cclosed=	0,
	Copen=		1,
	Cannounced=	2,
	Cconnected=	3,
	Cconnecting=	4,
	Chungup=	5,
	Creset=		6,
.
## diffname port/devnonet.c 1991/0419
## diff -e /n/bootesdump/1991/0413/sys/src/9/port/devnonet.c /n/bootesdump/1991/0419/sys/src/9/port/devnonet.c
204a
Chan*
nonetclwalk(Chan *c, char *name)
{
	return devclwalk(c, name);
}

.
## diffname port/devnonet.c 1991/0427
## diff -e /n/bootesdump/1991/0419/sys/src/9/port/devnonet.c /n/bootesdump/1991/0427/sys/src/9/port/devnonet.c
205,210d
## diffname port/devnonet.c 1991/0502
## diff -e /n/bootesdump/1991/0427/sys/src/9/port/devnonet.c /n/bootesdump/1991/0502/sys/src/9/port/devnonet.c
1393c
	s &= 0xffff;
	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;
.
1357a
	Block *first;
.
553c
	if(i<0 && Nnomsg+i<Window)
.
551c
	if(i>=0 && i<Window)	
.
542a
enum {
	Window=	1,
};

.
## diffname port/devnonet.c 1991/0503
## diff -e /n/bootesdump/1991/0502/sys/src/9/port/devnonet.c /n/bootesdump/1991/0503/sys/src/9/port/devnonet.c
1398a
if(0)
.
## diffname port/devnonet.c 1991/0604
## diff -e /n/bootesdump/1991/0503/sys/src/9/port/devnonet.c /n/bootesdump/1991/0604/sys/src/9/port/devnonet.c
1463c
				} else /**/
.
1460c
/*				if(cp->rexmit++ > 15){
.
## diffname port/devnonet.c 1991/0606
## diff -e /n/bootesdump/1991/0604/sys/src/9/port/devnonet.c /n/bootesdump/1991/0606/sys/src/9/port/devnonet.c
1472c
				nosendctl(cp, NO_NULL, 0);
.
1207c
	if(h->mid!=mp->mid || (f&NO_NULL)){
.
## diffname port/devnonet.c 1991/0608
## diff -e /n/bootesdump/1991/0606/sys/src/9/port/devnonet.c /n/bootesdump/1991/0608/sys/src/9/port/devnonet.c
1472c
				nosendctl(cp, /*NO_NULL*/0, 0);
.
1463c
				} else
.
1460c
				if(cp->rexmit++ > 15){
.
1268a
		noqack(cp, h->mid);
.
1194c
				DPRINT("Nonet call on connecting circ %d conv %d\n",
.
1187c
			DPRINT("Nonet call on connected/hanging-up circ %d conv %d\n",
.
1184c
			DPRINT("nonetrcvmsg %d %d\n", cp->rcvcircuit, cp - cp->ifc->conv);
			freeb(bp);
			return;
.
1165c
		DPRINT("reset received\n");
.
915d
## diffname port/devnonet.c 1991/0904
## diff -e /n/bootesdump/1991/0608/sys/src/9/port/devnonet.c /n/bootesdump/1991/0904/sys/src/9/port/devnonet.c
951c
	if(mp->first)
		freeb(mp->first);
.
## diffname port/devnonet.c 1991/0925
## diff -e /n/bootesdump/1991/0904/sys/src/9/port/devnonet.c /n/bootesdump/1991/0925/sys/src/9/port/devnonet.c
638d
636d
626,634c
	if(!waserror()){
		nosend(cp, mp);
		poperror();
.
## diffname port/devnonet.c 1991/0926
## diff -e /n/bootesdump/1991/0925/sys/src/9/port/devnonet.c /n/bootesdump/1991/0926/sys/src/9/port/devnonet.c
1473,1474d
1471c
		tsleep(&nonetkr, return0, 0, MSrexmit/2);
.
1461,1469c
			unlock(ifc);
.
1453,1459c
			ep = ifc->conv + conf.nnoconv;
			for(cp = ifc->conv; cp < ep; cp++){
				if(cp->state<=Copen || !canqlock(cp))
					continue;
				if(cp->state <= Copen){
					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
				 */
				while(cp->afirst!=cp->anext && cp->rq->next->len<16*1024){
					DPRINT("sending ack %d\n", cp->ack[cp->afirst]);
					nosendctl(cp, /*NO_NULL*/0, 0);
				}
				qunlock(cp);
.
1451c
			 *  loop through all active conversations
.
1445,1449c
	
.
1441,1443c
		for(ifc = noifc; ifc < &noifc[conf.nnoifc]; ifc++){
			if(ifc->wq==0 || !canlock(ifc))
.
1439c
		 *  loop through all active interfaces
.
1430,1437c
	for(;;){
.
616,620d
610,612c
	mp->first = first;
	mp->last = last;
	mp->len = len;
.
592,594c
		freeb(first);
.
588a
	 *  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;
	}

	/*
.
567c
	Block *first, *last;
	int len;
.
## diffname port/devnonet.c 1991/1101
## diff -e /n/bootesdump/1991/0926/sys/src/9/port/devnonet.c /n/bootesdump/1991/1101/sys/src/9/port/devnonet.c
1473,1474c
				if(cp->sendack){
					DPRINT("sending ack %d\n", cp->ack);
.
1271d
1031,1034c
	cp->sendack = 0;
	cp->hdr->ack = cp->ack;
.
975,981c
	cp->ack = mid;
	cp->sendack = 1;
.
687c
	cp->ack = 0;
	cp->sendack = 0;
.
22d
## diffname port/devnonet.c 1991/1105
## diff -e /n/bootesdump/1991/1101/sys/src/9/port/devnonet.c /n/bootesdump/1991/1105/sys/src/9/port/devnonet.c
760c
		sprint(buf, "%s %s", service, u->p->user);
.
## diffname port/devnonet.c 1991/1112
## diff -e /n/bootesdump/1991/1105/sys/src/9/port/devnonet.c /n/bootesdump/1991/1112/sys/src/9/port/devnonet.c
1471c
			nonetfreeifc(ifc);
.
1436a
			lock(ifc);
			if(ifc->wq==0){
				unlock(ifc);
				continue;
			}
			ifc->ref++;
			unlock(ifc);
.
1435c
			if(ifc->wq==0)
.
140c
	nonetdir[i].perm = 0666;
.
130c
		nonetdir[i].perm = 0777;
.
73,77c
	"addr",		{Naddrqid},	0,	0666,
	"listen",	{Nlistenqid},	0,	0666,
	"raddr",	{Nraddrqid},	0,	0666,
	"ruser",	{Nruserqid},	0,	0666,
	"stats",	{Nstatsqid},	0,	0666,
.
## diffname port/devnonet.c 1991/1114
## diff -e /n/bootesdump/1991/1112/sys/src/9/port/devnonet.c /n/bootesdump/1991/1114/sys/src/9/port/devnonet.c
1480c
		tsleep(&nonetkr, return0, 0, MSrexmit);
.
## diffname port/devnonet.c 1991/1115
## diff -e /n/bootesdump/1991/1114/sys/src/9/port/devnonet.c /n/bootesdump/1991/1115/sys/src/9/port/devnonet.c
1420a
	USED(arg);
.
409a
	USED(c, dp);
.
403a
	USED(c);
.
356c
		return stringread(a, n, stats, offset);
.
352c
		return stringread(a, n, cp->ruser, offset);
.
350c
		return stringread(a, n, cp->addr, offset);
.
348c
		return stringread(a, n, cp->raddr, offset);
.
305a
	USED(c, name, omode, perm);
.
## diffname port/devnonet.c 1991/1121
## diff -e /n/bootesdump/1991/1115/sys/src/9/port/devnonet.c /n/bootesdump/1991/1121/sys/src/9/port/devnonet.c
1456c
				if(cp->state != Cconnected && cp->state != Cconnecting){
.
1295c
		return 0;
	}
.
1293c
		return r;
	} else {
.
1291a
			return -1;
.
1270a
		r = mp->len;
.
1241c
			return -1;
.
1219c
		return -1;
.
1191,1197d
1189c
			return -1;
.
1182c
			return -1;
.
1164c
		return -1;
.
1135c
int
.
849,868c
		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;
.
846,847c
		bp = call.msg;
.
844d
793a
	Block *bp;
.
521,522d
511a
	qlock(cp);
.
508d
504,505c
		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();
.
502c
		 *  send hangup messages to the other side
		 *  until it hangs up or we get tired.
.
494,500c
		while(!isempty(cp))
			tsleep(&cp->r, isempty, cp, MSrexmit);

.
492c
		 *  wait till we have nothing to transmit
.
479,490c
	if(!waserror()){
.
464,469c
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;
	}
}
.
449c
/*
 *  wait until a hangup is received.
 *  then send a hangup message (until one is received).
 *
 *	State Transitions:	* -> Cclosed
 */
.
315,318c
	if(c->stream)
.
## diffname port/devnonet.c 1992/0111
## diff -e /n/bootesdump/1991/1121/sys/src/9/port/devnonet.c /n/bootesdump/1992/0111/sys/src/9/port/devnonet.c
7c
#include	"../port/error.h"
.
## diffname port/devnonet.c 1992/0113
## diff -e /n/bootesdump/1992/0111/sys/src/9/port/devnonet.c /n/bootesdump/1992/0113/sys/src/9/port/devnonet.c
279c
			error(Enolisten);
.
241c
		error(Enodev);
.
## diffname port/devnonet.c 1992/0129
## diff -e /n/bootesdump/1992/0113/sys/src/9/port/devnonet.c /n/bootesdump/1992/0129/sys/src/9/port/devnonet.c
379c
		if(n > sizeof buf - 1)
			n = sizeof buf - 1;
		strncpy(buf, a, n);
		buf[n] = '\0';
.
## diffname port/devnonet.c 1992/0219 # deleted
## diff -e /n/bootesdump/1992/0129/sys/src/9/port/devnonet.c /n/bootesdump/1992/0219/sys/src/9/port/devnonet.c
1,1513d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].