-- 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