<> <> <<>> <> <<>> DIRECTORY Basics USING [bytesPerWord, LongDiv, LongMult, LowHalf], Checksum USING [ComputeChecksum], CommBuffer USING [Overhead], CommDriver USING [BufferObject], CommDriverType USING [ethernetEncapsulationBytes, ethernetEncapsulationOffset, Encapsulation, ethernetMinBytes], Endian USING [FWORD, HWORD, bytesPerHWord], EthernetFace USING [GetNextDevice, GetStatusAndCollisions, GetStatusAndLength, Handle, IOCB, nullHandle, QueueInput, QueueOutput, TurnOff, TurnOn], GermPrivate USING [ShowMP], MiniEthernetDefs USING [timedOut], MPCodes USING [germFindingPupHostNumber, serverSaysNoPupAddress], XNS USING [Address, broadcastHost, Host, unknownNet, Socket], PrincOpsUtils USING [LongCopy], ProcessorFace USING [GetClockPulses, microsecondsPerHundredPulses, ProcessorID, processorID], Pup USING [Address, allHosts, Host, Net, nullHost, nullNet, nullSocket, Socket], PupBuffer USING [noChecksum, PupBufferPointer, WordsWithoutChecksum], PupType USING [bytesOfPupOverhead, Type]; MiniEthernetDriver: PROGRAM IMPORTS Basics, Checksum, EthernetFace, GermPrivate, PrincOpsUtils, ProcessorFace, PupBuffer EXPORTS CommBuffer, MiniEthernetDefs = { Encapsulation: PUBLIC TYPE = CommDriverType.Encapsulation; BYTE: TYPE = [0..100H); active: BOOL _ FALSE; last: {in, out, reset}; myEtherHost: XNS.Host _ LOOPHOLE[ProcessorFace.processorID]; myPupHost: Pup.Host; myPupNet: Pup.Net; <> bufWords: CARDINAL = 300; bufferBytes: CARDINAL = bufWords*Basics.bytesPerWord; fudge: CARDINAL = 30; eBuff: ARRAY [0..bufWords + fudge) OF WORD; eBuffer: POINTER = LOOPHOLE[@eBuff]; b: PupBuffer.PupBufferPointer; -- Global buffer for actual data transfers ether: EthernetFace.Handle; longIocb: EthernetFace.IOCB; bytesPerPupHeader: CARDINAL = PupType.bytesOfPupOverhead; DriverNotActive: PUBLIC ERROR = CODE; BufferOverflow: PUBLIC ERROR = CODE; SendToStrangePlace: PUBLIC ERROR = CODE; ReturnToStrangePlace: PUBLIC ERROR = CODE; ActivateDriver: PUBLIC PROC [iocb: LONG POINTER] RETURNS [BOOL] = { p: LONG POINTER _ @b.ovh.encap + CommDriverType.ethernetEncapsulationOffset; q: LONG POINTER _ b; fudge: LONG CARDINAL _ p - q; b _ eBuffer - fudge; IF ~FindTheBoard[] THEN RETURN[FALSE]; longIocb _ iocb; EthernetFace.TurnOff[ether]; EthernetFace.TurnOn[ether, 0, 0]; active _ TRUE; last _ reset; myPupNet _ Pup.nullNet; myPupHost _ [GetMyPupHostNumber[]]; last _ reset; RETURN[TRUE]; }; FindTheBoard: PROC RETURNS [BOOL] = { ether _ EthernetFace.GetNextDevice[EthernetFace.nullHandle]; RETURN[ether # EthernetFace.nullHandle]; }; KillDriver: PUBLIC PROC = { EthernetFace.TurnOff[ether]; active _ FALSE; }; BorrowTheBuffer: PUBLIC PROC RETURNS [p: LONG POINTER, bytes: CARDINAL] = { RETURN[eBuffer+fudge, bufferBytes]; }; SendPacket: PUBLIC PROC [dest: Pup.Address, me: Pup.Socket, type: PupType.Type, id: Endian.FWORD, data: LONG POINTER, bytes: CARDINAL] = { words: CARDINAL = (bytes + Basics.bytesPerWord-1)/Basics.bytesPerWord; SELECT TRUE FROM dest.host = Pup.allHosts => b.ovh.encap.ethernetDest _ XNS.broadcastHost; ENDCASE => ERROR SendToStrangePlace; b.byteLength _ bytesPerPupHeader + bytes; b.type _ type; b.id _ id; b.dest _ dest; b.source.socket _ me; PrincOpsUtils.LongCopy[to: @b.byte, from: data, nwords: words]; SendPupBuffer[]; }; ReturnPacket: PUBLIC PROC [type: PupType.Type, id: Endian.FWORD, data: LONG POINTER, bytes: CARDINAL] = { words: CARDINAL = (bytes + Basics.bytesPerWord-1)/Basics.bytesPerWord; temp: Pup.Socket; IF last # in THEN ERROR ReturnToStrangePlace; b.ovh.encap.ethernetDest _ b.ovh.encap.ethernetSource; b.byteLength _ bytesPerPupHeader + bytes; b.type _ type; b.id _ id; temp _ b.dest.socket; b.dest _ b.source; b.source.socket _ temp; PrincOpsUtils.LongCopy[to: @b.byte, from: data, nwords: words]; SendPupBuffer[]; }; SendPupBuffer: PROC = { b.hopCount _ 0; b.spares _ 0; b.source.net _ myPupNet; b.source.host _ myPupHost; SetPupChecksum[b]; b.ovh.encap.ethernetType _ oldPup; SendBuffer[b.byteLength]; }; SendBuffer: PROC [bytes: CARDINAL] = { IF ~active THEN ERROR DriverNotActive; IF bytes > bufferBytes THEN ERROR BufferOverflow; IF bytes < CommDriverType.ethernetMinBytes THEN bytes _ CommDriverType.ethernetMinBytes; b.ovh.encap.ethernetSource _ myEtherHost; last _ out; EthernetFace.QueueOutput[ ether, @b.ovh.encap + CommDriverType.ethernetEncapsulationOffset, bytes + CommDriverType.ethernetEncapsulationBytes, longIocb]; THROUGH [0..LAST[CARDINAL]) DO IF EthernetFace.GetStatusAndCollisions[longIocb].status # pending THEN EXIT; REPEAT FINISHED => { EthernetFace.TurnOff[ether]; EthernetFace.TurnOn[ether, 0, 0]; }; ENDLOOP; }; RecvPacket: PUBLIC PROC [source: LONG POINTER TO Pup.Address, me: Pup.Socket, data: LONG POINTER, maxBytes: CARDINAL, timeout: PROC RETURNS [BOOL]] RETURNS [bytes: CARDINAL, id: Endian.FWORD, type: PupType.Type] = { IF ~active THEN ERROR DriverNotActive; DO EthernetFace.QueueInput[ ether, @b.ovh.encap + CommDriverType.ethernetEncapsulationOffset, bufferBytes, longIocb]; UNTIL EthernetFace.GetStatusAndLength[longIocb].status # pending DO IF timeout[] THEN { EthernetFace.TurnOff[ether]; EthernetFace.TurnOn[ether, 0, 0]; last _ reset; RETURN[MiniEthernetDefs.timedOut, [0, 0], LOOPHOLE[0]]; }; ENDLOOP; IF EthernetFace.GetStatusAndLength[longIocb].status # ok THEN LOOP; bytes _ EthernetFace.GetStatusAndLength[longIocb].bytes; IF b.ovh.encap.ethernetType = oldPupTranslation THEN { -- See PupEthernetTranslation AddressPair: TYPE = MACHINE DEPENDENT RECORD [ big: XNS.Host, small: Pup.Host, filler: [0..377B]]; raw: LONG POINTER TO CommDriver.BufferObject = LOOPHOLE[b]; inOut: LONG POINTER TO CARDINAL = LOOPHOLE[@raw.data]; request: LONG POINTER TO AddressPair = LOOPHOLE[@raw.data + 1]; translationRequest: CARDINAL = 10101B; translationResponse: CARDINAL = 7070B; IF inOut^ # translationRequest THEN LOOP; IF request.small # myPupHost THEN LOOP; raw.ovh.encap.ethernetDest _ raw.ovh.encap.ethernetSource; inOut^ _ translationResponse; request.big _ myEtherHost; SendBuffer[Basics.bytesPerWord*(1+SIZE[AddressPair]+SIZE[AddressPair])]; <> LOOP; }; IF b.ovh.encap.ethernetType # oldPup THEN LOOP; <> <> IF myPupNet # Pup.nullNet AND myPupNet # b.dest.net AND b.dest.net # Pup.nullNet THEN LOOP; IF myPupHost # b.dest.host THEN LOOP; -- Can't recv broadcast IF me # b.dest.socket THEN LOOP; IF source.net # Pup.nullNet AND source.net # b.source.net AND b.source.net # Pup.nullNet THEN LOOP; IF source.host # Pup.nullHost AND source.host # b.source.host THEN LOOP; IF source.socket # Pup.nullSocket AND source.socket # b.source.socket THEN LOOP; IF myPupNet = Pup.nullNet THEN myPupNet _ b.dest.net; bytes _ b.byteLength - bytesPerPupHeader; IF bytes > maxBytes THEN LOOP; IF ~TestPupChecksum[b] THEN LOOP; PrincOpsUtils.LongCopy[to: data, from: @b.byte, nwords: (bytes + 1)/2]; IF source.net = Pup.nullNet THEN source.net _ b.source.net; IF source.host = Pup.nullHost THEN source.host _ b.source.host; IF source.socket = Pup.nullSocket THEN source.socket _ b.source.socket; last _ in; RETURN[bytes, b.id, b.type]; ENDLOOP; }; SetPupChecksum: PROC [b: PupBuffer.PupBufferPointer] = { words: NAT = PupBuffer.WordsWithoutChecksum[b.byteLength]; checksumLoc: LONG POINTER TO Endian.HWORD _ @b.byteLength + words; checksumLoc^ _ Checksum.ComputeChecksum[0, words, @b.byteLength]; }; TestPupChecksum: PROC [b: PupBuffer.PupBufferPointer] RETURNS [BOOL] = { words: NAT = PupBuffer.WordsWithoutChecksum[b.byteLength]; checksumLoc: LONG POINTER TO Endian.HWORD _ @b.byteLength + words; hisChecksum: Endian.HWORD _ checksumLoc^; checksum: Endian.HWORD; IF hisChecksum = PupBuffer.noChecksum THEN RETURN[TRUE]; checksum _ Checksum.ComputeChecksum[0, words, @b.byteLength]; RETURN[checksum = hisChecksum]; }; <> <<>> PacketType: TYPE = MACHINE DEPENDENT { pupAddrTransPacket(4), (LAST[BYTE]) }; NSBufferPointer: TYPE = LONG POINTER TO RECORD [ ovh: CommBuffer.Overhead, checksum: Endian.HWORD, pktLength: Endian.HWORD, -- in bytes, includes header transportControl: BYTE, packetType: MACHINE DEPENDENT { pupAddrTransPacket(4), (LAST[BYTE]) }, destination: XNS.Address, source: XNS.Address, id: Endian.FWORD, code: MACHINE DEPENDENT { request(1), response(2), error(3), (LAST[Endian.HWORD]) }, body: SELECT OVERLAID * FROM request => [request: XNS.Host], response => [response: Pup.Address], ENDCASE ]; pupAddressTranslation: XNS.Socket _ LOOPHOLE[9]; myNsSocket: XNS.Socket _ LOOPHOLE[Basics.LowHalf[ProcessorFace.GetClockPulses[]]]; id: Endian.FWORD _ LOOPHOLE[ProcessorFace.GetClockPulses[]]; GetMyPupHostNumber: PROC RETURNS [Pup.Host] = { nsBuffer: NSBufferPointer _ LOOPHOLE[b]; oldB: PupBuffer.PupBufferPointer _ b; GermPrivate.ShowMP[MPCodes.germFindingPupHostNumber]; DO start: LONG CARDINAL = SetTimeout[30]; EthernetFace.TurnOff[ether]; EthernetFace.TurnOn[ether, 0, 0]; nsBuffer.pktLength _ (15+6)*Basics.bytesPerWord; nsBuffer.transportControl _ 0; nsBuffer.packetType _ pupAddrTransPacket; nsBuffer.destination _ [XNS.unknownNet, XNS.broadcastHost, pupAddressTranslation]; nsBuffer.source _ [XNS.unknownNet, myEtherHost, myNsSocket]; nsBuffer.id _ id; nsBuffer.code _ request; nsBuffer.request _ myEtherHost; b.ovh.encap.ethernetDest _ XNS.broadcastHost; b.ovh.encap.ethernetType _ xns; SetNSChecksum[nsBuffer]; SendBuffer[nsBuffer.pktLength]; UNTIL TimeoutHasExpired[start] DO EthernetFace.QueueInput[ ether, @b.ovh.encap + CommDriverType.ethernetEncapsulationOffset, bufferBytes, longIocb]; UNTIL EthernetFace.GetStatusAndLength[longIocb].status # pending DO IF TimeoutHasExpired[start] THEN { EthernetFace.TurnOff[ether]; EthernetFace.TurnOn[ether, 0, 0]; EXIT; }; ENDLOOP; IF EthernetFace.GetStatusAndLength[longIocb].status # ok THEN LOOP; IF HostsDiffer[b.ovh.encap.ethernetDest, myEtherHost] THEN LOOP; IF b.ovh.encap.ethernetType # xns THEN LOOP; IF HostsDiffer[nsBuffer.destination.host, myEtherHost] THEN LOOP; IF nsBuffer.id # id THEN LOOP; IF nsBuffer.code = error THEN GermPrivate.ShowMP[MPCodes.serverSaysNoPupAddress]; IF nsBuffer.code # response THEN LOOP; RETURN[nsBuffer.response.host]; ENDLOOP; ENDLOOP; }; <> pulsesPerSecond: CARDINAL = Basics.LongDiv[100*1000000, ProcessorFace.microsecondsPerHundredPulses]; SetTimeout: PROC [timeout: CARDINAL --seconds--] RETURNS [timer: LONG CARDINAL] = { RETURN [ProcessorFace.GetClockPulses[] + Basics.LongMult[timeout, pulsesPerSecond]]; }; TimeoutHasExpired: PROC [timer: LONG CARDINAL] RETURNS [BOOL] = { RETURN [LOOPHOLE[ProcessorFace.GetClockPulses[]-timer, INT] >= 0]; }; SetNSChecksum: PROC [b: NSBufferPointer] = { words: NAT = (b.pktLength-1)/Endian.bytesPerHWord; b.checksum _ Checksum.ComputeChecksum[0, words, @b.pktLength]; }; TestNSChecksum: PROC [b: NSBufferPointer] RETURNS [BOOL] = { words: NAT = (b.pktLength-1)/Endian.bytesPerHWord; hisChecksum: Endian.HWORD _ Checksum.ComputeChecksum[0, words, @b.pktLength]; IF b.checksum = 0FFFFH THEN RETURN[TRUE]; IF b.checksum = hisChecksum THEN RETURN[TRUE]; RETURN[FALSE]; }; HostsDiffer: PROC [a, b: XNS.Host] RETURNS [BOOL] = { <> IF a.a # b.a THEN RETURN[TRUE]; IF a.b # b.b THEN RETURN[TRUE]; IF a.c # b.c THEN RETURN[TRUE]; IF a.d # b.d THEN RETURN[TRUE]; IF a.e # b.e THEN RETURN[TRUE]; IF a.f # b.f THEN RETURN[TRUE]; RETURN[FALSE]; }; }.