DIRECTORY
Basics USING [bytesPerWord],
BasicTime USING [GetClockPulses, MicrosecondsToPulses, Pulses],
CommBuffer USING [],
Checksum USING [ComputeChecksum],
Driver USING [AllocBuffer, Buffer, dataBytesInBuffer, FreeBuffer, GetNetworkChain, Network],
DriverType USING [Encapsulation, ethernetEncapsulationBytes, ethernetEncapsulationOffset, ethernetMinBytes],
EthernetFace USING [Handle, GetNextDevice, GetStatusAndCollisions, GetStatusAndLength, nullHandle, QueueInput, QueueOutput, Status, TurnOff, TurnOn],
EthernetOneFace USING [Handle, GetHostNumber, GetNextDevice, nullHandle],
MPCodes USING [emptyMP, findingPupAddress, serverSaysNoPupAddress],
NS USING [Address, broadcastHost, GetThisHost, Host, Socket, unknownNet],
ProcessorFace USING [SetMP],
Pup USING [Address, Host, nullHost];
HackPupHostNumber:
CEDAR
PROGRAM
IMPORTS BasicTime, Checksum, Driver, EthernetFace, EthernetOneFace, NS, ProcessorFace
EXPORTS CommBuffer = {
Encapsulation: PUBLIC TYPE = DriverType.Encapsulation;
Network: TYPE = Driver.Network;
BYTE: TYPE = [0..100H);
myHostNumber: Pup.Host ← Pup.nullHost;
SmashPupHostNumber:
PROC [new: Pup.Host] = {
myHostNumber ← new;
};
GetPupHostNumber:
PROC
RETURNS [Pup.Host] = {
ether: EthernetOneFace.Handle;
IF myHostNumber # Pup.nullHost THEN RETURN[myHostNumber]; -- easy known case
If the machine has a real EthernetOne then get the address from the device.
ether ← EthernetOneFace.GetNextDevice[EthernetOneFace.nullHandle];
IF ether # EthernetOneFace.nullHandle
THEN {
myHostNumber ← [EthernetOneFace.GetHostNumber[ether]];
RETURN[myHostNumber]; };
Hard case: There is no EthernetOne, so ask the name servers for our address.
ProcessorFace.SetMP[MPCodes.findingPupAddress];
myHostNumber ← GetPupHostNumberFromServer[];
ProcessorFace.SetMP[MPCodes.emptyMP];
RETURN[myHostNumber];
};
Snitched from Germ (MiniEthernetDriverDLion) after pitching OISCP. HGM, November 1, 1985
BufferBody:
TYPE =
RECORD [
checksum: CARDINAL,
bytes: CARDINAL, -- in bytes, includes header
transportControl: BYTE,
packetType: BYTE,
dest, source: NS.Address];
translationRequest: CARDINAL = 1;
translationResponse: CARDINAL = 2;
translationError: CARDINAL = 3;
pupAddressTranslation: NS.Socket ← [0, 9];
pupAddrTransPacket: BYTE ← 6;
bytesOnWire: NAT = DriverType.ethernetMinBytes + DriverType.ethernetEncapsulationBytes;
GetPupHostNumberFromServer:
PROC
RETURNS [host: Pup.Host] =
TRUSTED {
buffer: Driver.Buffer ← Driver.AllocBuffer[];
packet: LONG POINTER TO BufferBody = LOOPHOLE[@buffer.data];
packetBytes: NAT = SIZE[BufferBody, Basics.bytesPerWord];
Request:
TYPE =
MACHINE
DEPENDENT
RECORD [
id0, id1: CARDINAL, arg: WORD, who: NS.Host];
requestBytes: NAT = packetBytes + SIZE[Request, Basics.bytesPerWord];
request: LONG POINTER TO Request = LOOPHOLE[packet+SIZE[BufferBody]];
Reply:
TYPE =
MACHINE
DEPENDENT
RECORD [
id0, id1: CARDINAL, arg: WORD, answer: Pup.Address];
reply: LONG POINTER TO Reply = LOOPHOLE[packet+SIZE[BufferBody]];
replyBytes: NAT = packetBytes + SIZE[Reply, Basics.bytesPerWord];
timeout: BasicTime.Pulses ← BasicTime.MicrosecondsToPulses[15*1000000];
mySocket: NS.Socket ← pupAddressTranslation;
me: NS.Host ← NS.GetThisHost[];
ether: EthernetFace.Handle ← EthernetFace.GetNextDevice[EthernetFace.nullHandle];
IF ether = EthernetFace.nullHandle THEN ERROR No10MBDriverAndNo3MBDriver;
DO
startPulses: BasicTime.Pulses = BasicTime.GetClockPulses[];
EthernetFace.TurnOff[ether];
EthernetFace.TurnOn[ether, 0, 0];
request^ ← [0, 0, translationRequest, me];
buffer.ovh.encap ← Encapsulation[ ethernet [
ethernetDest: NS.broadcastHost,
ethernetSource: me,
ethernetType: ns ]];
packet.bytes ← requestBytes;
packet.transportControl ← 0;
packet.packetType ← pupAddrTransPacket;
packet.dest ← [
net: NS.unknownNet,
host: NS.broadcastHost,
socket: pupAddressTranslation];
packet.source ← [
net: NS.unknownNet,
host: me,
socket: mySocket];
SetChecksum[packet];
EthernetFace.QueueOutput[
ether,
@buffer.ovh.encap+DriverType.ethernetEncapsulationOffset,
bytesOnWire,
buffer.ovh.iocb];
WHILE (BasicTime.GetClockPulses[] - startPulses) <= timeout
DO
IF EthernetFace.GetStatusAndCollisions[buffer.ovh.iocb].status # pending THEN EXIT;
REPEAT
FINISHED => {
EthernetFace.TurnOff[ether];
EthernetFace.TurnOn[ether, 0, 0]; };
ENDLOOP;
WHILE (BasicTime.GetClockPulses[] - startPulses) <= timeout
DO
buffer.ovh.encap.ethernetType ← LOOPHOLE[0];
EthernetFace.QueueInput[
ether,
@buffer.ovh.encap + DriverType.ethernetEncapsulationOffset,
Driver.dataBytesInBuffer + DriverType.ethernetEncapsulationBytes,
buffer.ovh.iocb];
WHILE (BasicTime.GetClockPulses[] - startPulses) <= timeout
DO
status: EthernetFace.Status;
bytes: NAT;
[status, bytes] ← EthernetFace.GetStatusAndLength[buffer.ovh.iocb];
IF status = pending THEN LOOP;
IF status # ok THEN EXIT;
IF buffer.ovh.encap.ethernetType # ns THEN EXIT;
IF packet.dest.host # me THEN EXIT;
IF packet.dest.socket # mySocket THEN EXIT;
IF packet.source.socket # pupAddressTranslation THEN EXIT;
IF bytes < bytesOnWire THEN EXIT;
IF packet.bytes < replyBytes THEN EXIT;
IF ~TestChecksum[packet] THEN EXIT;
IF reply.arg = translationError
THEN
ProcessorFace.SetMP[MPCodes.serverSaysNoPupAddress];
IF reply.arg # translationResponse THEN EXIT;
EthernetFace.TurnOff[ether];
host ← reply.answer.host;
Driver.FreeBuffer[buffer];
RETURN
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
SetChecksum:
PROC [b:
LONG
POINTER
TO BufferBody] =
TRUSTED {
words: CARDINAL ← ((b.bytes + Basics.bytesPerWord - 1) / Basics.bytesPerWord)-1;
b.checksum ← Checksum.ComputeChecksum[0, words, @b.bytes];
TestChecksum:
PROC [b:
LONG
POINTER
TO BufferBody]
RETURNS [
BOOL] =
TRUSTED {
words: CARDINAL ← ((b.bytes + Basics.bytesPerWord - 1) / Basics.bytesPerWord)-1;
checksum: WORD = Checksum.ComputeChecksum[0, words, @b.bytes];
IF b.checksum = 0FFFFH THEN RETURN[TRUE];
IF b.checksum = checksum THEN RETURN[TRUE];
RETURN[FALSE];
No10MBDriverAndNo3MBDriver: PUBLIC ERROR = CODE;
FOR network: Network ← Driver.GetNetworkChain[], network.next
UNTIL network =
NIL
DO
IF network.type # ethernet THEN LOOP;
IF network.pup.host # Pup.nullHost THEN LOOP; -- ????
network.pup.host ← GetPupHostNumber[];
ENDLOOP;
}....