DIRECTORY BufferDefs USING [PupBuffer], DriverTypes USING [ethernetEncapsulationOffset], EthernetOneFace USING [AddCleanup, ControlBlock, DeviceHandle, GetEthernet1Address, GetNextDevice, GetStatus, GlobalStatePtr, nullDeviceHandle, QueueInput, QueueOutput, RemoveCleanup, TurnOff, TurnOn], MiniEthernetDefs USING [timedOut], PrincOpsUtils USING [LongCopy], PupTypes USING [Pair, PupAddress, PupHostID, PupNetID, PupSocketID, PupType]; MiniEthernetDriver: PROGRAM IMPORTS PrincOpsUtils, EthernetOneFace EXPORTS MiniEthernetDefs SHARES BufferDefs = { OPEN EthernetOneFace; active: BOOL _ FALSE; last: {in, out, reset}; knowBoardLocation: BOOL _ FALSE; myHost: PupTypes.PupHostID; myNet: PupTypes.PupNetID; hisEtherHost: PupTypes.PupHostID; -- separate value in case we are talking through a gateway hisNet: PupTypes.PupNetID; b: BufferDefs.PupBuffer; -- Global buffer for actual data transfers bufferSize: CARDINAL; ether: DeviceHandle; longIocb: ControlBlock; global: GlobalStatePtr; wordsPerPupHeader: CARDINAL = 11; bytesPerPupHeader: CARDINAL = wordsPerPupHeader*2; BoardLocationUnknown: PUBLIC ERROR = CODE; DriverNotActive: PUBLIC ERROR = CODE; BufferOverflow: PUBLIC ERROR = CODE; ReturnToStrangePlace: PUBLIC ERROR = CODE; ActivateDriver: PUBLIC PROC [ dataBuffer: LONG POINTER, length: CARDINAL, iocb: LONG POINTER, avoidCleanup: BOOL _ FALSE] RETURNS [BOOL] = { p: LONG POINTER _ @b.encapsulation + DriverTypes.ethernetEncapsulationOffset; q: LONG POINTER _ b; fudge: LONG CARDINAL _ p - q; net, host: CARDINAL; IF ~FindTheBoard[] THEN RETURN[FALSE]; knowBoardLocation _ TRUE; b _ dataBuffer - fudge; bufferSize _ length; longIocb _ iocb; [net, host] _ GetEthernet1Address[ether]; myHost _ [host]; myNet _ [net]; hisNet _ [0]; IF ~avoidCleanup THEN AddCleanup[ether]; TurnOn[ether, myHost, 0, 0, global]; active _ TRUE; last _ reset; RETURN[TRUE]; }; KillDriver: PUBLIC PROC [avoidCleanup: BOOL _ FALSE] = { TurnOff[ether]; IF ~avoidCleanup THEN RemoveCleanup[ether]; knowBoardLocation _ FALSE; }; GetEthernetHostNumber: PUBLIC PROC RETURNS [CARDINAL] = { net, host: CARDINAL; IF NOT knowBoardLocation THEN ERROR BoardLocationUnknown; [net, host] _ GetEthernet1Address[ether]; RETURN[host]; }; GetEthernetNetNumber: PUBLIC PROC RETURNS [CARDINAL] = { net, host: CARDINAL; IF NOT knowBoardLocation THEN ERROR BoardLocationUnknown; [net, host] _ GetEthernet1Address[ether]; RETURN[IF active THEN myNet ELSE net]; }; FindTheBoard: PROC RETURNS [BOOL] = { ether _ GetNextDevice[nullDeviceHandle]; RETURN[ether # nullDeviceHandle]; }; SendPacket: PUBLIC PROC [ dest: PupTypes.PupAddress, me: PupTypes.PupSocketID, type: PupTypes.PupType, id: PupTypes.Pair, data: LONG POINTER, bytes: CARDINAL] = { words: CARDINAL _ 2 + wordsPerPupHeader + (bytes + 1)/2; IF ~active THEN ERROR DriverNotActive; IF words > bufferSize THEN ERROR BufferOverflow; b.encapsulation.ethernetOneDest _ IF dest.net#myNet AND dest.net=hisNet AND hisNet#0 THEN hisEtherHost ELSE dest.host; b.encapsulation.ethernetOneSource _ myHost; b.encapsulation.ethernetType _ pup; b.pupLength _ bytesPerPupHeader + bytes; b.pupTransportControl _ 0; b.pupType _ type; b.pupID _ id; b.dest _ dest; b.source _ [myNet, myHost, me]; PrincOpsUtils.LongCopy[to: @b.pupWords, from: data, nwords: (bytes + 1)/2]; SetPupChecksum[b]; last _ out; QueueOutput[ ether, @b.encapsulation + DriverTypes.ethernetEncapsulationOffset, words, longIocb]; THROUGH [0..LAST[CARDINAL]) DO IF GetStatus[longIocb] # pending THEN EXIT; REPEAT FINISHED => { TurnOff[ether]; TurnOn[ether, myHost, 0, 0, global]; }; ENDLOOP; }; ReturnPacket: PUBLIC PROC [ type: PupTypes.PupType, data: LONG POINTER, bytes: CARDINAL] = { words: CARDINAL _ 2 + wordsPerPupHeader + (bytes + 1)/2; temp: PupTypes.PupAddress; IF ~active THEN ERROR DriverNotActive; IF words > bufferSize THEN ERROR BufferOverflow; IF last # in THEN ERROR ReturnToStrangePlace; b.encapsulation.ethernetOneDest _ b.encapsulation.ethernetOneSource; b.encapsulation.ethernetOneSource _ myHost; b.encapsulation.ethernetType _ pup; b.pupLength _ bytesPerPupHeader + bytes; b.pupTransportControl _ 0; b.pupType _ type; temp _ b.dest; b.dest _ b.source; b.source _ temp; PrincOpsUtils.LongCopy[to: @b.pupWords, from: data, nwords: (bytes + 1)/2]; SetPupChecksum[b]; last _ out; QueueOutput[ ether, @b.encapsulation + DriverTypes.ethernetEncapsulationOffset, words, longIocb]; THROUGH [0..LAST[CARDINAL]) DO IF GetStatus[longIocb] # pending THEN EXIT; REPEAT FINISHED => { TurnOff[ether]; TurnOn[ether, myHost, 0, 0, global]; }; ENDLOOP; }; RecvPacket: PUBLIC PROC [ source: LONG POINTER TO PupTypes.PupAddress, me: PupTypes.PupSocketID, data: LONG POINTER, words: CARDINAL, timeout: PROC RETURNS [BOOL]] RETURNS [bytes: CARDINAL, id: PupTypes.Pair, type: PupTypes.PupType] = { IF ~active THEN ERROR DriverNotActive; DO QueueInput[ ether, @b.encapsulation + DriverTypes.ethernetEncapsulationOffset, bufferSize, longIocb]; UNTIL GetStatus[longIocb] # pending DO IF timeout[] THEN { TurnOff[ether]; TurnOn[ether, myHost, 0, 0, global]; last _ reset; RETURN[MiniEthernetDefs.timedOut, [0, 0], LOOPHOLE[0]]; }; ENDLOOP; IF GetStatus[longIocb] # ok THEN LOOP; IF b.encapsulation.ethernetType # pup THEN LOOP; IF myNet # 0 AND myNet # b.dest.net AND b.dest.net # 0 THEN LOOP; IF myHost # b.dest.host THEN LOOP; -- Can't recv broadcast IF me # b.dest.socket THEN LOOP; IF source.net # 0 AND source.net # b.source.net AND b.source.net # 0 THEN LOOP; IF source.host # 0 AND source.host # b.source.host THEN LOOP; IF source.socket # [0, 0] AND source.socket # b.source.socket THEN LOOP; IF ~TestPupChecksum[b] THEN LOOP; IF myNet = 0 THEN myNet _ b.dest.net; IF hisNet=0 THEN {hisNet _ b.source.net; hisEtherHost _ [b.encapsulation.ethernetOneSource]}; IF (b.pupLength - bytesPerPupHeader) > words*2 THEN LOOP; bytes _ b.pupLength - bytesPerPupHeader; PrincOpsUtils.LongCopy[to: data, from: @b.pupWords, nwords: (bytes + 1)/2]; IF source.net = 0 THEN source.net _ b.source.net; IF source.host = 0 THEN source.host _ b.source.host; IF source.socket = [0, 0] THEN source.socket _ b.source.socket; last _ in; RETURN[bytes, b.pupID, b.pupType]; ENDLOOP; }; checksum: {software} = software; SetPupChecksum: PUBLIC PROC [b: BufferDefs.PupBuffer] = { size: CARDINAL _ (b.pupLength - 1)/2; checksumLoc: LONG POINTER _ @b.pupLength + size; cs, t: CARDINAL; SELECT checksum FROM software => { p: LONG POINTER TO ARRAY [0..0) OF WORD = LOOPHOLE[@b.pupLength]; i: CARDINAL; cs _ 0; FOR i IN [0..size) DO t _ cs + p[i]; cs _ (IF cs > t THEN t + 1 ELSE t); cs _ (IF cs >= 100000B THEN cs*2 + 1 ELSE cs*2); ENDLOOP; IF cs = 177777B THEN cs _ 0; checksumLoc^ _ cs; }; ENDCASE => NULL; }; TestPupChecksum: PUBLIC PROC [b: BufferDefs.PupBuffer] RETURNS [BOOL] = { size: CARDINAL _ ((LOOPHOLE[b.pupLength - 1, CARDINAL])/2); checksumLoc: LONG POINTER _ @b.pupLength + size; cs, t: CARDINAL; IF checksumLoc^ = 177777B THEN RETURN[TRUE]; SELECT checksum FROM software => { p: LONG POINTER TO ARRAY [0..0) OF WORD = LOOPHOLE[@b.pupLength]; i: CARDINAL; cs _ 0; FOR i IN [0..size) DO t _ cs + p[i]; cs _ (IF cs > t THEN t + 1 ELSE t); cs _ (IF cs >= 100000B THEN cs*2 + 1 ELSE cs*2); ENDLOOP; IF cs = 177777B THEN cs _ 0; }; ENDCASE => NULL; RETURN[checksumLoc^ = cs]; }; }. LOG Time: January 29, 1980 6:00 PM By: Dalal Action: fixed Core Software AR 2658. Time: February 7, 1980 11:18 PM By: Knutsen Action: ioPage now a long pointer. Initialize host socket right. INTEGER Divide Time: February 9, 1980 2:43 PM By: Knutsen/HGM Action: fix clobber of 4 words before buffer Time: April 20, 1980 4:03 PM By: HGM Action: Faceification, add ReturnPacket and timedOut Time: April 28, 1980 7:36 PM By: HGM Action: Fix QueueOutput bug (again!) in RecvPacket Time: July 2, 1980 5:44 PM By: HGM Action: Delete "DriverTypes." in front of pupEthernetPacket Time: August 20, 1980 2:23 PM By: BLyon Action: renamed EthernetFace to EthernetOneFace. Time: October 31, 1983 3:22 pm By: Birrell Action: conversion to 5.0. January 3, 1984 4:49 pm Taft Maintain separate hisEtherHost value to permit booting through gateways. φMiniEthernetDriver.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 allocate global storage Don't use constructor since that clobbers preceding 4 words Don't use constructor since that clobbers preceding 4 words should check words that arrived against pupLength? check here for routing table if we ever get that complicated Κ έ– "cedar" style˜codešœ™Kšœ Οmœ1™˜MKšœžœžœ˜Kšœžœžœ ˜Kšœ žœ˜Kšžœžœžœžœ˜&Kšœžœ˜K˜K˜K˜K˜)K˜K˜K˜ Kšžœžœ˜(Kšœ™K˜$Kšœ žœ˜K˜ Kšžœžœ˜ Kšœ˜K˜—š   œžœžœžœžœ˜8K˜Kšžœžœ˜+Kšœžœ˜Kšœ˜K˜—š  œžœžœžœžœ˜9Kšœ žœ˜Kšžœžœžœžœ˜9K˜)Kšžœ˜ Kšœ˜K˜—š  œžœžœžœžœ˜8Kšœ žœ˜Kšžœžœžœžœ˜9K˜)Kšžœžœžœžœ˜&Kšœ˜K˜—š  œžœžœžœ˜%K˜(Kšžœ˜!Kšœ˜K˜—š   œžœžœižœžœ žœ˜’Kšœžœ)˜8Kšžœ žœžœ˜&Kšžœžœžœ˜0Kšœ;™;Kš œ"žœžœžœ žœžœ ˜vK˜+K˜#K˜(K˜K˜K˜ K˜K˜KšœK˜KK˜K˜ ˜ K˜IK˜ —šžœžœžœž˜Kšžœžœžœ˜+šž˜šžœ˜ Kšœ9˜9——Kšžœ˜—Kšœ˜K˜—š   œžœžœ!žœžœ žœ˜\Kšœžœ)˜8K˜Kšžœ žœžœ˜&Kšžœžœžœ˜0Kšžœ žœžœ˜-Kšœ;™;K˜DK˜+K˜#K˜(K˜K˜K˜K˜K˜KšœK˜KK˜K˜ ˜ K˜IK˜ —šžœžœžœž˜Kšžœžœžœ˜+šž˜šžœ˜ Kšœ9˜9——Kšžœ˜—Kšœ˜K˜—š  œžœžœ žœžœžœ6žœžœ žœ žœžœžœžœ žœ0˜μKšžœ žœžœ˜&šž˜˜ K˜BK˜—šžœž˜&šžœ žœ˜K˜K˜$K˜ Kšžœ$žœ˜7Kšœ˜—Kšžœ˜—Kšžœžœžœ˜&Kšžœ$žœžœ˜0Kšœ2™2Kšœ<™