~kris/9p

9hist

c3dc8cd5101cc7ff27907ee6ed129ef579d9252e — David du Colombier 35 years ago 4c58d1a
Plan 9 from Bell Labs 1991-01-19
4 files changed, 199 insertions(+), 86 deletions(-)

M port/devnonet.c
M port/stnoether.c
M power/dat.h
M ss/dat.h
M port/devnonet.c => port/devnonet.c +154 -81
@@ 27,21 27,22 @@ enum {
};

/* 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	nonetkproc(void*);
static void	nonetiput(Queue*, Block*);
static void	nonetoput(Queue*, Block*);
static void	nonetstclose(Queue*);
static void	nonetstopen(Queue*, Stream*);
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;


@@ 85,8 86,7 @@ enum {
	Cconnected,
	Cconnecting,
	Chungup,
	Cclosing,
	Csuperceded,
	Creset,
};

/*


@@ 249,7 249,7 @@ nonetopen(Chan *c, int omode)
	int line;

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



@@ 276,7 276,7 @@ nonetopen(Chan *c, int omode)
		ifc = &noifc[c->dev];
		if(ifc->conv[line].state != Cannounced)
			error(Enoannounce);
		listen(c, ifc);
		nolisten(c, ifc);
		break;
	case Nraddrqid:
		/*


@@ 311,7 311,7 @@ nonetclose(Chan *c)
	Noifc *ifc;

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


@@ 374,7 374,7 @@ nonetwrite(Chan *c, void *a, long n)
		return streamwrite(c, a, n, 0);

	/*
	 *  easier to do here than in nonetoput
	 *  easier to do here than in nooput
	 */
	if(t == Sctlqid){
		strncpy(buf, a, sizeof buf);


@@ 382,9 382,9 @@ nonetwrite(Chan *c, void *a, long n)
		if(strcmp(field[0], "connect")==0){
			if(m < 2)
				error(Ebadarg);
			connect(c, field[1]);
			noconnect(c, field[1]);
		} else if(strcmp(field[0], "announce")==0){
			announce(c, field[1]);
			noannounce(c, field[1]);
		} else if(strcmp(field[0], "accept")==0){
			/* ignore */;
		} else if(strcmp(field[0], "reject")==0){


@@ 414,19 414,21 @@ nonetwstat(Chan *c, char *dp)
 */
Qinfo nonetinfo =
{
	nonetiput,
	nonetoput,
	nonetstopen,
	nonetstclose,
	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
nonetstopen(Queue *q, Stream *s)
noopen(Queue *q, Stream *s)
{
	Noifc *ifc;
	Noconv *cp;


@@ 443,6 445,8 @@ nonetstopen(Queue *q, Stream *s)
/*
 *  wait until a hangup is received.
 *  then send a hangup message (until one is received).
 *
 *	State Transitions:	* -> Cclosed
 */
static int
ishungup(void *a)


@@ 450,10 454,16 @@ ishungup(void *a)
	Noconv *cp;

	cp = (Noconv *)a;
	return cp->state == Chungup;
	switch(cp->state){
	case Chungup:
	case Creset:
	case Cclosed:
		return 1;
	}
	return 0;
}
static void
nonetstclose(Queue *q)
noclose(Queue *q)
{
	Noconv *cp;
	Nomsg *mp;


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

	qlock(cp);


@@ 488,9 509,11 @@ nonetstclose(Queue *q)

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



@@ 521,7 544,7 @@ acked(void *a)
	return mp->inuse;
}
static void
nonetoput(Queue *q, Block *bp)
nooput(Queue *q, Block *bp)
{
	Noconv *cp;
	int next;


@@ 594,7 617,7 @@ nonetoput(Queue *q, Block *bp)
	/*
	 *  send the message, the kproc will retry
	 */
	sendmsg(cp, mp);
	nosend(cp, mp);
	qunlock(&cp->mlock);
	poperror();
}


@@ 604,7 627,7 @@ nonetoput(Queue *q, Block *bp)
 *  none already exists for this circuit.
 */
void
startconv(Noconv *cp, int circuit, char *raddr, int state)
nostartconv(Noconv *cp, int circuit, char *raddr, int state)
{
	int i;
	char name[32];


@@ 647,7 670,8 @@ startconv(Noconv *cp, int circuit, char *raddr, int state)
	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;
	cp->rexmit = cp->bad = cp->sent = cp->rcvd = 0;
	cp->lastacked = Nnomsg|(Nnomsg-1);

	/*
	 *  used for demultiplexing


@@ 668,9 692,11 @@ startconv(Noconv *cp, int circuit, char *raddr, int state)

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



@@ 684,9 710,11 @@ announce(Chan *c, char *addr)
 *  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
connect(Chan *c, char *addr)
noconnect(Chan *c, char *addr)
{
	Noifc *ifc;
	Noconv *cp;


@@ 706,7 734,7 @@ connect(Chan *c, char *addr)
			error(Ebadctl);
	}

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

	if(service){
		/*


@@ 715,9 743,7 @@ connect(Chan *c, char *addr)
		cp->hdr->flag |= NO_SERVICE;
		sprint(buf, "%s %s", service, u->p->pgrp->user);
		c->qid.path = STREAMQID(STREAMID(c->qid.path), Sdataqid);
		DPRINT("sending request\n");
		streamwrite(c, buf, strlen(buf), 1);
		DPRINT("request sent\n");
		c->qid.path = STREAMQID(STREAMID(c->qid.path), Sctlqid);
	}
}


@@ 726,6 752,8 @@ connect(Chan *c, char *addr)
 *  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)


@@ 736,7 764,7 @@ iscall(void *a)
	return ifc->rptr != ifc->wptr;
}
static void
listen(Chan *c, Noifc *ifc)
nolisten(Chan *c, Noifc *ifc)
{
	Noconv *cp, *ep;
	Nocall call;


@@ 795,7 823,7 @@ listen(Chan *c, Noifc *ifc)
		 */
		f = ((Nohdr *)(call.msg->rptr))->flag;
		DPRINT("call from %d %s\n", call.circuit, call.raddr);
		startconv(cp, call.circuit, call.raddr, Cconnecting);
		nostartconv(cp, call.circuit, call.raddr, Cconnecting);
		DPRINT("rcving %d byte message\n", call.msg->wptr - call.msg->rptr);
		nonetrcvmsg(cp, call.msg);
		call.msg = 0;


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

	cp->state = Chungup;
	bp = allocb(0);
	bp->type = M_HANGUP;
	q = cp->rq;
	PUTNEXT(q, bp);
	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.  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);
}



@@ 848,7 909,7 @@ hangup(Noconv *cp)
 *  has any xmit buffers queued, free them.
 */
static void
rcvack(Noconv *cp, int mid)
norack(Noconv *cp, int mid)
{
	Nomsg *mp;
	Block *bp;


@@ 889,7 950,7 @@ rcvack(Noconv *cp, int mid)
 *  acknowledgements queued.
 */
static void
queueack(Noconv *cp, int mid)
noqack(Noconv *cp, int mid)
{
	int next;



@@ 904,7 965,7 @@ queueack(Noconv *cp, int mid)
 *  make a packet header
 */
Block *
mkhdr(Noconv *cp, int rem)
nohdr(Noconv *cp, int rem)
{
	Block *bp;
	Nohdr *hp;


@@ 923,11 984,11 @@ mkhdr(Noconv *cp, int rem)
 *  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
 *  called by nooput().  the qlock(mp) synchronizes these two
 *  processes.
 */
static void
sendmsg(Noconv *cp, Nomsg *mp)
nosend(Noconv *cp, Nomsg *mp)
{
	Noifc *ifc;
	Queue *wq;


@@ 971,7 1032,7 @@ sendmsg(Noconv *cp, Nomsg *mp)
		 *  short message:
		 *  copy the whole message into the header block
		 */
		last = pkt = mkhdr(cp, mp->len);
		last = pkt = nohdr(cp, mp->len);
		for(bp = mp->first; bp; bp = bp->next){
			memcpy(pkt->wptr, bp->rptr, n = BLEN(bp));
			pkt->wptr += n;


@@ 993,7 1054,7 @@ sendmsg(Noconv *cp, Nomsg *mp)
		SET(rptr);
		if(bp)
			rptr = bp->rptr;
		last = pkt = mkhdr(cp, msgrem);
		last = pkt = nohdr(cp, msgrem);
		n = 0;
		while(bp){
			/*


@@ 1003,7 1064,7 @@ sendmsg(Noconv *cp, Nomsg *mp)
				nonetcksum(pkt, ifc->hsize);
				last->flags |= S_DELIM;
				(*wq->put)(wq, pkt);
				last = pkt = mkhdr(cp, -msgrem);
				last = pkt = nohdr(cp, -msgrem);
				pktrem = msgrem > ifc->maxtu ? ifc->maxtu : msgrem;
			}
			n = bp->wptr - rptr;


@@ 1036,7 1097,6 @@ sendmsg(Noconv *cp, Nomsg *mp)
		mp->time = NOW + 10*MSrexmit;
	else
		mp->time = NOW + (cp->rexmit+1)*MSrexmit;
	DPRINT("xmit %d %lud %lud\n", cp->rexmit, NOW, mp->time);
	(*wq->put)(wq, pkt);
	qunlock(&cp->xlock);
	poperror();


@@ 1046,7 1106,7 @@ sendmsg(Noconv *cp, Nomsg *mp)
 *  send a control message (hangup or acknowledgement).
 */
static void
sendctlmsg(Noconv *cp, int flag, int new)
nosendctl(Noconv *cp, int flag, int new)
{
	Nomsg ctl;



@@ 1058,11 1118,13 @@ sendctlmsg(Noconv *cp, int flag, int new)
	else
		ctl.mid = cp->lastacked;
	cp->hdr->flag |= flag;
	sendmsg(cp, &ctl);
	nosend(cp, &ctl);
}

/*
 *  receive a message (called by the multiplexor; noetheriput, nofddiiput, ...)
 *
 *	State Transition:	(no NO_NEWCALL in msg) Cconnecting -> Cconnected
 */
void
nonetrcvmsg(Noconv *cp, Block *bp)


@@ 1089,14 1151,10 @@ nonetrcvmsg(Noconv *cp, Block *bp)
	/*
	 *  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 || cp->state==Csuperceded)){
	if((f&NO_NEWCALL) && cp->state==Cconnected){
		DPRINT("new call on connected channel\n"); 
		freeb(bp);
		if(cp->state != Csuperceded){
			cp->state = Csuperceded;
			hangup(cp);
		}
		noreset(cp);
		return;
	}



@@ 1106,13 1164,15 @@ nonetrcvmsg(Noconv *cp, Block *bp)
	if(h->mid != mp->mid){
		DPRINT("old msg %d instead of %d r==%d\n", h->mid, mp->mid, r);
		if(r == 0){
			rcvack(cp, h->ack);
			if(f & NO_HANGUP)
				hangup(cp);
			norack(cp, h->ack);
			if(f & NO_RESET)
				noreset(cp);
			else if(f & NO_HANGUP)
				nohangup(cp);
		} else {
			if(r>0){
				rcvack(cp, h->ack);
				queueack(cp, h->mid);
				norack(cp, h->ack);
				noqack(cp, h->mid);
			}
			cp->bad++;
		}


@@ 1163,9 1223,10 @@ nonetrcvmsg(Noconv *cp, Block *bp)
	 *  if not, strip off the delimiter.
	 */
	if(mp->rem == 0){
		rcvack(cp, h->ack);
		cp->hdr->flag &= ~(NO_NEWCALL|NO_SERVICE);
		norack(cp, h->ack);
		if(f & NO_ACKME)
			queueack(cp, h->mid);
			noqack(cp, h->mid);
		mp->last->flags |= S_DELIM;
		PUTNEXT(q, mp->first);
		mp->first = mp->last = 0;


@@ 1178,15 1239,27 @@ nonetrcvmsg(Noconv *cp, Block *bp)
		mp->mid ^= Nnomsg;

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

		/*
		 *  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);
		}
	} else
		mp->last->flags &= ~S_DELIM;

}


/*
 *  noifc
 */


@@ 1291,7 1364,7 @@ nonetcksum(Block *bp, int offset)
 *  the retransmission interval.
 */
static void
nonetkproc(void *arg)
nokproc(void *arg)
{
	Noifc *ifc;
	Noconv *cp, *ep;


@@ 1332,10 1405,10 @@ loop:
			if(cp->first!=cp->next && NOW>=cp->out[cp->first].time){
				if(cp->rexmit++ > 60){
					print("hanging up\n");
					hangup(cp);
					nohangup(cp);
				} else {
					mp = &(cp->out[cp->first]);
					sendmsg(cp, mp);
					nosend(cp, mp);
				}
			}



@@ 1344,7 1417,7 @@ loop:
			 */
			if(cp->afirst != cp->anext){
				DPRINT("sending ack %d\n", cp->ack[cp->afirst]);
				sendctlmsg(cp, 0, 0);
				nosendctl(cp, 0, 0);
			}
			qunlock(cp);
		}

M port/stnoether.c => port/stnoether.c +43 -4
@@ 112,6 112,47 @@ noetheroput(Queue *q, Block *bp)
}

/*
 *  respond to a misaddressed message with a close
 */
void
noetherbad(Noifc *ifc, Block *bp)
{
	Etherhdr *eh, *neh;
	int circuit;
	Block *nbp;

	/*
	 *  crack the packet header
	 */
	eh = (Etherhdr *)bp->rptr;
	print("bad c %d m %d f %d\n", eh->circuit[0], eh->mid, eh->flag);
	if(eh->flag & NO_RESET)
		goto out;

	/*
	 *  craft an error reply
	 */
	print("sending reset\n");
	nbp = allocb(60);
	nbp->flags |= S_DELIM;
	nbp->wptr = nbp->rptr + 60;
	memset(bp->rptr, 0, 60);
	neh = (Etherhdr *)nbp->rptr;
	memcpy(neh, eh, sizeof(Etherhdr));
	neh->circuit[0] ^= 1;
	neh->remain[0] = neh->remain[1] = 0;
	neh->flag = NO_HANGUP | NO_RESET;
	neh->ack = eh->mid;
	neh->mid = eh->ack;
	memcpy(neh->s, eh->d, sizeof(neh->s));
	memcpy(neh->d, eh->s, sizeof(neh->d));
	nonetcksum(nbp, 14);
	PUTNEXT(ifc->wq, nbp);
out:
	freeb(bp);
}

/*
 *  Input a packet and use the ether address to select the correct
 *  nonet device to pass it to.
 *


@@ 155,7 196,6 @@ noetheriput(Queue *q, Block *bp)
			ph = (Etherhdr *)(cp->media->rptr);
			if(circuit == cp->rcvcircuit
			&& memcmp(ph->d, h->s, sizeof(h->s)) == 0){
				cp->hdr->flag &= ~NO_NEWCALL;
				bp->rptr += ifc->hsize;
				nonetrcvmsg(cp, bp);
				qunlock(cp);


@@ 168,9 208,8 @@ noetheriput(Queue *q, Block *bp)
	/*
	 *  if not a new call, then its misaddressed
	 */
	if((h->flag & NO_NEWCALL) == 0) {
		DPRINT("misaddressed nonet packet %d %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", circuit, h->s[0], h->s[1], h->s[2], h->s[3], h->s[4], h->s[5]);
		freeb(bp);
	if((h->flag & NO_NEWCALL) == 0){
		noetherbad(ifc, bp);
		return;
	}


M power/dat.h => power/dat.h +1 -1
@@ 527,7 527,7 @@ struct Nohdr {
#define NO_HANGUP	0x2	/* flag bit requesting hangup */
#define NO_ACKME	0x4	/* acknowledge this message */
#define NO_SERVICE	0x8	/* message includes a service name */

#define NO_RESET	0x10	/* reset the connection */
/*
 *  a buffer describing a nonet message
 */

M ss/dat.h => ss/dat.h +1 -0
@@ 540,6 540,7 @@ struct Nohdr {
#define NO_HANGUP	0x2	/* flag bit requesting hangup */
#define NO_ACKME	0x4	/* acknowledge this message */
#define NO_SERVICE	0x8	/* message includes a service name */
#define NO_RESET	0x10	/* reset the connection */

/*
 *  a buffer describing a nonet message