-- 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.