EtherTesterMainImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Last Edited by: Willie-Sue, April 7, 1988 2:30:00 pm PDT
lifted from EtherTesterMain.mesa, AOF, 26-Sep-83 16:22:43
DIRECTORY
Checksum USING [ComputeChecksum],
DebuggerSwap USING [CallDebugger],
Process USING [
Detach, GetPriority, MsecToTicks, Pause, Priority, priorityBackground,
priorityForeground, SetPriority, SetTimeout, Ticks, Yield],
ProcessPriorities USING [priorityIOLow],
PrincOpsUtils USING [AllocateNakedCondition, DeallocateNakedCondition, LongCopy],
NSPilotSystem USING [broadcastHostNumber, HostNumber, nullNetworkNumber,
echoerSocket],
NSConstants USING [echoerSocket],
NSTypes USING [BufferBody],
NewEthernetFace USING [
AddCleanup, DeviceHandle, GetNextDevice, GetPacketLength, GetPacketsMissed,
GetRetries, GetStatus, nullDeviceHandle, QueueInput, QueueOutput, Status,
TurnOff, TurnOn],
NewEthernetFaceExtras USING [SetModeFor10MBEther],
EtherTesterOps USING [
Buffer, BufferBody, counter,
bumpPacketNumber, broadcasting, check, doChecksum, dallyBeforeOutput,
dallyIfBehind, dest, Header, hwMode,
me, numberOfRecvBuffers, numberOfSendBuffers, pattern, promiscuous, recvSize,
sendSize, showGarbage, showOnlyBadAlign, ShowPacket,
showRunts, showStrangeStatus, showWrongData, showWrongLength,
source, stats, StatsInit, StatsPeek, StatsPrint, TestMode,
ticksBeforeSend, UpdateNumbers,
AllocateOneBuffer, FreeOneBuffer, AllocateOneIOCB, FreeOneIOCB],
EtherTesterViewer USING [UpdateStatsBoxes];
EtherTesterMainImpl:
MONITOR
IMPORTS
Checksum, DebuggerSwap, PrincOpsUtils, Process,
NewEthernetFace, NewEthernetFaceExtras, EtherTesterOps, EtherTesterViewer
EXPORTS EtherTesterOps =
BEGIN OPEN EtherTesterOps;
Global Data
activeProcesses: PUBLIC CARD16 ← 0;
lensPattern: ARRAY [0..4) OF BYTE = [0, 125B, 377B, 125B];
Private Data
ether: NewEthernetFace.DeviceHandle;
pleaseStop: BOOL;
priorityIOLow: Process.Priority = 5; --from ProcessPriorities.mesa
Ethernet packet types:
ns: WORD = 3000B;
nullChecksum: WORD = 177777B;
lastInputBuffer, lastOutputBuffer: Buffer;
oldMissed, recvSequenceNumber, sendSequenceNumber: CARD16;
inInterruptBits, outInterruptBits: WORD;
inputWait, outputWait: LONG POINTER TO CONDITION ← NIL;
letBackgroundRun, waitToStart, oneTick, fiveSeconds: CONDITION;
endMarker: CARD16 = 119; -- Just a random number. . .
StartTest:
PUBLIC
PROC [test: TestMode, board:
CARD16]
RETURNS [status:
BOOL] =
BEGIN
IF ~InitEther[board] THEN RETURN[FALSE];
EtherTesterViewer.UpdateStatsBoxes[];
SELECT test
FROM
SendOnly => Start[EtherOutput, NIL];
ReceiveOnly => Start[EtherInput, NIL];
SendAndReceive => Start[EtherInput, EtherOutput];
Start receive before send to avoid lost packets
EchoServer => Start[EtherServer, NIL];
EchoUser => Start[EtherUser, NIL];
ENDCASE;
RETURN[TRUE];
END;
InitEther:
PROC [board:
CARD16]
RETURNS [status:
BOOL] =
BEGIN
ether ← NewEthernetFace.nullDeviceHandle;
THROUGH [1..board]
DO
ether ← NewEthernetFace.GetNextDevice[ether];
IF ether = NewEthernetFace.nullDeviceHandle THEN EXIT;
ENDLOOP;
IF ether = NewEthernetFace.nullDeviceHandle THEN RETURN[FALSE];
NewEthernetFace.AddCleanup[ether];
Process.SetTimeout[@oneTick, 1];
Process.SetTimeout[@fiveSeconds, Process.MsecToTicks[5000]];
RETURN[TRUE];
END;
StopTheWorld:
PUBLIC
PROC =
BEGIN
pleaseStop ← TRUE;
UNTIL activeProcesses = 0 DO Process.Pause[1]; PokeEverybody[]; ENDLOOP;
END;
EtherInput:
ENTRY
PROC =
BEGIN
this: Buffer ← SetupInputBuffers[];
UNTIL pleaseStop
DO
status: NewEthernetFace.Status ← WaitForInputToArrive[this];
IF status = pending THEN LOOP;
CollectInputStats[this, status];
IF status = ok
AND this.header.dest = me
AND this.header.source = dest
THEN
BEGIN
IF check THEN CheckBuffer[this];
IF doChecksum THEN CheckChecksum[this];
END;
AppendInput[this];
this ← this.next;
ENDLOOP;
UNTIL this.idle
DO
status: NewEthernetFace.Status ← WaitForInputToArrive[this];
IF status = pending THEN EXIT;
CollectInputStats[this, status];
IF status = ok
AND this.header.dest = me
AND this.header.source = dest
THEN
BEGIN
IF check THEN CheckBuffer[this];
IF doChecksum THEN CheckChecksum[this];
END;
this.idle ← TRUE;
this ← this.next;
ENDLOOP;
ReturnInputBuffers[];
Stopping[];
END;
EtherOutput:
ENTRY
PROC =
BEGIN
this: Buffer ← SetupOutputBuffers[TRUE];
UNTIL pleaseStop
DO
status: NewEthernetFace.Status ← WaitUntilBufferHasBeenSent[this];
IF status = pending THEN LOOP;
CollectOutputStats[this, status];
IF dallyIfBehind
AND ((sendSequenceNumber - recvSequenceNumber) >= numberOfSendBuffers)
THEN
BEGIN
stats.dallyForEcho ← stats.dallyForEcho + 1;
WAIT letBackgroundRun;
END;
SendBuffer[this];
this ← this.next;
ENDLOOP;
UNTIL this.idle
DO
status: NewEthernetFace.Status ← WaitUntilBufferHasBeenSent[this];
IF status = pending THEN EXIT;
CollectOutputStats[this, status];
this.idle ← TRUE;
this ← this.next;
ENDLOOP;
ReturnOutputBuffers[];
Stopping[];
END;
EtherServer:
ENTRY
PROC =
BEGIN
this: Buffer ← SetupInputBuffers[];
that: Buffer ← SetupOutputBuffers[FALSE];
UNTIL pleaseStop
DO
status: NewEthernetFace.Status ← WaitForInputToArrive[this];
IF status = pending THEN LOOP;
CollectInputStats[this, status];
IF status = ok
AND this.header.packetType = ns
AND this.body.destination.socket = NSPilotSystem.echoerSocket
AND this.body.packetType = echo
AND this.body.echoType = echoRequest THEN
BEGIN
outStatus: NewEthernetFace.Status←
IF that.idle THEN ok ELSE NewEthernetFace.GetStatus[that.iocb];
IF doChecksum THEN CheckChecksum[this];
IF outStatus # pending THEN
BEGIN
IF ~that.idle THEN CollectOutputStats[that, outStatus];
IF sendSize < NewEthernetFace.GetPacketLength[this.iocb] THEN
BEGIN
stats.packetsTooLongToEcho ← stats.packetsTooLongToEcho + 1;
AppendInput[this];
this ← this.next;
LOOP;
END;
that.header.dest ← this.header.source;
that.header.source ← source;
that.header.packetType ← ns;
that.length ← NewEthernetFace.GetPacketLength[this.iocb];
PrincOpsUtils.LongCopy[
to: @that.body, from: @this.body, nwords: that.length - SIZE[Header]];
Caution: sendSize must be large enough to hold echo packet!
that.body.transportControl ← [FALSE, 0, 0];
that.body.packetType ← echo;
that.body.destination ← this.body.source;
that.body.source ← this.body.destination;
that.body.source.host ← source; -- might be broadcast
that.body.echoType ← echoResponse;
IF doChecksum
THEN SetChecksum[that]
ELSE that.body.checksum ← nullChecksum;
that.idle ← FALSE;
AppendOutput[that];
that ← that.next;
stats.packetsEchoed ← stats.packetsEchoed + 1;
END
ELSE stats.packetsNotEchoed ← stats.packetsNotEchoed + 1;
END;
AppendInput[this];
this ← this.next;
ENDLOOP;
UNTIL that.idle
DO
status: NewEthernetFace.Status ← WaitUntilBufferHasBeenSent[that];
IF status = pending THEN EXIT;
CollectOutputStats[that, status];
that.idle ← TRUE;
that ← that.next;
ENDLOOP;
UNTIL this.idle
DO
status: NewEthernetFace.Status ← WaitForInputToArrive[this];
IF status = pending THEN EXIT;
CollectInputStats[this, status];
IF status = ok
AND this.header.dest = me
AND this.header.source = dest
THEN
BEGIN
IF check THEN CheckBuffer[this];
IF doChecksum THEN CheckChecksum[this];
END;
this.idle ← TRUE;
this ← this.next;
ENDLOOP;
ReturnOutputBuffers[];
ReturnInputBuffers[];
Stopping[];
END;
EtherUser:
ENTRY
PROC =
BEGIN
this: Buffer ← SetupInputBuffers[];
that: Buffer ← SetupOutputBuffers[TRUE];
dally: BOOL ← TRUE;
UNTIL pleaseStop
DO
IF dallyIfBehind
AND dally
AND ((sendSequenceNumber - recvSequenceNumber) >= numberOfSendBuffers)
THEN
BEGIN
stats.dallyForEcho ← stats.dallyForEcho + 1;
dally ← FALSE;
WAIT letBackgroundRun;
END
ELSE
BEGIN
-- input packets are piling up while we WAIT
status: NewEthernetFace.Status ← WaitUntilBufferHasBeenSent[that];
IF status # pending
THEN
BEGIN
CollectOutputStats[that, status];
SendBuffer[that];
that ← that.next;
END;
dally ← TRUE;
END;
UNTIL pleaseStop
DO
-- look all of the packets that have arrived
status: NewEthernetFace.Status ← NewEthernetFace.GetStatus[this.iocb];
IF status = pending THEN EXIT;
CollectInputStats[this, status];
ProcessEchoBuffer[this, status];
this ← this.next;
ENDLOOP;
ENDLOOP;
UNTIL that.idle
DO
status: NewEthernetFace.Status;
THROUGH [0..1000)
DO
status ← NewEthernetFace.GetStatus[that.iocb];
IF status # pending THEN EXIT;
ENDLOOP;
IF status = pending THEN EXIT;
CollectOutputStats[that, status];
that.idle ← TRUE;
that ← that.next;
ENDLOOP;
UNTIL this.idle
DO
status: NewEthernetFace.Status ← WaitForInputToArrive[this];
IF status = pending THEN EXIT;
CollectInputStats[this, status];
ProcessEchoBuffer[this, status];
this.idle ← TRUE;
this ← this.next;
ENDLOOP;
ReturnInputBuffers[];
ReturnOutputBuffers[];
Stopping[];
END;
SendBuffer:
INTERNAL
PROC [that: Buffer] =
BEGIN
IF check
THEN FillBuffer[that]
ELSE
BEGIN
IF bumpPacketNumber THEN sendSequenceNumber ← sendSequenceNumber + 1;
that.body.echoWords[0] ← sendSequenceNumber;
END;
IF doChecksum THEN SetChecksum[that] ELSE that.body.checksum ← nullChecksum;
IF dallyBeforeOutput THEN WAIT letBackgroundRun;
DelayBeforeSending[];
AppendOutput[that];
END;
ProcessEchoBuffer:
INTERNAL
PROC[this: Buffer, status: NewEthernetFace.Status] =
BEGIN
IF status = ok
AND this.header.dest = me
AND this.header.source = dest
AND this.body.echoType = echoResponse THEN
BEGIN
thisSequenceNumber: CARD16 ← this.body.echoWords[0];
IF doChecksum THEN CheckChecksum[this];
IF bumpPacketNumber THEN recvSequenceNumber ← recvSequenceNumber + 1;
SELECT
LOOPHOLE[thisSequenceNumber - recvSequenceNumber,
INTEGER]
FROM
0 =>
BEGIN
stats.packetsEchoed ← stats.packetsEchoed + 1;
IF check THEN CheckBuffer[this];
END;
> 0 =>
BEGIN -- Early, we must have lost something
UNTIL recvSequenceNumber = thisSequenceNumber
DO
stats.echosMissed ← stats.echosMissed + 1;
IF bumpPacketNumber
THEN
recvSequenceNumber← recvSequenceNumber + 1;
ENDLOOP;
Copy of code above for normal case
stats.packetsEchoed ← stats.packetsEchoed + 1;
IF check THEN CheckBuffer[this];
END;
< 0 =>
BEGIN
stats.lateEchos ← stats.lateEchos + 1;
IF bumpPacketNumber THEN recvSequenceNumber← recvSequenceNumber - 1;
END;
ENDCASE => ERROR;
END;
AppendInput[this];
END;
SetupInputBuffers:
INTERNAL
PROC
RETURNS [Buffer] =
BEGIN
recvSequenceNumber ← 0;
lastInputBuffer ← AllocateBuffer[recvSize];
lastInputBuffer.next ← lastInputBuffer;
THROUGH [1..numberOfRecvBuffers)
DO
temp: Buffer ← AllocateBuffer[recvSize];
put on front of chain
temp.next ← lastInputBuffer.next;
lastInputBuffer.next ← temp;
ENDLOOP;
oldMissed ← NewEthernetFace.GetPacketsMissed[ether];
FOR finger: Buffer ← lastInputBuffer.next, finger.next
DO
AppendInput[finger]; IF finger = lastInputBuffer THEN EXIT;
ENDLOOP;
WAIT waitToStart;
RETURN[lastInputBuffer.next];
END;
ReturnInputBuffers:
PROC =
BEGIN
finger: Buffer ← lastInputBuffer.next;
lastInputBuffer.next ← NIL;
TurnEtherOff[];
UNTIL finger =
NIL
DO
temp: Buffer ← finger.next; FreeBuffer[finger]; finger ← temp;
ENDLOOP;
END;
SetupOutputBuffers:
INTERNAL
PROC [start:
BOOL]
RETURNS [Buffer] =
BEGIN
sendSequenceNumber ← 0;
lastOutputBuffer ← AllocateBuffer[sendSize];
lastOutputBuffer.next ← lastOutputBuffer;
THROUGH [1..numberOfSendBuffers)
DO
temp: Buffer ← AllocateBuffer[sendSize];
put on front of chain
temp.next ← lastOutputBuffer.next;
lastOutputBuffer.next ← temp;
ENDLOOP;
FOR finger: Buffer ← lastOutputBuffer.next, finger.next
DO
DelayBeforeSending[];
FillBuffer[finger];
IF doChecksum
THEN SetChecksum[finger]
ELSE finger.body.checksum ← nullChecksum;
IF start THEN AppendOutput[finger] ELSE finger.idle ← TRUE;
IF finger = lastOutputBuffer THEN EXIT;
ENDLOOP;
RETURN[lastOutputBuffer.next];
END;
ReturnOutputBuffers:
PROC =
BEGIN
finger: Buffer ← lastOutputBuffer.next;
lastOutputBuffer.next ← NIL;
Give output a chance to unwind so we don't generate a bad packet
THROUGH [0..1000) DO Process.Yield[]; ENDLOOP;
TurnEtherOff[];
UNTIL finger =
NIL
DO
temp: Buffer ← finger.next; FreeBuffer[finger]; finger ← temp;
ENDLOOP;
END;
WaitForInputToArrive:
INTERNAL
PROC[b: Buffer]
RETURNS[status: NewEthernetFace.Status] =
BEGIN
status ← pending;
UNTIL pleaseStop
OR (status ← NewEthernetFace.GetStatus[b.iocb]) # pending
DO
WAIT inputWait;
ENDLOOP;
END;
CollectInputStats:
INTERNAL
PROC[this: Buffer, status: NewEthernetFace.Status] =
BEGIN
length: CARD16 = NewEthernetFace.GetPacketLength[this.iocb];
temp: CARD16 ← NewEthernetFace.GetPacketsMissed[ether];
IF this.endPlusOne^ # endMarker
THEN
BEGIN
ShowPacket["Microcode wrote past the end of the buffer", this];
DebuggerSwap.CallDebugger["Microcode wrote past the end of the buffer"L];
END;
stats.missed ← stats.missed + (temp - oldMissed);
oldMissed ← temp;
counter[2] ← counter[2] + 1;
IF length < SIZE[Header] THEN
BEGIN
stats.runts ← stats.runts + 1;
IF status = ok THEN stats.runtsMarkedOk ← stats.runtsMarkedOk + 1;
IF ~promiscuous AND this.header.dest # me
AND this.header.dest # NSPilotSystem.broadcastHostNumber THEN
stats.multicastRunts ← stats.multicastRunts + 1;
IF showRunts THEN ShowPacket["Runt", this];
RETURN;
END;
SELECT status
FROM
ok =>
BEGIN
stats.pktsIn ← stats.pktsIn + 1;
stats.wdsIn ← stats.wdsIn + length;
SELECT this.header.dest
FROM
NSPilotSystem.broadcastHostNumber =>
BEGIN
stats.bc ← stats.bc + 1;
stats.bcWords ← stats.bcWords + length;
END;
me => stats.toMe ← stats.toMe + 1;
ENDCASE => stats.toOther ← stats.toOther + 1;
SELECT this.header.source
FROM
me => stats.fromMe ← stats.fromMe + 1;
ENDCASE => NULL;
IF this.header.dest = me
AND this.header.source = dest
THEN
BEGIN
IF length # sendSize
THEN
BEGIN
IF length < sendSize THEN stats.shortIn ← stats.shortIn + 1;
IF length > sendSize THEN stats.longIn ← stats.longIn + 1;
IF showWrongLength
THEN
ShowPacket["Wrong length packet marked ok", this];
END;
END;
END;
ENDCASE =>
BEGIN
counter[0] ← counter[0] + 1;
stats.errsIn ← stats.errsIn + 1;
SELECT status
FROM
packetTooLong => stats.shortBuffer ← stats.shortBuffer + 1;
badAlignmentButOkCrc =>
BEGIN
stats.itIn ← stats.itIn + 1;
IF showOnlyBadAlign THEN ShowPacket["Only bad alignment", this];
END;
crc => stats.crcIn ← stats.crcIn + 1;
crcAndBadAlignment => stats.crcItIn ← stats.crcItIn + 1;
overrun => stats.overrunIn ← stats.overrunIn + 1;
ENDCASE =>
BEGIN
stats.funnyIn ← stats.funnyIn + 1;
IF showStrangeStatus
THEN
BEGIN
ShowPacket["Funny input status", this];
Pause[]; -- don't print out too much
END;
END;
IF showGarbage THEN ShowPacket["Garbage packet", this];
END;
END;
DelayBeforeSending:
INTERNAL
PROC =
{ THROUGH [0..ticksBeforeSend) UNTIL pleaseStop DO WAIT oneTick; ENDLOOP };
WaitUntilBufferHasBeenSent:
INTERNAL
PROC [b: Buffer]
RETURNS [status: NewEthernetFace.Status] =
BEGIN
UNTIL (status ← NewEthernetFace.GetStatus[b.iocb]) # pending
DO
IF pleaseStop THEN RETURN[pending]; WAIT outputWait;
ENDLOOP;
END;
CollectOutputStats:
INTERNAL
PROC[this: Buffer, status: NewEthernetFace.Status] =
BEGIN
counter[5] ← counter[5] + 1;
SELECT status
FROM
ok =>
BEGIN
retries: CARD16 = NewEthernetFace.GetRetries[this.iocb];
stats.pktsOut ← stats.pktsOut + 1;
stats.wdsOut ← stats.wdsOut + this.length;
stats.collisions ← stats.collisions + retries;
SELECT retries
FROM
0 => NULL;
1 => stats.coll1 ← stats.coll1 + 1;
2 => stats.coll2 ← stats.coll2 + 1;
3 => stats.coll3 ← stats.coll3 + 1;
4 => stats.coll4 ← stats.coll4 + 1;
5 => stats.coll5 ← stats.coll5 + 1;
6 => stats.coll6 ← stats.coll6 + 1;
7 => stats.coll7 ← stats.coll7 + 1;
8 => stats.coll8 ← stats.coll8 + 1;
9 => stats.coll9 ← stats.coll9 + 1;
10 => stats.coll10 ← stats.coll10 + 1;
11 => stats.coll11 ← stats.coll11 + 1;
12 => stats.coll12 ← stats.coll12 + 1;
13 => stats.coll13 ← stats.coll13 + 1;
14 => stats.coll14 ← stats.coll14 + 1;
15 => stats.coll15 ← stats.coll15 + 1;
ENDCASE =>
BEGIN
stats.collx ← stats.collx + 1;
IF showStrangeStatus
THEN
ShowPacket["Funny retransmission mask", this];
END;
END;
ENDCASE =>
BEGIN
counter[0] ← counter[0] + 1;
stats.errsOut ← stats.errsOut + 1;
SELECT status
FROM
tooManyCollisions => stats.loadOverflow ← stats.loadOverflow + 1;
underrun => stats.overrunOut ← stats.overrunOut + 1;
lateCollision =>
BEGIN
stats.lateCollisions ← stats.lateCollisions + 1;
IF showGarbage THEN ShowPacket["Late Collision", this];
END;
ENDCASE =>
BEGIN
stats.funnyOut ← stats.funnyOut + 1;
IF showStrangeStatus THEN ShowPacket["Funny output status", this];
Pause[]; -- don't print out too much
END;
END;
END;
FillBuffer:
PROC [this: Buffer] =
BEGIN
end:
CARD16 =
sendSize - SIZE[Header] - SIZE[echo NSTypes.BufferBody] - 1;
IF bumpPacketNumber THEN sendSequenceNumber ← sendSequenceNumber + 1;
IF end < sendSize
THEN
SELECT pattern
FROM
zeros => FOR i: CARD16 IN (0..end) DO this.body.echoWords[i] ← 0; ENDLOOP;
ones =>
FOR i: CARD16 IN (0..end) DO this.body.echoWords[i] ← 177777B; ENDLOOP;
alternating =>
FOR i: CARD16 IN (0..end) DO this.body.echoWords[i] ← 125252B; ENDLOOP;
pairs =>
FOR i: CARD16 IN (0..end) DO this.body.echoWords[i] ← 146314B; ENDLOOP;
oneTwentyFive =>
FOR i: CARD16 IN (0..end) DO this.body.echoWords[i] ← 125B; ENDLOOP;
countBytes =>
FOR i:
CARD16
IN (0..end)
DO
k: CARD16 ← i*2; this.body.echoWords[i] ← k*400B + k + 1; ENDLOOP;
countWords, ignore =>
FOR i: CARD16 IN (0..end) DO this.body.echoWords[i] ← i; ENDLOOP;
lenOne =>
FOR i:
CARD16
IN [2..2*end)
DO
this.body.echoBytes[i] ← lensPattern[i/1 MOD 4]; ENDLOOP;
lenSix =>
FOR i:
CARD16
IN [2..2*end)
DO
this.body.echoBytes[i] ← lensPattern[i/6 MOD 4]; ENDLOOP;
ENDCASE =>
FOR i: CARD16 IN (0..end) DO this.body.echoWords[i] ← 1000B; ENDLOOP;
this.header.dest ← IF broadcasting THEN NSPilotSystem.broadcastHostNumber ELSE dest;
this.header.source ← source;
this.header.packetType ← ns;
this.body ← [
checksum:, pktLength: 2*(sendSize - SIZE[Header]),
transportControl: [FALSE, 0, 0], packetType: echo,
destination: [NSPilotSystem.nullNetworkNumber, dest, NSPilotSystem.echoerSocket],
source: [NSPilotSystem.nullNetworkNumber, source, LOOPHOLE[sendSequenceNumber]],
nsBody: echo[echoType: echoRequest, echoBody:]];
this.body.echoWords[0] ← sendSequenceNumber;
END;
CheckBuffer:
PROC [this: Buffer] =
BEGIN
end:
CARD16 =
sendSize - SIZE[Header] - SIZE[echo NSTypes.BufferBody] - 1;
bad: CARD16 ← 0;
length: CARD16 = NewEthernetFace.GetPacketLength[this.iocb];
IF length # sendSize
THEN
{ stats.wrongLength ← stats.wrongLength + 1; RETURN };
IF end < sendSize
THEN
SELECT pattern
FROM
ignore => NULL;
zeros =>
FOR i:
CARD16
IN (0..end)
DO
IF this.body.echoWords[i] # 0 THEN bad ← bad + 1; ENDLOOP;
ones =>
FOR i:
CARD16
IN (0..end)
DO
IF this.body.echoWords[i] # 177777B THEN bad ← bad + 1; ENDLOOP;
alternating =>
FOR i:
CARD16
IN (0..end)
DO
IF this.body.echoWords[i] # 125252B THEN bad ← bad + 1; ENDLOOP;
pairs =>
FOR i:
CARD16
IN (0..end)
DO
IF this.body.echoWords[i] # 146314B THEN bad ← bad + 1; ENDLOOP;
oneTwentyFive =>
FOR i:
CARD16
IN (0..end)
DO
IF this.body.echoWords[i] # 125B THEN bad ← bad + 1; ENDLOOP;
countBytes =>
FOR i:
CARD16
IN (0..end)
DO
k: CARD16 ← i*2;
IF this.body.echoWords[i] # k*400B + k + 1 THEN bad ← bad + 1;
ENDLOOP;
countWords =>
FOR i:
CARD16
IN (0..end)
DO
IF this.body.echoWords[i] # i THEN bad ← bad + 1; ENDLOOP;
lenOne =>
FOR i:
CARD16
IN [2..end)
DO
IF this.body.echoBytes[i] # lensPattern[i/1 MOD 4] THEN bad ← bad + 1;
ENDLOOP;
lenSix =>
FOR i:
CARD16
IN [2..end)
DO
IF this.body.echoBytes[i] # lensPattern[i/6 MOD 4] THEN bad ← bad + 1;
ENDLOOP;
ENDCASE => NULL;
IF bad # 0
THEN
BEGIN
stats.wrongPackets ← stats.wrongPackets + 1;
stats.wrongWords ← stats.wrongWords + bad;
IF showWrongData THEN ShowPacket["Data mismatch", this];
END;
END;
SetChecksum:
PROC [b: Buffer] =
BEGIN
words: CARD16;
words ← (b.body.pktLength - 1)/2;
IF words <
SIZE[Header] +
SIZE[echo NSTypes.BufferBody]
THEN
b.body.checksum ← nullChecksum
ELSE
b.body.checksum ← Checksum.ComputeChecksum[
nWords: words, p: @b.body.pktLength];
END;
CheckChecksum:
PROC [b: Buffer] =
BEGIN
words: CARD16;
checksum: WORD;
IF b.body.checksum = nullChecksum THEN RETURN;
words ← (b.body.pktLength - 1)/2;
IF words > b.length THEN RETURN;
must be a bad length field in the packet
checksum ← Checksum.ComputeChecksum[nWords: words, p: @b.body.pktLength];
IF b.body.checksum # checksum THEN ShowPacket["Bad Software Checksum", b];
END;
AppendInput:
PROC [new: Buffer] =
BEGIN
p: LONG POINTER ← @new.header;
FOR i: CARD16 IN [0..20) DO (p + i)^ ← 0; ENDLOOP;
NewEthernetFace.QueueInput[ether, @new.header, new.length, new.iocb];
END;
AppendOutput:
PROC [new: Buffer] =
{ NewEthernetFace.QueueOutput[ether, @new.header, new.length, new.iocb] };
AllocateBuffer:
PROC [size:
CARD16]
RETURNS [b: Buffer] =
BEGIN
b← AllocateOneBuffer[SIZE[BufferBody] + size];
We're allocating more than we need. The driver thinks the buffer ends at
@b.header + size and it really ends at @b.header + size + SIZE[Header]
+ SIZE[echo NSTypes.BufferBody].
b.length ← size;
b.idle ← FALSE;
b.endPlusOne ← LOOPHOLE[@b.header + size];
b.endPlusOne^ ← endMarker;
marks the end of the buffer so we can see if the microcode overshoots
b.iocb ← AllocateOneIOCB[];
END;
FreeBuffer:
PROC [b: Buffer] =
BEGIN FreeOneIOCB[b.iocb]; FreeOneBuffer[b]; END;
InitializeCSBs:
PUBLIC
PROC =
BEGIN
[inputWait, inInterruptBits] ← PrincOpsUtils.AllocateNakedCondition[];
[outputWait, outInterruptBits] ← PrincOpsUtils.AllocateNakedCondition[];
Process.SetTimeout[inputWait, 100];
Process.SetTimeout[outputWait, 100];
END;
CleanThingsUp:
PUBLIC
PROC =
BEGIN
DoIt:
PROC [who:
POINTER
TO
LONG
POINTER
TO
CONDITION] =
BEGIN
IF who^ = NIL THEN RETURN;
PrincOpsUtils.DeallocateNakedCondition[who^];
who^ ← NIL;
END;
DoIt[@inputWait];
DoIt[@outputWait];
END;
TurnEtherOn:
PROC =
BEGIN
host: NSPilotSystem.HostNumber;
host ← IF promiscuous THEN NSPilotSystem.broadcastHostNumber ELSE source;
[]← NewEthernetFaceExtras.SetModeFor10MBEther[hwMode];
NewEthernetFace.TurnOn[ether, host, inInterruptBits, outInterruptBits, NIL];
END;
TurnEtherOff: PROC = { NewEthernetFace.TurnOff[ether] };
Pause: INTERNAL PROC = { WAIT fiveSeconds };
StartOne:
ENTRY
PROC [who:
PROC] =
BEGIN activeProcesses ← activeProcesses + 1; Process.Detach[FORK who[]]; END;
Start:
PROC [a, b:
PROC] =
BEGIN
oldPriority: Process.Priority = Process.GetPriority[];
activeProcesses ← 0; -- input watcher
pleaseStop ← FALSE;
StatsInit[];
TurnEtherOn[];
Process.SetPriority[priorityIOLow];
StartOne[WaitForStop];
Process.SetPriority[Process.priorityForeground];
IF a # NIL THEN StartOne[a];
IF b # NIL THEN StartOne[b];
Process.SetPriority[Process.priorityBackground];
Process.Detach[FORK Watcher[]];
Process.SetPriority[oldPriority];
END;
Watcher:
PROC =
BEGIN
THROUGH [0..100) DO Process.Yield[]; ENDLOOP;
counter ← [-1, 0, 0, 0, 0, 0, 0, -1];
StartEverybody[];
UNTIL activeProcesses = 0
DO
StatsPeek[];
Process.Yield[];
StartEverybody[];
UpdateNumbers[];
ENDLOOP;
StatsPrint[FALSE];
END;
StartEverybody:
ENTRY
PROC =
BEGIN BROADCAST waitToStart; BROADCAST letBackgroundRun; END;
PokeEverybody:
ENTRY
PROC =
BEGIN NOTIFY inputWait^; NOTIFY outputWait^; END;
DontBeAHog:
PUBLIC
PROC
RETURNS [stop:
BOOL] =
BEGIN
IF UserInput.UserAbort[log] THEN pleaseStop ← TRUE;
Process.Yield[];
RETURN[pleaseStop];
END;
WaitForStop:
PROC =
BEGIN
halfSecond: Process.Ticks = Process.MsecToTicks[500];
UNTIL pleaseStop
DO
IF UserInput.UserAbort[log] THEN pleaseStop ← TRUE;
Process.Pause[5]; -- don't hang on our ML if sender is swamped
ENDLOOP;
EnterStopping[];
END;
EnterStopping: ENTRY PROC = { Stopping[] };
Stopping:
INTERNAL
PROC =
BEGIN
activeProcesses ← activeProcesses - 1;
pleaseStop ← TRUE;
BROADCAST fiveSeconds;
BROADCAST inputWait^;
END;
END.