DIRECTORY Basics USING [LongNumber], ProcessorFace USING [GetClockPulses], StatsDefs USING [StatIncr], PupRouterDefs USING [bytesPerPupHeader, routerLock, routingTableUpdateTimeout, probeResponse, InThings, PupGateInfo, PupRouterSocket, RoutingTableEntry, RoutingTable, maxHop, TestPupChecksum, RejectPupWithBadChecksum, DontForwardPupBuffer, Reject], CommFlags USING [doShow, doStats, doStorms], DriverDefs USING [Network, Glitch], PupDefs USING [EnqueuePup, ReturnFreePupBuffer, PupBuffer, incomingPup, zappedIncomingPup], BufferDefs USING [BuffersLeft], PupTypes USING [allHosts, gatewaySoc, PupAddress, PupHostID, PupNetID], DriverTypes; PupRouterIn: MONITOR LOCKS PupRouterDefs.routerLock IMPORTS ProcessorFace, StatsDefs, PupRouterDefs, DriverDefs, PupDefs, BufferDefs EXPORTS BufferDefs, PupRouterDefs SHARES BufferDefs, DriverTypes = BEGIN OPEN StatsDefs, PupRouterDefs, DriverDefs, PupDefs, PupTypes; Network: PUBLIC TYPE = DriverDefs.Network; routerIsActive: PUBLIC BOOLEAN _ FALSE; firstSocket: PUBLIC PupRouterSocket _ NIL; routingTable: PUBLIC RoutingTable; pupForwarder: PUBLIC PROCEDURE [PupBuffer] _ DontForwardPupBuffer; inThings: PUBLIC InThings _ [inStormy: FALSE, watcherIsWatching: FALSE, watcherSeesBroadcast: FALSE, watcherCallsThis:, badChecksumProc: PupRouterDefs.RejectPupWithBadChecksum, showIn: FALSE, inShower:]; lightning: INTEGER _ 30; bolt: INTEGER _ 10; PupRouterNotActive: PUBLIC ERROR = CODE; BeSurePupIsOn: PUBLIC PROCEDURE = BEGIN IF ~routerIsActive THEN DriverDefs.Glitch[PupRouterNotActive]; END; PupInputer: PUBLIC ENTRY PROCEDURE [b: PupBuffer] = BEGIN so: PupRouterSocket; d: PupAddress _ b.dest; targetNet: PupNetID _ d.net; network: Network _ b.network; rte: RoutingTableEntry; IF CommFlags.doStats THEN StatIncr[statPupReceived]; IF b.pupLength < bytesPerPupHeader THEN BEGIN IF CommFlags.doStats THEN StatIncr[pupTooShort]; ReturnFreePupBuffer[b]; RETURN; END; IF ~TestPupChecksum[b] THEN BEGIN IF CommFlags.doStats THEN StatIncr[statReceivedBadPupChecksum]; inThings.badChecksumProc[b]; RETURN; END; IF CommFlags.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 mumble: LONG CARDINAL _ ProcessorFace.GetClockPulses[]; lightning _ -INTEGER[LOOPHOLE[mumble, Basics.LongNumber].lowbits MOD 20B]; bolt _ 10; END ELSE BEGIN lightning _ 0; bolt _ bolt + 1; END; END; IF CommFlags.doShow AND inThings.showIn THEN inThings.inShower[zappedIncomingPup, b]; ReturnFreePupBuffer[b]; IF CommFlags.doStats THEN StatIncr[statZappedP]; RETURN END; IF CommFlags.doShow AND inThings.showIn THEN inThings.inShower[incomingPup, b]; IF network.netNumber.b > 377B AND d.net = b.source.net AND (d.host = allHosts OR d.host = network.hostNumber) THEN targetNet _ d.net _ b.dest.net _ [0]; rte _ GetRoutingTableEntry[targetNet]; IF targetNet # 0 AND network.netNumber.b # 0 THEN BEGIN IF routingTable[network.netNumber.b].network # network THEN routingTable[network.netNumber.b] _ [net: [network.netNumber.b], hop: 0, time: 0, route: [0], network: network]; IF rte = NIL OR rte.network = NIL OR rte.hop # 0 OR (d.host = allHosts AND rte.network # network) THEN BEGIN pupForwarder[b]; RETURN; END; IF FALSE THEN -- It is more complicated than that..... b.pupTransportControl _ b.pupTransportControl + 20B; network _ rte.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.b = 0 AND targetNet # 0 THEN BEGIN -- packet for us, believe network number network.netNumber _ [0, targetNet]; IF targetNet < routingTable.length THEN rte^ _ [net: targetNet, hop: 0, time: 0, route: [0], network: network]; END; IF so.input.length > 1 AND BufferDefs.BuffersLeft[] < 2 THEN BEGIN IF CommFlags.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 CommFlags.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 IF b.dest.host = allHosts THEN ReturnFreePupBuffer[b] ELSE Reject[b, noProcessPupErrorCode]; END; END; ENDLOOP; END ELSE pupForwarder[b]; END; Timeout: PUBLIC ENTRY PROCEDURE = BEGIN WHILE routerIsActive DO EnumerateRoutingTable[FlushDeadNets]; WAIT routingTableUpdateTimeout; -- 30 seconds ENDLOOP; END; FlushDeadNets: PROCEDURE [rte: RoutingTableEntry] = BEGIN IF rte.hop = 0 THEN RETURN; -- directly connected IF rte.network = NIL THEN RETURN; -- no way to get there IF (rte.time _ rte.time + 30) > 180 THEN rte.network _ NIL 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 newRoute = 0 OR (length MOD 2*SIZE[PupGateInfo]) # 0 THEN BEGIN IF CommFlags.doStats THEN StatIncr[statMouseTrap]; RETURN; END; IF newRoute = network.hostNumber THEN RETURN; -- from self IF CommFlags.doStats THEN StatIncr[statPupGatewayPacketsRecv]; IF network.netNumber = [0, 0] THEN BEGIN -- we don't know our network number on this device yet net: PupNetID _ b.source.net; network.netNumber _ [0, net]; IF net < routingTable.length THEN routingTable[net] _ [net: net, hop: 0, time: 0, route: [0], network: network]; NOTIFY probeResponse; END; BEGIN data: LONG POINTER TO PupGateInfo _ LOOPHOLE[@b.pupWords[0]]; THROUGH [0..length/(2*SIZE[PupGateInfo])) DO newHop, newTime: CARDINAL; net: PupNetID _ [data.net]; rte: RoutingTableEntry; newHop _ data.hop + 1; data _ data + SIZE[PupGateInfo]; IF net >= routingTable.length THEN LOOP; -- too big, skip it rte _ GetRoutingTableEntry[net]; IF rte.hop = 0 THEN LOOP; -- directly connected IF ((rte.network = NIL OR rte.hop > maxHop) AND newHop > maxHop) THEN LOOP; IF rte.network = NIL OR (rte.route = newRoute AND rte.network = network) OR rte.time > 90 OR newHop < rte.hop OR (newHop = rte.hop AND network.speed > rte.network.speed) THEN BEGIN IF newHop > maxHop THEN BEGIN newHop _ maxHop + 1; -- dangling entry, don't rejuvenate timer newTime _ rte.time; END ELSE newTime _ 0; IF rte.hop # newHop THEN new _ TRUE; rte^ _ [net: net, hop: newHop, time: newTime, route: newRoute, network: network]; END; ENDLOOP; END; END; GetRoutingTableEntry: PUBLIC PROCEDURE [net: PupNetID] RETURNS [rte: RoutingTableEntry] = BEGIN IF net >= routingTable.length THEN RETURN[NIL]; RETURN[@routingTable[net]]; END; EnumerateRoutingTable: PUBLIC PROCEDURE [proc: PROCEDURE [RoutingTableEntry]] = BEGIN FOR n: CARDINAL IN [0..routingTable.length) DO proc[@routingTable[n]]; ENDLOOP; END; SetPupForwarder: PUBLIC PROCEDURE [proc: PROCEDURE [PupBuffer]] = BEGIN pupForwarder _ proc; END; END. PupRouterIn.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. HGM February 25, 1981 3:17 PM Birrell June 20, 1983 11:54 am Levin, August 9, 1983 9:46 am EXPORTed TYPEs SemiPublic things for PupRouterCold and friends parameters for killing packets Only called by dispatcher when a Pup arrives. Alto Pulses are short Patch to recveive broadcasts on anonymous nets from old Gateways (or replies to broadcasts) Patch in case network.netNumber isn't reflected in routingTable. This can happen if the NS router finds the network number and doesn't tell us. End patch -- Hack for Gateway init Hack special case check to avoid touching another module 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. Patch for Anonymous networks OR b.source.net ~IN[1..routingTable.length) Note: If we are not a gateway, we have probably just learned the network number of the standard Ethernet device. The users process that called PupRouterOn will normally be waiting so kick him loose. What should we do if the network number from this Pup doesn't match the one we know in network.netNumber? This is where we actually update the routing table. For all the details, see Taft's memo stored on: [MAXC]GatewayInformation.bravo 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. rejuvenate timer if nothing else Κ =˜codešœ™Kšœ Οmœ1™K˜&Kšžœ˜Kšžœ˜—K˜Kšžœ ˜Kšžœ˜Kšžœ˜—šž˜šžœ˜ Kšžœ ˜šžœžœž˜9K˜—šž˜Kšžœ (˜.šžœž˜Kšžœžœ)˜BKšžœ!˜%—Kšžœžœžœ˜7šžœžœ ž˜;Kšœžœžœ˜5—Kšžœ˜—K˜šž˜˜Kšž˜Kšœ8™8Kšžœžœ˜5Kšžœ"˜&Kšžœ˜——Kšžœ˜——Kšžœ˜—Kšž˜—Kšžœ˜Kšžœ˜K˜—šŸœžœžœž œ˜!Kšž˜šžœž˜Kšœ|™|K˜%Kšžœ  ˜-Kšžœ˜—Kšžœ˜K˜—šŸ œž œ˜3Kšž˜Kšžœ žœžœ ˜1Kš žœžœžœžœ ˜8Kšžœ"žœž˜:Kšžœ˜K˜—š Ÿ œžœžœž œžœžœ˜HKšžœžœžœ˜!K˜—š Ÿ œžœž œžœžœ˜FKšž˜K˜$K˜Kšœžœ˜$Kšœžœ ˜Kšžœ˜Kšœ™Kšœ+™+š žœžœ žœžœž˜šžœž˜"Kšžœ 6˜K˜Kšž˜—Kšžœ ˜Kšžœžœžœ˜$Kšœ ™ ˜˜7K˜——Kšžœ˜—Kšžœ˜—Kšžœ˜Kšžœ˜K˜—šŸœžœž œ˜6Kšžœ˜"Kšž˜Kšžœžœžœžœ˜/Kšžœ˜Kšžœ˜K˜—šŸœžœž œž œ˜OKšž˜šžœžœžœž˜.Kšœžœ˜ —Kšžœ˜K˜—šŸœžœž œž œ˜AKšž˜K˜Kšžœ˜K˜—Kšžœ˜K˜K˜——…—-a