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 CONDITIONNIL;
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: BOOLTRUE;
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.