/* dslc.c
L. Stewart January 21, 1983 5:10 PM
D. Swinehart July 12, 1982 8:45 AM
L. Stewart January 21, 1983 7:38 PM, new EtherHost
L. Stewart January 22, 1983 3:35 PM, new statistics
L. Stewart January 23, 1983 5:44 PM, Fix StartRx call
*/
#include <Lark.h>
#include <Ec.h>
#include <Env.h>
#include <Alloc.h>
#include <Queue.h>
#include <Pup.h>
struct ccb {
char cmda;
char *addra;
char counta;
char stata;
};
/* Runtime */
extern InByte();
extern Swab();
extern CallSwat();
/* Context package */
extern InitNContext();
extern Block();
/* Queue package */
extern Enqueue();
extern Dequeue();
extern InitQueue();
/* Runtime */
extern int DoubleEq();
/* Timer package */
extern SetTmr();
extern TmrExp();
/* Ethernet machine language */
extern SLCInit();
extern SLTStart();
extern SLRStart();
/* Pup level 1 */
extern GetPBI();
extern MaybeGetPBI();
extern SetLocalNet();
extern int currentHost;
extern int localHost;
extern int localNet;
extern int lenPup;
extern struct SocketEntry pupSockets[1 /*maxPupSockets*/];
/* transmit and receive SLC control blocks */
static struct ccb rxccb;
static struct PBI *rxPBI;
static struct ccb txccb;
static struct PBI *txPBI;
/* if txPBI is non-zero, then a transmission is in progress */
static int rBufCount;
/* transmit and receive timeout timers */
static int txtmr[1];
static int rxtmr[1];
/* ether output queue */
static struct Queue outQ[1];
/* stack space */
static int etherStack[200];
/* statistics */
static int slcrp; /* packet counters */
static int slctp;
static int slrsmash; /* SLC resets due to timeout */
static int sltsmash;
static int noBuffer; /* lost packets due to buffer shortage */
static EtherPr()
{
struct EtherEncapsulation *ee;
int temp;
for (;;) {
Block();
/* test for reception or hung receiver */
if (rxccb.stata & 0x80) {
if (rxccb.stata == 0x88) {
temp = (int) rxPBI->pup;
temp = temp - 4;
ee = (struct EtherEncapsulation *) temp;
if (ee->type == 2) { /* Swabbed typePup */
rxPBI = IntLev1(rxPBI);
};
};
StartRx();
};
if (TmrExp(rxtmr)) {
SLCReset(); /* violent ! */
slrsmash += 1;
};
if (txPBI && TmrExp(txtmr)) {
SLCReset(); /* violent ! */
sltsmash += 1;
};
/* test for completion of transmit or hung transmitter */
if (txPBI) {
if (txccb.stata & 0x80) {
Enqueue(txPBI->queue, txPBI);
txPBI = Dequeue(outQ);
if (txPBI) Txpkt(txPBI);
};
};
};
};
/* The socket dispatch runs at interrupt level, but the associcated
procedure is called by pup level 1 process */
struct PBI *IntLev1(pbi)
struct PBI *pbi;
{
struct Pup *pup;
struct PBI *npbi;
int dNet, dHost, i, temp;
slcrp += 1;
pup = pbi->pup;
if (pup->sPort.host == 0) goto BcastSource;
/* If the destination is not us, discard packet. */
if ((dNet = pup->dPort.net) == 0) goto ZeroDNet;
if (dNet != localNet) {
if (!localNet) SetLocalNet(dNet);
else goto Misaddressed;
};
/* If checksum exists and is to be checked, here's the place to do it. */
/* This line is a simulation of a successful checksum checking activity. */
/* TEMP? Pups not addressed to our multicast or specific address cannot be
supported. Not sure they could be received, anyhow. */
if (((dHost = pup->dPort.host) != 0) && (dHost != currentHost) &&
(dHost != localHost)) goto BadHost;
/* Dispatch Other designated packets (e.g., voice data) */
for (i = 1; i <= maxPupSockets; ++i) {
if (DoubleEq(&pupSockets[i].port.socket, &pup->dPort.socket)) {
temp = (int) pupSockets[i].PortProc;
pbi->clientWord = temp;
if ((npbi = MaybeGetPBI(0)) != 0) {
Enqueue(pupSockets[i].q, pbi)
pbi = npbi;
};
else noBuffer += 1;
goto FoundIt;
};
};
Misaddressed:
BcastSource:
ZeroDNet:
BadHost:
FoundIt:
return(pbi);
};
InitEther(zone, ctxQ, x)
struct ZN *zone;
struct Queue *ctxQ;
int x;
{
int myc;
txPBI = rxPBI = 0;
noBuffer = slrsmash = sltsmash = 0;
rBufCount = (lenPup + lenEtherEncapsulation) << 1;
if (rBufCount > 256) CallSwat(ecPup1 + 19);
rBufCount = (-rBufCount) & 0x00ff;
myc = InitNContext("EtherPr", etherStack, 200, &EtherPr);
Enqueue(ctxQ, myc);
InitQueue(outQ);
SLCReset();
};
static SLCReset()
{
SLCInit(EtherHost());
if (txPBI) {
Enqueue(txPBI->queue, txPBI);
if (txPBI = Dequeue(outQ)) Txpkt(txPBI);
};
StartRx();
};
static StartRx()
{
if (rxPBI == 0) rxPBI = GetPBI(0);
rxccb.cmda = 0x00;
rxccb.addra = rxPBI->pup;
rxccb.addra = rxccb.addra - 4;
rxccb.counta = rBufCount;
rxccb.stata = 0;
SetTmr(10000, rxtmr);
SLRStart(&rxccb);
};
int EtherHost()
{
return ((InByte(piob) & 0x003f) + 0x0040);
};
TransmitPacket(pbi)
struct PBI *pbi;
{
if (txPBI) Enqueue(outQ, pbi);
else Txpkt(pbi);
};
static Txpkt(pbi)
struct PBI *pbi;
{
int len;
txPBI = pbi;
len = Swab(txPBI->pup->length);
len = (len + 5) & 0x0fffe;
if (len > 256) CallSwat(ecPup1+20);
txccb.cmda = 0x50;
txccb.addra = txPBI->pup;
txccb.addra = txccb.addra - 4;
txccb.counta = len & 0x00ff;
txccb.stata = 0;
SLTStart(&txccb);
SetTmr(2000, txtmr);
slctp += 1;
};