-- Copyright (C) 1983 by Xerox Corporation. All rights reserved.
-- SimpleNSIOPhoneImpl.mesa, HGM, 31-Oct-83 21:33:58
-- From Dale's SimpleNSIOEthernetImpl of 9-Aug-83 17:05:33
-- This module implements SimpleNSIO on the Ethernet (NOT the EthernetOne). It supplies level one and level zero encapsulation.
-- NOTE: The module SimpleNSIOEthernetOneImpl is a near-copy of this one. IF YOU MAKE A CHANGE HERE, it probably should be made to it too. SimplePUPIOEthernetOneImpl is another, somewhat less-similar module.
DIRECTORY
BootChannel USING [Result],
Checksum USING [ComputeChecksum],
Device USING [Type],
DriverTypes USING [DeviceType, Encapsulation],
Environment USING [Byte, bytesPerWord, first64K],
PhoneFace USING [
controlBlockSize, GetPacketLength, GetRecvStatus, GetSendStatus, Line,
maxLines, phoneLine, QueueInput, QueueOutput, TurnOff, TurnOn],
GermOps USING [GermWorldError],
Inline USING [LowHalf],
NSTypes USING [BufferBody, bytesPerIDPHeader, maxIDPWordsPerPacket, PacketType],
PilotMP USING [cGermERROR],
ProcessorFace USING [processorID],
ResidentHeap USING [FreeNode, MakeNode],
SimpleNSIO USING [
ByteCount, cantHandleDevice, Cleanups, timedOutBytes, timedOutResult],
SpecialSystem USING [
HostNumber, NetworkNumber, nullNetworkNumber, ProcessorID, SocketNumber],
System USING [
GetClockPulses, Microseconds, MicrosecondsToPulses, NetworkAddress,
nullHostNumber, nullNetworkNumber, nullSocketNumber, Pulses, SocketNumber];
SimpleNSIOPhoneImpl: PROGRAM
IMPORTS
Checksum, PhoneFace, GermOps, Inline, ProcessorFace, ResidentHeap, System
EXPORTS SimpleNSIO, System
SHARES GermOps =
BEGIN
-- PARAMETERS:
sendTimeOut: System.Microseconds = 3000000;
-- TYPES AND VARIABLES:
HostNumber: PUBLIC --System-- TYPE = SpecialSystem.HostNumber;
NetworkNumber: PUBLIC --System-- TYPE = SpecialSystem.NetworkNumber;
SocketNumber: PUBLIC --System-- TYPE = SpecialSystem.SocketNumber;
NetworkAddress: TYPE = System.NetworkAddress;
ByteCount: TYPE = SimpleNSIO.ByteCount;
Byte: TYPE = Environment.Byte;
PhonePacketType: TYPE = MACHINE DEPENDENT{
pupPhonePacket(100B),
nsPhonePacket(300B),
turnAroundPhonePacket(301B),
turnAroundMTSPhonePacket(302B),
terminatePhonePacket(303B),
terminateAckPhonePacket(304B),
(LAST[Byte])};
Encapsulation: TYPE = MACHINE DEPENDENT RECORD [
SELECT OVERLAID DriverTypes.DeviceType FROM
phonenet => [
framing0, framing1, framing2, framing3, framing4, framing5: Byte,
recognition: Byte, -- 0 for auto recognition of NS vs SDLC/HDLC
pnType: PhonePacketType,
pnSrcID: SpecialSystem.ProcessorID],
ENDCASE];
phoneEncapsulationOffset: CARDINAL = 3;
phoneEncapsulationBytes: CARDINAL = 8;
encapsulationTrap: BOOLEAN [TRUE..TRUE] =
(SIZE[Encapsulation] = SIZE[DriverTypes.Encapsulation]);
-- Level zero Ethernet packet format:
LevelZeroPacket: TYPE = MACHINE DEPENDENT RECORD [
encapsulation(0): Encapsulation,
levelOnePacket(7): NSTypes.BufferBody];
slop: CARDINAL = 12; -- Hal says we need this. We should ask why.
bufferSize: CARDINAL =
SIZE[DriverTypes.Encapsulation] +
NSTypes.maxIDPWordsPerPacket +
slop;
buffer: LONG POINTER TO LevelZeroPacket;
line: PhoneFace.Line;
longIocb: LONG POINTER ← NIL;
returnData: RECORD [returnTo, returnedFrom: NetworkAddress];
--==============================
-- Public Procedures
--==============================
GetRawBufferSize: PUBLIC PROCEDURE RETURNS [rawBufferSize: CARDINAL] = {
RETURN[bufferSize]};
Initialize: PUBLIC PROC [
deviceType: Device.Type, deviceOrdinal: CARDINAL, rawBuffer: LONG POINTER,
cleanups: SimpleNSIO.Cleanups]
RETURNS [
result: BootChannel.Result, bufferBody: LONG POINTER TO NSTypes.BufferBody] =
BEGIN
IF deviceType # PhoneFace.phoneLine THEN RETURN[SimpleNSIO.cantHandleDevice, NIL];
IF line >= PhoneFace.maxLines THEN GermOps.GermWorldError[123];
IF line # 0 THEN GermOps.GermWorldError[124];
line ← deviceOrdinal;
longIocb ← @Environment.first64K[
ResidentHeap.MakeNode[PhoneFace.controlBlockSize, a4].node];
buffer ← rawBuffer;
bufferBody ← @buffer.levelOnePacket;
TurnOn[];
RETURN[[ok[]], @buffer.levelOnePacket];
END; --Initialize--
Finalize: PUBLIC PROC [cleanups: SimpleNSIO.Cleanups] =
BEGIN
PhoneFace.TurnOff[];
[] ← ResidentHeap.FreeNode[Inline.LowHalf[longIocb]];
longIocb ← NIL;
END;
ReceivePacket: PUBLIC PROC [
getFrom: NetworkAddress, mySocket: System.SocketNumber,
timeout: System.Microseconds]
RETURNS [
result: BootChannel.Result, dataBytes: ByteCount, type: NSTypes.PacketType,
source, destination: LONG POINTER TO NetworkAddress] =
BEGIN
startTime: System.Pulses = System.GetClockPulses[];
DO --UNTIL packet arrives on requested socket--
PhoneFace.QueueInput[
line,
longIocb,
@buffer.encapsulation + phoneEncapsulationOffset,
bufferSize*Environment.bytesPerWord];
UNTIL PhoneFace.GetRecvStatus[longIocb] # pending DO
IF TimeExpired[timeout: timeout, startTime: startTime] THEN
BEGIN
PhoneFace.TurnOff[]; -- abort the input.
TurnOn[];
RETURN[
dataBytes: SimpleNSIO.timedOutBytes,
type: TRASH, source: TRASH, destination: TRASH,
result: SimpleNSIO.timedOutResult];
END;
ENDLOOP;
IF PhoneFace.GetRecvStatus[longIocb] ~= ok THEN LOOP;
IF buffer.encapsulation.pnType#nsPhonePacket THEN LOOP;
IF ~TestChecksum[@buffer.levelOnePacket] THEN LOOP;
IF buffer.levelOnePacket.destination.host ~= ProcessorFace.processorID THEN LOOP;
IF getFrom.net ~= System.nullNetworkNumber
AND getFrom.net ~= buffer.levelOnePacket.source.net THEN LOOP;
IF getFrom.host ~= System.nullHostNumber
AND getFrom.host ~= buffer.levelOnePacket.source.host THEN LOOP;
IF getFrom.socket ~= System.nullSocketNumber
AND getFrom.socket ~= buffer.levelOnePacket.source.socket THEN LOOP;
IF mySocket ~= System.nullSocketNumber
AND mySocket ~= buffer.levelOnePacket.destination.socket THEN LOOP;
IF PhoneFace.GetPacketLength[longIocb] <
BytesPerPhonePacket[
buffer.levelOnePacket.pktLength] THEN LOOP;
IF buffer.levelOnePacket.pktLength >= NSTypes.bytesPerIDPHeader THEN EXIT;
ENDLOOP;
returnData.returnTo ← (source ← @buffer.levelOnePacket.source)↑;
returnData.returnedFrom ← (destination ← @buffer.levelOnePacket.destination)↑;
RETURN[
dataBytes: buffer.levelOnePacket.pktLength - NSTypes.bytesPerIDPHeader,
type: buffer.levelOnePacket.packetType,
source: @buffer.levelOnePacket.source,
destination: @buffer.levelOnePacket.destination,
result: [ok[]]];
END; --ReceivePacket--
ReturnPacket: PUBLIC PROC [dataBytes: ByteCount, type: NSTypes.PacketType]
RETURNS [result: BootChannel.Result] =
BEGIN
buffer.levelOnePacket.source ← returnData.returnedFrom;
buffer.levelOnePacket.destination ← returnData.returnTo;
RETURN SendBuffer[dataBytes, type];
END;
SendPacket: PUBLIC PROC [
dataBytes: ByteCount, type: NSTypes.PacketType, sourceSocket: SocketNumber,
dest: NetworkAddress]
RETURNS [result: BootChannel.Result] =
BEGIN
buffer.encapsulation ← [
phonenet[
framing0: 0, framing1: 0, framing2: 0, framing3: 0, framing4: 0,
framing5: 0, recognition: 0,
pnType: nsPhonePacket, pnSrcID: LOOPHOLE[ProcessorFace.processorID]] ];
buffer.levelOnePacket.source ← [
net: SpecialSystem.nullNetworkNumber, host: ProcessorFace.processorID,
socket: sourceSocket];
buffer.levelOnePacket.destination ← dest;
[] ← SendBuffer[dataBytes, type]; -- %%%%%% STARTUP KROCK
RETURN SendBuffer[dataBytes, type];
END;
--==============================
-- Private Procedures
--==============================
Error: PROC = {GermOps.GermWorldError[PilotMP.cGermERROR]};
SendBuffer: PROC [dataBytes: ByteCount, type: NSTypes.PacketType]
RETURNS [result: BootChannel.Result] =
-- Sends buffer; doesn't return till it is sent (but times out if can't send).
BEGIN
startTime: System.Pulses;
buffer.encapsulation ← [
phonenet[
framing0: 0, framing1: 0, framing2: 0, framing3: 0, framing4: 0,
framing5: 0, recognition: 0,
pnType: nsPhonePacket, pnSrcID: LOOPHOLE[ProcessorFace.processorID]] ];
buffer.levelOnePacket.pktLength ← dataBytes + NSTypes.bytesPerIDPHeader;
buffer.levelOnePacket.transportControl ← [
trace: FALSE, filler: 0, hopCount: 0];
buffer.levelOnePacket.packetType ← type;
SetChecksum[@buffer.levelOnePacket];
PhoneFace.QueueOutput[
line, longIocb,
@buffer.encapsulation + phoneEncapsulationOffset,
BytesPerPhonePacket[buffer.levelOnePacket.pktLength]];
startTime ← System.GetClockPulses[];
DO --until sent or timed out
IF PhoneFace.GetSendStatus[longIocb] # pending THEN EXIT;
IF TimeExpired[timeout: sendTimeOut, startTime: startTime] THEN {
PhoneFace.TurnOff[]; TurnOn[]; EXIT};
ENDLOOP;
RETURN[[ok[]]];
END; --SendBuffer--
SetChecksum: PROC [b: LONG POINTER TO NSTypes.BufferBody] = {
b.checksum ← Checksum.ComputeChecksum[
0, (b.pktLength + 1 - 2)/2, @b.pktLength]};
TestChecksum: PROC [b: LONG POINTER TO NSTypes.BufferBody] RETURNS [BOOLEAN] = {
RETURN[
b.checksum = Checksum.ComputeChecksum[
0, (b.pktLength + 1 - 2)/2, @b.pktLength] OR b.checksum = 177777B]};
TimeExpired: PROC [timeout, startTime: System.Microseconds] RETURNS [BOOLEAN] =
BEGIN
IF timeout = LAST[System.Microseconds] THEN RETURN[FALSE]
ELSE
RETURN[
(System.GetClockPulses[] - startTime) > System.MicrosecondsToPulses[
timeout]];
END;
TurnOn: PROC = {PhoneFace.TurnOn[0]};
BytesPerPhonePacket: PROC [bodyBytes: CARDINAL] RETURNS [bytes: CARDINAL] =
BEGIN
words: CARDINAL ←
SIZE[DriverTypes.Encapsulation] - phoneEncapsulationOffset +
(bodyBytes + Environment.bytesPerWord-1)/Environment.bytesPerWord;
bytes ← words * Environment.bytesPerWord;
END;
END.