home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
142.lha
/
DNet
/
dnet
/
control.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-11-21
|
14KB
|
603 lines
/*
* CONTROL.C
*
* DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
*
*/
#include "dnet.h"
#include <stdio.h>
static ubyte Dctl;
/*
* 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
*/
do_rto(ior)
IOT *ior;
{
AbortIO(RNet);
WaitIO(RNet);
RNet->io_Data = (APTR)&Raux->sync;
RNet->io_Length = 3;
SendIO(RNet);
if (RState == RS_DATA && (Dctl & PKF_MASK) == PKCMD_WRITE)
replywindow(Dctl >> 5); /* NAK the packet */
RState = 0;
}
/*
* WTO: Write timeout (unresolved output windows exist). Resend a CHECK
* command for all unresolved (READY) output windows
*/
void
do_wto(ior)
{
register short i;
register PKT *pkt;
if (Restart) {
NetWrite(RestartPkt, 3, 1);
return;
}
for (i = 0; i < WPUsed; ++i) {
pkt = WPak[i];
if (pkt->state == READY) /* send check */
NetWrite(CheckPkt[(WPStart+i)&7], 3, 1);
}
}
/*
* RNET: Receved data ready from network. The RNet request will
* automagically be reissued on return.
*
* NOTE: The buffer the data is contained in can be anything, and
* is not restricted to the Auxillary request this routine uses.
*
* called from iosink loop, signal mask can be cleared.
*/
do_rnet(ior)
IOR *ior;
{
register ubyte *ptr = (ubyte *)ior->io_Data;
register long len = ior->io_Actual;
long n;
ubyte cd;
static uword dlen;
static uword dblen;
if (len <= 0) {
len = 0;
RState = RS_SYNC;
}
while (len) {
switch(RState) {
case RS_SYNC:
--len;
if (*ptr++ == SYNC)
RState = RS_CTL;
break;
case RS_CTL:
--len;
Dctl = *ptr++;
RState = RS_CCHK;
break;
case RS_CCHK:
if ((ubyte)(((SYNC<<1)^Dctl)) == *ptr) {
++ptr;
--len;
if (Dctl & PKF_DATA) {
RState = RS_LEN1;
break;
}
RState = RS_SYNC;
do_cmd(Dctl, NULL, 0);
} else {
if (len) { /* Resync at earliest point */
++len;
--ptr;
}
}
RState = RS_SYNC;
break;
case RS_LEN1:
dlen = *ptr;
++ptr;
--len;
RState = RS_LEN2;
break;
case RS_LEN2:
dlen = (dlen << 8) + *ptr + 2;
if (dlen < 2)
fprintf(stderr, "WARNING, DATALEN <2: %02lx %ld\n", Dctl, dlen);
if (dlen > MAXPKT+2) {
fprintf(stderr, "DATALEN FAILURE: %02lx %ld\n", Dctl, dlen);
RState = RS_SYNC;
break;
}
++ptr;
--len;
dblen = 0;
RState = RS_DATA;
break;
case RS_DATA:
len += dblen; /* move to beginning of data buffer */
ptr -= dblen;
if (dlen <= len) {
register uword chk = chkbuf(ptr, dlen - 2);
if ((chk >> 8) == ptr[dlen-2] && (ubyte)chk == ptr[dlen-1]) {
do_cmd(Dctl, ptr, dlen-2);
len -= dlen;
ptr += dlen;
} else {
if ((Dctl & PKF_MASK) == PKCMD_WRITE)
replywindow(Dctl >> 5); /* NAK the packet */
}
RState = RS_SYNC;
} else {
goto break2; /* incomplete read */
}
break;
}
}
break2:
if (Rto_act) {
AbortIO(&Rto);
WaitIO(&Rto);
Rto_act = 0;
}
n = NetReady(ior, &cd);
if (n > MAXPKT)
n = MAXPKT;
switch(RState) {
default:
printf("SoftError: Illegal state %ld\n", RState);
RState = RS_SYNC;
/* fall through */
case RS_SYNC: /* Wait for sync & cmd. No timeout needed */
RNet->io_Data = (APTR)&Raux->sync;
RNet->io_Length = MAX(3, n);
break;
case RS_CTL: /* Have sync, need CTL and CCHK. */
RNet->io_Data = (APTR)&Raux->ctl;
RNet->io_Length = MAX(2, n);
break;
case RS_CCHK:
RNet->io_Data = (APTR)&Raux->cchk;
RNet->io_Length = MAX(1, n);
break;
case RS_LEN1:
RNet->io_Data = (APTR)&Raux->lenh;
RNet->io_Length = MAX(2, n);
break;
case RS_LEN2:
RNet->io_Data = (APTR)&Raux->lenl;
RNet->io_Length = MAX(1, n);
break;
case RS_DATA: /* need dlen, have len. Start read request and TO */
if (ptr != Raux->data && len)
CopyMem(ptr, Raux->data, len);
dblen = len;
RNet->io_Data = (APTR)((char *)Raux->data + dblen);
RNet->io_Length = dlen - len;
Rto.tr_time.tv_secs = RTimeoutVal / 1000000; /* packet to */
Rto.tr_time.tv_micro= RTimeoutVal % 1000000;
SendIO(&Rto);
Rto_act = 1;
break;
}
do_wupdate();
return ((cd) ? 1 : -1);
}
/*
* WNET: The last data packet has been sent to the network... Start a
* timeout sequence (1 second). If this times out we will send
* a CHECK packet for all unresolved transmission windows.
*/
do_wnet()
{
if (Wto_act) {
AbortIO(&Wto);
WaitIO(&Wto);
}
Wto.tr_time.tv_secs = WTimeoutVal / 1000000;
Wto.tr_time.tv_micro= WTimeoutVal % 1000000;
SendIO(&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.
*
* First two bits determine CMD as follows:
* 0bbbbbbb DATA 0-127 bytes of DATA
* 10bbbccc DATA 0-7 bytes of DATA, ccc=channel
* command.
* 11bbbbbb bbbbbbbb DATA 0-1023 bytes of DATA
*/
do_wupdate()
{
static short XPri;
int maxpktsize;
register IOR *ior;
register PKT *pkt;
register long len;
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(0);
while (WPUsed != 4 && (ior = (IOR *)RemHead(&TxList))) {
register 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(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;
pkt->sync = SYNC;
pkt->ctl = PKCMD_WRITE | PKF_DATA | ((WPStart + WPUsed)<<5);
pkt->cchk = (pkt->sync << 1) ^ pkt->ctl;
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;
pkt->data[offset+0] = 0x80|SCMD_SWITCH|(2<<3);
pkt->data[offset+1] = WChan >> 8;
pkt->data[offset+2] = WChan;
offset += 3;
}
len = ior->io_Length - ior->io_Actual;
if (ior->io_Command == SCMD_DATA) { /* DATA */
if (offset + len > (maxpktsize-4))
len = (maxpktsize-4) - offset;
if (len < 128) {
pkt->data[offset] = len;
++offset;
} else {
pkt->data[offset+0] = (len>>8)|0xC0;
pkt->data[offset+1] = len;
offset += 2;
}
} else { /* COMMAND */
pkt->data[offset] = 0x80|ior->io_Command|(len<<3);
++offset;
}
CopyMem((char *)ior->io_Data + ior->io_Actual, pkt->data + offset, len);
offset += len;
ior->io_Actual += len;
if (ior->io_Actual == ior->io_Length) {
ReplyMsg(ior);
ior = (IOR *)RemHead(&TxList); /* Next packet */
if (ior == NULL)
break;
}
}
pkt->iolength = offset + OVERHEAD;
pkt->lenh = offset >> 8;
pkt->lenl = offset;
{
register uword chksum = chkbuf(pkt->data, offset);
pkt->data[offset+0] = chksum >> 8;
pkt->data[offset+1] = chksum;
}
NetWrite(&pkt->sync, pkt->iolength, 1);
if (ior) {
++ior->io_Message.mn_Node.ln_Pri;
Enqueue(&TxList, ior);
--ior->io_Message.mn_Node.ln_Pri;
}
++WPUsed;
}
}
do_cmd(ctl, buf, bytes)
ubyte ctl;
ubyte *buf;
{
ubyte window = ctl >> 5;
ubyte rwindow;
switch(ctl & PKF_MASK) {
case PKCMD_WRITE:
rwindow = (window - RPStart) & 7;
if (rwindow < 4) {
CopyMem(buf, RPak[rwindow]->data, bytes);
RPak[rwindow]->iolength = bytes;
RPak[rwindow]->state = READY;
do_rupdate();
}
replywindow(window);
break;
case PKCMD_CHECK:
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 */
NetWrite(&WPak[rwindow]->sync, WPak[rwindow]->iolength, 0);
} else {
puts("Soft Error: Illegal NAK");
}
break;
case PKCMD_RESTART:
case PKCMD_ACKRSTART:
if ((ctl & PKF_MASK) == PKCMD_ACKRSTART)
Restart = 0;
do_netreset();
/* RxPtr? */
if ((ctl & PKF_MASK) == PKCMD_RESTART) {
short len;
uword chksum;
static ubyte buf[32];
NetWrite(NULL, 0, 0);
strcpy(buf+5, HostName);
len = strlen(buf+5)+1;
buf[0] = SYNC;
buf[1] = PKCMD_ACKRSTART | PKF_DATA;
buf[2] = (SYNC << 1) ^ buf[1];
buf[3] = 0;
buf[4] = len;
chksum = chkbuf(buf+5, len);
buf[5+len] = chksum >> 8;
buf[6+len] = chksum;
NetWrite(buf, 7+len, 1);
}
/*
if (bytes)
setlistenport(buf);
else
setlistenport("");
*/
break;
}
do_rupdate();
}
do_rupdate()
{
while (RPak[0]->state == READY) {
register PKT *pkt = RPak[0];
register ubyte *ptr = pkt->data;
register uword len;
uword iolen = pkt->iolength;
ubyte cmd;
while (iolen) {
cmd = SCMD_DATA;
len = ptr[0];
++ptr;
--iolen;
if (len >= 128) {
if (len < 0xC0) {
cmd = len & 7;
len = (len >> 3) & 7;
} else {
len = ((len << 8) | *ptr) & 0x3FFF;
++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;
}
}
do_reccmd(cmd, ptr, len)
ubyte *ptr;
{
switch(cmd) {
case SCMD_DATA: /* data for channel */
if (RChan < MAXCHAN && (Chan[RChan].flags & CHANF_ROK)) {
register IOR *ior = (IOR *)AllocMem(sizeof(IOR), MEMF_PUBLIC);
ior->io_Unit = (struct Unit *)RChan;
ior->io_Data = (APTR)AllocMem(len, MEMF_PUBLIC);
ior->io_Length = len;
ior->io_Actual = 0;
CopyMem(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, ior);
}
break;
case SCMD_SWITCH:
RChan = (ptr[0]<<8)|ptr[1];
break;
case SCMD_OPEN:
{
register 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), -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), -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 */
{
register CCLOSE *clo = (CCLOSE *)ptr;
uword chan = (clo->chanh<<8)|clo->chanl;
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) {
Chan[chan].state = CHAN_FREE;
ReplyMsg(Chan[chan].ior);
Chan[chan].ior = NULL;
} else { /* send EOF */
WritePort(Chan[chan].port, DNCMD_CLOSE, NULL, 0, PKT_REQ, chan);
}
}
break;
case SCMD_ACKCMD: /* acknowledge of my open */
{
register 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(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(Chan[chan].ior);
Chan[chan].ior = NULL;
}
}
break;
case SCMD_EOFCMD: /* EOF on channel */
{
register 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;
default:
/*
* actually just unsupported... IOCTL maybe
printf("BAD SCMD, %ld\n", cmd);
*/
break;
}
}
replywindow(window)
{
ubyte rwindow = (window - RPStart) & 7;
if (rwindow >= 4 || RPak[rwindow]->state == READY) /* data ready */
NetWrite(AckPkt[window], 3, 0);
else
NetWrite(NakPkt[window], 3, 0);
}