-- File: PupRouterIn.mesa, Last Edit: HGM October 15, 1979 10:08 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY StatsDefs: FROM "StatsDefs" USING [StatIncr], CommUtilDefs: FROM "CommUtilDefs" USING [GetTicks], PupRouterDefs: FROM "PupRouterDefs" USING [ routerLock, routingTableUpdateTimeout, probeResponse, InThings, PupGateInfo, PupRouterSocket, PupRoutingTableEntry, maxHop, ForwardThisPupBuffer, TestPupChecksum, RejectPupWithBadChecksum, Reject], DriverDefs: FROM "DriverDefs" USING [doShow, doStats, doStorms, Network, Glitch], PupDefs: FROM "PupDefs" USING [ EnqueuePup, ReturnFreePupBuffer, PupBuffer, incomingPup, zappedIncomingPup], BufferDefs: FROM "BufferDefs" USING [BuffersLeft], PupTypes: FROM "PupTypes" USING [ allHosts, gatewaySoc, PupAddress, PupHostID, PupNetID, noProcessPupErrorCode, resourceLimitsPupErrorCode], DriverTypes: FROM "DriverTypes"; PupRouterIn: MONITOR LOCKS PupRouterDefs.routerLock IMPORTS StatsDefs, CommUtilDefs, PupRouterDefs, DriverDefs, PupDefs, BufferDefs EXPORTS PupRouterDefs SHARES BufferDefs, DriverTypes = BEGIN OPEN StatsDefs, PupRouterDefs, DriverDefs, PupDefs, PupTypes; -- SemiPublic things for PupRouterCold and friends pupRouterIsActive: PUBLIC BOOLEAN _ FALSE; firstSocket: PUBLIC PupRouterSocket _ NIL; pupRoutingTable: PUBLIC DESCRIPTOR FOR ARRAY OF PupRoutingTableEntry; inThings: PUBLIC InThings _ [ inStormy: FALSE, watcherIsWatching: FALSE, watcherSeesBroadcast: FALSE, watcherCallsThis: , badChecksumProc: PupRouterDefs.RejectPupWithBadChecksum, showIn: FALSE, inShower: ]; -- parameters for killing packets lightning: INTEGER _ 30; bolt: INTEGER _ 10; PupRouterNotActive: PUBLIC ERROR = CODE; BeSurePupIsOn: PUBLIC PROCEDURE = BEGIN IF ~pupRouterIsActive THEN DriverDefs.Glitch[PupRouterNotActive]; END; -- Only called by dispatcher when a Pup arrives. PupInputer: PUBLIC ENTRY PROCEDURE [b: PupBuffer] = BEGIN so: PupRouterSocket; d: PupAddress _ b.dest; targetNet: PupNetID _ d.net; network: Network; routing: POINTER TO PupRoutingTableEntry; IF doStats THEN StatIncr[statPupReceived]; IF ~TestPupChecksum[b] THEN BEGIN IF doStats THEN StatIncr[statReceivedBadPupChecksum]; inThings.badChecksumProc[b]; RETURN; END; IF doStorms AND inThings.inStormy -- 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 inThings.showIn THEN inThings.inShower[zappedIncomingPup,b]; ReturnFreePupBuffer[b]; IF doStats THEN StatIncr[statZappedP]; RETURN END; IF doShow AND inThings.showIn THEN inThings.inShower[incomingPup,b]; network _ b.network; routing _ @pupRoutingTable[targetNet]; IF targetNet#0 AND network.netNumber#0 THEN BEGIN IF targetNet ~IN [0..LENGTH[pupRoutingTable]) OR routing.network=NIL OR routing.hop#0 OR (d.host=allHosts AND routing.network#network) THEN BEGIN ForwardThisPupBuffer[b]; RETURN; END; IF FALSE THEN -- It is more complicated than that..... b.pupTransportControl _ b.pupTransportControl+20B; -- Hack for Gateway init network _ routing.network; -- fixup backdoor problems END; IF (d.host=network.hostNumber OR d.host=allHosts) THEN BEGIN -- packet for us - incomming or local FOR so_firstSocket,so.next UNTIL so=NIL DO IF so.local.socket=d.socket THEN BEGIN IF network.netNumber=0 AND targetNet#0 THEN BEGIN -- packet for us, believe network number network.netNumber _ targetNet; IF targetNet1 AND BufferDefs.BuffersLeft[]<2 THEN BEGIN IF doStats THEN StatIncr[statPupInputQueueOverflow]; Reject[b,resourceLimitsPupErrorCode]; EXIT; END; EnqueuePup[@so.input,b]; NOTIFY so.ready; EXIT; END; REPEAT FINISHED => BEGIN -- not in socket table IF b.pupType=gatewayInfo AND d.socket=gatewaySoc THEN [] _ GatewaySee[b] ELSE BEGIN -- non gateway packet for unknown socket IF doStats THEN IF d.host#allHosts THEN StatIncr[statJunkPupsForUsNoLocalSocket] ELSE StatIncr[statJunkBroadcastPups]; IF ~inThings.watcherIsWatching THEN GOTO RejectThisPup; IF (d.host#allHosts OR inThings.watcherSeesBroadcast) AND inThings.watcherCallsThis[b] THEN GOTO RejectThisPup; END; ReturnFreePupBuffer[b]; EXITS RejectThisPup => BEGIN -- Hack special case check to avoid touching another module IF b.dest.host=allHosts THEN ReturnFreePupBuffer[b] ELSE Reject[b,noProcessPupErrorCode]; END; END; ENDLOOP; END ELSE ForwardThisPupBuffer[b]; END; Timeout: PUBLIC ENTRY PROCEDURE = BEGIN n: CARDINAL; rte: POINTER TO PupRoutingTableEntry; WHILE pupRouterIsActive DO -- There isn't any need to probe the Gateways if we don't know our network number, since they broadcast every 30 seconds or so. FOR n IN [0..LENGTH[pupRoutingTable]) DO rte _ @pupRoutingTable[n]; IF rte.hop=0 THEN LOOP; -- directly connected IF rte.network=NIL THEN LOOP; -- no way to get there IF (rte.time_rte.time+30)>180 THEN rte.network _ NIL ENDLOOP; WAIT routingTableUpdateTimeout; -- 30 seconds ENDLOOP; END; PupGatewaySee: PUBLIC ENTRY PROCEDURE [b: PupBuffer] RETURNS [BOOLEAN] = BEGIN RETURN[GatewaySee[b]]; END; GatewaySee: INTERNAL PROCEDURE [b: PupBuffer] RETURNS [new: BOOLEAN] = BEGIN newRoute: PupHostID = b.source.host; network: Network = b.network; length: CARDINAL = b.pupLength-22; new _ FALSE; -- no changes yet IF b.pupType#gatewayInfo OR b.source.net ~IN[1..LENGTH[pupRoutingTable]) OR newRoute=0 OR (length MOD 2*SIZE[PupGateInfo])#0 THEN BEGIN IF doStats THEN StatIncr[statMouseTrap]; RETURN; END; IF newRoute=network.hostNumber THEN RETURN; -- from self IF doStats THEN StatIncr[statPupGatewayPacketsRecv]; IF network.netNumber=0 THEN BEGIN -- we don't know our network number on this device yet network.netNumber _ b.source.net; IF network.netNumberGatewayInformation.bravo BEGIN newHop, newTime, net: CARDINAL; data: POINTER TO PupGateInfo _ LOOPHOLE[@b.pupWords[0]]; rt: POINTER TO PupRoutingTableEntry; THROUGH [0..length/(2*SIZE[PupGateInfo])) DO net _ data.net; newHop _ data.hop+1; data _ data+SIZE[PupGateInfo]; IF net>=LENGTH[pupRoutingTable] THEN LOOP; -- too big, skip it rt _ @pupRoutingTable[net]; IF rt.hop=0 THEN LOOP; -- directly connected -- This is a bit tricky. We want to keep entrys with hop>maxHop until they timeout so that Gateways will do the right things about propagating changes, but we don't want to learn new paths to nowhere. IF ((rt.network=NIL OR rt.hop>maxHop) AND newHop>maxHop) THEN LOOP; IF rt.network=NIL OR (rt.route=newRoute AND rt.network=network) OR rt.time>90 OR newHopmaxHop THEN BEGIN newHop _ maxHop+1; -- dangling entry, don't rejuvenate timer newTime _ rt.time; END ELSE newTime _ 0; IF rt.hop#newHop THEN new _ TRUE; -- rejuvenate timer if nothing else rt^ _ [ hop: newHop, time: newTime, route: newRoute, network: network ]; END; ENDLOOP; END; END; -- initialization END. -- PupRouterIn(2048)\888b11B804t10b13B2t0 16t10 11t0 68t10 7t0 51b10B1328b56B1615i70I214b7B119i132I337b13B101b10B820i147I11i45I35i250I417i206I183b120B