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]; }; }. "MiniEthernetDriver.mesa Hal Murray, June 3, 1986 3:55:16 pm PDT If you make an edit in this module, consider making the same change in MiniEthernetOneDriver. Ethernet buffer. This is merely storage for MiniDriver Extra AddressPair in the answer is a Quirk to keep Unix happy. should check words that arrived against pupLength? check here for routing table if we ever get that complicated Kludgery to use XNS protocols to learn our Pup Host number Timers - From BootChannelEther Oops. Dorados don't have multi word compare in microcode. Κ Β– "cedar" style˜codešœ™K™'—K™K™]K™šΟk ˜ Kšœœ,˜8Kšœ œ˜!Kšœ œ ˜Kšœ œ˜ Kšœœ\˜pKšœœœœ˜+Kšœ œEœ8˜“Kšœ œ ˜Kšœœ ˜"Kšœœ4˜AKšœœ4˜=Kšœœ ˜KšœœJ˜]KšœœG˜PKšœ œ6˜EKšœœ˜)K˜—šœ˜KšœU˜\Kšœ!˜(—K˜Kšœœœ ˜:K˜Kšœœ ˜K˜Kšœœœ˜K˜K˜Kšœ œœ˜™>—Kšœ˜Kšœ˜—Kšœ#œœ˜/Kšœ2™2Kšœ<™˜>šœ˜K˜——šŸœœœœ˜