-- File: Pup10MBitImpl.mesa - last edit: -- AOF 30-Jul-85 14:54:58 -- HGM 7-Dec-85 18:25:26 -- Copyright (C) 1985 by Xerox Corporation. All rights reserved. DIRECTORY Buffer USING [Buffer, GetBuffer, Type], CommFlags USING [doDebug], CommHeap USING [zone], Driver USING [Network], DriverTypes USING [Encapsulation], Process USING [ DisableTimeout, EnableAborts, SecondsToTicks, SetPriority, SetTimeout, Abort], ProcessPriorities USING [priorityIOHigh], Protocol1 USING [EncapsulatorProc, DecapsulatorProc], PupPktOps USING [pupBuffers], Pup10MBit USING [], PupRouterDefs USING [ContextObject, NetworkContext], PupStream USING [], PupTypes USING [allHosts, PupHostID], SpecialSystem USING [GetProcessorID, HostNumber, ProcessorID], System USING [ broadcastHostNumber, GetClockPulses, HostNumber, MicrosecondsToPulses, nullHostNumber, Pulses]; Pup10MBitImpl: MONITOR IMPORTS Process, Buffer, PupPktOps, CommHeap, SpecialSystem, System EXPORTS Buffer, Pup10MBit, System = BEGIN Network: PUBLIC TYPE = Driver.Network; HostNumber: PUBLIC TYPE = SpecialSystem.HostNumber; chain: Handle ← NIL; Handle: PUBLIC TYPE = LONG POINTER TO Object; Object: PUBLIC TYPE = RECORD[ depth: CARDINAL ← 0, me, all, head: TranslateEntry ← NIL, event: CONDITION, demon: PROCESS ← NIL, driver: Network, next: Handle]; TranslatePair: TYPE = LONG POINTER TO TranslateRecord; TranslateRecord: TYPE = MACHINE DEPENDENT RECORD [ nsAddr: HostNumber, pupHost: PupTypes.PupHostID, filler: [0..377B]]; TranslateEntry: TYPE = LONG POINTER TO TranslateObject; TranslateObject: TYPE = RECORD [ nextLink: TranslateEntry, translatePair: TranslateRecord, tries: CARDINAL, timeStamp: System.Pulses, status: TranslateStatus]; TranslateStatus: TYPE = {new, pending, active, zombie}; --constants retryLimit: CARDINAL = 10B; retryPulses: System.Pulses ← System.MicrosecondsToPulses[2000000]; deactivatePulses: System.Pulses ← System.MicrosecondsToPulses[180000000]; translationRequest: CARDINAL = 10101B; translationResponse: CARDINAL = 7070B; myNSHost: SpecialSystem.ProcessorID = SpecialSystem.GetProcessorID[]; Capsulators: PUBLIC PROC RETURNS[ decap: Protocol1.DecapsulatorProc, encap: Protocol1.EncapsulatorProc] = {RETURN[DecapsulatePupEthernet, EncapsulatePupEthernet]}; Create: PUBLIC PROC[driver: Network, host: PupTypes.PupHostID] RETURNS[xlate: Handle] = BEGIN xlate ← CommHeap.zone.NEW[Object]; xlate.me ← xlate.all ← xlate.head ← NIL; xlate.demon ← NIL; xlate.driver ← driver; xlate.next ← NIL; Process.EnableAborts[@xlate.event]; xlate.all ← AddTranslateRecord[xlate, [System.broadcastHostNumber, PupTypes.allHosts, 0]]; xlate.me ← AddTranslateRecord[xlate, [myNSHost, [host], 0]]; xlate.demon ← FORK Demon[driver, xlate]; IF chain = NIL THEN chain ← xlate ELSE FOR finger: Handle ← chain, finger.next DO IF finger.next # NIL THEN LOOP; finger.next ← xlate; EXIT; ENDLOOP; END; --Create Destroy: PUBLIC PROC[xlate: Handle] = BEGIN IF xlate.demon # NIL THEN {Process.Abort[xlate.demon]; JOIN xlate.demon}; --cleanup in case demon was never running UNTIL xlate.head = NIL DO e: TranslateEntry ← xlate.head; xlate.head ← e.nextLink; CommHeap.zone.FREE[@e]; ENDLOOP; IF chain = xlate THEN chain ← chain.next ELSE FOR finger: Handle ← chain, finger.next UNTIL finger.next = NIL DO IF finger.next # xlate THEN LOOP; finger.next ← finger.next.next; EXIT; ENDLOOP; END; --Delete EncapsulatePupEthernet: PUBLIC Protocol1.EncapsulatorProc = --EncapsulatorProc: TYPE = PROC[b: Buffer.Buffer, immediate: LONG POINTER]; BEGIN OPEN context: LOOPHOLE[b.context, PupRouterDefs.NetworkContext]; destination: CARDINAL ← immediate↑; nsAddr: HostNumber ← Translate[context.protocol, [destination]]; b.encapsulation ← [ethernet[ethernetDest: nsAddr, ethernetSource: myNSHost, ethernetType: pup]]; b.driver.length ← (b.pup.pupLength + 1)/2 + SIZE[DriverTypes.Encapsulation]; END; --EncapsulatePupEthernet DecapsulatePupEthernet: PUBLIC Protocol1.DecapsulatorProc = --DecapsulatorProc: TYPE = PROC[b: Buffer.Buffer] RETURNS[Buffer.Type]; BEGIN bytes: CARDINAL; ecap: CARDINAL = SIZE[DriverTypes.Encapsulation]; IF b.driver.length < ecap THEN RETURN[orphan]; --bad no matter what SELECT b.encapsulation.ethernetType FROM translation => {ReceiveTranslate[b]; RETURN[orphan]}; --one of those # pup => RETURN[vagrant]; --still unknown ENDCASE; bytes ← (b.driver.length - ecap)*2; IF bytes < b.pup.pupLength THEN RETURN[orphan] ELSE RETURN[pup]; END; --DecapsulatePupEthernet Translate: PUBLIC ENTRY PROC[xlate: Handle, pupHost: PupTypes.PupHostID] RETURNS [nsAddr: HostNumber] = BEGIN e: TranslateEntry; SELECT TRUE FROM ((e ← FindTranslate[xlate, pupHost]) = NIL) => BEGIN e ← CommHeap.zone.NEW[TranslateObject]; AddTranslate[xlate, e]; e.translatePair.pupHost ← pupHost; e.translatePair.nsAddr ← System.nullHostNumber; NOTIFY xlate.event; e.status ← new; e.tries ← 0; nsAddr ← System.nullHostNumber; e.timeStamp ← System.GetClockPulses[]; END; (e.status = active) => BEGIN IF e # xlate.head THEN {RemoveTranslate[xlate, e]; AddTranslate[xlate, e]}; nsAddr ← e.translatePair.nsAddr; e.timeStamp ← System.GetClockPulses[]; END; (e.status = zombie) => BEGIN IF e # xlate.head THEN {RemoveTranslate[xlate, e]; AddTranslate[xlate, e]}; NOTIFY xlate.event; e.status ← new; e.tries ← 0; nsAddr ← System.nullHostNumber; e.timeStamp ← System.GetClockPulses[]; END; ENDCASE; END; --interface FindTranslate: INTERNAL PROC[xlate: Handle, pupHost: PupTypes.PupHostID] RETURNS [entry: TranslateEntry] = BEGIN entry ← xlate.head; WHILE entry # NIL DO IF pupHost = entry.translatePair.pupHost THEN RETURN; entry ← entry.nextLink; ENDLOOP; END; AddTranslate: INTERNAL PROC[xlate: Handle, entry: TranslateEntry] = BEGIN entry.nextLink ← xlate.head; xlate.head ← entry; xlate.depth ← xlate.depth + 1; END; --AddTranslate RemoveTranslate: INTERNAL PROC[xlate: Handle, entry: TranslateEntry] = BEGIN e, pred: TranslateEntry; IF (pred ← xlate.head) = entry THEN {xlate.head ← xlate.head.nextLink; RETURN}; FOR e ← pred.nextLink, e.nextLink UNTIL e = NIL DO IF e # entry THEN pred ← e ELSE BEGIN pred.nextLink ← entry.nextLink; xlate.depth ← xlate.depth - 1; EXIT; END; ENDLOOP; END; AddTranslateRecord: ENTRY PROC[xlate: Handle, pair: TranslateRecord] RETURNS [e: TranslateEntry] = BEGIN e ← FindTranslate[xlate, pair.pupHost]; SELECT e FROM (NIL) => {e ← CommHeap.zone.NEW[TranslateObject]; AddTranslate[xlate, e]}; (xlate.all), (xlate.me) => RETURN; ENDCASE; e.translatePair ← pair; e.status ← active; e.timeStamp ← System.GetClockPulses[]; END; Demon: ENTRY PROC[driver: Network, xlate: Handle] = BEGIN SendRequest: INTERNAL PROC[] = BEGIN b: Buffer.Buffer; request: TranslatePair; b ← Buffer.GetBuffer[, PupPktOps.pupBuffers, send, smallBuffer, FALSE]; IF b # NIL THEN BEGIN b.encapsulation ← [ethernet[ ethernetDest: System.broadcastHostNumber, ethernetSource: myNSHost, ethernetType: translation]]; b.driver.length ← SIZE[DriverTypes.Encapsulation] + 2*SIZE[TranslateRecord] + 1; b.rawWords[0] ← translationRequest; request ← LOOPHOLE[@b.rawWords[1]]; request↑ ← e.translatePair; --also send our addresses, so responder does not fault request ← request + SIZE[TranslateRecord]; request↑ ← xlate.me.translatePair; driver.sendRawBuffer[b]; END; END; --SendRequest age: System.Pulses; e, nextE: TranslateEntry; pendingEntries: BOOLEAN; Process.SetPriority[ProcessPriorities.priorityIOHigh]; --UNTIL ABORTED-- DO ENABLE ABORTED => EXIT; WAIT xlate.event; pendingEntries ← FALSE; FOR e ← xlate.head, nextE UNTIL e = NIL DO nextE ← e.nextLink; age ← [System.GetClockPulses[] - e.timeStamp]; SELECT e.status FROM active, zombie => BEGIN SELECT TRUE FROM (age <= deactivatePulses) => NULL; (e = xlate.me) => e.timeStamp ← System.GetClockPulses[]; (e = xlate.all) => e.timeStamp ← System.GetClockPulses[]; ENDCASE => {RemoveTranslate[xlate, e]; CommHeap.zone.FREE[@e]}; END; pending => BEGIN SELECT TRUE FROM (age < retryPulses) => NULL; ((e.tries ← e.tries + 1) > retryLimit) => e.status ← zombie; ENDCASE => {SendRequest[]; e.timeStamp ← System.GetClockPulses[]}; pendingEntries ← TRUE; END; new => BEGIN e.status ← pending; SendRequest[]; e.timeStamp ← System.GetClockPulses[]; pendingEntries ← TRUE; END; ENDCASE => IF CommFlags.doDebug THEN ERROR; ENDLOOP; --end of queue entries loop IF ~pendingEntries THEN Process.DisableTimeout[@xlate.event] ELSE Process.SetTimeout[@xlate.event, Process.SecondsToTicks[1]]; ENDLOOP; FOR e ← xlate.head, nextE UNTIL e = NIL DO nextE ← e.nextLink; CommHeap.zone.FREE[@e]; e ← nextE; ENDLOOP; xlate.head ← xlate.me ← xlate.all ← NIL; END; --Demon ReceiveTranslate: PROC[b: Buffer.Buffer] = BEGIN OPEN context: LOOPHOLE[b.context, PupRouterDefs.NetworkContext]; xlate: Handle = context.protocol; SELECT b.rawWords[0] FROM translationRequest => BEGIN a: Buffer.Buffer; requesterAddr: TranslatePair; request: TranslatePair ← LOOPHOLE[@b.rawWords[1]]; request ← LOOPHOLE[@b.rawWords[1]]; IF request.pupHost = xlate.me.translatePair.pupHost THEN BEGIN --since the requester is probably going to talk to us, --add his address before we take a fault requesterAddr ← request + SIZE[TranslateRecord]; [] ← AddTranslateRecord[xlate, requesterAddr↑]; request.nsAddr ← xlate.me.translatePair.nsAddr; --send the ack back a ← Buffer.GetBuffer[, PupPktOps.pupBuffers, send, smallBuffer, FALSE]; IF a = NIL THEN RETURN; --nothing going to happen here a.encapsulation ← [ ethernet[ ethernetDest: b.encapsulation.ethernetSource, ethernetSource: myNSHost, ethernetType: translation]]; a.driver.length ← SIZE[DriverTypes.Encapsulation] + SIZE[TranslateRecord] + 1; a.rawWords[0] ← translationResponse; LOOPHOLE[@a.rawWords[1], TranslatePair]↑ ← request↑; -- UNIX checks to see if the answer is "for it" -- MIN length roundup sends the extra bits LOOPHOLE[@a.rawWords[1+SIZE[TranslateRecord]], TranslatePair]↑ ← requesterAddr↑; NARROW[b.network, Network].sendRawBuffer[a]; END; END; translationResponse => BEGIN IF b.encapsulation.ethernetDest = xlate.me.translatePair.nsAddr THEN [] ← AddTranslateRecord[xlate, LOOPHOLE[@b.rawWords[1], TranslatePair]↑]; END; ENDCASE; END; --ReceiveTranslate -- NB: There aren't any reasonable values of PupHostID to reserve for starting/stopping -- So this routine is actually just a lookup. -- If the entry doesn't exist (or is dead) nullHostNumber is returned. EnumerateTranslation: PUBLIC ENTRY PROC [old: PupTypes.PupHostID, network: Driver.Network] RETURNS[new: PupTypes.PupHostID, translation: System.HostNumber] = BEGIN entry: TranslateEntry; translation ← System.nullHostNumber; new ← old; FOR xlate: Handle ← chain, xlate.next UNTIL xlate = NIL DO IF xlate.driver # network THEN LOOP; entry ← FindTranslate[xlate, old]; IF entry # NIL AND entry.status = active THEN translation ← entry.translatePair.nsAddr; EXIT; ENDLOOP END; END... --Pup10MBitImpl