DIRECTORY Basics USING [bytesPerWord], Checksum USING [ComputeChecksum], CommBuffer USING [], CommDriverType USING [ethernetOneEncapsulationBytes, ethernetOneEncapsulationOffset, Encapsulation], Endian USING [FWORD, HWORD, bytesPerHWord], EthernetOneFace USING [GetHostNumber, GetNextDevice, GetStatusAndCollisions, GetStatusAndLength, Handle, IOCB, nullHandle, QueueInput, QueueOutput, TurnOff, TurnOn], MiniEthernetDefs USING [timedOut], PrincOpsUtils USING [LongCopy], Pup USING [Address, allHosts, Host, Net, nullHost, nullNet, nullSocket, Socket], PupBuffer USING [noChecksum, PupBufferPointer, WordsWithoutChecksum], PupType USING [bytesOfPupOverhead, Type]; MiniEthernetOneDriver: PROGRAM IMPORTS Checksum, EthernetOneFace, PrincOpsUtils, PupBuffer EXPORTS CommBuffer, MiniEthernetDefs = { Encapsulation: PUBLIC TYPE = CommDriverType.Encapsulation; active: BOOL _ FALSE; last: {in, out, reset}; myHost: Pup.Host; myNet: 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: EthernetOneFace.Handle; longIocb: EthernetOneFace.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.ethernetOneEncapsulationOffset; q: LONG POINTER _ b; fudge: LONG CARDINAL _ p - q; IF ~FindTheBoard[] THEN RETURN[FALSE]; b _ eBuffer - fudge; longIocb _ iocb; myHost _ [EthernetOneFace.GetHostNumber[ether]]; myNet _ Pup.nullNet; EthernetOneFace.TurnOn[ether, 0, 0]; active _ TRUE; last _ reset; RETURN[TRUE]; }; FindTheBoard: PROC RETURNS [BOOL] = { ether _ EthernetOneFace.GetNextDevice[EthernetOneFace.nullHandle]; RETURN[ether # EthernetOneFace.nullHandle]; }; KillDriver: PUBLIC PROC = { EthernetOneFace.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.ethernetOneDest _ Pup.allHosts; 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.ethernetOneDest _ b.ovh.encap.ethernetOneSource; 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 _ myNet; b.source.host _ myHost; SetPupChecksum[b]; b.ovh.encap.ethernetOneType _ pup; SendBuffer[b.byteLength]; }; SendBuffer: PROC [bytes: CARDINAL] = { IF ~active THEN ERROR DriverNotActive; IF bytes > bufferBytes THEN ERROR BufferOverflow; b.ovh.encap.ethernetOneSource _ myHost; last _ out; EthernetOneFace.QueueOutput[ ether, @b.ovh.encap + CommDriverType.ethernetOneEncapsulationOffset, bytes + CommDriverType.ethernetOneEncapsulationBytes, longIocb]; THROUGH [0..LAST[CARDINAL]) DO IF EthernetOneFace.GetStatusAndCollisions[longIocb].status # pending THEN EXIT; REPEAT FINISHED => { EthernetOneFace.TurnOff[ether]; EthernetOneFace.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 EthernetOneFace.QueueInput[ ether, @b.ovh.encap + CommDriverType.ethernetOneEncapsulationOffset, bufferBytes, longIocb]; UNTIL EthernetOneFace.GetStatusAndLength[longIocb].status # pending DO IF timeout[] THEN { EthernetOneFace.TurnOff[ether]; EthernetOneFace.TurnOn[ether, 0, 0]; last _ reset; RETURN[MiniEthernetDefs.timedOut, [0, 0], LOOPHOLE[0]]; }; ENDLOOP; IF EthernetOneFace.GetStatusAndLength[longIocb].status # ok THEN LOOP; bytes _ EthernetOneFace.GetStatusAndLength[longIocb].bytes; IF b.ovh.encap.ethernetOneType # pup THEN LOOP; IF myNet # Pup.nullNet AND myNet # b.dest.net AND b.dest.net # Pup.nullNet THEN LOOP; IF myHost # 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 myNet = Pup.nullNet THEN myNet _ 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]; }; }. &MiniEthernetOneDriver.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. BLyon on: February 6, 1981 10:35 AM Birrell, October 31, 1983 3:23 pm Taft, January 3, 1984 5:12 pm Russ Atkinson (RRA) February 20, 1985 6:31:56 pm PST Hal Murray, June 3, 1986 3:57:09 pm PDT If you make an edit in this module, consider making the same change in MiniEthernetDriver. Ethernet buffer. This is merely storage for MiniDriver should check words that arrived against pupLength? check here for routing table if we ever get that complicated Κε– "cedar" style˜codešœ™Kšœ Οmœ1™