home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * CONTROL.C
- *
- * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
- *
- * Main packet control. Medium level. Interprets formatted received
- * packets and sends formatted tx packets. Uses low level packet
- * construction and reception routines in PACKET.C
- */
-
- #include "dnet.h"
- #include <stdio.h>
-
- void do_rupdate();
- void do_reccmd();
- void replywindow();
- void StartWriteTimeout();
-
- /*
- * RTO: read timeout. Timeout occured while waiting for the rest of
- * a packet. Reset state and restart read.
- *
- * called from iosink loop, ok if signal mask cleared
- */
-
- void
- do_rto(ior)
- IOT *ior;
- {
- NetStartRead(RecvPacket(NULL, 0));
- }
-
- /*
- * WTO: Write timeout (unresolved output windows exist). Resend a CHECK
- * command for all unresolved (READY) output windows
- */
-
- void
- do_wto(ior)
- IOT *ior;
- {
- short i;
- PKT *pkt;
- short to = 0;
-
- if (Restart) {
- WriteRestart();
- return;
- }
- for (i = 0; i < WPUsed; ++i) {
- pkt = WPak[i];
- if (pkt->state == READY) {
- WriteChk((WPStart + i) & 7);
- ++to;
- }
- }
- if (to)
- StartWriteTimeout(8);
- }
-
- void
- do_rnet(ptr, len)
- ubyte *ptr;
- long len;
- {
- long expect;
- long n;
-
- if (len < 0)
- ptr = NULL;
- expect = RecvPacket(ptr, len);
- n = NetReady();
- if (n > expect)
- expect = n;
- NetStartRead(expect);
- }
-
- /*
- * StartWriteTimeout()
- *
- * Begins a timeout for written packets. This timeout normally never
- * occurs even with data errors (the receiver detects missing windows
- * and sends the appropriate NAK).
- */
-
- void
- StartWriteTimeout(secs)
- {
- if (Wto_act) {
- AbortIO((IOR *)&Wto);
- WaitIO((IOR *)&Wto);
- Wto_act = 0;
- }
- if (secs) {
- Wto.tr_time.tv_secs = secs;
- Wto.tr_time.tv_micro= 0;
- SendIO((IOR *)&Wto);
- Wto_act = 1;
- }
- }
-
- /*
- * DO_WUPDATE()
- *
- * (1) Remove EMPTY windows at head of transmit queue.
- * (2) Fill up transmit queue with pending requests, if any.
- * (3) Start timeout for write if did send packet.
- *
- * CMD 0x20-0x3F 0-31 bytes data
- * 0x40-0x7F 0-N bytes data (w/ extend byte 0x20-0x7F)
- * 0x80-0xFF Command.
- *
- * Note that normal data encoding overhead uses 0x20-0x7F,
- * thereby allowing 7 bit data to be transmitted with normal
- * packets instead of expanded (8->6 bits) packets.
- */
-
- void
- do_wupdate()
- {
- static short XPri;
- static ubyte DBuf[MAXPACKET];
- int maxpktsize;
- IOSTD *ior;
- PKT *pkt;
- long len;
- char wrotePkt = 0;
-
- while (WPUsed && WPak[0]->state == EMPTY) {
- pkt = WPak[0];
- WPak[0] = WPak[1];
- WPak[1] = WPak[2];
- WPak[2] = WPak[3];
- WPak[3] = pkt;
- --WPUsed;
- ++WPStart;
- }
- if (Restart)
- return;
-
- /*
- * Fill new packets and send.
- */
-
- while (WPUsed != 4 && (ior = (IOSTD *)RemHead(&TxList))) {
- long offset = 0;
- if (DDebug)
- printf("Extract Request: %08lx %ld bytes\n", ior, ior->io_Length);
- {
- short npri;
-
- if (ior->io_Command == SCMD_DATA) {
- ubyte chan = (ulong)ior->io_Unit;
- if (Chan[chan].state == CHAN_CLOSE) { /* channel closed */
- ior->io_Error = 1;
- ReplyMsg((MSG *)ior);
- continue;
- }
- npri = ior->io_Message.mn_Node.ln_Pri << 2;
- } else {
- npri = XPri;
- }
- if (npri >= XPri)
- XPri = npri;
- else {
- if (XPri - npri > 100)
- XPri -= 10;
- else if (XPri - npri > 50)
- XPri -= 5;
- else
- --XPri;
- }
- maxpktsize = MAXPKT - (XPri - npri);
- if (maxpktsize < MINPKT)
- maxpktsize = MINPKT;
- }
- pkt = WPak[WPUsed];
- pkt->state = READY;
-
- for (;;) {
- if (offset > (maxpktsize-8)) /* not enough room */
- break;
- if (ior->io_Command == SCMD_DATA && (ulong)ior->io_Unit != WChan) {
- /* CSWITCH */
- WChan = (ulong)ior->io_Unit;
- DBuf[offset+0] = 0x80|SCMD_SWITCH|(2<<3);
- DBuf[offset+1] = WChan >> 8;
- DBuf[offset+2] = WChan;
- offset += 3;
- }
- len = ior->io_Length - ior->io_Actual;
- if (ior->io_Command == SCMD_DATA) { /* DATA OUT */
- if (offset + len > (maxpktsize-4))
- len = (maxpktsize-4) - offset;
- if (len < 0x20) {
- DBuf[offset] = len + 0x20;
- ++offset;
- } else {
- DBuf[offset+0] = 0x40 + len / 96;
- DBuf[offset+1] = 0x20 + len % 96;
- offset += 2;
- }
- BytesOut += len;
- } else { /* COMMAND OUT */
- DBuf[offset] = 0x80|ior->io_Command|(len<<3);
- ++offset;
- }
- BMov((char *)ior->io_Data + ior->io_Actual, DBuf + offset, len);
- offset += len;
- ior->io_Actual += len;
- if (ior->io_Actual == ior->io_Length) {
- ReplyMsg((MSG *)ior);
- ior = (IOSTD *)RemHead(&TxList); /* Next packet */
- if (ior == NULL)
- break;
- }
- }
-
- BuildDataPacket(pkt, (WPStart + WPUsed) & 7, DBuf, offset);
- WritePacket(pkt);
- wrotePkt = 1;
-
- if (ior) {
- ++ior->io_Message.mn_Node.ln_Pri;
- Enqueue(&TxList, (NODE *)ior);
- --ior->io_Message.mn_Node.ln_Pri;
- }
- ++WPUsed;
- ++PacketsOut;
- ResetIdle();
- break; /* One at a time, else would take too long */
- }
- if (wrotePkt)
- StartWriteTimeout(8);
- }
-
-
- void
- dumpcheck(ptr)
- ubyte *ptr;
- {
- short i;
- for (i = 0; i < 8; ++i) {
- if (ptr[i])
- replywindow(i);
- ptr[i] = 0;
- }
- }
-
- void
- do_cmd(ctl, buf, bytes)
- uword ctl; /* usually just 8 bits though */
- ubyte *buf;
- {
- ubyte window = ctl & PKF_SEQUENCE;
- ubyte rwindow;
- static ubyte Chk, Chkwin[8];
-
- if (ctl == 0xFFFF) {
- if (Chk) {
- dumpcheck(Chkwin);
- Chk = 0;
- }
- return;
- }
-
- if (DDebug)
- printf("RECV-PACKET %02x %4ld bytes\n", ctl, bytes);
-
- if ((ctl & PKF_MASK) == PKCMD_CHECK) {
- Chkwin[window] = 1;
- Chk = 1;
- return;
- }
- if (Chk) {
- dumpcheck(Chkwin);
- Chk = 0;
- }
- switch(ctl & PKF_MASK) {
- case PKCMD_WRITE:
- case PKCMD_WRITE6:
- case PKCMD_WRITE7:
- rwindow = (window - RPStart) & 7;
- if (rwindow < 4) {
- BMov(buf, RPak[rwindow]->data, bytes);
- RPak[rwindow]->buflen = bytes; /* dummy */
- RPak[rwindow]->state = READY;
- do_rupdate();
-
- /*
- * Check for missing receive packet. rwindow 1..3 and
- * (rwindow - 1) != READY
- */
-
- if (rwindow && RPak[rwindow-1]->state != READY)
- WriteNak((window - 1) & 7);
- }
- replywindow(window);
- break;
- case PKCMD_ACK:
- rwindow = (window - WPStart) & 7;
- if (rwindow < WPUsed) /* mark as sent */
- WPak[rwindow]->state = EMPTY;
- break;
- case PKCMD_NAK: /* resend */
- rwindow = (window - WPStart) & 7;
- if (rwindow < WPUsed) { /* resend */
- ++PacketsResent;
- WritePacket(WPak[rwindow]);
- StartWriteTimeout(8);
- } else {
- printf("Soft Error: Illegal NAK: %ld %ld %ld %ld\n",
- window, WPStart, rwindow, WPUsed
- );
- }
- break;
- case PKCMD_RESTART:
- case PKCMD_ACKRSTART:
- if ((ctl & PKF_MASK) == PKCMD_ACKRSTART)
- Restart = 0;
- do_netreset();
- /* RxPtr? */
-
- if ((ctl & PKF_MASK) == PKCMD_RESTART) {
- static ubyte buf[32];
-
- strcpy(buf, " ");
-
- /*
- * note, restart packet may contain only ascii 0x20-0x7F
- * 00 is definitely out.
- */
-
- WritePacket(BuildRestartAckPacket(buf, strlen(buf)));
- StartWriteTimeout(5);
- }
- break;
- }
- do_rupdate();
- }
-
- /*
- * Multiplex data onto the low level stream
- *
- * 0x20-0x3F 0-31 bytes of data for current channel
- * 0x80-0xBF control-command w/0-7 bytes of data
- * 0x40-0x7F this + extend byte (0x20-0x7F) for long data pkts
- */
-
- void
- do_rupdate()
- {
- while (RPak[0]->state == READY) {
- PKT *pkt = RPak[0];
- ubyte *ptr = pkt->data;
- uword len;
- uword iolen = pkt->buflen;
- ubyte cmd;
-
- while (iolen) {
- cmd = SCMD_DATA;
- len = ptr[0];
- ++ptr;
- --iolen;
- if (len >= 128) {
- cmd = len & 7;
- len = (len >> 3) & 7;
- } else {
- if (len < 0x40) {
- len -= 0x20;
- if (len < 0) {
- printf("HLP len error1 %d\n", len);
- len = 0;
- }
- } else {
- if (*ptr < 0x20)
- printf("HLP len error2 %02x %02x\n", len, *ptr);
- len = (len - 0x40) * 96 + (*ptr - 0x20);
- ++ptr;
- --iolen;
- }
- }
- iolen -= len;
- if (DDebug)
- printf("RECEIVE CMD %2ld ", cmd);
- do_reccmd(cmd, ptr, len);
- ptr += len;
- }
- RPak[0] = RPak[1];
- RPak[1] = RPak[2];
- RPak[2] = RPak[3];
- RPak[3] = pkt;
- pkt->state = EMPTY;
- ++RPStart;
- }
- }
-
- void
- do_reccmd(cmd, ptr, len)
- int cmd;
- ubyte *ptr;
- int len;
- {
- switch(cmd) {
- case SCMD_DATA: /* data for channel */
- if (RChan < MAXCHAN && (Chan[RChan].flags & CHANF_ROK)) {
- IOSTD *ior = AllocMem(sizeof(IOSTD), MEMF_PUBLIC);
- ior->io_Unit = (struct Unit *)RChan;
- ior->io_Data = AllocMem(len, MEMF_PUBLIC);
- ior->io_Length = len;
- ior->io_Actual = 0;
- BMov(ptr, ior->io_Data, len);
- ior->io_Message.mn_Node.ln_Name = (char *)PKT_REQ;
- ior->io_Command = DNCMD_WRITE;
- ior->io_Message.mn_ReplyPort = IOSink;
- PutMsg(Chan[RChan].port, (MSG *)ior);
- BytesIn += len;
- ResetIdle(); /* not idle, have received data */
- }
- break;
- case SCMD_SWITCH:
- RChan = (ptr[0]<<8)|ptr[1];
- break;
- case SCMD_OPEN:
- {
- COPEN *cop = (COPEN *)ptr;
- PORT *port;
- CACKCMD ack;
- char buf[32];
- uword chan = (cop->chanh << 8) | cop->chanl;
- uword portnum = (cop->porth << 8) | cop->portl;
-
- ack.chanh = cop->chanh;
- ack.chanl = cop->chanl;
- ack.error = 0;
-
- if (chan >= MAXCHAN || Chan[chan].state) {
- ack.error = 33; /* magic */
- WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), (uword)-1);
- break;
- }
- sprintf(buf, "DNET.PORT.%ld", portnum);
- if ((port = (PORT *)FindPort(buf)) == NULL) {
- RunServer(portnum);
- if ((port = (PORT *)FindPort(buf)) == NULL) {
- ack.error = 2;
- WriteStream(SCMD_ACKCMD, &ack, sizeof(CACKCMD), (uword)-1);
- break;
- }
- }
- /* ln_Name type of 0 causes reply to go to DNetPort */
- WritePort(port, DNCMD_SOPEN, NULL, 0, 0, chan);
- Chan[chan].state = CHAN_ROPEN;
- Chan[chan].pri = cop->pri;
- }
- break;
- case SCMD_CLOSE: /* receive close */
- {
- CCLOSE *clo = (CCLOSE *)ptr;
- uword chan = (clo->chanh<<8)|clo->chanl;
-
- if (DDebug)
- printf("Remote close, chan %d state %d\n", chan, Chan[chan].state);
-
- if (chan >= MAXCHAN || Chan[chan].state == CHAN_FREE) {
- break;
- }
- Chan[chan].state = CHAN_CLOSE;
- Chan[chan].flags |= CHANF_RCLOSE;
- Chan[chan].flags &= ~(CHANF_ROK|CHANF_WOK);
- if (Chan[chan].flags & CHANF_LCLOSE) {
- if (DDebug)
- printf("Local already closed, reply %08lx\n", Chan[chan].ior);
- Chan[chan].state = CHAN_FREE;
- ReplyMsg((MSG *)Chan[chan].ior);
- Chan[chan].ior = NULL;
- } else { /* send EOF */
- if (DDebug)
- printf("Local not already closed\n");
- WritePort(Chan[chan].port, DNCMD_CLOSE, NULL, 0, PKT_REQ, chan);
- }
- }
- break;
- case SCMD_ACKCMD: /* acknowledge of my open */
- {
- CACKCMD *cack = (CACKCMD *)ptr;
- uword chan = (cack->chanh<<8)|cack->chanl;
- if (chan >= MAXCHAN || Chan[chan].state != CHAN_LOPEN) {
- break;
- }
- /*
- * Channel in use (collision), try again
- */
- if (cack->error == 33) {
- uword newchan = alloc_channel();
- COPEN co;
- if (newchan < MAXCHAN) {
- Chan[newchan] = Chan[chan];
- Chan[chan].state = CHAN_FREE;
- Chan[chan].ior = NULL;
- co.chanh = newchan >> 8;
- co.chanl = newchan;
- co.porth = (ulong)Chan[newchan].ior->io_Unit >> 8;
- co.portl = (ulong)Chan[newchan].ior->io_Unit;
- co.error = 0;
- co.pri = Chan[chan].pri;
- WriteStream(SCMD_OPEN, &co, sizeof(COPEN), chan);
- break;
- }
- }
- if (cack->error) {
- Chan[chan].state = CHAN_FREE;
- Chan[chan].ior->io_Error = cack->error;
- ReplyMsg((MSG *)Chan[chan].ior);
- Chan[chan].ior = NULL;
- } else {
- Chan[chan].state = CHAN_OPEN;
- Chan[chan].ior->io_Error = 0;
- Chan[chan].ior->io_Unit = (struct Unit *)chan;
- Chan[chan].flags = CHANF_ROK|CHANF_WOK;
- ReplyMsg((MSG *)Chan[chan].ior);
- Chan[chan].ior = NULL;
- }
- }
- break;
- case SCMD_EOFCMD: /* EOF on channel */
- {
- CEOFCMD *eof = (CEOFCMD *)ptr;
- uword chan = (eof->chanh<<8)|eof->chanl;
-
- if (chan < MAXCHAN && Chan[chan].state == CHAN_OPEN) {
- Chan[chan].flags &= ~eof->flags;
- if (eof->flags & CHANF_ROK)
- WritePort(Chan[chan].port, DNCMD_EOF, NULL, 0, PKT_REQ, chan);
- } else {
- printf("SCMD_EOFCMD: Error chan %ld state %ld\n",
- chan, Chan[chan].state
- );
- }
- }
- break;
- case SCMD_IOCTL:
- {
- CIOCTL *cio = (CIOCTL *)ptr;
- uword chan = (cio->chanh<<8)|cio->chanl;
-
- if (Chan[chan].state == CHAN_OPEN)
- WritePort(Chan[chan].port, DNCMD_IOCTL, cio, sizeof(*cio), PKT_REQ, chan);
- }
- break;
- default:
- if (DDebug)
- printf("BAD SCMD, %ld\n", cmd);
- break;
- }
- }
-
- void
- replywindow(window)
- int window;
- {
- ubyte rwindow = (window - RPStart) & 7;
-
- if (rwindow >= 4 || RPak[rwindow]->state == READY) { /* data ready */
- WriteAck(window);
- ++PacketsIn;
- } else {
- WriteNak(window);
- ++PacketsNakd;
- }
- }
-
-