-- File: PupRouterCold.mesa - last edit: -- AOF 30-Jul-85 15:07:51 -- HGM 26-Nov-85 1:36:07 -- Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved. DIRECTORY Buffer USING [ Buffer, AccessHandle, DataWordsPerPupBuffer, DestroyPool, Enqueue, GetBuffer, MakePool, Queue, ReturnBuffer, Type], CommFlags USING [doDebug], CommHeap USING [zone], CommunicationInternal USING [CommPackageGo, CommPackageOff], CommUtil USING [GetEthernetHostNumber], Driver USING [ ChangeNumberOfInputBuffers, GetInputBuffer, Glitch, Network, PutOnGlobalDoneQueue, GetDeviceChain], Frame USING [GetReturnFrame, ReadGlobalLink], Heap USING [FreeNode, MakeNode], Process USING [ EnableAborts, SetTimeout, MsecToTicks], Protocol1 USING [ Action, MatrixRecord, EvictFamily, Family, FamilyUnit, RegisterFamily, AddFamilyMember], PupDefs USING [ defaultNumberOfNetworks, SetPupContentsWords, PupRouterBroadcastThis], PupPktOps, Pup10MBit USING [Capsulators, Create, Destroy], PupRouterDefs USING [ PupRouterIn, PupRouterOut, PupChecksums, PupErrors, inThings, outThings, checksum, routerIsActive, BeSurePupIsOn, Timeout, routingTable, RoutingTableObject, RoutingTableEntry, GetRoutingTableEntry, ContextObject, dataWordsPerPup, maxHop, PupInputer, PupBroadcaster, NetworkContext], PupStream USING [], PupTypes USING [PupHostID, gatewaySoc]; PupRouterCold: MONITOR LOCKS routerLock IMPORTS Frame, Heap, Process, Buffer, CommunicationInternal, CommUtil, Driver, PupDefs, Pup10MBit, PupRouterDefs, Protocol1, CommHeap EXPORTS Buffer, PupStream, PupDefs, PupRouterDefs, PupPktOps = PUBLIC BEGIN OPEN PupRouterDefs; FreeQueueNotInitialized: ERROR = CODE; QueueSealBroken: ERROR = CODE; Network: PUBLIC TYPE = Driver.Network; routerLock: PUBLIC MONITORLOCK; routingTableUpdateTimeout: PUBLIC CONDITION; probeResponse: PUBLIC CONDITION; numberOfNetworks: PUBLIC CARDINAL ← PupDefs.defaultNumberOfNetworks; pupUseCount: CARDINAL ← 0; routerTimeoutFork: PROCESS; pupBuffersToAllocate: CARDINAL ← 15; pupBuffers: PUBLIC Buffer.AccessHandle ← NIL; -- For the entire pup package. doDebug: BOOLEAN = CommFlags.doDebug; pupProtocolFamily: PUBLIC Protocol1.FamilyUnit ← [ name: pup, status: dead, spy: NIL, state: NIL, receive: PupInputer, broadcast: PupBroadcaster, stateChanged: PupStateChanged]; CantChangeBuffersWhenActive: PUBLIC ERROR = CODE; AdjustBufferParms: PUBLIC PROC[bufferPoolSize: CARDINAL] = BEGIN IF doDebug AND pupUseCount # 0 THEN Driver.Glitch[CantChangeBuffersWhenActive]; IF bufferPoolSize # 0 THEN pupBuffersToAllocate ← bufferPoolSize; END; GetClumpOfPupBuffers: PUBLIC ENTRY PROC[ q: Buffer.Queue, n: CARDINAL, wait: BOOLEAN] = BEGIN ENABLE UNWIND => NULL; b: Buffer.Buffer; IF doDebug THEN SELECT TRUE FROM (pupUseCount = 0) => Driver.Glitch[FreeQueueNotInitialized]; (q.seal # queueSeal) => Driver.Glitch[QueueSealBroken]; ENDCASE; THROUGH [0..n) DO b ← Driver.GetInputBuffer[wait]; -- get a buffer without accounting. IF b = NIL THEN EXIT; b.type ← pup; b.pup.pupType ← data; IF CommFlags.doDebug THEN b.debug ← Frame.ReadGlobalLink[Frame.GetReturnFrame[]]; Buffer.Enqueue[q, b]; ENDLOOP; END; -- GetClumpOfPupBuffers PupPackageMake: PUBLIC PROC RETURNS [Protocol1.Family] = BEGIN AlreadyStarted: ENTRY PROC RETURNS[BOOLEAN] = INLINE {RETURN[(pupUseCount ← pupUseCount + 1) > 1]}; ProbeToStartTable: ENTRY PROC = --INLINE BEGIN ENABLE UNWIND => NULL; FOR i: CARDINAL IN [0..10) DO gotRoutingPup: BOOLEAN ← FALSE; ProbeForRoutingInfo[]; WAIT probeResponse; FOR i: CARDINAL IN [0..LENGTH[routing]) DO IF routing[i].context # NIL AND routing[i].hop # 0 THEN gotRoutingPup ← TRUE; ENDLOOP; IF gotRoutingPup THEN EXIT; ENDLOOP; END; --ProbeToStartTable driver: Network; matrix: Protocol1.MatrixRecord ← [ family: @pupProtocolFamily, context: NIL, encapsulator: NIL, decapsulator: NIL]; routing: LONG DESCRIPTOR FOR ARRAY OF RoutingTableObject; IF AlreadyStarted[] THEN RETURN[@pupProtocolFamily]; CommunicationInternal.CommPackageGo[]; Driver.ChangeNumberOfInputBuffers[TRUE]; routing ← DESCRIPTOR[ -- allocates network zero too Heap.MakeNode[ z: CommHeap.zone, n: (numberOfNetworks + 1)*SIZE[RoutingTableObject]], numberOfNetworks + 1]; FOR i: CARDINAL IN [0..LENGTH[routing]) DO routing[i] ← [net: [i], hop: maxHop + 1, time: 210, route:, context: NIL]; ENDLOOP; dataWordsPerPup ← Buffer.DataWordsPerPupBuffer[]; pupBuffers ← Buffer.MakePool[send: pupBuffersToAllocate, receive: 0]; routingTable ← routing; routerIsActive ← TRUE; routerTimeoutFork ← FORK Timeout[]; BEGIN OPEN context: LOOPHOLE[matrix.context, PupRouterDefs.NetworkContext]; Protocol1.RegisterFamily[@pupProtocolFamily]; --make pup known FOR driver ← Driver.GetDeviceChain[], driver.next UNTIL driver = NIL DO IF (driver.device # ethernet) OR ~driver.alive THEN LOOP; matrix.context ← CommHeap.zone.NEW[PupRouterDefs.ContextObject]; context.protocol ← NIL; context.pupNetNumber ← 0; context.network ← driver; context.pupHostNumber ← CommUtil.GetEthernetHostNumber[]; [matrix.decapsulator, matrix.encapsulator] ← Pup10MBit.Capsulators[]; Protocol1.AddFamilyMember[driver, @matrix]; ENDLOOP; IF routingTable[0].context = NIL THEN routingTable[0] ← [ net: [0], hop: 0, time: 0, route: [0], context: matrix.context]; END; pupProtocolFamily.status ← alive; ProbeToStartTable[]; RETURN[@pupProtocolFamily]; END; --PupPackageMake ProbeForRoutingInfo: PROC= BEGIN b: Buffer.Buffer; b ← Buffer.GetBuffer[pup, pupBuffers, send, smallBuffer, FALSE]; IF b = NIL THEN RETURN; b.bypassZeroNet ← FALSE; b.pup.pupType ← gatewayRequest; b.pup.pupID ← [0, 0]; b.pup.dest.socket ← b.pup.source.socket ← PupTypes.gatewaySoc; PupDefs.SetPupContentsWords[b, 0]; PupDefs.PupRouterBroadcastThis[b]; END; PupPackageDestroy: PUBLIC PROC= BEGIN IF doDebug THEN BeSurePupIsOn[]; IF PupPackageDestroyLocked[] THEN RETURN; WaitTillDispatcherIdle[]; JOIN routerTimeoutFork; Heap.FreeNode[z: CommHeap.zone, p: BASE[routingTable]]; Buffer.DestroyPool[pupBuffers]; Driver.ChangeNumberOfInputBuffers[FALSE]; CommunicationInternal.CommPackageOff[]; END; PupPackageDestroyLocked: ENTRY PROC RETURNS [BOOLEAN] = INLINE BEGIN IF (pupUseCount ← pupUseCount - 1) # 0 THEN RETURN[TRUE]; pupProtocolFamily.status ← dead; --turn him off Protocol1.EvictFamily[pup]; --stop dispatcher's access routerIsActive ← FALSE; NOTIFY routingTableUpdateTimeout; RETURN[FALSE]; END; WaitTillDispatcherIdle: ENTRY PROC= BEGIN ENABLE UNWIND => NULL; hit: BOOLEAN ← FALSE; arrived: CONDITION; DispatcherCalledUs: ENTRY PROC[b: Buffer.Buffer] = BEGIN ENABLE UNWIND => NULL; hit ← TRUE; Buffer.ReturnBuffer[b]; NOTIFY arrived; END; b: Buffer.Buffer = Buffer.GetBuffer[pup, pupBuffers, send, smallBuffer]; Process.EnableAborts[@arrived]; b.requeueProcedure ← DispatcherCalledUs; Driver.PutOnGlobalDoneQueue[b]; UNTIL hit DO WAIT arrived; ENDLOOP; END; GetPupPackageUseCount: PUBLIC PROC RETURNS [CARDINAL] = BEGIN RETURN[pupUseCount]; END; AddNetworkPup: PROC[driver: Network, context: PupRouterDefs.NetworkContext] = BEGIN rte: RoutingTableEntry; IF context = NIL THEN RETURN; IF driver.device = ethernet AND context.protocol = NIL THEN context.protocol ← Pup10MBit.Create[driver, [context.pupHostNumber]]; rte ← GetRoutingTableEntry[[context.pupNetNumber]]; IF rte # NIL AND context.pupNetNumber # 0 THEN rte↑ ← [ net: [context.pupNetNumber], hop: 0, time: 0, route: [0], context: context]; rte ← GetRoutingTableEntry[[0]]; IF rte.context = NIL THEN rte↑ ← [net: [0], hop: 0, time: 0, route: [0], context: context]; END; --AddNetworkPup RemoveNetworkPup: PROC[driver: Network, context: LONG POINTER] = BEGIN OPEN c: LOOPHOLE[context, PupRouterDefs.NetworkContext]; probe: BOOLEAN ← FALSE; IF ~routerIsActive THEN RETURN; -- Try to avoid ML tangle FOR i: CARDINAL IN [0..LENGTH[routingTable]) DO IF routingTable[i].context # context THEN LOOP; routingTable[i] ← [ net: [i], hop: maxHop + 1, time: 210, route:, context: NIL]; probe ← TRUE; ENDLOOP; IF driver.device = ethernet THEN Pup10MBit.Destroy[c.protocol]; IF probe THEN ProbeForRoutingInfo[]; END; --RemoveNetworkPup PupStateChanged: PROC[ driver: Network, context: LONG POINTER, why: Protocol1.Action] = BEGIN SELECT why FROM add => AddNetworkPup[driver, context]; remove => RemoveNetworkPup[driver, context]; ENDCASE; END; --StateChangedPup -- Various junky routines that live here because this is very cold code SetPupStormy: PUBLIC PROC[new: BOOLEAN] = BEGIN outThings.outStormy ← inThings.inStormy ← new; END; SetBadPupProc: PUBLIC PROC[proc: PROC[Buffer.Buffer]] = BEGIN inThings.badChecksumProc ← proc; END; InspectIncomingPups: PUBLIC PROC[ new: BOOLEAN, proc: PROC[CARDINAL, Buffer.Buffer]] = BEGIN inThings.showIn ← new; inThings.inShower ← proc; END; InspectOutgoingPups: PUBLIC PROC[ new: BOOLEAN, proc: PROC[CARDINAL, Buffer.Buffer]] = BEGIN outThings.showOut ← new; outThings.outShower ← proc; END; InspectStrayPups: PUBLIC PROC[ on, seeBroadcast: BOOLEAN, proc: PROC[Buffer.Buffer] RETURNS [error: BOOLEAN]] = BEGIN inThings.watcherIsWatching ← on; inThings.watcherSeesBroadcast ← seeBroadcast; inThings.watcherCallsThis ← proc; END; UseNullChecksumMicrocode: PUBLIC PROC= BEGIN PupRouterDefs.checksum ← none; END; UseSoftwareChecksumMicrocode: PUBLIC PROC= BEGIN PupRouterDefs.checksum ← software; END; UseAltoChecksumMicrocode: PUBLIC PROC= BEGIN PupRouterDefs.checksum ← alto; END; UsePrincOpsChecksumMicrocode: PUBLIC PROC= BEGIN PupRouterDefs.checksum ← princOps; END; -- initialization Process.EnableAborts[@routingTableUpdateTimeout]; Process.EnableAborts[@probeResponse]; START PupRouterDefs.PupRouterIn; START PupRouterDefs.PupRouterOut; START PupRouterDefs.PupChecksums; START PupRouterDefs.PupErrors; Process.SetTimeout[@routingTableUpdateTimeout, Process.MsecToTicks[30000]]; Process.SetTimeout[@probeResponse, Process.MsecToTicks[500]]; END. LOG 9-Jul-84 9:59:13 AOF Post Klamath.