-- File: PupRouterOut.mesa, Last Edit: HGM October 16, 1979 11:08 PM

-- Copyright Xerox Corporation 1979, 1980

DIRECTORY
StatsDefs: FROM "StatsDefs" USING [StatIncr],
CommUtilDefs: FROM "CommUtilDefs" USING [GetTicks],
PupRouterDefs: FROM "PupRouterDefs" USING [
routerLock, maxHop, OutThings,
PupRoutingTableEntry, BeSurePupIsOn, SetPupChecksum],
DriverDefs: FROM "DriverDefs" USING [
firstNetwork, doDebug, doShow, doStats, doStorms,
Glitch, Network, PutOnGlobalDoneQueue],
PupDefs: FROM "PupDefs" USING [
outgoingPup, zappedOutgoingPup, PupBuffer],
BufferDefs: FROM "BufferDefs",
PupTypes: FROM "PupTypes" USING [
allNets, allHosts, PupType,
PupAddress, PupHostID, PupNetID],
DriverTyp
es: FROM "DriverTypes" USING [bufferSeal];

PupRouterOut: MONITOR LOCKS PupRouterDefs.routerLock
IMPORTS StatsDefs, CommUtilDefs, PupRouterDefs, DriverDefs
EXPORTS PupRouterDefs, PupDefs
SHARES BufferDefs, DriverTypes =
BEGIN OPEN StatsDefs, PupRouterDefs, DriverDefs, PupDefs, PupTypes;

pupRoutingTableOut: PUBLIC DESCRIPTOR FOR ARRAY OF PupRoutingTableEntry;
dataWordsPerPup: PUBLIC CARDINAL;

outThings: PUBLIC OutThings ← [
outStormy: FALSE,
showOut: FALSE,
outShower: ];

-- parameters for killing packets
lightning: INTEGER ← 30;
bolt: INTEGER ← 10;

BufferSealBroken: PUBLIC ERROR = CO
DE;
IllegalPupLen
gth: PUBLIC ERROR = CODE;

PupRouterSendThis: PUBLIC ENTRY PROCEDURE [b: PupBuffer] =
BEGIN
IF b.dest.net=allNets AND b.dest.host=allHosts THEN
BEGIN
PupRouterBroadcastThis[b];
RETURN;
END;
SendUnlocked[b];
END;

SneakySendUnlocked: PUBLIC P
ROCEDURE [b: PupBuffer] = JustSendUnlocked;
JustSendUnlocked: INTERNAL PROCEDURE [b: PupB
uffer] =
B
EGIN
SendUnlocked[b];
END;

SendUnlocked: INTERNAL PROCEDURE [b: PupBuffer] =
BEGIN
d: PupAddress ← b.dest;
n: PupNetID ← d.net;
routing: POINTER TO PupRoutingTableEntry;
network: Network;
h: PupHostID;
IF doStats THE
N StatIncr[statPupSent];

IF doDebug THEN BeSurePupIsOn[];
IF doDebug AND b.seal#DriverTypes.bufferSeal THEN Glitch[BufferSealBroken];

IF doStorms AND outThings.outStormy -- for debugging only
AND (lightning←lightning+1)>bolt OR lightning<0 THEN
BEGIN
IF lightning>bolt THEN
BEGIN
IF bolt>100 THEN
BEGIN
lightning←-INTEGER[CommUtilDefs.GetTicks[] MOD 20B];
bolt←10;
END
ELSE BEGIN lightning←0; bolt←bolt+1; END;
END;
IF doShow AND outThings.showOut THEN outThings.outShower[zappedOutgoingPup,b];
PutOnGlobalDoneQueue[b];
IF doStats THEN StatIncr[statZappedP];
RETURN;
END;

-- Maybe we should do something for the local case?

b.pupTransportControl ← 0;
routing ← @pupRoutingTableOut[n];
network ← routing.network;
IF n ~IN [0..LENGTH[pupRoutingTableOut]) OR routing.hop>maxHop OR network=NIL THEN
BEGIN -- don’t know where to send it
IF doStats THEN StatIncr[statPupsSentNowhere];
IF n ~IN [0..LENGTH[pupRoutin
gTableOut]) OR network=NIL THEN
BEGIN -- Send hi
m an error Pup, but beware of RequeueProc-- END;
PutOnGlobalDoneQueue[b];
RETURN; -- wait to see if there is an alternate path
END;
b.source.host ← [network.hostNumber]; -- tell the truth
b.source.net ← [network.netNumber];
IF doShow AND outThings.showOut THEN outThings.outShower[outgoingPup,b];
h ← routing.route;
IF h=0 THEN h ← b.dest.host; -- we are on the same net
IF doDebug AND ((b.pupLength+1)/2)>dataWordsPerPup+wordsPerPupHeader THEN
DriverDefs.Glitch[IllegalPupLength];
SetPupChecksum[b];
network.encapsulat
ePup[b,h];
network.s
endBuffer[b];
END;

PupRouterBroadcastThis: PUBLIC PROCEDURE [b: PupBuffer] =
BEGIN
IF doStats THEN St
atIncr[statPupBroadcast];
IF doDebug THEN BeSurePupIsOn[];
IF doDebug AND b.seal#DriverTypes.bufferSeal THEN Glitch[BufferSealBroken];
IF DriverDefs.firstNetwork=NIL THEN BEGIN PutOnGlobalDoneQueue[b]; RETURN; END;
b.allNets ← TRUE; -- this is where it gets turned on
b.network ← DriverDefs.firstNetwork;
b.dest.host ← allHosts;
PupBroadcaster[b];
END;

-- b.netwo
rk is already set up to the desired network
PupBroadcaster: PUBLIC PROCEDURE [b: PupBuffer] =
BEGIN
network: Network ← b.network;
IF b.bypassZeroNet AND network.netNumber=0 THEN
BEGIN PutOnGlobalDoneQueue[b]; RETURN; END; -- goes (slowly) around in circles
b.pupTransportControl ← 0;
b.dest.net ← b.source.net ← [network.netNumber];
b.source.host ← [network.hostNumber];
network.encapsulatePup[b,PupTypes.allHosts];
SetPupChecksum[b];
network.sendBuffer[b];
END;

-- Pup is assumed to have arrived f
rom somewhere else. We fixup defaults here.
SwapPupSourceAndDest: PUBLIC PROCEDURE [b: PupBuffer] =
BEGIN
network: DriverDefs.Network ← b.network;
temp: PupAddress;
IF doDebug AND b.seal#DriverTypes.bufferSeal THEN Glitch[BufferSealBroken];
temp ← b.so
urce;
b.source ← b.dest;
b.dest ← temp;
--
in case we are returning a broadcast packet
IF b.dest
.net=0 THEN b.dest.net ← [network.netNumber];
IF b.source.n
et=0 THEN b.source.net ← [network.netNumber];
IF b.source.
host=PupTypes.allHosts THEN b.source.host ← [network.hostNumber];
END;

ReturnPup: PUBLIC PROCEDURE [b: PupBuffer, type: PupTypes.PupType, bytes: CARDINAL] =
BEGIN
SwapPupSourceAndDest[b];
SendPup[b,type,bytes];
END;


wordsPerPupHeader: CARDINAL = 11;
bytesPer
PupHeader: CARDINAL = wordsPerPupHeader*2;

GetPupContentsBytes: PUBLIC PROCEDURE [b: PupBuffer] RETURNS [bytes: CARDINAL] =
BEGIN
RET
URN[b.pupLength-bytesPerPupHeader];
END;

SetPupContentsBytes: PUBLIC PROCEDURE [b: PupBuffer, bytes: CARDINAL] =
BEGIN
IF bytes>dataWordsPerPup*2 THEN Glitch[IllegalPupLength];
b.p
upLength ← bytes+bytesPerPupHeader;
END;

SetPupContentsWords: PUBLIC PROCEDURE [b: PupBuffer, words: CARDINAL] =
BEGIN
IF words>dataWordsPerPup THEN Glitch[IllegalPupLength];
b.pup
Length ← words*2+bytesPerPupHeader;
END;

SendPup: PUBLIC PROCEDURE [b: PupBuffer, type: PupType, bytes: CARDINAL] =
BEGIN
b.pupType ← type;
SetPupContentsBytes[b,bytes];
PupRouterSendThis[b];
END;


END. -- PupRouterOut