From c3dc8cd5101cc7ff27907ee6ed129ef579d9252e Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 19 Jan 1991 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1991-01-19 --- port/devnonet.c | 235 +++++++++++++++++++++++++++++++---------------- port/stnoether.c | 47 +++++++++- power/dat.h | 2 +- ss/dat.h | 1 + 4 files changed, 199 insertions(+), 86 deletions(-) diff --git a/port/devnonet.c b/port/devnonet.c index 6b96149f2028f1b9113189b7ad89d2b1bcd189cb..39377a79cf914791401ce8f9c8bc685ab58e837c 100644 --- a/port/devnonet.c +++ b/port/devnonet.c @@ -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); } diff --git a/port/stnoether.c b/port/stnoether.c index 78256885f5a728113c1b98a33d0e8932547a42d6..00cbab2bc3268c72a7c7aa29f5832e3c8bd6704b 100644 --- a/port/stnoether.c +++ b/port/stnoether.c @@ -111,6 +111,47 @@ noetheroput(Queue *q, Block *bp) PUTNEXT(q, 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; } diff --git a/power/dat.h b/power/dat.h index c761b1df26e0fcc9ee1f15088c28e77a9ad2ccc2..775fb8a450fdc8585d97878eaaeb48dc8c6d0373 100644 --- a/power/dat.h +++ b/power/dat.h @@ -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 */ diff --git a/ss/dat.h b/ss/dat.h index ba4054ff50a4df2c18e00df20b01b68bf4fba74f..688565875d4df72f79cb730dab7e47682f868d28 100644 --- a/ss/dat.h +++ b/ss/dat.h @@ -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