;TITLE ROUTER - Routing Layer Service for DECnet-36 V075 ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ;OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ;COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1976, 1986. ;ALL RIGHTS RESERVED. SUBTTL Loose ends ;Fix events returned to NTMAN (poorly formatted) ;Don't do BUG??? in RTCRTE if endnode ;Improve LSH's at RTR2R4 - Build into RTROAV when entered into cache? ;Highest address in Partial Routing Update Loss SUBTTL V. Brownell & Anthony J. Rizzolo/Tarl/AJR/HMP 19 FEB 86 SEARCH D36PAR,MACSYM SALL ENTRY RTRINI ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED ; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ;COPYRIGHT (C) 1981,1982,1983,1984,1985,1986 by DIGITAL EQUIPMENT CORPORATION, ; MAYNARD, MASS. ;ALL RIGHTS RESERVED. ; ; XP ROUTER,075 IFN FTOPS20,< SEARCH PROLOG TTITLE ROUTER,,< - Routing Layer Service for DECnet-36> > IFN FTOPS10,< SEARCH F,S TITLE ROUTER - Routing Layer Service for DECnet-36 .CPYRT<1981,1986> >;END OF IFN FTOPS10 D36SYM ;SET UP D36 SPECIFIC PARAMETERS IFN FTOPS10,<$RELOC> XRESCD ;RELOC TO HIGHSEG (RSCOD PSECT ON TOPS-20) SUBTTL Table of Contents ; Table of Contents for ROUTER ; ; ; Section Page ; 1. V. Brownell & Anthony J. Rizzolo/Tarl/AJR/HMP 15 Jan 85 3 ; 2. Table of Contents. . . . . . . . . . . . . . . . . . . 4 ; 3. Definitions ; 3.1. External References . . . . . . . . . . . . . 5 ; 3.2. Accumulators. . . . . . . . . . . . . . . . . 7 ; 3.3. Macros. . . . . . . . . . . . . . . . . . . . 8 ; 3.4. Packet Route Header . . . . . . . . . . . . . 9 ; 3.5. Router Control Message. . . . . . . . . . . . 10 ; 3.6. Routing Vectors . . . . . . . . . . . . . . . 11 ; 3.7. NI Hello IINFO format . . . . . . . . . . . . 12 ; 3.8. Miscellaneous . . . . . . . . . . . . . . . . 13 ; 4. Network management tables. . . . . . . . . . . . . . . 14 ; 4.1. Executor counters . . . . . . . . . . . . . . 14 ; 4.2. Circuit counters. . . . . . . . . . . . . . . 15 ; 4.3. Node parameters . . . . . . . . . . . . . . . 16 ; 4.4. Executor parameters . . . . . . . . . . . . . 17 ; 4.5. Circuit parameters. . . . . . . . . . . . . . 18 ; 5. RTRINI - Initialize Router User. . . . . . . . . . . . 19 ; 6. RTRON - Turn Router (and DECnet) On. . . . . . . . . . 20 ; 7. RTROFF - Turn Router (and DECnet) Off. . . . . . . . . 21 ; 8. RTRSEC - Once a second processing for Router . . . . . 22 ; 9. RTRJIF - Once a jiffy processing for Router. . . . . . 23 ; 10. RTRLCK - Get the RTR interlock . . . . . . . . . . . . 25 ; 11. RTRXMT - NSP's entry into Router . . . . . . . . . . . 27 ; 12. RTRFWD - Perform Routing of Message. . . . . . . . . . 28 ; 13. RTR2RM - Send Message to Remote Node . . . . . . . . . 34 ; 14. RTRBEH - Build header for ethernet data messages . . . 37 ; 15. R2NODN - Return Output Done to NSP . . . . . . . . . . 38 ; 16. R2NRTN - Return Message to NSP . . . . . . . . . . . . 39 ; 17. R2NRCV - Pass received Message to NSP. . . . . . . . . 40 ; 18. R2KINI - Initialize a Kontroller's Circuit . . . . . . 41 ; 19. R2KCLS - Close the data link circuit . . . . . . . . . 42 ; 20. CALKON - Call the Kontroller . . . . . . . . . . . . . 43 ; 21. CALQOB - Call CALKON for queued output.. . . . . . . . 44 ; 22. XMTFAI/CIRFAI - Transmit/Line failed . . . . . . . . . 45 ; 23. RTRRCR - Recompute Routing . . . . . . . . . . . . . . 46 ; 24. RTRBSV - Build scratch routing vector. . . . . . . . . 47 ; 25. RTRBNV - Build the normal vector from scratch vector . 48 ; 26. RTRBMV - Maybe vector update when running as an endnode 49 ; 27. RTRUPD - Send routing messages if needed . . . . . . . 50 ; 28. RTRSNI - Send hello/routing message on the NI. . . . . 57 ; 29. CKECTO - Check the cache timer for each node . . . . . 58 ; 30. SELDSR - Select a desiginated router . . . . . . . . . 59 ; 31. RTRTMR - Routine to perform timer functions. . . . . . 60 ; 32. RTRENH - Send Ethernet end-node hello. . . . . . . . . 67 ; 33. RTRCHH - Build common part of Ethernet hellos. . . . . 68 ; 34. DSRCHK - Check the DSR timer for each circuit. . . . . 69 ; 35. Data Link Layer Interface. . . . . . . . . . . . . . . 70 ; 35.1. RTRDLE - Entry into Router from DLL . . . . . 70 ; 35.2. RTICCB - Create circuit block . . . . . . . . 72 ; 35.3. RTILSC - Process line state change. . . . . . 73 ; 35.4. RTIOTC - Process Output Complete. . . . . . . 74 ; 35.5. RTIINC - Process Input Complete . . . . . . . 75 ; 36. RTRSTI - Send routing intitialization message. . . . . 78 ; 37. Control Message Processors ; 37.1. RTCINI - Inititialization Messages. . . . . . 80 ; 37.2. RTCVER - Verification Messages. . . . . . . . 82 ; 37.3. RTCRTE - Routing Messages . . . . . . . . . . 83 ; 37.4. RTCTST - Test or Hello Messages . . . . . . . 85 ; 37.5. RTCL2M - Level 2 Routing Messages . . . . . . 86 ; 37.6. RTCERH - Ethernet Router Hello. . . . . . . . 87 ; 37.7. RHMASR - Hello message if Endnode . . . . . . 88 ; 37.8. RHMASR - Hello message if Router. . . . . . . 89 ; 37.9. RTCNIE - NI Endnode Hello message . . . . . . 91 ; 38. RTCILL - Illegal message received. . . . . . . . . . . 92 ; 39. RTRBAV - Build adjacency's routing vector from routing update 93 ; 40. RTCRME - Routing message error processor . . . . . . . 96 ; 41. RTRPNI - Parse a Message Header for NI Hello messages 97 ; 42. PSINFO - Parse the info field of Ethernet router hello 98 ; 43. RTRRCV - Read version information from message . . . . 99 ; 44. RTRHDP - Parse a Input Router Message Header . . . . . 100 ; 45. RTRCTD - Check for valid test pattern in Hello/Test message 103 ; 46. RTRGNA - Get node address from message header. . . . . 104 ; 47. PADSKP - Skip over pad bytes in an Ethernet message header 105 ; 48. Network Management ; 48.1. RTRNMX - Entry into Router. . . . . . . . . . 106 ; 48.2. Read/Set/Clear a parameter. . . . . . . . . . 107 ; 49. Network management ; 49.1. Common routine for parameters . . . . . . . . 108 ; 49.2. Setup for loading parameter data. . . . . . . 109 ; 50. Network Management ; 50.1. Qualified parameters. . . . . . . . . . . . . 110 ; 50.2. READ node/executor state. . . . . . . . . . . 111 ; 50.3. Read circuit state. . . . . . . . . . . . . . 112 ; 50.4. Set/Clear executor state. . . . . . . . . . . 113 ; 50.5. Set/Clear circuit state . . . . . . . . . . . 114 ; 50.6. Show counters . . . . . . . . . . . . . . . . 115 ; 50.7. Show and zero counters. . . . . . . . . . . . 115 ; 50.8. Return list . . . . . . . . . . . . . . . . . 116 ; 50.9. Show known/active nodes . . . . . . . . . . . 117 ; 50.10. Show adjacent nodes . . . . . . . . . . . . . 118 ; 50.11. Show active circuits. . . . . . . . . . . . . 119 ; 50.12. Show known circuits . . . . . . . . . . . . . 120 ; 50.13. Return list of adjacencies on a circuit . . . 121 ; 51. Network Management Event Interface ; 51.1. Router Event Types. . . . . . . . . . . . . . 122 ; 51.2. Event Reason Definitions. . . . . . . . . . . 124 ; 51.3. RTNEVT - Event Reporter . . . . . . . . . . . 125 ; 51.4. Event Parameter Processors. . . . . . . . . . 126 ; 51.5. Event Processor Subroutines . . . . . . . . . 129 ; 51.6. Miscellaneous Event Processors. . . . . . . . 130 ; 52. Miscellaneous Routines ; 52.1. RTRSAO - Set Adjacency off line . . . . . . . 132 ; 52.2. RTRZCB - Zap Circuit Block. . . . . . . . . . 133 ; 52.3. RTRZAA - Zap all Adjacancies associated with RC 134 ; 53. RTRZAB - Zap an adjacency block. . . . . . . . . . . . 135 ; 54. Miscellaneous Routines ; 54.1. RTRMAJ - Make an Adjacency Block. . . . . . . 136 ; 54.2. RTRMCB - Make a Circuit Block . . . . . . . . 137 ; 54.3. RTRGCB - Get Circuit Block Pointer. . . . . . 138 ; 54.4. CPYMSG - Copy all MSDs together . . . . . . . 141 ; 55. Miscellaneous Routine ; 55.1. RTRGBS - Get maximum blocksize. . . . . . . . 142 ; 56. Miscellaneous Routines ; 56.1. RTRCBS - Get useable blocksize. . . . . . . . 143 ; 56.2. FREMSG - Toss a Message . . . . . . . . . . . 144 ; 56.3. CKSNRM - Normalize Checksum . . . . . . . . . 145 ; 57. Local Router Storage . . . . . . . . . . . . . . . . . 146 ; 58. End of ROUTER. . . . . . . . . . . . . . . . . . . . . 147 SUBTTL Definitions -- External References ;These are the external references to the D36COM library of routines. EXT DNGINI ;INITIALIZE FOR INPUT (DGXYBY) EXT DNPINI ;INITIALIZE FOR OUTPUT (DPXYBY) EXT DNP1BY ;PUT ONE BYTE IN MESSAGE EXT DNP2BY ;PUT TWO BYTES IN MESSAGE EXT DNPHIO ;Put 4 bytes of ethernet address into message EXT DNPENA ;DEPOSIT 6 BYTES FOR NI ADDRESSES EXT DNPEBY ;PUT AN EXTENSIBLE BYTE IN MESSAGE EXT DNPZB ;Write (T1) bytes of zeros into the message EXT DNG1BY ;GET ONE BYTE FROM MESSAGE EXT DNG2BY ;GET TWO BYTES FROM MESSAGE EXT DNGHIO ;Get four bytes of hi-order ethernet address EXT DNGENA ;GET SIX BYTES FROM MESSAGE EXT DNGEBY ;GET EXTENSIBLE BYTE FROM MESSAGE EXT DNGMSG ;GET DECNET-36 MESSAGE BLOCK EXT DNFMSG ;FREE MESSAGE BLOCK EXT DNMINI ;RE-USE MESSAGE BLOCK EXT DNNMSG ;GET NUMBER OF BUFFERS AVAILABLE TO ROUTER EXT DNLENG ;GET THE MESSAGE LENGTH EXT DNSLNG ;FIND THE SEGMENT LENGTH EXT DNGWDS ;GET SOME WORDS EXT DNGWDZ ;GET SOME ZEROED WORDS EXT DNFWDS ;FREE SOME WORDS EXT DNSWDS ;SMEAR SOME WORDS EXT DNBKBY ;GO BACKWARDS SOME BYTES EXT DNSKBY ;SKIP SOME BYTES EXT DNRPOS ;RETURN POSTION IN MESSAGE EXT DNGPOS ;GO TO POSITION IN MESSAGE EXT DNGOPS ;GO TO POSITION IN OUTPUT MESSAGE EXT DNLMSS ;LINK MESSAGE SEGMENT INTO MESSAGE BLOCK EXT DNCPMS ;COPY MESSAGE BLOCKS IFN FTRTST,< EXT UPDTCK ; Better TODCLK > EXT DNGTIM ;RETURN CURRENT UPTIME (IN MS) EXT NTPARM ; Routine to load parameters EXT NTCTRS ; Routine to load counters EXT TIMBAS ;Fractions of a second used for time ; computation ;References to DNADLL EXT DNDDSP ;Entry into DNADLL EXT DNDINI ;Initialization point for DNADLL EXT DNDSEC ;DNADLL second routine ;These are external data locations. EXT DCNSTA ;THE STATE VARIABLE OF DECNET EXT DCNTSB ;Maximum system buffers EXT RTRHOM ; Home area EXT RTRADR ; Our node number EXT RTRHIO ; High order Ethernet address EXT RTRLOO ; Low order Ethernet address EXT RTRBSZ ; Blocksize we advertise EXT RTRMXN ; Maximum node address we talk to EXT RTRMX3 ; Maximum number of Phase III nodes EXT RTRVER ; Version of ROUTER EXT RTRECO ; ECO level of ROUTER EXT RTRCUS ; Customer version EXT RTRXPW ; Our transmit password EXT IBBLK ;DECnet-36 initialization block ;This is the reference to LLINKS. EXT NSPRTR ;THE ONE AND ONLY ;We need to know our node name for Phase II NI messages. EXT SCTA2N ;PERFORM TRANSLATION FROM ADDRESS TO NODE NAME ;These are some default parameters EXT %RTMXN ;DEFAULT MAXIMUM NODE NUMBER EXT %RTMXC ;DEFAULT MAXIMUM CIRCUIT COST EXT %RTMXH ;DEFAULT MAXIMUM HOPS EXT %RTMX3 ;MAXIMUM NUMBER OF PHASE III NODES EXT %RTMXV ;MAXIMUM VISITS COUNT IFN FTOPS10,EXT %RTADR ;DEFAULT LOCAL ADDRESS EXT %RTRMA ;"ALL ROUTERS" MULTICAST ADDRESS EXT %RTEMA ;"ALL ENDNODES" MULTICAST ADDRESS EXT %RTHIO ;HI PART OF THE NI ADDRESS EXT %RTHOM ;HOME AREA FOR THIS NODE EXT %RTMXR ;Default maximum number of routers on the NI EXT %RTBRA ;NUMBER OF BROADCAST ROUTER ADJACENCIES EXT %RTBEA ;NUMBER OF BROADCAST ENDNODE ADJACENCIES EXT %RTPRI ;Priority to be the designated router (NI) EXT %RTTM1 ;LONG TIMER FOR POINT TO POINT EXT %RTBT1 ;LONG TIMER FOR BROADCAST EXT %RTTM3 ;DEFAULT HELLO MESSAGE TIMER EXT %RTTM4 ;DEFAULT NODE LISTENER TIMEOUT VALUE EXT %RTT3M ;HELLO TIMER MULTIPLIER FOR NON-BROADCAST EXT %RTB3M ;HELLO TIMER MULTIPLIER FOR BROADCAST CIRCUITS EXT %RTITM ;TI TIMER EXT %RTCTO ;Time we can spend in cache without update EXT %RTCST ;DEFAULT CIRCUIT COST EXT %RTVER ;ROUTER VERSION NUMBER EXT %RTECO ;EDIT LEVEL EXT %RTCUS ;CUSTOMER EDIT LEVEL ;Other external references EXT NMXEVT ;REPORT AN EVENT TO NMX EXT NTEIPV ;TELL NETWORK MANAGEMENT THAT BAD VALUE EXT KONCST ;TABLE OF DEFAULT COSTS PER KONTROLLER TYPE EXT EVSDRP ;Whether as an endnode we listen to packets ; sent to multicast ID "all routers" EXT RTN ;NON-SKIP RETURN EXT RSKP ;SKIP RETURN IFN FTOPS10,< EXT BITTBL ;TABLE OF BITS BITS==BITTBL >; END IFN FTOPS10 ;Interlock management IFN FTOPS10,< ; EXT RTRLOK ;ROUTER INTERLOCK ; EXT RTRLKO ;INTERLOCK OWNER EXT .CPCPN ;CURRENT CPU NUMBER EXT .CPSK0 ;SKIP IF CURRENT CPU IS BOOT CPU > SUBTTL Definitions -- Accumulators ;These are some local AC defintions for Router-36. RC=FREE1 ;RC USUALLY POINTS TO THE CIRCUIT BLOCK AJ=FREE2 ;AJ USUALLY POINTS TO THE ADJACENCY ENTRY PURGE FREE1 ;LOSE THIS SYMBOL PURGE FREE2 ;LOSE THIS ONE TOO IFN FTOPS10,< Q1=T5 ;RE-DEFINE THESE AGAIN Q2=T6 ;TO MATCH TOPS-20 > SUBTTL Definitions -- Macros ;Event Logging Macro DEFINE EVENT(TYPE,TEXT,MSGBLK),< CALL [ IFN FTTRACE,< ETRACE RTR, > MOVX T1,TYPE ;;PUT EVENT TYPE IN T1 IFNB ,MOVE T4,'MSGBLK ;;IF HE GAVE MB POINTER, GIVE IT IFB , SETZ T4, ;;IF NOT, GIVE RTNEVT A ZERO CALLRET RTNEVT] ;;CALL THE EVENT PROCESSOR AND RETURN > REPEAT 0,< DEFINE EVENT(TYPE,TEXT,MSGBLK),< CALL RTNEVT CAI [IFN FTTRACE,> TYPE MSGBLK] > > SUBTTL Definitions -- Packet Route Header ;The first byte of the packet route header is defined in the Router ;section of the message block structure. This is purely for convience ;sake. The whole byte is called RMFST and each bit is defined within ;this field. ;The only other field that has to be defined (other than the source and ;destination address) is the FORWARD field which simply consists of the ;VISITS field. BEGSTR FW ;FORWARD BYTE FIELDM VST,77 ; VISITS COUNT ENDSTR SUBTTL Definitions -- Router Control Message ;The following are field definitions for the Router Control messages. ;Control message all begin with the field CTLFLG, which specifies the type ;of control message. BEGSTR CM ;CTLFLG FIELDM TYP,7_1 ; TYPE OF MESSAGE FIELDM CTL,1 ENDSTR ;These are the various types of router control messages (in CMTYP). XP RCM.TI,0 ;Router init XP RCM.TV,1 ;Router verification XP RCM.TT,2 ;Router hello and test XP RCM.1R,3 ;Level 1 routing message XP RCM.2R,4 ;Level 2 routing message XP RCM.RH,5 ;Ethernet Router hello message XP RCM.EH,6 ;Ethernet Endnode hello mesaage ;Routing control messages consist of a RTGINFO entry for every node in ;the network, followed by a two byte checksum. BEGSTR RG ;RTGINFO FIELDM HOP,37_^D10 ; HOPS FIELDM CST,1777 ; COST ENDSTR ;Transport Initialization control messages start with field TIINFO which ;contains the node type and verification required flags. BEGSTR TI ;TIINFO FIELDM RSV,36_3 ; RESERVED FIELDM BLO,1_3 ;BLOCKING REQUESTED FIELDM VER,1_2 ; VERIFY FLAG FIELDM NTY,3 ; NODE TYPE ENDSTR XP TI.MXL,^D12 ;MAX LENGTH OF ROUTER INIT MSG ;These are the possible types of nodes that can be at the other end ;of a circuit (in FIELD TINTY). XP ANT.XX,0 ;RESERVED XP ANT.L2,1 ;LEVEL 2 ROUTER XP ANT.L1,2 ;LEVEL 1 ROUTER XP ANT.RT,2 ;ROUTING XP ANT.NR,3 ;NON-ROUTING ;Router hello message has NO.HEL bytes of the byte HEL.LO. XP NO.HEL,^D10 ;NUMBER OF TEST BYTES XP NO.NIH,^D64 ;Number of test bytes in endnode hello XP HEL.LO,^O252 ;CONSTANT FOR HELLO AND TEST MESSAGES SUBTTL Definitions -- Routing Vectors ;These are the definitions for each entry in both the scratch and the ;normal routing vectors. The vectors consist of one entry for each ;possible node in the network. Non-existant (un-reachable) nodes are ;set to the maximum node cost and hops. BEGSTR RN FIELD FLG,6 ;Flags BIT RCH ;If set, node is reachable BIT LCL ;Node is local NSP user BIT CHG ;Node status was changed BIT CCH ;Node is in the on-ethernet cache BIT MBY ;Node maybe reachable (if we are an endnode) FILLER 15 FIELD HOP,5 ;MIN HOPS FIELD CST,10 ;MIN COST ENDSTR ;Define right justified symbols for max-cost and max-hops. XP RN%CST,MASK.(WID(RNCST),^D35) ;MAX COST XP RN%HOP,MASK.(WID(RNHOP),^D35) ;MAX HOPS SUBTTL Definitions -- NI Hello IINFO format BEGSTR II FIELDM TYP,3 ;NODE TYPE FIELDM VRQ,1_2 ;VERIFICATION REQUIRED (0 FOR NI) FIELDM RJF,1_3 ;REJECT FLAG FIELDM VFL,1_4 ;VERIFICATION FAILED FIELDM MTA,1_5 ;NO MULTI-CAST ACCEPTED FIELDM BRQ,1_6 ;BLOCKING REQUESTED FLAG FIELDM RSV,1_7 ;RESERVED BIT ENDSTR ;These are the values in the IITYP field XP IIT.L2,1 ;LEVEL 2 ROUTER XP IIT.L1,2 ;LEVEL 1 ROUTER XP IIT.EN,3 ;ENDNODE SUBTTL Definitions -- Miscellaneous SUBTTL Network management tables SUBTTL Network management tables -- Executor counters ;Generate the executor counter table XSWAPCD EXCTAB: COUNTER(^D900,^D8,,,,) COUNTER(^D901,^D16,,,,< Node unreachable packet loss>) COUNTER(^D902,^D8,,,,< Node out-of-range packet loss>) COUNTER(^D903,^D8,,,,) COUNTER(^D910,^D8,,,,) COUNTER(^D920,^D8,,,,< Partial routing update loss>) COUNTER(^D930,^D8,,,,) EXCTBL==.-EXCTAB SUBTTL Network management tables -- Circuit counters CICTAB: ;Circuit counters maintained by the circuit COUNTER (^D0,^D16, LOAD T2,RCSLZ,(RC) ; Time stamp of last zeroed CALL DNGTIM ; Current time SUB T1,T2 ; Compute milliseconds IDIVI T1,TIMBAS ; and return as seconds RET ]>,< CALL [CALL DNGTIM STOR T1,RCSLZ,(RC) RET ]>,,) COUNTER(^D800,^D32,,,,< Terminating packets received>) COUNTER(^D801,^D32,,,,< Originating packets sent>) COUNTER(^D802,^D16,,,,< Terminating congestion loss>) COUNTER(^D810,^D32,,,,< Transit packets received>) COUNTER(^D811,^D32,,,,< Transit packets sent>) COUNTER(^D812,^D16,,,,< Transit congestion loss>) COUNTER(^D820,^D8,,,,) COUNTER(^D821,^D8,,,,< Initialization failure>) COUNTER (^D2500,^D16,,,,< Transmit packets discarded-blocksize exceeded>) CICTBL==.-CICTAB SUBTTL Network management tables -- Node parameters NOSET==PANST ;From BEGSTR in D36PAR NOCLR==PANCL BEX==PABEX ;Buffer expected NDPTAB: PARAMETER(0,,,,,,,,) PARAMETER(^D810,,,,,,< CALL [SKIPN AJ RNMXND LOAD T2,AJNTY,(AJ) RNMXOK ]>,,< Adjacency type>) PARAMETER(^D820,,,,,,< CALL [SKIPN P2 RNMXND LOAD T2,RNCST,(P2) RNMXOK ]>,,) PARAMETER(^D821,,,,,,< CALL [SKIPN P2 RNMXND LOAD T2,RNHOP,(P2) RNMXOK ]>,,) PARAMETER(^D822,,,,,,,,) PARAMETER(^D830,,,,,,< CALL [SKIPN AJ RNMXND MOVE T2,RTRNTY CAIE T2,RNT.NR IFSKP. LOAD T2,NFEID,(P1) MOVE T1,T2 LSH T1,-^D10 CAME T1,RTRHOM IFSKP. TXZ T2,RN%ARE ADD T2,RTRNRV TMNN RNCCH,(T2) IFSKP. LOAD T2,NFEID,(P1) RNMXOK ENDIF. ENDIF. ENDIF. LOAD T2,AJADR,(AJ) RNMXOK ]>,,< Next node>) ;Note: The following parmameter is used for the NODE JSYS function .NDGNT ; only. Is is NEVER used by NTMAN and is not part of the specified ; DECnet architecture. PARAMETER(^D2503,,,,,,,,) NDPTBL==.-NDPTAB SUBTTL Network management tables -- Executor parameters EXPTAB: PARAMETER(0,,,,,,,,< Executor state>) PARAMETER(^D900,,,,,,,,) PARAMETER(^D901,,,,,,,,) PARAMETER(^D910,,,,<%RTTM1>,,< CALL [MOVE T2,RTRTM1 IDIVI T2,TIMBAS RNMXOK ]>,< CALL [IMULI T2,TIMBAS MOVEM T2,RTRTM1 RNMXOK ]>,) PARAMETER(^D912,,,,<%RTBT1>,,< CALL [MOVE T2,RTRBT1 IDIVI T2,TIMBAS RNMXOK ]>,< CALL [IMULI T2,TIMBAS MOVEM T2,RTRBT1 RNMXOK ]>,) PARAMETER(^D920,,,,,,,,) PARAMETER(^D921,,<^D20>,<^D1>,<^D20>,,,< MOVEM T2,RTRMCN>,) PARAMETER(^D922,,<^D1022>,<1>,<%RTMXC>,,,< MOVEM T2,RTRMXC>,) PARAMETER(^D923,,<^D30>,<1>,<%RTMXH>,,,< MOVEM T2,RTRMXH>,) PARAMETER(^D924,,<^D30>,<1>,<%RTMXV>,,,< MOVEM T2,RTRMXV>,) PARAMETER(^D926,,<^D1022>,<0>,<%RTBEA>,,,< MOVEM T2,RTNBEA>,) PARAMETER(^D927,,<^D64>,<0>,<%RTBRA>,,,< MOVEM T2,RTNBRA>,) PARAMETER(^D930,,,,,,,,) PARAMETER(^D931,,,,,,,,) PARAMETER(^D932,,,,,,,,) ;See note above PARAMETER(^D2503,,,,,,,,) EXPTBL==.-EXPTAB SUBTTL Network management tables -- Circuit parameters CCPTAB: PARAMETER(0,,,,,,,,< Circuit state>) PARAMETER(^D800,,,,,,,,) PARAMETER(^D801,,,,,,,,) PARAMETER(^D810,,,,,,,,) PARAMETER(^D900,,<^D25>,<1>,<1>,,< LOAD T2,RCCST,(RC)>,< CALL [ STOR T2,RCCST,(RC) CALL SETRCX RNMXOK]>,) PARAMETER(^D901,,<^D255>,<0>,<%RTMXR>,,< LOAD T2,RCMXR,(RC)>,< STOR T2,RCMXR,(RC)>,) PARAMETER(^D902,,<^D127>,<0>,<0>,,,< MOVEM T2,RTRPRI>,) PARAMETER(^D906,,<^D8191>,<1>,<%RTTM3>,,< CALL [LOAD T2,RCTM3,(RC) IDIVI T2,TIMBAS RNMXOK ]>,< CALL [IMULI T2,TIMBAS STOR T2,RCTM3,(RC) RNMXOK ]>,) PARAMETER(^D907,,,,,,,,< Listen timer>) CCPTBL==.-CCPTAB XRESCD SUBTTL Initialization - Compute Core Requirements ;RTRCCR computes ROUTER's core requirements. ;Call: ; PUSHJ P,RTRCCR ;Returns: ; T1/ Size of ROUTER core IFN FTOPS10,< RTRCCR::LOAD T1,IBMXA,+IBBLK ;GET MAXIMUM NODE ADDRESS ADDI T1,1 ;PLUSE ONE FOR NODE 0 ASH T1,1 ;COMPUTE SIZE OF OUR ROUTING VECTOR RET ;AND RETURN >; END IFN FTOPS10 SUBTTL RTRINI - Initialize Router User ;RTRINI - Set up a router user ; ; Call: ; with nothing ; ; Return: ; RET ;ON RESOURCE FAILURE ; RETSKP ;ON SUCCESS ; ; Uses: T1-T3 ; ;This routine gets called at system initialization. It sets up the memory ;for the routing vectors and the node type vector. Must be called before ;DECnet is turned on. INTERN RTRINI XSWAPCD RTRINI: TRACE RTR, ;Get the Router parameters defined in SETSPD's config file XMOVEI T2,IBBLK ; Get pointer to initialization block LOAD T1,IBRTR,(T2) ; Get Router type desired MOVEM T1,RTRNTY ; Save as our node type SETZM ENFLG ; Assume routing IV CAIN T1,RNT.NR ; Are we an endnode today? SETOM ENFLG ; Yes, then non-routing IV IFN FTOPS10,< MOVX T1,ST%END ; Get configuration status endnode flag SKIPE ENFLG ; Are we running as an endnode today? IORM T1,CNFST2## ; Yes, set flag >; END IFN FTOPS10 LOAD T1,IBADR,(T2) ; Get 16 bit node address MOVEM T1,RTRNAD TXZ T1,RN%ARE ; Clear the area number MOVEM T1,RTRADR ; and save the node number MOVE T1,RTRNAD ; Now get the area number TXZ T1,RN%NOD ; from the address LSH T1,-^D10 ; Right justify MOVEM T1,RTRHOM LOAD T1,IBBSZ,(T2) ; Get blocksize to use CAMGE T1,RTRBSZ ; Compare with default (576) MOVEM T1,RTRBSZ ; If smaller use that, else keep default LOAD T1,IBMXA,(T2) ; Get the maximum node address MOVEM T1,RTRMXN CAMGE T1,RTRMX3 ; Is it less than maximum for Phase III nodes? MOVEM T1,RTRMX3 ; Yes, use it then ;Here to allocate the "normal" and "scratch" routing vectors. MOVE T1,RTRMXN ;GET THE MAXIMUM NODE NUMBER ADDI T1,1 ;Add one for node 0 (nearest area router) ASH T1,1 ;MAKE IT TWICE AS LONG (HALF FOR REACH VECTOR ; HALF FOR OUTPUT ADJACENCY VECTOR) IFN FTOPS20,< CALL DNGWDZ ;GET THAT MANY WORDS RET ;COULD NOT INITIALIZE >; END IFN FTOPS20 IFN FTOPS10,< EXCH T1,DCNVFF## ;GET ADDRESS OF NEXT FREE CORE ADDM T1,DCNVFF## ;UPDATE PAST ROUTING VECTOR >; END IFN FTOPS10 MOVEM T1,RTRNRV ;SAVE POINTER TO NORMAL ROUTING VECTOR MOVE T2,RTRMXN ;GET OUR CURRENT MAXIMUM NODES ADDI T2,1 ;START THE RTRNOV AT ONE ALSO MOVEM T2,RTROFS ;SAVE AS OFFSET FROM START OF NRV AND SRV ; NOTE THAT MXN CANNOT GET LARGER! ADD T1,T2 ;CALCULATE START OF NORMAL OUTPUT VECTOR MOVEM T1,RTRNOV ;SAVE IT MOVE T2,RTRNRV ;PREPARE TO CALC END OF SMEAR ADD T2,RTRMXN ;ADD NUMBER OF ENTRIES TO SPRAY MOVE T1,RTRNRV ;POINT TO THE HEAD OF THE NORMAL VECTOR MOVX T3,RNHOP!RNCST ;SMEAR WITH MAXIMUM COST AND HOPS CALL DNSWDS ;SPRAY THE BLOCK WITH MAXS MOVE T1,RTRMXN ;GET THE MAXIMUM NODE NUMBER ADDI T1,1 ;Add one for node 0 (nearest area router) IDIVI T1,^D36 ;Compute size of routing vector bitmap SKIPE T2 ;Round up ADDI T1,1 ;... CALL DNGWDZ ;Allocate memory for routing vector bitmap RET ;Return if allocation error MOVEM T1,RTRNVB ;Save address ;Get and initialize an EC (Event Communication) block MOVX T1,EV.GEC ;Function code "get EC block" CALL NMXEVT RET ; -failed to get memory for block MOVEM T1,RTRECP ;Save pointer MOVX T2,^D8 ;ROUTER may queue 8 event blocks on queue STOR T2,ECMAX,(T1) IFN FTOPS10,< CALL D36LIN## ;Initialize DTEs and KDPs >; End IFN TOPS10 CALL DNDINI ;Initialize DNADLL RETSKP ;RETURN NICELY SUBTTL RTRON - Turn Router (and DECnet) On ;RTRON - Turn Router (and DECnet) On ; ; Call: ; With nothing special ; ; Return: ; RET ;ON FAILURE (DECNET IS ALREADY ON, NO ; ;LOCAL NODE NUMBER DEFINED, ETC.) ; RETSKP ;WITH DECNET TURNED ON ; ; Uses: T1-T4 ; ;Note that RTRINI must be called to set up the routing vectors for ;Router before DECnet is turned on. INTERN RTRON RTRON: SAVEAC MOVE T1,DCNSTA ;Get DECnet state CAIE T1,DS.ON ;Is it on? SKIPN T1,RTRADR ;AND DO WE HAVE AN ADDRESS FOR ROUTER? RET ;NO, CANNOT TURN DECNET ON YET DPB T1,[POINTR (T2,RN%NOD)] ; Generate our node address in MOVE T1,RTRHOM ; Ethernet string format DPB T1,[POINTR (T2,RN%ARE)] LSHC T1,^D28 ; DPB T1,[POINT 8,T2,15] MOVEM T2,RTRLOO ; Low order in string format MOVE T1,RTRADR ADD T1,RTRNRV ;FIND THE ENTRY IN THE NORMAL REACH VECTOR D36OFF ;TURN ON INTERLOCK SETONE ,(T1) ;LOCAL AND REACHABLE and in cache SETZRO ,(T1) ;ZERO THE HOPS AND COST FOR THIS NODE MOVE T2,[XCDSEC,,NSPRTR] ;GET NSP'S ENTRY VECTOR ADD T1,RTROFS ;POINT TO OUTPUT-CIRCUIT VECTOR ENTRY MOVEM T2,(T1) ;SAVE THE ENTRY VECTOR D36ON ;TURN OFF INTERLOCK ;And turn DECnet on! MOVX T1,DS.ON ;GET THE ON STATE MOVEM T1,DCNSTA ;SET IT SETZM RTRLMG ;Reset rounting message offset ;Now go through all the circuits, initializing each one. SKIPN RC,RTRCBQ ;PICK UP FIRST CIRCUIT BLOCK RETSKP ;NONE THERE, RETURN SUCCESS RTRON1: CALL R2KINI ;INITIALIZE THIS CIRCUIT TRN LOAD RC,RCNXT,(RC) ;Step to next circuit, if any, JUMPN RC,RTRON1 ; and initialize RETSKP ;NO MORE, JUST RETURN SUCCESS SUBTTL RTROFF - Turn Router (and DECnet) Off ;RTROFF - Turn Router (and DECnet) Off ; ; Call: ; With nothing special ; ; Return: ; RETSKP ;ALWAYS ; ; Uses: T1-T4 RTROFF: SAVEAC ;Now go through all the circuits, halting each one. SKIPA RC,RTRCBQ ;GET THE FIRST CIRCUIT BLOCK RTROF1: LOAD RC,RCNXT,(RC) ;STEP THROUGH TO NEXT ONE JUMPE RC,RTROF2 ;NONE THERE, RETURN SUCCESS CALL RTIDWN CALL R2KCLS JRST RTROF1 ; RTROF2: MOVX T1,DS.OFF ;SET THE STATE OF DECNET MOVEM T1,DCNSTA ; TO "OFF" RETSKP ;NO MORE, JUST RETURN SUCCESS SUBTTL RTRSEC - Once a second processing for Router ;RTRSEC - Once a second processing ; ; Call: ; With nothing ; ;Return: ; RET ;ALWAYS ; ; Uses: T1 ; ;This is the clock level routine for Router. Once a second this ;routine gets executed. If we are running TOPS-10 SMP, we must make ;sure that this is run on the BOOT CPU. The routine simply calls RTRRCR ;(to recompute the routing) if needed and calls RTRUPD to see if ;routing messages need to be sent out on any or all circuits. Next, we ;call the hello processor to check hello and listener timers for each ;circuit. Finally, it checks the resend queue, and if there are any ;messages on it, it forwards them. INTERN RTRSEC XRESCD RTRSEC: MOVE T1,DCNSTA ;Get DECnet state CAIE T1,DS.ON ;Is it on? RET ;NO, NOTHING TO DO IFN FTOPS10,< XCT .CPSK0 ;SKIP IF BOOT CPU RET ;NO, SHOULDN'T BE HERE, BUT JUST RETURN > ;END IFN FTOPS10 CALL DNDSEC ;Poll DNADLL each second ; SKIPL RTRLOK ;CHECK TO SEE IF ANYONE HAS INTERLOCK ; JRST [SETOM RTRSSV ;COULDN'T GET IT, JUST RETURN ; RET] ; WITH SERVICE NEEDED ; SETZM RTRSSV ;WE HAVE PROVIDED SERVICE ;Note that we did not get the interlock here; we only tested it. ;The interlock is just to keep this clock level code from changing ;the database while any process level code is running. We may ;get interrupted now by interrupt code, but this won't affect us ;as our critical sections are surronded by D36ON/D36OFF. SAVEAC ;SAVE SOME NON-SMASHABLE ACS CALL RTRTMR ;CALL THE TIMER PROCESSOR, WHICH MAY TURN ; ON RTRRCF SKIPE RTRRCF ;IS THE RECOMPUTE ROUTING FLAG ON? CALL RTRRCR ; YES, GO RECOMPUTE THE ROUTING CALL RTRUPD ;Now go through the update process ; SETOM RTRLKO ;CLEAR OWNER OF INTERLOCK IFN FTRTST,< SKIPE T1,TSTFLG CALL RTRTST SETZM TSTFLG > SKIPN ENFLG ;Endnode? CALL SELDSR ;No, select a designated router SKIPGE ENFLG ;Endnode? CALL CKECTO ;Yes, check the cache timer RET ; AND RETURN SUBTTL RTRJIF - Once a jiffy processing for Router ;RTRJIF - Once a jiffy processing ; ; Call: ; With nothing ; ; Return: ; RET ;ALWAYS ; ; Uses: T1 ; ;This routine's only purpose is to service kontroller requests that ;CALKON queues when the request is for a device on the wrong CPU. Since ;this is a TOPS-10 SMP only problem, it does nothing for TOPS-20. INTERN RTRJIF XRENT RTRJIF IFN FTOPS20, ;Nothing to do for TOPS20 IFN FTOPS10,< IFN FTMP,< ; SKIPL RTRLOK ;TEST THE ROUTER INTERLOCK ; RET ;SOMEONE HAS IT, WE'LL TRY AGAIN LATER SAVEAC ;SAVE SOME ACS TO USE SKIPA RC,RTRCBQ ;START WITH THE FIRST CIRCUIT BLOCK RTRJI1: LOAD RC,RCNXT,(RC) ;GET PTR TO NEXT CIRCUIT BLOCK JUMPE RC,RTN ;NO MORE, JUST RETURN LOAD T1,LIKON,+RC.LID(RC) ;GET THE POINTER TO THE CIRCUIT BLOCK CAME T1,.CPCPN ;ARE WE RUNNING ON THE CPU FOR THIS CIRCUIT? JRST RTRJI1 ;NO, CHECK OUT THE NEXT BLOCK ;Check the circuit's resend queue for any requests that we can queue ;for it now that we are running on the correct CPU. RTRJI2: ;CHECK IF OTHER CPU HAD KONTROLLER TASKS ; QUEUED UP. JE RCCLS,(RC),RTRJI3 ;IF NO HALT REQUESTED, SKIP THIS CODE SETZRO RCCLS,(RC) ;CLEAR BIT MOVEI T1,DF.CLS ;KONTROLLER FUNCTION HALT. MOVE T2,RC ;POINT TO CIRCUIT BLOCK CALL CALKON ;AND TRY TO DO IT. JRST RTIDWN ;IF IT FAILS, DECLARE THE CIRCUIT DEAD. RTRJI3: JE RCOPN,(RC),RTRJI4 ;IF NO INITIALIZE REQUESTED, SKIP THIS CODE SETZRO RCOPN,(RC) ;CLEAR BIT MOVEI T1,DF.OPN ;THE OTHER CPU DID REQUEST THIS. MOVE T2,RC ;SET UP POINTER TO CIRCUIT BLOCK CALL CALKON ;INITIALIZE THE LINE JRST RTIDWN ;AND DECLARE THE CIRCUIT DOWN. RTRJI4: D36OFF ;TURN OFF INTERRUPTS WHILE PLAYING WITH QUEUES DEQUE MB,RC.JSQ(RC),MB.NXT,RTRJI6 ;DEQUEUE ANYTHING THAT'S THERE D36ON ;TURN INTERRUPTS BACK ON ;WE KNOW THAT BY VIRTUE OF GETTING THE MESSAGE ;BLOCK FROM RC.JSQ, RC IS SET UP CORRECTLY. CALL CALQOB ;SEND THE BLOCK OUT. JRST RTRJI2 ;SEE IF ANYTHING ELSE ON CIRCUIT'S Q RTRJI6: D36ON ;TURN THE INTERRUPTS BACK ON JRST RTRJI1 ; AND CHECK THE NEXT CIRCUIT'S QUEUE >;End of IFN FTMP RET >;End of IFN FTOPS10 SUBTTL RTRLCK - Get the RTR interlock REPEAT 0,< ;RTRLCK - Grab the RTR interlock ; ; Call: ; With nothing special ; ; Return: ; RET ;ALWAYS WITH INTERLOCK ; ; Uses: Nothing ; ;Note: This interlock routine is only called by RTRXMT. RTRXMT, which ;is NSP's entry point, will never be called by more than one CPU due to ;the NSP interlock. If the NSP interlock changes, we may have to modify ;this assumption. The Router interlock is used to keep Router's clock ;level from modifying the database at clock level (Note that the ;database is only modified at clock level), while someone at process ;level is using it. Route-through happens at interrupt level, so we ;don't have to worry. Our only process level caller is NSP, who always ;has his "global interlock". RTRLCK: AOSE RTRLOK ;GRAB THE INTERLOCK RET ;SOMEONE HAS IT (PROBABLY INTERRUPT LEVEL) ; WE DON'T CARE AS LONG AS CLOCK LEVEL ; KNOWS THAT IT CAN'T RUN APRID RTRLKO ;SET THE OWNER OF THE INTERLOCK ADJSP P,-1 ;WE'LL CALL THE CALLER PUSHJ P,@1(P) ; SO WE DON'T NEED HIM ON STACK TRNA ;NON-SKIP RETURN AOS -1(P) ;SKIP RETURN SETOM RTRLKO ;CLEAR THE OWNER OF THE INTERLOCK SETOM RTRLOK ;GIVE UP THE LOCK SKIPE RTRSSV ;DID WE GET A REQUEST FOR SERVICE? CALLRET RTRSEC ;YES, GIVE IT RET ;OTHERWISE, JUST RETURN > IFN FTRTST,< RTRTST: SAVEAC P1 MOVEI P1,TSTBLK ; Test data block STOR T1,TRTND,(P1) ; Node to loop with MOVX T1,^D300 ; Length of data segment CALL DNGMSG ; Get that many bytes RET ; Resource failure, tough luck MOVE MB,T1 ; Set up MB with message block pointer XMOVEI T1,UD.MSD(MB) ; Initialize the user data segment CALL DNPINI LOAD T1,TRTSN ; Get serial number CALL DNP2BY ; Place serial number in message MOVX T3,^D298 ; Get the count for loop RTRTS2: MOVX T1,HEL.LO ; Word that goes in hello messsage CALL DNP1BY ; Put one in SOJG T3,RTRTS2 ; and continue till we have enough MOVE T1,RTRADR DPB T1,[POINTR (T2,RN%NOD)] MOVE T1,RTRHOM DPB T1,[POINTR (T2,RN%ARE)] STOR T2,MBSRC,(MB) SETZ T1, MOVX T2,LD.ETH ; Get the device type for ethernet STOR T2,LIDEV,+T1 ; Save it CALL RTRGCB ; Get the circuit block in RC CALLRET FREMSG LOAD T1,TRTND,(P1) ; Get number of node to test with STOR T1,MBDST,(MB) ; CALL RTRGAJ ; Get the correct adjacency in AJ CALLRET FREMSG STOR AJ,RMOAP,(MB) ; Save for RTRFWD CALL TSTTIM STOR T1,TRTAF,(P1) ; Save as time at RTRFWD SETONE RMTST,(MB) ; Indicate this is a test message SETZ T1, ; No flags CALLRET RTRXMT ; Try to send it > SUBTTL RTRXMT - NSP's entry into Router ;RTRXMT - Routine to forward messages from NSP ; ; Call: ; MB/ Ptr to Message Block ; T1/ RQR flag (RT%RQR) ; ODN flag (RT%ODN) ; TRY flag (RT%TRY) ; Public portion of message block must be filled with destination ; and source nodes and output circuit. ; ; Returns: ; RTN ;ALWAYS ; ;This is the only way which an NSP calls router (except for ;initialization). The ODN flag in T1 specifies whether or not NSP ;really wants message back (see FREMSG). The RQR flag specifies ;whether or not NSP is requesting this message be returned. INTERN RTRXMT XRESCD RTRXMT: MOVE T2,DCNSTA ;Get DECnet state CAIE T2,DS.ON ;Is it on? CALLRET FREMSG ;NO, PUNT THE MESSAGE CORRECTLY AND LEAVE SAVEAC ;SAVE A FEW FOR NSP ; CALL RTRLCK ;GET INTERLOCK MOVX T2,RMRQR ;GET RETURN REQUEST BIT FOR MESSAGE BLK ANDCAM T2,RM.RQR(MB) ;CLEAR FLAG, ASSUMING NOT INTERESTED TXNE T1,RT%RQR ;DOES HE WANT IT BACK? IORM T2,RM.RQR(MB) ;YES, SET BIT IN THE MESSAGE BLK MOVX T2,RMODN ;GET "NSP WANTS MSG BACK" BIT ANDCAM T2,RM.ODN(MB) ;CLEAR FLAG, ASSUMING CALLER NOT INTERESTED TXNE T1,RT%ODN ;DOES HE WANT OUTPUT DONE CALL? IORM T2,RM.ODN(MB) ;YES, SET FLAG FOR FREMSG AND R2NODN MOVX T2,RMTRY ;Get "TRYHARD" on NI bit ANDCAM T2,RM.TRY(MB) ;Assume not requesting us to try hard TXNE T1,RT%TRY ;Asked to "try hard"? IORM T2,RM.TRY(MB) ;Yes, set flag to clear destination from cache SETZRO RMICP,(MB) ;THERE'S NO INPUT CIRCUIT BLOCK POINTER SETZRO RMIAP,(MB) ; and no input adjacency SETZRO RMOAP,(MB) ;THERES NO OUTPUT ADJACENCY YET EITHER SETZRO MBVST,(MB) ;ZERO VISITS COUNT SETONE RMMB1,(MB) ;BIT THAT MUST BE ONE IN FIRST BYTE LOAD T1,MBSRC,(MB) ;GET SOURCE NODE ADDRESS LDB T2,[POINTR (T1,RN%ARE)] ;GET THE AREA NUMBER LDB T1,[POINTR(T1,RN%NOD)] ;GET THE NODE NUMBER CAME T2,RTRHOM ;IN OUR AREA JRST CKLOOP ;NOPE ,THEN FORGET ABOUT IT ADD T1,RTRNRV ;ADD OFFSET TO NORMAL ROUTING VECTOR TMNN RNLCL,(T1) ;IS THIS THE LOCAL NODE? BUG.(CHK,ROUBSN,ROUTER,SOFT,,,< Cause: We have received a message from NSP to send. However, the source node address is not that of the local Router. Action: Check in LLINKS or SCLINK to see how we got an invalid source node address. >,FREMSG) CKLOOP: LOAD T1,MBCHN,(MB) ;GET CHANNEL NUMBER (circuit id) JUMPE T1,RTRFWD ;IF NO LOOP BACK CIRCUIT SPECIFIED BY ;SESSION CONTROL, DON'T SET CIRCUIT PTR CALL RTRGCB ;YES, TRANSLATE INTO A CIRCUIT BLK PTR BUG.(CHK,ROUILS,ROUTER,SOFT,,,< Cause: There was a request to send a message on a particular circuit, however the circuit has never been intialized by the routing layer. >,FREMSG) STOR RC,RMOCP,(MB) ;Store it as output circuit LOAD AJ,RCAJQ,(RC) ;Get an adjacency pointer ;Note that this grabs the the first adjacency which is the only one for point ; to point, but not necessarily for broadcast STOR AJ,RMOAP,(MB) ;Save it for forward routine (this is enough JE RCBCT,(RC),RTRFWD ; unless circuit is broadcast) CKLOO1: LOAD T1,AJNTY,(AJ) ;Get adjacency type CAIN T1,ADJ.LN ; If a routing node IFSKP. STOR AJ,RMOAP,(MB) ; Save it for forward routine JRST RTRFWD ; and then forward the message ENDIF. LOAD AJ,AJNXT,(AJ) ; Else get next adjacency JUMPE AJ,FREMSG ; none found then cannot forward the message JRST CKLOO1 ; check the one we got SUBTTL RTRFWD - Perform Routing of Message ;RTRFWD - Routine to do routing ; ; Call: ; MB/ Ptr to Message Block ; ; Return: ; RTN ;ALWAYS ; ; Uses T1-T3 ; ;This routine takes an input message, checks its Router header and ;routes it to the correct destination using the "normal" routing ;vector. The relavent fields in the public section of the Message ;Block must have been set up. RTRFWD: XMOVEI T1,RM.MSD(MB) ; Router's private MSD CALL DNPINI ; Initialize it, as this is where we will ; build the routing layer header LOAD T1,MBDST,(MB) ; Get the destination address LDB T2,[POINTR(T1,RN%ARE)] ; Extract the area number LDB T1,[POINTR(T1,RN%NOD)] ; and the node number from it CAME T2,RTRHOM ; Is it in our area? SETZ T1, ; No, select the area router SKIPL T1 ;LESS THAN 0 CAMLE T1,RTRMXN ;GREATER THAN THE MAX NODE ADDRESS? JRST RTRFOR ;DEST IS OUT OF RANGE ADD T1,RTRNRV ; Add in the offset to routing vector OPSTR ,RMOAP,(MB) ; Have we selected an output adjacency? IFSKP. TMNN RNLCL,(T1) ; No, is destination local? IFSKP. SETONE MBLCL,(MB) ; Yes, indicate that in message block JRST RTRFD2 ; and skip ahead ENDIF. ENDIF. SKIPN ENFLG ; Endnode? IFSKP. ; Yes MOVE RC,RTRCBQ ; Get pointer to our only circuit JUMPE RC,RTRFUR ; If no circuit can't do much LOAD T2,RCSTA,(RC) ; If circuit is not running CAIE T2,RCS.RN ; cannot forward message JRST RTRFUR STOR RC,RMOCP,(MB) ; Save circuit block address SETONE ,(MB) ; Set intra-ethernet and long format hdr CALL RTRBEH ; Build the ethernet header JRST RTR2RM ; and try to send message ELSE. TMNE RNRCH,(T1) ; Is destination reachable? IFSKP. SETONE MBUNR,(MB) ; No, indicate that, SETZRO RMOAP,(MB) ; clear output adjacency, JRST RTRPHR ; and skip further checking ENDIF. ENDIF. OPSTR ,RMOAP,(MB) ;Compute an adjacency if we don't have one IFSKP. ADD T1,RTROFS ; Index into the output adjacency vector MOVE T2,(T1) ; Get the output adjacency STOR T2,RMOAP,(MB) ; and use it as the adjacency to forward to ENDIF. LOAD T2,AJSTA,(T2) ; Get state of adjacency CAIE T2,ADJ.UP ; Is it up? JRST FREMSG ; No, toss the message ;Now check for over aged packet RTRFD2: JE RMIAP,(MB),RTRFD3 ; If from our NSP then visit count is zero LOAD T1,RMFST,(MB) ;GET THE FIRST BYTE OF MESSAGE OPSTRM ,MBVST,(MB) ; AND UPDATE AND GET VISITS FIELD MOVE T3,RTRMXV ;THIS IS THE MAXIMUM VISITS COUNT ALLOWED TXNE T1,RM%RTS ;IS THIS GOING TO BE COMING BACK? ASH T3,2 ;YES, GIVE IT TWICE AS MANY HOPS CAMG T2,T3 ;HAS IT AGED TOO MUCH? JRST RTRFD3 ;NO, PUT HEADER ON MSG ;Here to report a aged packet loss event. SETZ T2, ;THIS EVENT HAS NO ENTITY ASSOCIATED WITH IT SETZ T3, ;Default address to nothing SKIPE AJ LOAD T3,AJNAN,(AJ) ;Get address of last router in path EVENT RE.APL,,MB AOS RTRCAP ;INCREMENT THE AGED PACKET COUNTER CALLRET FREMSG ;FREE THE MESSAGE AND RETURN ;Now decide if destination is point-point or broadcast and build the ;appropriate routing message header. RTRFD3: TMNE MBLCL,(MB) ;IS THE DESTINATION OUR LOCAL NSP? JRST RTRPHR ;YES, THEN WE CAN SKIP THE REST OF THIS IFN FTRTST,< LOAD T1,MBSRC,(MB) ;Get source address TMNE RMTST,(MB) ;Is this a test message JRST [STOR T1,MBDST,(MB) ;Then we want it back SETZRO MBVST,(MB) ;Reset the visits JRST .+1] > LOAD AJ,RMOAP,(MB) ; OUTPUT ADJACENCY LOAD RC,AJCBP,(AJ) ; OUTPUT CIRCUIT BLOCK JN RCBCT,(RC),RTRFNI ; Jump if broadcast circuit? ;Build a short data packet header for packets going out on point-to-point SETZRO ,(MB) ;Short format header - Not intra-NI LOAD T1,RMFST,(MB) ;GET THE FIRST BYTE OF MESSAGE CALL DNP1BY ;PUT IT IN MESSAGE HEADER AREA LOAD T1,MBDST,(MB) ;GET THE DESTINATION NODE ADDRESS LDB T2,[POINTR(T1,RN%ARE)] ;GET THE AREA LDB T1,[POINTR(T1,RN%NOD)] ;GET THE NODE NUMBER SKIPN T2 ;HAVE ONE? MOVE T2,RTRHOM ;GET OURS THEN TMNE AJPH4,(AJ) ;Is "next hop" Phase IV? DPB T2,[POINTR(T1,RN%ARE)] ; Yes, then we need an area CALL DNP2BY ;PUT DESTINATION NODE ADDRESS INTO MESSAGE LOAD T1,MBSRC,(MB) ;GET THE SOURCE NODE ADDRESS LDB T2,[POINTR(T1,RN%ARE)] ;GET THE AREA LDB T1,[POINTR(T1,RN%NOD)] ;GET THE NODE NUMBER SKIPN T2 ;Have an area? MOVE T2,RTRHOM ;NO, USE OURS THEN TMNE AJPH4,(AJ) ;Is the next hop Phase IV? IFSKP. CAME T2,RTRHOM ;No, is this from a foreign area? CALLRET RTRFUR ;Yes, treat as unreachable because we cannot ; forward a P4 packet to an adjacent P3 node ELSE. DPB T2,[POINTR(T1,RN%ARE)] ;Yes, P4 nodes get an area number ENDIF. CALL DNP2BY ;PUT SOURCE NODE ADDRESS INTO MESSAGE LOAD T1,MBVST,(MB) ;GET VISITS BYTE CALL DNP1BY ;AND PUT THAT IN, TOO JRST RTRPHR ;DO THE COMMON HEADER STUFF ;Here when the output circuit is an Ethernet RTRFNI: SETONE RMMZ3,(MB) ;****INDICATES LONG FORMAT TRANSPORT HEADER** LOAD T2,RMIAP,(MB) ;GET THE INPUT ADJACENCY POINTER JUMPE T2,RTRFN1 ;MESSAGE IS FROM LOCAL NSP LOAD T3,AJNTY,(T2) ;GET THE NODE TYPE LOAD T4,AJNTY,(AJ) ;GET THE NODE TYPE FOR THE OUTPUT ADJACENCY CAIN T3,ADJ.LN ;IT IS AN ENDNODE? CAME T3,T4 ;YES, ARE THEY BOTH? JRST RTRFN2 ;NO, THEN SKIP THIS ;They are both endnodes, see if the input/output circuits are the same NI LOAD T2,AJCBP,(T2) ;GET THE INPUT CIRCUIT BLOCK POINTER LOAD T2,RCLID,(T2) ;GET THE LINE ID LOAD T4,LIDEV,+T2 ;GET THE DEVICE TYPE CAXE T4,LD.ETH ;IS IT AN ETHERNET? JRST RTRFN2 ;NO, THEN NO INTRA-ETHERNET ; LOAD T2,LIUNI,+T2 ;UNIT NUMBER LOAD T3,RCLID,(RC) ;AND THE ONE FOR OUTPUT ; LOAD T3,LIUNI,+T3 ;GET THE UNIT NUMBER CAME T2,T3 ;ARE THEY THE SAME NI? TRNA ;NOT NI OR NOT SAME ONE RTRFN1: SETONE RMMZ2,(MB) ;YES, THEN SET THE INTRA-NI BIT RTRFN2: CALL RTRBEH ;Now build the Ethernet header RTRPHR: CALL DNRPOS ;GET CURRENT POSITION IN THE BLOCK STOR T1,RMMK1,(MB) ;AND SET MARK IN BLOCK TMNE MBLCL,(MB) ;FOR THE LOCAL NSP? JRST RTRFLC ;AND FORWARD TO LOCAL NSP TMNE MBUNR,(MB) ;UNREACHABLE? JRST RTRFUR ;YES, LOG IT THEN JN RMOAP,(MB),RTR2RM ;If output adjacency was spec'd, forward it LOAD T1,MBDST,(MB) ;HAVE A DESTINATION LDB T1,[POINTR(T1,RN%NOD)] ;GET THE NODE NUMBER BUG. (CHK,ROUIFS,ROUTER,SOFT,,,< Cause: RTRFWD got through its Forward process and either did not pick up a route or failed to flag a message which was for the local node or an unreachable message. Action: Look for corruption in the routing vector. >,FREMSG) ;Here when destination node is out-of-range. RTRFOR: TMNE RMRQR,(MB) ;WAS RETURN REQUESTED JRST RTRFRT ;YES, RETURN IT LOAD T2,RMICP,(MB) ;GET THE CIRCUIT IT CAME IN ON SKIPN T2 BUG.(CHK,ROUNSO,ROUTER,SOFT,,,< Cause: There is a request to forward a packet to a node whose address is outside the range of our routing vector. Either our NSP has given a packet we cannot forward or we have received one from the wire. Action: If the source is local check to see how NSP could give a packet whose destination node address is greater than RTRMXN. If the source is remote then there is something wrong with its routing database or algorithm. >,FREMSG) LOAD T2,RCLID,(T2) ;Get device ID SETZ T3, ;Default address to nothing SKIPE AJ LOAD T3,AJNAN,(AJ) ;Get address of last router in path EVENT RE.NOR,,MB AOS RTRCNO ;INCREMENT OUT-OF-RANGE COUNT CALLRET FREMSG ;RETURN THE MSG BLK ;Here when destination node is unreachable. RTRFUR: TMNE RMRQR,(MB) ;WAS RETURN REQUESTED? JRST RTRFRT ;WE HAVE TO RETURN MESSAGE OPSTR ,RMICP,(MB) ;GET THE CIRCUIT IT CAME IN ON IFSKP. LOAD T2,RCLID,(T2) ; and get the circuit ID SETZ T3, ;Default address to nothing SKIPE AJ LOAD T3,AJNAN,(AJ) ;Get address of last router in path EVENT RE.NUR,,MB AOS RTRCNU ;INCREMENT EXECUTOR NODE COUNTER ENDIF. CALLRET FREMSG ;GIVE THE MESSAGE BACK AND RETURN ;Here to return message to sender due to unreachability. RTRFRT: ETRACE RTR, CALL RTRERH ;EAT THE ROUTER HEADER WE PUT ON THE MESSAGE SETZRO RMRQR,(MB) ;ZERO THE RQR FLAG SETONE RMRTS,(MB) ;SET THE RETURN TO SENDER FLAG LOAD T1,MBDST,(MB) ;GET THE DST ADDR LOAD T2,MBSRC,(MB) ; AND THE SRC ADDR STOR T2,MBDST,(MB) ;SWITCH THEM STOR T1,MBSRC,(MB) ; AROUND TMNN RMICP,(MB) ;THIS MSG COME FROM LOCAL NSP? JRST [CALL CPYMSG ;YES, MAKE THIS MSG LOOK LIKE AN INPUT ; BY COPYING SEGMENTS TOGETHER CALLRET FREMSG ;OOPS, COULDN'T GET MSG BLOCK, FORGET IT EXCH T1,MB ;POINT TO THE NEW MSG IN MB CALL DNFMSG ;FREE THE OLD MSG CALLRET R2NRTN] ; AND RETURN THE NEW MSG CALLRET RTRFWD ;TRY TO FORWARD AGAIN ;Here when the message is for a local NSP. RTRFLC: LOAD RC,RMICP,(MB) ;SEE WHERE MSG CAME FROM JUMPE RC,RTRF2C ;IF ICP IS ZERO, MSG IS FROM NSP, ; SO WE HAVE TO COPY DATA ;IF ICP IS NON-ZERO, MSG IS FROM ; OUTSIDE & JUST FALL THROUGH ;We are here when we have to pass an incoming message to NSP. INCR RCCAP,(RC) ;INCR ARRIVING PACKETS RECEIVED (TO NSP) RTRF2N: TMNE RMRTS,(MB) ;IS THIS A RETURNED MESSAGE? CALLRET R2NRFR ;Yes, then give it to NSP CALLRET R2NRCV ;NO, THIS IS GOOD OLDE RECEIVED DATA RTRF2C: ;*************************************** TORESCD DNSNUP(RTRLTR) ;Label for DNSNUP to find local messages TOXRESCD ;*************************************** CALL RTRERH ;EAT THE ROUTING HEADER CALL CPYMSG ;COPY THE MSD'S TOGETHER CALLRET FREMSG ;DON'T CARE IF IT FAILS, THEN FREE IT UP PUSH P,T1 ;SAVE THE POINTER TO NEW THE MESSAGE CALL FREMSG ;RETURN THE ORIGINAL TO NSP POP P,MB ;AND WE CAN DIDDLE WITH OUR NEW COPY JRST RTRF2N ;NOW PASS THE MESSAGE ON TO NSP ; Get some bytes that we put in the router MSD above. This was to fix problems ; with Event processing, But the local NSP and the Return to sender code does ; not expect these fields to be set up. So we will punt them here. RTRERH: LOAD T1,MBFMS,(MB) ;GET THE POINTER TO THE FIRST MSD XMOVEI T2,RM.MSD(MB) ;GET THE ADDRESS OF THE ROUTER MSD CAME T1,T2 ;SEE IF IT AGREES WITH THE FIRST ONE THERE RET ;JUST RETURN MUST BE LLINKS RETURN MESSAGE LOAD T1,MDNXT,+RM.MSD(MB) ;GET THE NEXT MSD POINTER STOR T1,MBFMS,(MB) ;SAVE AS THE FIRST ONE RET ;AND RETURN SUBTTL RTR2RM - Send Message to Remote Node ;RTR2RM - Queue Out Message to Remote through the DLL ; ; Call: ; MB/ Pointer to message block ; RC/ Pointer to circuit block ; AJ/ Pointer to adjacency block if we are a level 1 router ; ; Return: ; RET ;ALWAYS ; ; Uses: P1-P2, T1-T3 RTR2RM: LOAD T1,RCSTA,(RC) ;GET THE CIRCUIT'S STATE CAIE T1,RCS.RN ;IS IT RUNNING CAIN T1,RCS.TT ; OR IN TEST? TRNA ;YES, WE CAN FORWARD THE PACKET CALLRET FREMSG ;NO, DESTROY THE PACKET SKIPN ENFLG IFSKP. INCR RCCDP,(RC) ; Count data packets JRST RTR2R1 ; and continue ENDIF. JE RMICP,(MB),[INCR RCCDP,(RC) ;IS THE PACKET FROM OUR LOCAL NSP? JRST RTR2R1] ;YES, INCREMENT COUNT OF NSP PACKETS ; AND SEND MSG WITHOUT WORRYING ABOUT ; SQUARE-ROOT LIMIT LOAD T1,RMICP,(MB) ;GET THE INPUT CIRCUIT BLOCK LOAD T1,LIDEV,+RC.LID(T1) ;GET THE LINE ID LOAD T2,RMIAP,(MB) ;GET THE SOURCE ADJACENCY LOAD T2,AJNTY,(T2) ;GET THE SOURCE NODE TYPE CAXN T2,ADJ.LN ;IS IT AN END NODE? CAXE T1,LD.ETH ;IS THIS THE ETHERNET CHANNEL JRST RTRCSQ ;HAVE BOTH GOT TO BE ON THE ETHERNET ;Get here when we have a source which is an NI endnode. The SPEC says ;if we get an NI endnode as the source and the destination is not one, ;then we have to check to be sure the hiorder bytes of S-ID are set to ;HIORD. If they are not, we discard the packet. We must do this here ;as opposed to when we receive the packet, as we do not know the ;output adjacency when we have just received it. LOAD T1,LIDEV,+RC.LID(RC) ;GET THE DEVICE TYPE LOAD T2,AJNTY,(AJ) ;GET THE NODE TYPE CAXN T1,LD.ETH ;IS THIS ON AN ETHERNET TOO? CAXE T2,ADJ.LN ; AND IS THE DESTINATION AN END NODE? TRNA ;NOT ON AN NI OR NOT AN END NODE JRST RTRCSQ ;THEN SKIP THIS LOAD T1,MBSR1,(MB) ;GET THE FIRST 4 BYTES OF SOURCE ADDRESS CAME T1,RTRHIO ;IS THIS THE HIORDER? JSP T1,RTEMFE ;++MESSAGE FORMAT ERROR EVENT LOAD T1,MBDS1,(MB) ; Now check the first 4 bytes of the CAME T1,RTRHIO ; destination address JSP T1,RTEMFE ;We now check the "square-root" limit criterion, to see if the message ;should be discarded. We check this by comparing the number of message ;blocks queued out on this circuit with the number of message blocks that ;the memory manager has guaranteed router divided by the square-root ;of the number of circuits (We simplify things by just using the number ;of circuits divided by two, which is close enough for a small number of ;circuits). RTRCSQ: INCR RCCTR,(RC) ;NO, INCREMENT THE TRANSIT PACKETS RECEIVED CALL DNNMSG ;GET NUMBER OF MESSAGE BLOCKS AVAILABLE MOVE T2,RTRNLN ;FIND THE NUMBER OF CIRCUITS IN USE ASH T2,-1 ;DIVIDE BY TWO IDIV T1,T2 ;DIVIDE TO FIND THE QUEUE THRESHOLD OPSTR ,RCCMQ,(RC) ;COMPARE WITH NUMBER OF MSG BLKS QUEUED JRST RTR2R1 ;WE DON'T HAVE TO FLUSH IT ;Here to discard a message that has exceeded the "square-root" limit. TRACE RTR, INCR RCCTL,(RC) ;INCREMENT THE CONGESTION LOSS COUNTER CALLRET FREMSG ;FREE THE MESSAGE AND RETURN ;All packets to be sent come through here. RTR2R1: ;Now we have to diddle with the MSD pointers slightly to convince ;the DLL not to get the router header from the input MSD. XMOVEI T1,RM.MSD(MB) ;POINT TO THE ROUTER MSD STOR T1,MBFMS,(MB) ;STORE IN FIRST MSD SLOT MOVE T1,MB CALL DNLENG ; Get length of message OPSTR ,MDBYT,+RM.MSD(MB) ; Don't count Router's header SKIPN ENFLG ; Endnode? IFSKP. LOAD T2,RCRBS,(RC) ; Check against our receive block size ELSE. LOAD T2,AJBSZ,(AJ) ; else check against adjacencies ENDIF. CAMG T1,T2 ; Too many bytes for IFSKP. ; destination's buffer? INCR RCBSX,(RC) ; Yes, count the times this happens CALLRET FREMSG ; and toss the message ENDIF. JE RMICP,(MB),RTR2R4 ;DID IT COME FROM A REMOTE NODE? INCR RCCTS,(RC) ;IT DID, INCREMENT TRANSIT COUNT LOAD T1,MDPTR,+IN.MSD(MB) ;ALSO GET THE DYNAMIC BYTE POINTER STOR T1,MDAUX,+IN.MSD(MB) ; AND STORE IT IN THE ORIGNAL BYTE POINTER ; SO THE DLL DOESN'T USE THE OLD ROUTER ; HEADER, WHICH WE JUST STRIPED AWAY ;Now set up the arguments for the data link and give it the packet RTR2R4: INCR RCCMQ,(RC) ;INCREMENT NUMBER OF MESSAGES QUEUED MOVX T1,DF.XMT ;Function is transmit SKIPN ENFLG ; Endnode? IFSKP. ;Clear cache if try-hard LOAD T2,MBDST,(MB) ; Yes, get the destination address MOVE T3,T2 ; In case we need it later TXZ T2,RN%ARE ; Clear the area number field ADD T2,RTRNRV ; Add reach vector offset TMNN RMTRY,(MB) ; "Try hard" flag set? IFSKP. SETZRO RNCCH,(T2) ; Yes, clear the in-cache flag ENDIF. ;Now we must determine the next hop address. The following rules apply: ; If destination is in cache then nexthop = destination ; else ; If designated router .ne. 0 then nexthop = desiginated router ; else ; nexthop = destination LOAD T4,RCDSL,(RC) ; No, get address of designated router TMNN RNCCH,(T2) ; Is cache flag set? JUMPN T4,RTR2R5 ; Not in cache, use DSR if we have one CAME T3,RTRNAD ; Is this destined for us? IFSKP. ; Yes, must be loop node from NML SKIPE T4 ; Do we have a DSR? JRST RTR2R5 ; Yes, send it there ENDIF. ; No, send it to ourselves (this will fail) SETZ T4, ; Start clean LSHC T3,-^D8 ; Convert from 0,,N1,N2 to N2,N1,,0 LSH T3,2 LSH T4,-^D18 ; Shift back to last character in string IOR T4,T3 ; Put it in T4 with the next to last char. ELSE. LOAD T4,AJNAL,(AJ) ; Address of next hop (Ethernet only) ENDIF. RTR2R5: HRLZ T4,T4 ; Position address correctly MOVE T2,RC ; Send on this circuit MOVE T3,MB ; this message CALL CALKON ; Call the data link layer (DNADLL) CALLRET XMTFAI ; The transmit failed - Restart data link RET ;GIVE A GOOD RETURN TO CALLER SUBTTL RTRBEH - Build header for ethernet data messages RTRBEH: LOAD T1,RMFST,(MB) ;GET THE FIRST BYTE CALL DNP1BY ;PUT IT INTO THE MESSAGE SETZ T1, ;CLEAR OUT SOME RESERVED FIELDS CALL DNP2BY ;D-AREA, D-SUBAREA MOVE T1,RTRHIO ;Get HIORD CALL DNPHIO ;Place in message LOAD T1,MBDST,(MB) ; and the 16 bit node address NSP gave us CALL DNP2BY SETZ T1, ;ZERO SOME MORE FIELDS CALL DNP2BY ;S-AREA, S-SUBAREA MOVE T1,RTRHIO ;Get HIORD CALL DNPHIO LOAD T1,MBSRC,(MB) ; and the 16 bit source address CALL DNP2BY SETZ T1, ;SOME MORE RESERVEDS CALL DNP1BY ;NEXT LEVEL 2 ROUTER LOAD T1,MBVST,(MB) ;Get visits count CALL DNP1BY SETZ T1, ;NEXT 2 FIELDS ARE RESERVED, JUST WRITE ZERO'S ; LOAD T1,MBSCL,(MB) ;GET THE SERVICE CLASS CALL DNP1BY ;INTO THE MESSAGE ; LOAD T1,MBPRO,(MB) ;GET THE PROTOCAL TYPE CALL DNP1BY ;INTO THE MESSAGE RET SUBTTL R2NODN - Return Output Done to NSP ;R2NODN - Give Output Done to NSP ; ; Call: ; MB/ Pointer to Message Block ;The relevant fields must be set up in the public portion of the message ;block (i.e., source and destination node addresses, etc.) ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 R2NODN: MOVX T3,NV.ODN ;GET THE OUTPUT DONE ENTRY TYPE MOVE T4,MB ;SET UP MB FOR NSP LOAD T1,MBSRC,(MB) ;IT'S GOING BACK TO SOURCE LDB T1,[POINTR(T1,RN%NOD)] ;GET THE NODE NUMBER CALLRET R2NCL1 ;CALL NSP SUBTTL R2NRTN - Return Message to NSP ;R2NRTN - Return Message to NSP ; ; Call: ; MB/ Pointer to Message Block ;Fields must be set up correctly in the Public portion of the message ;block. ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 R2NRTN: SKIPA T3,[NV.RTS] ;Returned by local router to local NSP R2NRFR: MOVX T3,NV.RFR ;Returned by remote router to local NSP CALLRET R2NCAL ;MERGE WITH THE OTHER CODE SUBTTL R2NRCV - Pass received Message to NSP ;R2NRCV - Pass received message to router user (ususally NSP) ; ; Call: ; MB/ Pointer to Message Block ;Fields must be set up correctly in the public portion of the message ;block. ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 ; ;R2NCAL, which is the actual routine which calls a router user (also called ;an NSP), will check the message block for the destination address and use ;this to find look up the correct entry vector in the normal routing vector. ;RTRNOV contains the entry vector for NSP when the node entry for RTRNRV ;says it is a local node (RNLCL is on). R2NRCV: LOAD T2,MBSRC,(MB) ;GET THE SOURCE OF THIS MESSAGE LDB T1,[POINTR(T2,RN%ARE)] ;GET THE AREA NUMBER CAME T1,RTRHOM ;OUR AREA? JUMPN T1,R2NRC1 ;JUMP IF FROM ANOTHER AREA LDB T1,[POINTR(T2,RN%NOD)] ;GET THE NODE NUMBER SKIPLE T1 ;RANGE CHECK THE ADDRESS CAMLE T1,RTRMXN ; FOR REASONABLENESS SKIPA ;OUT OF RANGE JRST R2NRC1 ;ALL OK, CONTINUE EVENT RE.NOR,,MB AOS RTRCNO ;INCREMENT OUT-OF-RANGE COUNT CALLRET FREMSG ;RETURN THE MESSAGE BLOCK R2NRC1: MOVX T3,NV.RCV ;GIVE RECEIVED MESSAGE ENTRY TYPE R2NCAL: SKIPN T4,MB ;HE WANTS THE MESSAGE BLOCK PTR IN T4 BUG.(CHK,ROUXNZ,ROUTER,SOFT,,,< Cause: Somehow MB was trashed in the forward process. It is unlikely to get this far if RTRFWD rececived a bad MB. Action: Look for faulty code in the forward process >,RTN) LOAD T1,MBDST,(MB) ;GET THE DESTINATION OF THIS MESSAGE LDB T2,[POINTR(T1,RN%ARE)] ;GET THE AREA IN T2 LDB T1,[POINTR(T1,RN%NOD)] ;GET THE NODE NUMBER SKIPE T2 ;Do we have an area? CAMN T2,RTRHOM ;Yes, is it ours? SKIPA ;Ours or don't have one JRST R2NCLE ;Not ours, THEN LET SOMEONE ELSE WORRY ABOUT IT R2NCL1: ADD T1,RTRNRV ;GET NODE'S ENTRY IN "NORMAL" VECTOR JN RNLCL,(T1),R2NCL2 ;IF IT IS A LOCAL NODE, RETURN MESSAGE TMNE RMODN,(MB) ;NOT LOCAL, CHECK FLAGS FOR CONSISTENCY BUG.(CHK,ROUNLN,ROUTER,SOFT,,,< Cause: We have decided to return a message to the local NSP but the local NSP was not the originator. >,R2NCLE) R2NCLE: SETZRO RMODN,(MB) ;MAKE FREMSG TOSS THE MSG NOW CALLRET FREMSG ;RETURN MSG BLK TO FREE POOL R2NCL2: ADD T1,RTROFS ;GET THE VECTORED ENTRY POINT POINTER MOVE T1,(T1) ;GET THE CORRECT ENTRY CALLRET (T1) ;CALL WHATEVER IS ABOVE US SUBTTL R2KINI - Initialize a Kontroller's Circuit ;R2KINI - Initialize a DLL circuit ; ; Call: ; RC/ Pointer to Circuit Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T2 R2KINI: LOAD T1,RCSTA,(RC) ;GET THE CIRCUIT STATE CAIE T1,RCS.OF ;We must be in OFF or CAIN T1,RCS.RJ ; rejected state TRNA RET ;NO, THEN SKIP THIS MOVX T1,DF.OPN ; Function is open MOVE T2,RC ; Circuit block LOAD T3,RCLID,(RC) ; Get the line ID for sanity check CALL CALKON ; Try to open the port IFSKP. JE RCBCT,(RC),R2KIN1 ; Point-to-point doesn't send NI hellos CAIE T1,LS.ON ; Is line running? IFSKP. MOVX T1,RCS.RN ; Yes, then put circuit into the run state SETONE RCSHM,(RC) ; Send a hello message to start things off ELSE. MOVX T1,RCS.WT ; No, say "waiting" then ENDIF. STOR T1,RCSTA,(RC) ; Set the state SETZRO RCTIN,(RC) ; Clear timer RETSKP ELSE. CALL DNGTIM ; Get the current time ADD T1,RTRCRT ; Wait before re-attempting the open STOR T1,RCTIN,(RC) RET ; and indicate failure ENDIF. R2KIN1: MOVX T1,RCS.WT ; Advance to the wait state STOR T1,RCSTA,(RC) MOVX T1,ADJ.IN ;SAY THE ADJACENCY IS INITIALIZING OPSTR ,RCAJQ,(RC) ;Get the adjacency STOR T1,AJSTA,(AJ) ;STORE IT IN THE ADJACENCY BLOCK IFN FTOPS20,< LOAD T1,LIDEV,+RC.LID(RC) ; Get the device type CAIE T1,LD.DTE ; If DTE then give it a TOPS20 IFSKP. MOVX T1,RE.LDL ; specific event. This is so the LOAD T2,RCLID,(RC) ; Data Link Watcher will wiggle MOVX T3,RS.LSL ; the DTE again. SETZ T4, CALL RTNEVH ; Give a hidden event to NML ENDIF. > ;End IFN FTOPS20 RETSKP ;GIVE GOOD RETURN ABOVE SUBTTL R2KCLS - Close the data link circuit ;R2KCLS - Close a DLL circuit ; ; Call: ; RC/ Pointer to Circuit Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T2 ; ;We have to set the state of the circuit to off state. R2KCLS: MOVX T1,RCS.OF ;We are in "OFF" state STOR T1,RCSTA,(RC) ;Store this state MOVX T1,DF.CLS ;Function is close MOVE T2,RC ;Circuit block CALL CALKON ;Tell the DLL we are shutting down TRN RET SUBTTL CALKON - Call the Kontroller ;CALKON - Call the DLL level "kontroller" ; ; Call: ; T1/ Kontroller Function Code ; T2/ Pointer to circuit block ; T3/ Argument (Usually Pointer to Message Block) ; T4/ Next hop for the NI ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 ; ;This routine will call the correct Kontroller on the correct circuit ;given the line id. The kontroller is called with T1 containing the ;function to perform, T2 containing the hardware line address and T3 ;with function specific data. If the device is on the wrong CPU (only ;DTEs on TOPS-10 SMP), CALKON will queue the request to be serviced ;at once-a-jiffy service on the correct CPU. CALKON: SAVEAC ;SAVE A COUPLE ACS MOVE RC,T2 ;SET UP THE CIRCUIT BLOCK POINTER IFN FTMP,< PUSH P,T4 ;SAVE T4 LOAD T4,LIDEV,+RC.LID(RC) ;GET THE DEVICE TYPE CAIE T4,LD.DTE ;IS IT CPU-DEPENDANT? JRST CALKO5 ;NOT CPU DEPENDANT, GO AHEAD AND DO IT. LOAD T4,LIKON,+RC.LID(RC) ;GET THE CPU NUMBER OF THE CIRCUIT CAMN T4,.CPCPN ;ARE WE ON THAT CPU NOW? JRST CALKO5 ;YES CAIN T1,DF.XMT ;QUEUED OUTPUT? JRST CALKO4 ;YES, QUEUE UP THE MESSAGE BLOCK. CAIE T1,DF.OPN ;IS THIS AN INITIALIZE FUNCTION? JRST CALKO1 ;NO, TRY FOR SOMETHING ELSE SETONE RCOPN,(RC) ;FLAG INITIALIZE TO BE DONE AT JIFFY LEVEL. POP P,T4 ;RESTORE T4 MOVEI T1,LS.OFF ;PRETEND LINE STATE IS OFF RETSKP ;SAY WE DID IT. CALKO1: CAIE T1,DF.CLS ;IS THIS A HALT KONTROLLER FUNCTION? BUG.(CHK,ROUIKF,ROUTER,SOFT,,,< Cause: CALKON was called with an illegal function code. The only allowed values are DF.XMT, DF.OPN, and DF.CLS. >,RTN) SETONE RCCLS,(RC) ;FLAG HALT TO BE DONE AT JIFFY LEVEL. POP P,T4 ;RESTORE T4 RETSKP ;SAY WE DID IT CALKO4: D36OFF ;NO, WE'LL HAVE TO QUEUE THE MESSAGE ENDQUE T3,RC.JSQ(RC),MB.NXT,T1 ;QUEUE THE MESSAGE D36ON ;TURN INTERRUPTS BACK ON POP P,T4 ;RESTORE T4 RETSKP ; AND RETURN TO SENDER CALKO5: POP P,T4 ;RESTORE T4 >;End of IFN FTMP LOAD T2,RCDLB,(RC) ;GET THE KONTROLLER'S BLOCK ADDRESS LOAD P1,LIDEV,+RC.LID(RC) ;GET THE DEVICE TYPE ;************************ TORESCD DNSNUP(RTROTR) ;LABEL FOR DNSNUP TO FIND OUTPUT MESSAGES TOXRESCD ;EXPECTS (T3) = MESSAGE BLOCK ;************************ CALLRET DNDDSP ;DISPATCH TO DNADLL AND RETURN +1 OR +2 SUBTTL CALQOB - Call CALKON for queued output. ;CALQOB - Send a message to the DLL "kontroller" ; ; Call: ; RC/ Pointer to the circuit block ; MB/ Pointer to message block ; T4/ Next hop address (if any) ; Return: ; +1, Always. If the output fails, it calls XMTFAI which returns ; the message in MB and closes the port, setting a time at ; which to reopen it. ; ;This routine is a jacket around CALKON to make the code sending messages ;simpler and easier to read. CALQOB: INCR RCCMQ,(RC) ;INCREMENT NUMBER OF MESSAGES QUEUED MOVX T1,DF.XMT ;SET UP FUNCTION CODE MOVE T2,RC ;COPY POINTER TO CIRCUIT BLOCK MOVE T3,MB ;COPY POINTER TO MESSAGE BLOCK CALL CALKON ;CALL THE KONTROLLER CALLRET XMTFAI ;OUTPUT FAILED RET ;RETURN SUCCESS SUBTTL XMTFAI/CIRFAI - Transmit/Line failed ;Call: ; RC/ Circuit block ; MB/ Message that couldn't be transmitted XMTFAI: SETZRO RMDRM,(MB) ; Don't try to resend this MOVE T3,MB ; SET UP MESSAGE BLOCK POINTER FOR RTIOTC CALL RTIOTC ; FREE UP THE MESSAGE BLOCK CIRFAI: CALL RTIDWN ; SAY THE LINE IS NOW DOWN CALL R2KCLS ; Close the port MOVX T1,RCS.RJ ; Set state to rejected STOR T1,RCSTA,(RC) CALL DNGTIM ; and try to reopen it soon STOR T1,RCTIN,(RC) ; RET SUBTTL RTRRCR - Recompute Routing ;RTRRCR - Routine to Recompute Routing Vector ; ; Call: ; RTRNRV is expected to contain a ptr to the current "normal" ;routing vector, while RTRNVB points to the routing vector bitmap. ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 ; ; AC Usage: ; AJ/ Pointer to the adjacency block ; RC/ Ptr to circuit block ; T4/ Index into scratch routing vector ; T3/ Index into normal routing vector ; ;This routine is called whenever it is thought that the topology of ;the network may have changed. RTRNRV is the normal routing vector ;which is used by the forwarding routine, while RTRNVB is a bitmap ;of which nodes need to be recomputed. RTRRCR: SKIPN RTRCBQ ;Any circuits yet? RET ;If not, just return TRACE RTR, STKVAR SKIPN ENFLG ; Endnode? IFSKP. SKIPE EVSDRP ; If we are not eavesdropping then nothing to CALL RTRBMV ; update. Update "maybe" vector ELSE. SETZM RTRRCF ; Clear the "recompute-routing" flag CALL RTRBNV ; Build normal routing vector ENDIF. SKIPN T1,AJOFLQ ; Any adjacencies to free? RET ; No RTRRC2: LOAD P1,AJNXT,(T1) ; Get next adjacency on queue if any CALL DNFWDS ; Return the memory MOVE T1,P1 ; Get possible next adjacency to free JUMPN T1,RTRRC2 ; If another tryto free it SETZM AJOFLQ ; The queue is now empty RET ; And now we are done SUBTTL RTRBNV - Build normal routing vector ;Here to recompute the normal routing vector. We also ;look for local users in the "normal" routing vector as we go ;through. With local users, RTRNOV has the address of the vector entry ;to that "NSP", therefore it is left alone. RTRBNV: STKVAR SETZM UPDCNT ;Initialize update count IFN FTOPS20,< STKVAR SETZM TCIFLG ;Initialize topology change count >; END IFN FTOPS20 MOVE T1,RTRMXN ;Get maximum node address ADDI T1,1 ;Adjust for node 0 IDIVI T1,^D36 ;Compute size of routing vector bitmap SKIPE T2 ;Round up ADDI T1,1 ;... MOVNS T1 ;Create an AOBJN pointer to bitmap HRLZS T1 ;... RTRBN1: MOVEM T1,NVBAOJ ;Save routing vector bitmap AOBJN pointer HRRZ T2,T1 ;Get current routing vector bitmap offset ADD T2,RTRNVB ;Add address of routing vector bitmap SETZ T1, ;Get a zero for entry EXCH T1,(T2) ;Clear entry and get current value MOVEM T1,NVBENT ;Save current entry RTRBN2: MOVE T1,NVBENT ;Get current entry value JUMPE T1,RTRBN8 ;Jump if current entry zero JFFO T1,.+1 ;Find next bit set within entry MOVE T1,BITS(T2) ;Clear bit just found in saved entry value ANDCAM T1,NVBENT ;... HRRZ P2,NVBAOJ ;Compute node number of node to recompute IMULI P2,^D36 ;... ADD P2,T2 ;... CAMLE P2,RTRMXN ;Range check computed node number BUG.(CHK,ROUBMC,ROUTER,SOFT,,,,RTRBN9) MOVE P1,RTRNRV ;Get address of normal routing vector ADD P1,P2 ;Offset to node being recomputed MOVE T4,(P1) ;Get current routing information TXNE T4,RNLCL ;Is this the local node? JRST RTRBN2 ;Yes, skip over this node ;Continued on next page ;Continued from previous page MOVX Q1,RNHOP!RNCST ;Start off with maximum cost and hops SETZ Q2, ;And no known adjacency pointer SKIPN RC,RTRCBQ ;Get address of first circuit block JRST RTRBN7 ;None there? RTRBN3: LOAD AJ,RCAJQ,(RC) ;Get address of first adjacency block JUMPE AJ,RTRBN6 ;None there, ignore this circuit RTRBN4: LOAD T1,AJSTA,(AJ) ;Get current state of adjacency CAXE T1,ADJ.UP ;Is it up? JRST RTRBN5 ;No, skip this adjacency LOAD T1,AJNAN,(AJ) ;Get node address of adjacent node JUMPE T1,RTRBN5 ;Skip this adjacency if no node address CAME T1,P2 ;Recomputing this node's information? IFSKP. SETZ T4, ;Yes, get dummy routing information ELSE. LOAD P1,AJRTV,(AJ) ;Get address of adjacency's routing vector JUMPE P1,RTRBN5 ;No routing information if an endnode ADD P1,P2 ;Offset to node being recomputed MOVE T4,(P1) ;Get current routing information ENDIF. LOAD T1,RNCST,+T4 ;Compute cost to subject node OPSTR ,RCCST,(RC) ;... LOAD T2,RNHOP,+T4 ;Compute hops to subject node ADDI T2,1 ;... CAMG T1,RTRMXC ;Cost and hops within range? CAMLE T2,RTRMXH ;... JRST RTRBN5 ;No, skip this adjacency LOAD T3,RNCST,+Q1 ;Get best cost so far CAMLE T1,T3 ;Is cost via this adjacency the same or better? JRST RTRBN5 ;No, skip this adjacency CAMN T1,T3 ;Is this adjacency the same cost? JUMPN Q2,[LOAD T3,AJNAN,(AJ) ;Yes, get node address of adjacent node LOAD T4,AJNAN,(Q2) ;And address of best (so far) adjacency CAMG T3,T4 ;Is new adjacency node address greater? JRST RTRBN5 ;No, ignore this adjacency JRST .+1] ;Yes, use this adjacency STOR T1,RNCST,+Q1 ;Update best cost and hops values STOR T2,RNHOP,+Q1 ;... TXO Q1,RNRCH ;Mark node as reachable MOVE Q2,AJ ;Remember chosen adjacency for this node RTRBN5: LOAD AJ,AJNXT,(AJ) ;Step to next adjacency JUMPN AJ,RTRBN4 ;Loop back for all adjacencies RTRBN6: LOAD RC,RCNXT,(RC) ;Step to next circuit JUMPN RC,RTRBN3 ;Loop back for all adjacencies ;Continued on next page ;Continued from previous page RTRBN7: MOVE P1,RTRNRV ;Get address of normal routing vector ADD P1,P2 ;Offset to node being recomputed MOVE T4,(P1) ;Get current routing information LDB T1,[POINTR (Q1,RNCST!RNHOP)] ;Get cost and hops values LDB T2,[POINTR (T4,RNCST!RNHOP)] ;... MOVE T3,P1 ;Get address of current entry ADD T3,RTROFS ;Offset to output adjacency vector MOVE T3,(T3) ;Get current output adjacency CAMN T1,T2 ;Any change in cost or hops? CAME T3,Q2 ;Or output adjacency? IFNSK. TXO Q1,RNCHG ;Yes, set change flag AOS UPDCNT ;Increment update count SUB T1,T2 ;Update routing vector checksum ADDM T1,RTRCKS ;... XOR T4,Q1 ;Did reachability change? TXNN T4,RNRCH ;... IFSKP. IFN FTOPS20,< AOS TCIFLG ;Increment topology change count >; END IFN FTOPS20 TXNE Q1,RNRCH ;Is node now reachable? TDZA T3,T3 ;Yes, get reachable flag and skip MOVEI T3,1 ;No, get unreachable flag MOVE T2,P2 ;Get node number MOVE T1,RTRHOM ;Generate full node address DPB T1,[POINTR (T2,RN%ARE)] ;... EVENT RE.NRC, ENDIF. MOVE T1,P1 ;Get address of current entry ADD T1,RTROFS ;Offset to output adjacency vector MOVEM Q2,(T1) ;Store updated routing information MOVEM Q1,(P1) ;... ENDIF. JRST RTRBN2 ;Loop back for entire bitmap entry RTRBN8: MOVE T1,NVBAOJ ;Get AOBJN pointer to bitmap vector AOBJN T1,RTRBN1 ;Loop back to inspect entire bitmap RTRBN9: SKIPN UPDCNT ;Any changes in routing vector? RET ;No, return IFN FTOPS20,< SKIPE TCIFLG ;Topology change? CALLX (MSEC1,NTCIN) ;Yes, signal topology change interrupt >; END IFN FTOPS20 SKIPN RC,RTRCBQ ;Get address of first circuit block RET ;None? Give up now RTRBN0: SETONE RCSRM,(RC) ;Set send routing message flag LOAD RC,RCNXT,(RC) ;Get address of next circuit block JUMPN RC,RTRBN0 ;Loop back to set SRM for all circuits RET ;And then return SUBTTL RTRBMV - Maybe vector update when running as an endnode RTRBMV: CALL DNGTIM ; Get current milliseconds CAMG T1,BMVTIM ; and see if time for another update RET ; of the maybe vector. ADD T1,BMVIVL ; Compute time of next update MOVEM T1,BMVTIM SKIPN RC,RTRCBQ ; Do we have a circuit RET OPSTR ,RCAJQ,(RC) ; Get the only adjacency IFSKP. MOVE T1,RTRNRV ; Address of vector MOVE T2,RTRMXN ; Number of slots in vector AOJ T2, ; including node 0 DO. SETZRO RNMBY,(T1) ; Clear the "maybe bit" SOJLE T2,RTN ; Exit when all elements done AOJ T1, ; Point to next element LOOP. ; Loop back ENDDO. ENDIF. LOAD P2,AJRTV,(AJ) ; Get pointer to routing vector JUMPE P2,RTN ; Just in case ADDI P2,1 ; Start with node 1 SKIPN P1,RTRNRV ; Get reach vector RET LOAD T1,RCCST,(RC) ; Get the cost on the Ethernet STOR T1,RNCST,(P1) ; and save it in element 0 of the vector MOVEI T1,1 ; and dummy up the hops STOR T1,RNHOP,(P1) ADDI P1,1 ; Step to node 1 MOVE Q1,RTRMXN ; Get the maximum number of nodes RTRBM1: SETZRO RNMBY,(P1) ; Assume not reachable LOAD T2,RNCST,(P2) ; Get the cost OPSTR ,RCCST,(RC) ; Add the circuit cost LOAD T1,RNHOP,(P2) ; Get the number of hops AOS T1 ; Adjust it by us CAMGE T2,RTRMXC ; Is the cost within the max? CAML T1,RTRMXH ; How about the hops? JRST RTRBM2 ; No, then do the next node SETONE RNMBY,(P1) ; Yes, assume reachable RTRBM2: AOJ P1, ; Do the next one AOJ P2, ; on both of them SOJGE Q1,RTRBM1 ; Loop for the next node SETZM RTRRCF ; Clear the "recompute-routing" flag RET SUBTTL RTRUPD - Send routing messages if needed ;RTRUPD - Routine to perform the update process (send routing messages) ; ; Call: ; RTRNRV must contain the ptr to the normal routing vector ; RTRCBQ must contain a ptr to the first circuit block ; ; Return: ; RET ;Always ; ; Uses: T1-T4 ;Loop through all the circuit blocks and see if the long timer (T2) has ;expired. If it has we send a routing message, if it hasn't check ;the send routing message flag and if set, send the routing message if ;the short timer has expired. The routing message is built from the ;"normal" routing vector. After the routing message has been queued, ;the circuit block "last routing message sent" timer is updated, and ;the "send routing message" flag is cleared. RTRUPD: SKIPGE ENFLG ;If an endnode RET ; then don't send a routing message TRVAR STKVAR SKIPA RC,RTRCBQ ;GET THE BEGINNING OF THE CIRCUIT QUEUE UPDLOP: LOAD RC,RCNXT,(RC) ;GET THE POINTER TO THE NEXT ONE ;Careful if this call is moved (JRST RTRCHK) JUMPE RC,RTRCHK ;IF DONE THEN GO CHECK THE ROUTING VECTOR LOAD T1,RCSTA,(RC) ;GET THE STATE OF THIS CIRCUIT CAIE T1,RCS.TT ;IS THE STATE IN TEST CAIN T1,RCS.RN ; OR OK STATE TRNA ;YES, SEND ROUTING MESSAGE JRST UPDLOP ;NO, LOOK AT NEXT CIRCUIT SETZM TOTALNF ;CLEAR OUT TOTAL NODE FLAG SETZM EMPTY ;Clear flag saying data in message OPSTR ,RCTLR,(RC) ;Have we ever sent an update? JRST RTRSRB ;No, send one now CALL DNGTIM ;GET THE CURRENT TIME IN T1 SUB T1,T2 ; Compute the elapsed time since last update MOVE T2,RTRTM1 ; Get the long timer for point to point TMNE RCBCT,(RC) ; Broadcast circuit? MOVE T2,RTRBT1 ; Yes, use the broadcast timer CAML T1,T2 ; Has the update timer (T1) expired? JRST RTRSRB ; Yes, send all nodes now TMNN RCSRM,(RC) ; Forced update? JRST UPDLOP ; No, look at next circuit TRNA RTRSRB: SETOM TOTALNF ; Indicate we need to send complete topology LOAD T1,RCBSZ,(RC) ;GET THE CIRCUIT BLOCK SIZE SKIPN T1 ;HAVE ONE TO USE? BUG.(CHK,ROUBSZ,ROUTER,SOFT,,,< Cause: The blocksize for a circuit is defaulted to RTRBSZ and updated which information from nodes on the circuit to determine a new minimum blocksize for the circuit. Somehow this ended up as zero. >,UPDLOP) LOAD AJ,RCAJQ,(RC) ; No, then get pointer to only adjacency for ; point-point or any for broadcast JUMPE AJ,UPDLOP ; No adjacencies, give up... JN RCBCT,(RC),RTRSX1 ; If broadcast don't check adjacency state LOAD T1,AJSTA,(AJ) ; Get state of adjacency CAIE T1,ADJ.UP ; Is it "up" JRST UPDLOP ; No, try next circuit RTRSX1: MOVE P1,RTRNRV ;POINT TO NORMAL ROUTING VECTOR SETZ P2, ;CLEAR OUT CHECKSUM LOAD T1,AJNTY,(AJ) ;GET THE NODE TYPE IN T1 CAIE T1,ADJ.3F ;IS IT A PHASE III ROUTER? JRST SP4RM ;NO, THEN CHECK FOR PHASE IV MOVE T1,RTRMX3 ;GET THE MAXIMUM NUMBER OF PHASE III NODES MOVEM T1,NODCNT ;SAVE AS THE COUNT OF NODES LSH T1,1 ;TWO BYTES PER NODE ADDI T1,2 ;ADD IN SPACE FOR CHECKSUM CALL DNGMSG ;GET THE MESSAGE BLOCK JRST UPDLOP ;COULDN'T, THEN TRY NEXT CIRCUIT MOVE MB,T1 ;GET THE MESSAGE BLOCK POINTER XMOVEI T1,UD.MSD(MB) ;GET POINTER TO USER DATA MSD CALL DNPINI ;INITIALIZE THE MSD AND HEADER SP3LOP: AOS P1 ;PHASE III STARTS WITH NODE 1 LDB T1,[POINTR((P1),)] ;GET THE HOP!COST ADD P2,T1 ;SUM THE CHECKSUM CALL DNP2BY ;PLACE BYTES IN ROUTING MESSAGE SOSLE NODCNT ;DO IT FOR ALL THE NODES but not zero JRST SP3LOP ;Continue until last node done MOVE T1,P2 ;Checksum in T1 CALL RTRSNS ;SEND THE SEGMENT OUT TRN ;ON ERROR TRY NEXT CIRCUIT JRST UPDLOP ;AND DO THE NEXT ONE ; Here to handle a Phase IV message, but first we have to check for ; Phase III small nodes. If it is one then we exit and do the next circuit ; T1 was set up with the node type from the adjacency vector above. SP4RM: JN RCBCT,(RC),SP4RM1 ;If broadcast don't check adjacency type CAIE T1,ADJ.3S ;PHASE III SMALL NODE CAIN T1,ADJ.LN ;OR PHASE IV END NODE JRST UPDLOP ;Yes, then no routing update need be sent SP4RM1: ADD P1,RTRLMG ;Add in offset so we don't start with the same ; node in the vector each time MOVE T1,RTRMXN ;GET THE MAXIMUM NUMBER OF NODES MOVEM T1,MAXNODE ;SAVE AS MAXIMUM TO SEND SP4RM3: MOVEI P2,1 ;THE CHECKSUM STARTS AT 1 FOR PHASE IV LOAD T1,RCBSZ,(RC) ;GET THE NUMBER OF BYTES FOR MESSAGE BLOCK CALL DNGMSG ;GET THE MESSAGE BLOCK JRST UPDLOP ;COULDN'T, THEN TRY NEXT CIRCUIT MOVE MB,T1 ;GET THE MESSAGE BLOCK POINTER XMOVEI T1,UD.MSD(MB) ;GET POINTER TO USER DATA MSD CALL DNPINI ;INITIALIZE THE MSD AND HEADER LOAD T1,RCBSZ,(RC) ;Number of bytes we can fit into one message SUBI T1,6 ;Minus the header length and checksum LSH T1,-1 ;Divide by two since all parts of a segment MOVEM T1,MAXSEG ; are two bytes in width SP4RM4: SETZM NODCNT ;CLEAR OUT THE NODE COUNT FOR THIS SEGMENT SETZM OVFLG ;CLEAR THE OVERFLOW FLAG NOW SKIPE TOTALNF ;ARE WE TO INCLUDE ALL NODES? JRST SP4RM6 ;YES, THEN START WITH THIS ONE ; Here we loop until we get a node which has the CHANGE bit set in the routing ; vector. SP4RM5: LOAD T1,RNCHG,(P1) ;GET THE CHANGE BIT JUMPN T1,SP4RM6 ;When set start with this node AOS P1 ;INCREMENT THE COUNT MOVE T1,P1 ;GET THE NODE NUMBER SUB T1,RTRNRV ;FROM THE INDEX INTO ROUTING TABLE CAMLE T1,RTRMXN ;HAVE WE REACHED THE END OF THE VECTOR? MOVE P1,RTRNRV ;YES, THEN RESET TO THE BEGINNING SOSL MAXNODE ;DECREMENT COUNT OF NODES LEFT TO LOOK AT JRST SP4RM5 ;LOOP UNTIL WE FIND ONE WITH CHANGE SET JRST SP4RM9 ;WE HAVE LOOKED AT ALL NODES ;Here to begin a new segment of the routing message SP4RM6: MOVE T1,MAXSEG ;Get number of 2-byte fields left in buffer CAIGE T1,3 ;Is there enough room for a one node segemnt? JRST SP4RM8 ;No, then send current message and start anew CALL DNRPOS ;READ THE CURRENT POSITION MOVEM T1,COUNTPOS ;SAVE THE POSITION FOR COUNT SETZ T1, ;GET A ZERO CALL DNP2BY ;PUT THE COUNT IN MOVE T1,P1 ;GET THE NODE NUMBER INDES SUB T1,RTRNRV ;MAKE IT A NODE NUMBER ADD P2,T1 ;ADD INTO THE CHECKSUM CALL DNP2BY ;PUT THE 2 BYTES INTO THE MESSAGE SOS MAXSEG ;Start-ID = 2 bytes SOS MAXSEG ; and count = 2 bytes SP4RM7: LDB T1,[POINTR((P1),)] ;Get COST/HOPS for this entry ADD P2,T1 ;ADD TO CHECKSUM AOS NODCNT ;INCREMENT THE COUNT OF NODES IN THIS SEGMENT SETOM EMPTY ;Flag to indicate data in message CALL DNP2BY ;Put COST/HOPS into the message AOS P1 ;DO THE NEXT ONE MOVE T1,P1 ;GET THE NODE NUMBER SUB T1,RTRNRV ;FROM THE INDEX INTO ROUTING TABLE CAMG T1,RTRMXN ;HAVE WE REACHED THE MAXIMUM YET? IFSKP. SETOM OVFLG ;SET THE OVERFLOW FLAG SO WE END THE SEGMENT MOVE P1,RTRNRV ; and reset to the beginning of the vector ENDIF. SOSG MAXNODE ;DECREMENT TOTAL NODE COUNT JRST SP4RM9 ; JUMP IF DONE SOSG MAXSEG ; Two COST/HOP bytes and see if more room JRST SP4RM8 ; NO, THEN SEND IT AND LOOP BACK SKIPE OVFLG ;OVERFLOW SET? IFSKP. ; No LOAD T1,RNCHG,(P1) ;GET THE CHANGE BIT FOR NEXT NODE SKIPN TOTALNF ;IS THE TOTAL NODE FLAG SET? SKIPE T1 ; or do we have a change bit set? JRST SP4RM7 ; Yes, go do the next entry ENDIF. CALL CLSSEG ; Close the current segment JRST SP4RM4 ; and possibly start a new one SP4RM8: CALL CLSSEG ; Close out the current segment MOVE T1,P2 ; Checksum to T1 CALL RTRSNS ;SEND THE SEGMENT OUT JRST UPDLOP ;ERROR, THEN GO TO THE NEXT CIRCUIT (MB freed) JRST SP4RM3 ;SUCCESS, START A NEW MESSAGE ;Here when all nodes in the normal vector have been looked at ;See if we found any and if so send the routing message. SP4RM9: SKIPE EMPTY ; Any data in message? IFSKP. ; No CALL FREMSG ; Return the message block JRST UPDLOP ; and step to next circuit ENDIF. SKIPE NODCNT ; Yes, do we have any nodes in this segment? CALL CLSSEG ; Yes, close off the segment MOVE T1,P2 ; Checksum must be in T1 CALL RTRSNS ;SEND THE SEGMENT OUT JRST UPDLOP ;ERROR, THEN GO TO THE NEXT CIRCUIT MOVE T1,RTRBSZ ;Get the block size IDIVI T1,5 ; and use it to compute ADD T1,RTRLMG ; a new starting point CAML T1,RTRMXN ;HAVE WE GONE TOO FAR? SETZ T1, ; Start over again MOVEM T1,RTRLMG ;MAKE THIS NEW START JRST UPDLOP ; Now advance to the next circuit ENDSV. ;Here because we have reached the end of a segment. That was determined ;by the absence of a CHANGE flag in the vector for some node, or the end of a ;message, or the end of the reach vector has been reached. We will now ;close the segment. CLSSEG: CALL DNRPOS ;GET OUR CURRENT POSITION EXCH T1,COUNTPOS ;Get the previously reverved spot for the count CALL DNGOPS ;GO TO THAT POSITION MOVE T1,NODCNT ;GET THE NUMBER OF NODES FOR THIS SEGMENT ADD P2,T1 ;ADD THE COUNT TO THE CHECKSUM CALL DNP2BY ;PLACE IT INTO THE MESSAGE MOVE T1,COUNTPOS ;GET THE END OF THE MESSAGE BACK CALL DNGOPS ;AND GO THERE RET ;Here to checksum the routing vector to see if it may be corrupted RTRCHK: SOSLE CHKCNT ;TIME TO CHECK ROUTING VECTOR CHECKSUM? RET ;NO, RETURN MOVE T1,CHKVAL ;YES, RESET CHECKSUM COUNTER MOVEM T1,CHKCNT ;... MOVE T3,RTRMXN ;GET THE MAXIMUM NUMBER OF NODES MOVE P1,RTRNRV ;GET THE POINTER TO THE NORMAL ROUTING VECTOR SETZ P2, ;CLEAR OUT REG FOR CHECKSUM RTRCK1: SETZRO RNCHG,(P1) ;CLEAR OUT CHANGE FLAG LDB T1,[POINTR((P1),)] ;GET THE HOPS!COST ADD P2,T1 ;ADD INTO MESSAGE AOJ P1, ;ADD IN THE NEXT ONE SOJGE T3,RTRCK1 ;LOOP FOR THEM ALL CAME P2,RTRCKS ;IS IT THE SAME AS THE OLD CHECKSUM? SKIPN RTRCKS ; AND DID WE HAVE ONE? TRNA ;IT'S OK BUG.(CHK,ROUBCD,ROUTER,SOFT,,,< Cause: Somehow our internal reachability vector has been damaged since the last rebuilding. >) MOVEM P2,RTRCKS ;STORE THE CHECKSUM RET ;RETURN TO CALLER ; ; All Outgoing Routing Messages Both Phase III And Phase IV ; pass through this routine. It expects the unnormalized checksum ; in P2. RTRSNS: MOVE T1,P2 ;GET COPY OF CHECKSUM CALL CKSNRM ;NORMALIZE THE CHECKSUM CALL DNP2BY ; AND WRITE IT IN MESSAGE ;Now we must make up the router header XMOVEI T1,RM.MSD(MB) ;GET POINTER TO ROUTER'S MSD CALL DNPINI ;SET UP TO WRITE HEADER SETZ T1, ;BUILD FIRST BYTE IN T1 MOVX T2,RCM.1R ;TYPE = ROUTING MESSAGE STOR T2,CMTYP,+T1 ;PLACE IT IN CORRECT FIELD SETONE CMCTL,+T1 ;INDICATE IT IS A CONTROL MESSAGE CALL DNP1BY ;PLACE THE BYTE MOVE T1,RTRADR ;GET OUR ADDRESS MOVE T3,RTRHOM ; and our area TMNE AJPH4,(AJ) ; If Phase IV include the area number DPB T3,[POINTR(T1,RN%ARE)] CALL DNP2BY ;PUT ADDRESS IN MESSAGE SETZ T1, ;ZERO FOR A RESERVED PHASE IV BYTE TMNE AJPH4,(AJ) ; If Phase IV include a reserved byte CALL DNP1BY XMOVEI T1,UD.MSD(MB) ;POINT TO USER DATA MSD XMOVEI T2,RM.MSD(MB) ;MAKE RTR MSD POINT TO USER DATA MSD SETZ T3, ;DON'T CHANGE BYTE POINTERS CALL DNLMSS ;LINK IN THE MESSAGE SEGMENT TRACE RTR, JE RCBCT,(RC),RTRSN2 ;If not broadcast send packet now DMOVE T1,RTRALR ;Sending to "all-routers" CALL RTRSNI ;Broadcast set it up differently TRNA RTRSN2: CALL CALQOB ;OUTPUT THE MESSAGE BLOCK TRN SETZRO RCSRM,(RC) ;INDICATE WE HAVE SENT ROUTING MESSAGE CALL DNGTIM ;Get current time SKIPE TOTALNF ;Was this a complete update? STOR T1,RCTLR,(RC) ;Yes, remember the time we sent it RETSKP ;GIVE GOOD RETURN ENDTV. SUBTTL RTRSNI - Send hello/routing message on the NI ;Call: ; T1/ Destination address high order ; T2/ Destination address low order RTRSNI: STOR T1,MBDS1,(MB) ; Save address of destination (High-order) STOR T2,MBDST,(MB) ; Low order address SETZ T4, ; No next hop for broadcast messages CALL CALQOB ; RET ;AND CONTINUE ON SUBTTL CKECTO - Check the cache timer for each node CKECTO: SOSLE CCHTIM ; Time to check cache flags? RET ; No MOVE T4,RTRMXN ; Count of slots in vector MOVE T3,RTRNRV ; Point to the reach vector which contains ; the cache flag CKECT1: JE RNCCH,(T3),CKECT2 ; If cache flag is set check cache timeout MOVE T2,T3 ; Copy current vector address ADD T2,RTROFS ; Add offset to timer value CALL DNGTIM ; Get current time CAMG T1,(T2) ; Is current time past time out value IFSKP. SETZRO RNCCH,(T3) ; Yes, clear the in-cache flag ENDIF. CKECT2: AOJ T3, ; Step to next node SOJGE T4,CKECT1 ; More to do? MOVE T1,RTRADR ; Get local address ADD T1,RTRNRV ; and index into reach vector slot SETONE RNCCH,(T1) ; and set the in-cache flag MOVEI T1,^D120 ; Two minutes before we check again MOVEM T1,CCHTIM RET SUBTTL SELDSR - Select a desiginated router SELDSR: SKIPA RC,RTRCBQ ; Loop through all circuit blocks SELDS1: LOAD RC,RCNXT,(RC) JUMPE RC,RTN ; If done, just return TMNN RCBCT,(RC) ; We only compute a desiginated router for JRST SELDS1 ; for broadcast circuits SETZRO RCPRI,(RC) ; Start at lowest priority SETZ P1, OPSTR ,RCAJQ,(RC) ;Get pointer to first adjacency SELDS2: LOAD AJ,AJNXT,(AJ) ; Step to next SKIPN AJ IFSKP. LOAD T1,AJSTA,(AJ) ; Get state of adjacency CAIE T1,ADJ.IN ; If state is not initializing CAIN T1,ADJ.UP ; or up, don't consider it TRNA JRST SELDS2 LOAD T1,AJPRI,(AJ) ; Get the adjacency's priority LOAD T3,AJNAH,(AJ) ; Get the address LOAD T4,AJNAL,(AJ) ELSE. MOVE T1,RTRPRI ; No more adjacencies, check ourselves MOVE T3,RTRHIO ; Get our address in string format HLRZ T4,RTRLOO ENDIF. CAIGE T1,(P1) ; Is it greater/equal than what we have so far? JRST SELDS3 ; No, step to next CAIE T1,(P1) ; Was it the same? IFSKP. LOAD T2,RCDSL,(RC) ; Get current designated router's address CAMG T4,T2 ; Is new one higher? JRST SELDS3 ; No, keep the one we have ENDIF. MOVE P1,T1 ; Save this as the highest DMOVE Q1,T3 ; and save address SELDS3: JUMPN AJ,SELDS2 ; Check next adjacency or ultimately ourselves STOR P1,RCPRI,(RC) ; Save new priority OPSTR ,RCDSL,(RC) ; Has the designated router changed? RET ; No, then done STOR Q2,RCDSL,(RC) ; Save the designated routers address HRLZ Q2,Q2 ; Reposition low order CAME Q2,RTRLOO ; Are we the designated router? IFSKP. MOVEI T2,^D5 ; Seconds to wait STOR T2,RCDRT,(RC) ; before we assume DSR role ELSE. SETZRO RCDRT,(RC) ; No longer waiting to assume DSR role SETZRO RCDSR,(RC) ; We are not the DSR ENDIF. STOR Q1,RCDSH,(RC) ; Save high order of address JRST SELDS1 ; and check next circuit SUBTTL RTRTMR - Routine to perform timer functions ;RTRTMR - Hello, Listener and other timer processes ; ; Call: ; RTRCBQ must point to the first circuit block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 ; ;This code implements the Update Process, the Node Talker Process, and the ;Node Listener Process. ;First we do the Node Listener Process. This consists of ensuring that we ;have heard from all adjacencies within time T3 * T3MULT (or BCT3MULT). (T3 ;is the adjacencies hello timer). Ie: current_time - AJTLR < AJNHT. If the ;previous expression is not true, then if the circuit is a: ; point to point - set off-line ; broadcast (Ethernet) - the adjacency is destroyed. RTRTMR: SAVEAC SKIPA RC,RTRCBQ ;GET THE FIRST CIRCUIT BLOCK RTRTR1: LOAD RC,RCNXT,(RC) ;GET NEXT CIRCUIT BLOCK JUMPE RC,RTRSHM ;Send hellos if necessary LOAD P1,RCSTA,(RC) ;Get state of circuit CAILE P1,RCS.RJ ;Is state off or rejected? JRST RTRTR2 ;No, check TI state LOAD T2,RCTIN,(RC) ;Is the timer running? JUMPE T2,RTRTR2 ;No, look no further (maybe to TR3) CALL DNGTIM ;Get the current time in T1 CAMGE T1,T2 ;Has time elapsed? IFSKP. ;Yes CALL R2KINI ;Try to reopen circuit TRN JRST RTRTR3 ; and move to next circuit ENDIF. RTRTR2: CAIE P1,RCS.TI ;IS LINK IN TI WAIT? CAIN P1,RCS.TV ;IS IT IN TV WAIT? TRNA ;YES, CHECK OUT TI TIMER JRST RTRTR3 ;NO, CHECK OUT OTHER TIMERS CALL DNGTIM ;GET THE CURRENT TIME OPSTR ,RCTIN,(RC) ;SUBTRACT WHEN WE GOT THE LINE UP CAMGE T1,RTRITM ;HAS TIME EXPIRED? JRST RTRTR3 ;NO, JUST CONTINUE ON ;Here when the time allowed for the response to the RI we sent has expired. ETRACE RTR, MOVX T1,RS.VRT ;EVENT REASON: VERIFICATION RECEIVE TIMEOUT CALL RTEINL ;REPORT INITIALIZATION FAILURE EVENT CALL CIRFAI ;Close the portal and set reopen time ; SETOM RTRRCF ;RECOMPUTE ROUTING LATER JRST RTRTR1 ; AND TRY THE NEXT CIRCUIT ;Now check the hello and listener timers. RTRTR3: CAIE P1,RCS.TT ; Is circuit in test state CAIN P1,RCS.RN ; or is it running? TRNA ;YES, OK TO DO THINGS JRST RTRTR1 ;NO, CHECK OUT THE NEXT CIRCUIT RTRCHT: OPSTR ,RCAJQ,(RC) ;Get pointer to first adjacency RTRCH1: LOAD AJ,AJNXT,(AJ) ;Get next adjacency JUMPE AJ,[CALL RTRTLK ;Check the hello timer CALL DSRCHK ; and the desiginated router timer JRST RTRTR1] ;Now, step to next circuit LOAD T1,AJSTA,(AJ) ;Get the state of the adjacency CAIE T1,ADJ.UP ;Is it up? JRST RTRCH1 ;No, then don't check further CALL DNGTIM ;GET THE CURRENT TIME OPSTR ,AJTLR,(AJ) ;SUBTRACT THE TIME LAST MESSAGE WAS RECEIVED OPSTR ,AJNHT,(AJ) ;DID THE LISTENER TIMER EXPIRE? JRST RTRCH1 ; No, check the next adjacency ;Here when the listener timer has been exceeded. The adjacency is declared ;down. On point to point circuits, the circuit gets recycled. LOAD T3,AJNAN,(AJ) ;Get the node address INCR RCAJD,(RC) ;Count adjacency down events LOAD T2,RCLID,(RC) ;Get the device ID EVENT RE.AJD,, CALL SETRCA ;Yes, set recompute routing flags JN RCBCT,(RC),RTRCH3 ;No circuit down if broadcast ETRACE RTR, MOVX T1,RS.ALT ;EVENT REASON: ADJACENT NODE LISTENER TIMEOUT CALL RTELDL ;REPORT CIRCUIT DOWN - CIRCUIT FAULT EVENT CALL CIRFAI ;Close the port and set reopen time JRST RTRCH1 ; Check next adjacency RTRCH3: SKIPN ENFLG ; Endnode? IFSKP. MOVX T1,ADJ.UN ; Set adjacency state to unused STOR T1,AJSTA,(AJ) SETZRO RCDSL,(RC) ; Clear DR address ELSE. MOVE T1,AJ ;The adjacency to zap MOVE T2,RC ; and the circuit block it belongs to CALL RTRZAB ;Flush the adjacency block ENDIF. JRST RTRCH1 ; down and check next ;This code implements the Node Talker Process. Loop through all circuits, ;sending hello messages on any circuits that need them. For point to ;point circuits, a hello message is sent when no other traffic has been sent ;within T3 (the hello timer period for this circuit). ;Ie: current_time - RCTLS >= RCTM3. For broadcast circuits, a hello message ;is sent when when T3 seconds have elapsed since the last hello message ;(current_time - RCTLH >= RCTM3). RTRTLK: CALL DNGTIM ;Get the time again LOAD T3,RCTLS,(RC) ;Assume point to point for a moment TMNE RCBCT,(RC) ;Broadcast circuit? LOAD T3,RCTLH,(RC) ; Yes, then compare against last hello time SUB T1,T3 ;Compute amount of elapsed time MOVX T2,RCSHM ;Get the send hello message flag OPSTR ,RCTM3,(RC) ;Have we been quiet for too long?? IORM T2,$RCSHM(RC) ; Yes, set send Hello message flag RET ; Here to send hello messages to all circuits that have RCSHM set RTRSHM: SKIPA RC,RTRCBQ ;Point to first circuit block RTRSH1: LOAD RC,RCNXT,(RC) ;Get next circuit block JUMPE RC,RTN ;And return when done... TMNN RCSHM,(RC) ;Do we need to send a hello message? JRST RTRSH1 ; Nope, try again ;We have just found a circuit that needs a hello message, determine what type ;of circuit it is, send the appropriate message. JN RCBCT,(RC),RTREHM ; Broadcst circuit? MOVX T1,NO.HEL+1 ;LENGTH OF DATA SEGMENT CALL DNGMSG ;GET THAT MANY BYTES JRST RTRSH1 ;RESOURCE FAILURE, TRY NEXT CIRCUIT MOVE MB,T1 ;SET UP MB WITH MESSAGE BLOCK POINTER XMOVEI T1,UD.MSD(MB) ;INITIALIZE THE USER DATA SEGMENT CALL DNPINI ;DO IT MOVX T1,NO.HEL ;GET THE NUMBER OF HELLOS IN MESSAGE CALL DNP1BY ;PLACE THE IMAGE COUNT IN THE MESSAGE MOVX T3,NO.HEL ;GET THE COUNT FOR LOOP RTRSH2: MOVX T1,HEL.LO ;WORD THAT GOES IN HELLO MESSSAGE CALL DNP1BY ;PUT ONE IN SOJG T3,RTRSH2 ; AND DO ANOTHER ONE IF NEEDED ;Make up the router header. XMOVEI T1,RM.MSD(MB) ;POINT TO THE ROUTER PORTION OF MESSAGE CALL DNPINI ;INITIALIZE IT SETZ T1, ;BUILD THE BYTE IN T1 MOVX T2,RCM.TT ;TYPE OF CONTROL MESSAGE IS TEST MESSAGE STOR T2,CMTYP,+T1 ;PUT IN BYTE SETONE CMCTL,+T1 ;SAY IT'S A CONTROL MESSAGE CALL DNP1BY ;PUT IN THE CTLFLG BYTE MOVE T1,RTRADR ;GET OUR LOCAL ADDRESS MOVE T3,RTRHOM ;GET MY AREA LOAD AJ,RCAJQ,(RC) ;Get the adjacency on this circuit TMNE AJPH4,(AJ) ;Phase IV node? DPB T3,[POINTR(T1,RN%ARE)] ; AREA IF PHASE IV CALL DNP2BY ;PUT THE SOURCE ADDRESS IN MESSAGE XMOVEI T1,UD.MSD(MB) ;LINK THE USER DATA XMOVEI T2,RM.MSD(MB) ; TO THE ROUTER HEADER SETZ T3, ;DON'T CHANGE ANY POINTERS CALL DNLMSS ;LINK THEM TRACE RTR, CALL CALQOB ;QUEUE THE MESSAGE BLOCK SETZRO RCSHM,(RC) ;Indicate that we sent the hello JRST RTRSH1 ; AND DO IT ALL AGAIN FOR THE NEXT CIRCUIT ;Here to send a hello message on a broadcast style circuit RTREHM: CALL DNGTIM ;Get the current time OPSTR ,RCTLH,(RC) ;Compute time since the last hello CAMG T1,RTRTM2 ;Has enough time elapsed? JRST RTRSH1 ; Nope, come back later SKIPGE ENFLG ; Endnode? JRST RTRENH ; Yes, send endnode hello MOVE T1,RTNBRA ;Maximum number of Router BRA's ADDI T1,1 ; plus one for the reserved IMULI T1,7 ;Each one takes seven bytes OPSTR ,RCBSZ,(RC) ;Will this exceed the minimum block size? JRST RTREH6 ;Yes, then don't do it CALL DNGMSG ;Get space for message JRST RTRSH1 ;Can't, try next circuit block MOVE MB,T1 ;Set message pointer XMOVEI T1,UD.MSD(MB) ;Initialize user data segment CALL DNPINI ; ; Now for the 18 bytes of header ; SETZ T1, ;Start clean MOVX T2,RCM.RH ;Control message type is Router hello STOR T2,CMTYP,+T1 SETONE CMCTL,+T1 ;Say type is control CALL DNP1BY ;Write byte into message CALL RTRCHH ;Build common Hello header MOVX T1,IIT.L1 ;We are a level 1 router CALL DNP1BY ;Write IINFO LOAD T1,RCRBS,(RC) ; and the blocksize we advertise CALL DNP2BY MOVE T1,RTRPRI ;Get our priority to be designated router CALL DNP1BY SETZ T1, CALL DNP1BY ;Reserved byte (area) LOAD T1,RCTM3,(RC) ;Hello timer IDIVI T1,^D1000 ;Convert it to seconds CALL DNP2BY SETZ T1, CALL DNP1BY ;Reserved (MPD) ; ; Set up E-LIST (List of Ethernet nodes we have heard from recently) ; CALL DNRPOS ;Get current position in the message STOR T1,RMMK1,(MB) ; and set mark in block SETZ T1, ;Reserve a byte for the count CALL DNP1BY MOVEI T1,^D7 ;Write 7 reserved bytes CALL DNPZB CALL DNRPOS ;Get current position in the block STOR T1,RMMK2,(MB) ; and set mark in block CALL DNP1BY ; MOVEI P1,^D8 ;Keep track of number written so far OPSTR ,RCAJQ,(RC) ;Pointer to adjacencies on this circuit RTREH3: LOAD AJ,AJNXT,(AJ) ;Step to next adjacency JUMPE AJ,RTREH4 ;No more try next circuit LOAD T2,AJNTY,(AJ) ;Get adjacency's node type CAIE T2,ADJ.L2 ;Phase IV level 2 router CAIN T2,ADJ.L1 ; or plain routing node? TRNA JRST RTREH3 ;Not a router, don't include it LOAD T2,AJSTA,(AJ) ;Get state of this adjacency SKIPN T2 ;Valid state? BUG.(CHK,ROUAWS,ROUTER,SOFT,,,< Cause: An adjacency block has been left in the queue of active adjacencies but its state is unused. >,RTREH3) LOAD T1,AJNAH,(AJ) ;Hi-order NI address LOAD T2,AJNAL,(AJ) ; and the low-order HRLZ T2,T2 ;Put into string format CALL DNPENA ;Put ID into message LOAD T1,AJPRI,(AJ) ;Get adjacency's priority TRZ T1,200 ;Set state to unknown LOAD T2,AJSTA,(AJ) ;Get the state of the adjacency CAIN T2,ADJ.UP ;Is it up? TRO T1,200 ; Yes, then say "known 2-way" CALL DNP1BY ;Write into message ADDI P1,7 ;Account for the 7 bytes just written JRST RTREH3 ;Check next adjacency ; Here when done with inserting routing adjacencies we know about. Update ; counts in the message. RTREH4: CALL DNRPOS ;Get position at end of message OPSTR ,RMMK1,(MB) ;Save EOM count, get pos of 1st counter CALL DNGOPS ;Repostion to count MOVE T1,P1 ;Get count CALL DNP1BY ;Write it SUBI P1,^D8 ;Subtract reserved name and count LOAD T1,RMMK2,(MB) ;Bytes to second count CALL DNGOPS ;Reposition MOVE T1,P1 ;Get second adjusted count CALL DNP1BY ;Write it LOAD T1,RMMK1,(MB) ;Get pointer to end of message CALL DNGOPS ;Point to the true end of the message LOAD T1,RCDSL,(RC) ;Get designated router on this circuit HLRZ T2,RTRLOO ;Get our address in string format CAIE T1,(T2) ;Is it us? IFSKP. SETONE RMDRM,(MB) ;Yes, set flag so we resend to "all-endnodes" ENDIF. TRACE RTR, DMOVE T1,RTRALR ;Send to "ALL-ROUTERS" CALL RTRSNI ;Queue this message ;Send one to all-endnodes RTREH6: SETZRO RCSHM,(RC) ;We have sent the Hello CALL DNGTIM ;Time stamp STOR T1,RCTLH,(RC) ; Bamm! JRST RTRSH1 ; and onto the next circuit SUBTTL RTRENH - Send Ethernet end-node hello RTRENH: CALL DNGTIM ;Get the current time OPSTR ,RCTLH,(RC) ;Compute time since the last hello CAMG T1,RTRTM2 ;Has enough time elapsed? JRST RTRSH1 ; Nope, come back later MOVEI T1, ;Number of bytes for hello message CALL DNGMSG ;Get space for message JRST RTRSH1 ;Can't, try next circuit block MOVE MB,T1 ;Set message pointer XMOVEI T1,UD.MSD(MB) ;Initialize user data segment CALL DNPINI ; ; Now for the 18 bytes of header ; SETZ T1, ;Start clean MOVX T2,RCM.EH ;Control message type is Endnode hello STOR T2,CMTYP,+T1 SETONE CMCTL,+T1 ;Say type is control CALL DNP1BY ;Write byte into message CALL RTRCHH ;Build common Hello header MOVX T1,IIT.EN ;We are an ethernet endnode CALL DNP1BY ;Write IINFO LOAD T1,RCRBS,(RC) ;Get the blocksize we will advertise CALL DNP2BY SETZ T1, CALL DNP1BY ;Reserved byte (area) MOVEI T1,^D8 ;Write 8 bytes of zeros for the seed CALL DNPZB LOAD T1,RCDSH,(RC) ;Address of the designated router LOAD T2,RCDSL,(RC) ; we believe exists LSH T2,^D18 ;Position as a string CALL DNPENA LOAD T1,RCTM3,(RC) ;Hello timer IDIVI T1,^D1000 ;Convert it to seconds CALL DNP2BY SETZ T1, CALL DNP1BY ;Reserved MOVX T1,NO.NIH ;Send NO.NIH bytes of test message CALL DNP1BY ;Place the image count in the message MOVX T3,NO.NIH ;Get the count for loop RTREN2: MOVX T1,HEL.LO ;Word that goes in hello messsage CALL DNP1BY ;Put one in SOJG T3,RTREN2 ; and do another one if needed TRACE RTR, DMOVE T1,RTRALR ;Send to "all-routers" CALL RTRSNI ;Queue this message SETZRO RCSHM,(RC) ;We have sent the Hello CALL DNGTIM ;Time stamp STOR T1,RCTLH,(RC) ; Bamm! JRST RTRSH1 ; and onto the next circuit SUBTTL RTRCHH - Build common part of Ethernet hellos RTRCHH: MOVE T1,RTRVER ;Version number of ROUTER CALL DNP1BY ;Stuff it SETZ T1, ;ECO # and User ECO # are 0 CALL DNP2BY ;Stuff them MOVE T1,RTRHIO ;High order MOVE T2,RTRLOO ; and low order CALL DNPENA ;Write the address into the message RET SUBTTL DSRCHK - Check the DSR timer for each circuit DSRCHK: TMNN RCBCT,(RC) ;If not broadcast, we don't care RET LOAD T1,RCDRT,(RC) ;Is "wait to be DSR" timer running JUMPE T1,RTN ;If not just exit SOJG T1,DSRCK1 ;Count down the timer SETONE RCDSR,(RC) ; and if it expires set the DSR flag DSRCK1: STOR T1,RCDRT,(RC) ;Save the new value RET SUBTTL Data Link Layer Interface SUBTTL Data Link Layer Interface -- RTRDLE - Entry into Router from DLL ; Call: ; T1/ Function Code ; T2/ Router Circuit Block Address (except if DI.CCB) ; T3/ Data (ususally pointer to message block) ; T4/ Additional data ; ; Return: ; RET ;Always ; ; Uses: T1-T4 ; ;We simply check the arguments, set up some arguments for the routines ;which handle the functions and dispatch to those routines. ; ;Note that we decide what to do if DECnet is not running at each ;individual interrupt handler. For example if DECnet is turned off ;between the buffer request and the input done, we could have problems. ;We do not accept and new buffer requests or protocol ups once DECnet ;has been turned off. INTERN RTRDLE XRESCD RTRDLE: IFN FTPARANOIA,< CAXL T1,DI.ODN ;RANGE CHECK THE CAXLE T1,DI.ICB ; FUNCTION CODE BUG.(CHK,ROUIFD,ROUTER,SOFT,,,< Cause: The module DNADLL and ROUTER get their function code from the D36PAR. They must have been compiled from different UNVs. Action: Compile from the same D36PAR.UNV >,RTN) > ;END IFN FTPARANOIA SAVEAC ;SAVE SOME AC'S STKVAR ; Place to save word from dispatch table MOVE RC,T2 ;GET THE ROUTER CIRCUIT BLOCK MOVE P1,RTRDTB-1(T1) ;GET BITS AND DISPATCH FOR THIS FUNCTION. HRRM T1,DSPWRD ; Save function in case can't dispatch HLLM P1,DSPWRD ; Save function flags RTRDS2: TXZN P1,RD.CMB ;SHOULD I CHECK FOR A VALID MB? JRST RTRDS4 ;NO, THIS FUNCTION DOESN'T HAVE AN MB. SKIPN MB,T3 ;COPY THE MB RTRDS3: BUG.(CHK,ROUBMB,ROUTER,SOFT,,,< Cause: DNADLL has called RTRDLE with a function requiring a message block, and the pointer supplied (in T3) is either 0 or out of range. Action: Determine why DNADLL gave a bogus pointer since he originally should have obtained it from us. >,RTRDS9) IFN FTPARANOIA,< CALL DNCHMB## ;ASK D36COM TO CHECK THIS POINTER FOR US JRST RTRDS9 ;BAD POINTER, FORGET THIS REQUEST. > ;END IFN FTPARANOIA RTRDS4: TXZN P1,RD.CKS ;SHOULD WE CHECK DECNET/CIRCUIT STATE? JRST RTRDS6 ;DON'T WORRY ABOUT STATE MOVE T1,DCNSTA ;Get DECnet state CAIE T1,DS.ON ;Is it on? JRST RTRDS7 ;NO, RETURN NOW. LOAD T2,RCSTA,(RC) ;GET THE CIRCUIT STATE CAXE T2,RCS.OF ;If state is off CAXN T2,RCS.RJ ; or rejected TRNA RTRDS6: CALLRET (P1) ;NO, CALL APPROPRIATE ROUTINE AND RETURN RTRDS7: MOVE P1,DSPWRD ; Recover dispatch flags TXNE P1,RD.CMB ; Does this function have an MB? CALL FREMSG ; Yes, dispose of it properly, MB = message TLZ P1,-1 ; Remove flags CAIE P1,DI.ODN ; If output done then... JRST RTRDS9 DECR RCCMQ,(RC) ; message no longer queued to the DLL RTRDS9: SETZ T1, ;MAKE SURE THAT THE REQUESTOR UNDERSTANDS RET ; THAT THE REQUEST FAILED RD.CRC==1B0 ;CHECK RC. MAKE SURE IT IS NON-ZERO, AND IF ; FTPARANOIA, RANGE CHECK AND FIND ON RTRCBQ RD.CMB==1B1 ;CHECK MB. MAKE SURE IT IS NON-ZERO, AND IF ; FTPARANOIA, CALL DNCHFB TO ENSURE IT IS GOOD. RD.CKS==1B2 ;CHECK STATES BEFORE CALLING. IF EITHER DECNET ; OR LINE STATE IS OFF, SIMPLY ZERO T1 AND ; RETURN. RTRDTB: RD.CRC+RD.CKS+RD.CMB+RTIOTC ;OUTPUT DONE RD.CRC+RD.CKS+RD.CMB+RTIINC ;INPUT COMPLETE RD.CKS+RD.CRC+RTILSC ;LINE STATE CHANGE RTICCB ;CREATE CIRCUIT SUBTTL Data Link Layer Interface -- RTICCB - Create circuit block ;RTICCB - Create a circuit block ; ; Call: ; T2/ Data Link Block address ; T3/ Line-ID ; T4/ Blocksize to advertise for this circuit ; ; We can not get here if the circuit state is OFF ; ; Return: ; RET ;Always, returns with T1 containing circuit ; ; block address or zero if it couldn't ; ; allocate a new one ; ; Uses: T1-T4 ; RTICCB: DMOVE P1,T2 ; Save DLB and line ID MOVE Q1,T4 ; and blocksize MOVE T1,P2 ; Get the LINE-ID SKIPN ENFLG ; Endnode? IFSKP. ; Yes LOAD T2,LIDEV,+T1 ; Then get the device type on this line CAIE T2,LD.ETH ; Is it an ethernet? JRST RTRCCE ; No, then don't initialize with it ENDIF. CALL RTRMCB ; Make up the circuit block JRST RTRCCE ; and return if can't allocate memory MOVE RC,T1 ; Circuit block pointer we got. STOR P1,RCDLB,(RC) ; Save data link block address for later calls STOR Q1,RCRBS,(RC) ; and maximum blocksize we can advertise ENDQUE RC,RTRCBQ,RC.NXT,T1 ; Add circuit block to queue JN RCBCT,(RC),RTRCC1 ; If broadcast don't make adjacency block JN RCAJQ,(RC),RTRCC1 ; If we have an adjacency block don't make one SETO T1, ; Flag to indicate we expect routing adjacency CALL RTRMAJ ; Make up the adjacency block JRST RTRCCE ; Error return RTRCC1: MOVE T1,RC ; Return circuit block address as callback ID RET RTRCCE: SETZ T1, ; Indicate failure RET SUBTTL Data Link Layer Interface -- RTILSC - Process line state change ; RTILSC - "Line state change" interrupt from the DLL ; ; Call: ; T2/ Circuit block address ; T3/ New Line State ; ; Return: ; RET ;ALWAYS ; ; Uses: RTILSC: TRACE RTR, CAIE T3,LS.OFF ; Is new state off? JRST RTION ; No, must be on RTIDWN: MOVX T1,RS.LSL ;EVENT REASON: CIRCUIT SYNCHRONIZATION LOST ;*** Was it ever up ?? No event if not CALL RTELDL ;REPORT CIRCUIT DOWN - CIRCUIT FAULT EVENT CALL SETRCC ;SET RECOMPUTE ROUTING FLAGS CALL RTRZCB ;CLEAN OUT THE CIRCUIT BLOCK CALL RTRSAO ;SET ANY REMAINING ADJACENCIES TO UNUSED LOAD T1,RCSTA,(RC) ;Get current state MOVX T2,RCS.FA ; Failed state code CAIG T1,RCS.RJ ; If off/rejected, don't change state IFSKP. STOR T2,RCSTA,(RC) ;STORE AS CURRENT STATE FOR THIS CIRCUIT TMNN RCBCT,(RC) ;If broadcast, then close portal IFSKP. CALL R2KCLS ;Close it CALL DNGTIM ;Get current uptime ADDI T1,^D1000 ;Wait a second STOR T1,RCTIN,(RC) ; to reopen the portal ENDIF. ENDIF. RET RTION: LOAD T2,RCSTA,(RC) ;GET CIRCUIT STATE CAIN T2,RCS.RN ; Are we already on? RET ; Yes, ignore notification CAIE T2,RCS.WT ;MAKE SURE WE'RE IN WAITING STATE CAIN T2,RCS.FA ; or failed TRNA JRST [ETRACE RTR, CALLRET CIRFAI] ;TRY TO REINITIALIZE THE CIRCUIT LOAD T2,RCLID,(RC) ;Get the line-id for the event EVENT RE.LUP, ;Generate the event TMNN RCBCT,(RC) ; Is this a broadcast circuit? IFSKP. MOVX T1,RCS.RN ; The circuit state is run STOR T1,RCSTA,(RC) ; SETONE RCSHM,(RC) ; Send a hello message to start things off ELSE. MOVX T1,RCS.TI ;NEW STATE = TRANSPORT INITIALIZATION WAIT STOR T1,RCSTA,(RC) ;STORE THE NEW CIRCUIT STATE CALL RTRSTI ENDIF. RET SUBTTL Data Link Layer Interface -- RTIOTC - Process Output Complete ;RTIOTC - Routine to process output complete interrupt ; ; Call: ; RC/ Circuit block address ; T3/ Message block address ; T4/ Status ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T3 RTIOTC: TRACE RTR, MOVE MB,T3 ;GET THE MESSAGE BLOCK ADDRESS MOVE T1,MB ;ARG FOR DNLENG CALL DNLENG ;FIGURE OUT THE LENGTH OF THE MESSAGE DECR RCCMQ,(RC) ;DECREMENT MESSAGES QUEUED COUNT CALL DNGTIM ;Get the current time STOR T1,RCTLS,(RC) ;Update time last sent. It is ok to do this on ; ethernets for "all-routers & "all-endnodes" ; since they use TLH for the "talker" process. TMNN RMDRM,(MB) ;Should this be resent to "all-endnodes"? IFSKP. SETZRO RMDRM,(MB) ;Yes, but resend it only once DMOVE T1,RTRAEN ;Set "all-endnodes" address CALLRET RTRSNI ENDIF. TMNN RMICP,(MB) ;Is this from the local node? IFSKP. INCR RCCTS,(RC) ;No, increment the transit count IFN FTRTST,< MOVEI P1,TSTBLK CALL TSTTIM STOR T1,TRTOC,(P1) LOAD T2,TRTAF,(P1) SUB T1,T2 STOR T1,TRTFD,(P1) > CALLRET FREMSG ; and discard the packet ENDIF. INCR RCCLC,(RC) ;OTHERWISE, INCREMENT THE LOCAL COUNT CALLRET FREMSG ;GIVE PACKET TO BACK TO NSP, OR FREE IT SUBTTL Data Link Layer Interface -- RTIINC - Process Input Complete ;RTIINC - Process input complete interrupt ; ; Call: ; RC/ Circuit block pointer ; T3/ Pointer to message block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T3 RTIINC: TRACE RTR, MOVE MB,T3 ;GET POINTER TO MESSAGE BLOCK STOR RC,RMICP,(MB) ;STORE THE INPUT CIRCUIT ADDRESS ;**************************************** TORESCD DNSNUP(RTRITR) ;Label for DNSNUP to find input messages TOXRESCD ;**************************************** LOAD AJ,RCAJQ,(RC) ;Get first adjacency in queue JE RCBCT,(RC),RTRIN4 ;If point-to-point be satisfied with it LOAD T1,MBSRC,(MB) ;Yes, get address of sender CALL RTRGAJ ;Look for adjacency with this address... CALLRET FREMSG ; Not in our area, dump the message RTRIN4: STOR AJ,RMIAP,(MB) ; and store it for the forwarding routine SETZRO RMOAP,(MB) ;SO WE DON'T CONFUSE OURSELVES SETZRO RMOCP,(MB) MOVE T1,MB ;COPY POINTER TO MESSAGE BLOCK CALL DNLENG ;SIZE OF THIS MESSAGE SKIPGE ENFLG ;Endnode? IFSKP. CALL DNGTIM ; NO, GET THE CURRENT TIME SKIPE AJ ; Skip if this adjacency is not initialized STOR T1,AJTLR,(AJ) ;STORE TIME WE LAST HEARD FOR NEIGHBOR ENDIF. CALL RTRHDP ;PARSE THE HEADER JSP T1,RTEMFE ;REPORT THE MESSAGE FORMAT ERROR EVENT JE RMCTL,(MB),RTIIN1 ;IF IT'S A DATA MESSAGE, PROCESS IT ;We have a control message here, find the type and dispatch LOAD T1,RCSTA,(RC) ;GET THE CIRCUIT'S STATE LOAD T2,RMCTY,(MB) ;GET THE CONTROL MESSAGE TYPE CALL @RTIIND(T2) ; AND DISPATCH ON THAT TYPE RET ;RETURN TO SENDER RTIIND: IFIW ;ROUTER INITIALIZATION (0) IFIW ;ROUTER VERIFICATION (1) IFIW ;ROUTER TEST MESSAGE (2) IFIW ;ROUTER ROUTING MESSAGE (3) IFIW ;ROUTER LEVEL 2 ROUTING MESSAGE (4) IFIW ;NI ROUTER HELLO MESSAGE (5) IFIW ;NI ENDNODE HELLO MESSAGE (6) IFIW ;Illegal message type ;Here with a data message. RTIIN1: IFN FTRTST,< LOAD T1,MBSRC,(MB) ; Get source node LOAD T2,MBDST,(MB) ; and destination CAMN T1,T2 ; The same? JRST [SETONE RMTST,(MB) ; Yes, assume this is a test message MOVEI P1,TSTBLK ; Get address of test data block LOAD T1,TRTND,(P1) ; Get the loop node address STOR T1,MBDST,(MB) ; Save that as the destination CALL TSTTIM ; Get the uptime in ms. STOR T1,TRTIC,(P1) ; Save it as time received here LOAD T2,TRTAF,(P1) ; SUB T1,T2 ; Compute elapsed time STOR T1,TRTTA,(P1) ; Save for interested parties CALL TSTTIM ; Get time again STOR T1,TRTAF,(P1) ; and save it as time at RTRFWD JRST .+1] > TMNE MBEBF,(MB) ;IS THIS MESSAGE IN AN EMERGENCY BUFFER? JRST RTIINF ;YES, HANDLE IT DIFFERENTLY RTIIN2: LOAD T1,RCSTA,(RC) ;GET THE STATE OF THE CIRCUIT CAIE T1,RCS.TT ;SEE IF THIS IS A GOOD STATE TO BE IN CAIN T1,RCS.RN ; FOR RECIEVING DATA TRNA ;WE SEEM TO BE OK JRST [ETRACE RTR, CALLRET FREMSG] CALLRET RTRFWD ;FORWARD THE MESSAGE ;Here to discard an arriving packet due to congestion. RTIINF: OPSTR ,MBDST,(MB) ;GET THE DESTINATION CALLRET RTRFOR ;DESTINATION IS OUT-OF-RANGE LDB T2,[POINTR(T2,RN%NOD)] ;GET THE NODE NUMBER CAMLE T2,RTRMXN ;RANGE CHECK IT CALLRET RTRFOR ;DESTINATION IS OUT-OF-RANGE ADD T2,RTRNRV ;GET THE NODE'S ROUTING VECTOR ENTRY TMNE RNLCL,(T2) ;IF IT WAS SUPPOSED TO COME TO US IFSKP. INCR RCCAL,(RC) ;REPORT IT AS ARRIVED CONGESTION LOSS ELSE. INCR RCCTL,(RC) ; else increment the transit congestion loss ENDIF. CALLRET FREMSG ;FREE MSG BLK & RETURN SUBTTL RTRSTI - Send routing intitialization message RTRSTI: MOVX T1,TI.MXL ;MAX LENGTH OF A TI MESSAGE CALL DNGMSG ; USER MESSAGE AREA CALLRET CIRFAI ;CAN'T DO IT, Close the port and try again MOVE MB,T1 ;MAKE MB POINT TO MESSAGE XMOVEI T1,UD.MSD(MB) ;POINT TO THE USER-DATA MSD CALL DNPINI ;INITIALIZE MS & THE MSD SETZ T1, ;MAKE UP FIRST BYTE IN T1/ 0 SETONE CMCTL,+T1 ;TURN ON THE CONTROL MESSAGE BIT IFN RCM.TI,< MOVX T2,RCM.TI ;TYPE IS ROUTER INIT STOR T2,CMTYP,+T1 ;AND STORE THAT IN THE TYPE FIELD > CALL DNP1BY ;WRITE THE FIRST BYTE LOAD AJ,RCAJQ,(RC) ;GET THE ADJACENCY JUMPE AJ,CIRFAI ;If we don't have one reinitialize MOVE T1,RTRADR ;GET OUR ADDRESS MOVE T2,RTRHOM ;GET MY AREA LOAD T3,RCLID,(RC) ;GET CIRCUIT IDENTIFIER LOAD T3,LIDEV,+T3 ;GET LINE TYPE LOAD T4,AJVER,(AJ) ;GET ADJACENCY VERSION CAIE T3,LD.DTE ;IF A DTE CIRCUIT CAIN T4,1 ;OR A PHASE III NODE SKIPA ;THEN DON'T INCLUDE AREA NUMBER DPB T2,[POINTR(T1,RN%ARE)] CALL DNP2BY ;STORE THE NODE ADDRESS ;Build TIINFO. SETZ T1, ;START BUILDING TIINFO FIELD MOVEI T2,ANT.RT ; Assume we are a routing node MOVEI T3,RNT.L1 ; See what type of node we are this time CAME T3,RTRNTY ; Are we a routing node? MOVEI T2,ANT.NR ; No, then say we are non-routing STOR T2,TINTY,+T1 ;STORE THE NODE TYPE SKIPE RTRVRQ ;IS VERIFICATION REQUIRED? TXO T1,TIVER ;YES, TELL HIM ABOUT IT CALL DNP1BY ;PUT THE BYTE IN ;Give a blocksize. LOAD T1,RCRBS,(RC) ;GET THE BLOCKSIZE CALL DNP2BY ;TWO BYTES WORTH ;Fill in version, etc. LOAD T3,AJVER,(AJ) ;GET THE ADJACENCY ROUTING VERSION CAMN T3,RTRVER ;IS IT THE SAME AS OURS? JRST FILVER ;YES, THEN FILL IN THE VERSION NUMBER ADDI T3,1 ;SEE IF ITS ONE MINUS OURS CAMN T3,RTRVER ;IS IT? JRST [LOAD T3,AJVER,(AJ) ;THEN USE HIS VERSION NUMBER JRST FILVR1] ;STORE IN THE MESSAGE FILVER: MOVE T3,RTRVER ;VERSION OF RTR FILVR1: MOVE T1,T3 ;GET VERSION TO SEND IN INIT CALL DNP1BY ;PUT IT IN MESSAGE LOAD T1,AJECO,(AJ) ;GET THE ECO LEVEL CALL DNP1BY ;PUT IT IN, ALSO MOVE T1,RTRCUS ;CUSTOMER ARGUMENT NUMBER CALL DNP1BY ;AND STORE THAT ALSO ;Now for the HELLO timer LOAD T1,RCTM3,(RC) ;GET TIMER VALUE FOR THIS CIRCUIT IDIVI T1,^D1000 ;SEND TIMER AS SECONDS CAIL T3,2 ;ONLY OUTPUT IF PHASE IV OR GREATER CALL DNP2BY ;TWO BYTES WORTH ;Now fill in one reserved byte SETZ T1, ;USE A ZERO CALL DNP1BY ;PUT IN THE BYTE ;Here we give the message to the DLL to send. TRACE RTR, CALL CALQOB ;OUTPUT THE MESSAGE CALL DNGTIM ;GET THE CURRENT TIME STOR T1,RCTIN,(RC) ;RECORD THE TIME THAT WE SENT THE TI RET SUBTTL Control Message Processors -- RTCINI - Inititialization Messages ;RTCINI - Process Incoming Router Init Message ; ; Call: ; T1/ Circuit State ; RC/ Ptr to Circuit Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 RTCINI: TRACE RTR, CAIE T1,RCS.TI ;ARE WE IN RTR INIT WAIT STATE? JRST [ETRACE RTR, MOVX T1,RS.UPT ;EVENT REASON: UNEXPECTED PACKET LOSS CALLRET RTELDS] ;REPORT THE CIRCUIT DOWN - SOFTWARE FAULT EVENT LOAD T1,MBSRC,(MB) ;GET THE SOURCE NODE LDB T2,[POINTR(T1,RN%ARE)] ;GET THE AREA NUMBER LDB T1,[POINTR(T1,RN%NOD)] ;GET THE NODE NUMBER SKIPN T2 ; If Phase III... MOVE T2,RTRHOM ; then default the area CAME T2,RTRHOM ;MY AREA? JRST RTCNHA ;NO, THEN DON'T DO IT RTCI9N: CAIL T1,1 ;CHECK NODE ADDRESS CAMLE T1,RTRMXN ; FOR REASONABLENESS RTCNHA: JRST [MOVX T1,RS.ANO ;REASON: ADJACENT NODE ADDRESS OUT OF RANGE CALLRET RTEINO] ;REPORT THE INITIALIZATION FAILURE EVENT STOR T1,AJNAN,(AJ) ;Store the node's number STOR T2,AJNAA,(AJ) ; and node's area MOVX T1,ADJ.UP ;SAY THE ADJACENCY IS NOW UP STOR T1,AJSTA,(AJ) MOVE T1,MB ;POINT TO INPUT MESSAGE CALL DNLENG ;CALCULATE THE LENGTH CAIL T1,^D6 ;IS IT THE CORRECT LENGTH FOR RTR INIT MSGS? CALL DNG1BY ;GET THE INITINFO FIELD JSP T1,RTEMFE ;++MESSAGE FORMAT ERROR ; TXNE T1,TIRSV ;IS THE RESERVED FIELD ZERO? ; JSP T1,RTEMFE ;++MESSAGE FORMAT ERROR EVENT MOVX T2,AJVRQ ;GET THE VERFIFY AND REQUIRED BIT ANDCAM T2,AJ.VRQ(AJ) ;ASSUME THAT VERIFICATION ISN'T REQUIRED TXNE T1,TIVER ;IS IT REALLY REQUIRED? IORM T2,AJ.VRQ(AJ) ;YES, SET IT MOVX T2,AJBLO ;GET THE BLOCKING REQUESTED BIT ANDCAM T2,AJ.VRQ(AJ) ;ASSUME THAT BLOCKING WAS NOT REQUESTED TXNE T1,TIBLO ;BLOCKING REQUESTED? IORM T2,AJ.VRQ(AJ) ;YES, THEN SET IT LOAD T2,TINTY,+T1 ;GET NODE TYPE FROM BYTE STOR T2,AJNTY,(AJ) ;STORE THE NODE TYPE IN CIRCUIT BLOCK ;Get the blocksize CALL DNG2BY ;GET TWO BYTE BLOCKSIZE JSP T1,RTEMFE ;++MESSAGE FORMAT ERROR EVENT CAMGE T1,RTRBSZ ;IS THE BLOCKSIZE REASONABLE JRST [MOVX T1,RS.ABS ;EVENT REASON: Adjacency block size too small CALLRET RTEINO] ;REPORT THE INITIALIZATION FAILURE EVENT STOR T1,RCBSZ,(RC) ;Save for use when building routing updates STOR T1,AJBSZ,(AJ) ; and here for network management ;Next comes the Version number, ECO number and Customer args. CALL DNG1BY ;GET THE VERSION NUMBER JSP T1,RTEMFE ;++MESSAGE FORMAT ERROR EVENT STOR T1,AJVER,(AJ) ;STORE IT IN CIRCUIT BLOCK CAIE T1,1 ;IS THE ADJACENCY PHASE III OR IV? IFSKP. LOAD T2,AJNTY,(AJ) ;(III) GET THE NODE TYPE FROM ABOVE (TIINFO) SETO T1, ;Use T1 to hold node type for adjacency block CAIN T2,ANT.RT ;IS IT A ROUTING NODE? MOVX T1,ADJ.3F ;YUP, MUST BE A PHASE III FULL NODE CAIN T2,ANT.NR ;IS IT A NON-ROUTING NODE? MOVX T1,ADJ.3S ;YES, WELL ITS A PHASE III SMALL NODE SKIPGE T1 ;DID WE GET ONE? JSP T1,RTEMFE ;++MESSAGE FORMAT ERROR EVENT STOR T1,AJNTY,(AJ) ;SAVE IT SETZRO AJPH4,(AJ) ;Note that this node is not a PH4 node ELSE. LOAD T2,AJNTY,(AJ) ; (IV) GET THE NODE TYPE FROM ABOVE (TIINFO) SETO T1, ;Use -1 as a flag CAXN T2,ANT.L1 ;IS IT A LEVEL 1 ROUTER MOVX T1,ADJ.L1 ;SAY SO CAXN T2,ANT.L2 ;LEVEL 2 MOVX T1,ADJ.L2 ;SAY SO CAXN T2,ANT.NR ;NON-ROUTING MOVX T1,ADJ.LN ;SAY SO SKIPGE T1 ;HAVE ONE? JSP T1,RTEMFE ;NO, THEN WE HAVE AN ERROR STOR T1,AJNTY,(AJ) ;SAVE IT SETONE AJPH4,(AJ) ;Indicate we have a Phase IV node ENDIF. RTCIN0: CALL DNG1BY ;GET THE ECO NUMBER JSP T1,RTEMFE ;++MESSAGE FORMAT ERROR EVENT STOR T1,AJECO,(AJ) ;STORE IT CALL DNG1BY ;ALSO THE CUSTOMER ARGUMENT JSP T1,RTEMFE ;++MESSAGE FORMAT ERROR EVENT STOR T1,AJCUS,(AJ) ;STORE IT ALSO ; Get the hello timer from the router init message, there is one TMNN AJPH4,(AJ) ;Phase IV node? JRST RTCIN1 ;NO, THEN HELLO TIMER IS NOT THERE CALL DNG2BY ;GET THE HELLO TIMER NOW JSP T1,RTEMFE ;MESSAGE FORMAT ERROR+++ IMULI T1,%RTT3M*^D1000 ;Hello timer multiplier and convert to ms. STOR T1,AJNHT,(AJ) ;SAVE AS NEIGHBOR'S HELLO TIMER ;Now we have read the whole message, next send a verification if necessary. RTCIN1: CALL DNG1BY ;Now get the reserved field JSP T1,RTEMFE ;None, bum message SKIPE T1 ;It must be zero JSP T1,RTEMFE ;We can't understand non-zero TMNE AJVRQ,(AJ) ;DOES HE WANT VERIFICATION? IFSKP. ; No, he doesn't SETZRO RCTIN,(RC) ;ZERO THE TIME WE SENT TI TIMER CALL FREMSG ; FREE MESSAGE ELSE. MOVE T1,MB ;PASS PTR TO MSG BLK TO DNMINI LDB T2,[POINT 8,RTRXPW,7];GET COUNT OF PASSWORD BYTES AOJ T2, ; + COUNT BYTE AS LENGTH OF DATA SPACE CALL DNMINI ;FIX UP THE MSG BLK RET ;PROPOGATE ERROR RETURN XMOVEI T1,RM.MSD(MB) ;GET ADDR OF ROUTER MSD CALL DNPINI ;GET READY TO STICK BYTES IN MESSAGE SETZ T1, ;BUILD FIRST BYTE IN T1 MOVX T2,RCM.TV ;TYPE = ROUTER VERIFICATION STOR T2,CMTYP,+T1 ;FILL IN FIELD IN AC SETONE CMCTL,+T1 ;TV MESSAGE IS A CONTROL MESSAGE CALL DNP1BY ;STORE IN MESSAGE MOVE T1,RTRADR ;GET OUR (ROUTER'S) ADDRESS MOVE T3,RTRHOM ;GET MY AREA TMNE AJPH4,(AJ) ;Phase IV node? DPB T3,[POINTR(T1,RN%ARE)] ; AREA IF PHASE IV CALL DNP2BY ;STORE THAT ;Put a password at the end of the verification msg MOVE T3,[POINT 8,RTRXPW];POINT TO PASSWORD STRING ILDB T2,T3 ;GET COUNT OF BYTES IN PASSWORD SKIPA T1,T2 ;COPY COUNT AS DATA BYTE RTCIN2: ILDB T1,T3 ;GET NEXT DATA BYTE CALL DNP1BY ;TELL MSG ABOUT IT SOJGE T2,RTCIN2 ;CONTINUE TILL DONE TRACE RTR, CALL CALQOB ;OUTPUT THE MESSAGE CALL DNGTIM ;GET CURRENT TIME STOR T1,RCTIN,(RC) ;REGISTER THE TIME THAT WE SENT THE TV ENDIF. ; MOVX T1,RCS.TV ;ASSUME THAT WE REQUIRE VERIFICATION ; SKIPN RTRVRQ ;DO WE REQUIRE VERIFICATION? MOVX T1,RCS.RN ;NO, WE'RE NOW IN RUN STATE STOR T1,RCSTA,(RC) ;INDICATE THAT IN THE CIRCUIT BLOCK MOVX T1,ADJ.UP ;SAY THE ADJACENCY IS UP NOW STOR T1,AJSTA,(AJ) ; AND RUNNING MOVN T1,RTRTM1 ;SET TIMER TO FORCE SENDING ROUTING MESSAGE STOR T1,RCTLR,(RC) ;... LOAD T2,RCLID,(RC) ;Get the device ID LOAD T3,AJADR,(AJ) ;Address needed for the event EVENT RE.AUP, LOAD T1,AJNAN,(AJ) ;Get node number CALL SETRCF ;Set recompute routing flags MOVN T1,RTRTM1 ;Reset the time of last routing STOR T1,RCTLR,(RC) ; message LOAD T1,AJVER,(AJ) ; Get adjacent node's version CAIN T1,1 ; Phase III node? CALLRET RTRSTI ; Yes, send TI response and return RET ; AND RETURN SUBTTL Control Message Processors -- RTCVER - Verification Messages ;RTCVER - Routine to handle verification messages ; ; Call: ; T1/ Circuit State ; RC/ Pointer to Circuit Block ; MB/ Pointer to Message Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 RTCVER: TRACE RTR, CAIE T1,RCS.TV ;ARE WE WAITING FOR A VERIFICATION JRST [ETRACE RTR, MOVX T1,RS.UPT ;EVENT REASON: UNEXPECTED PACKET type CALLRET RTELDS] ;REPORT CIRCUIT DOWN - SOFTWARE ERROR EVENT CALL DNG1BY ;GET FIRST BYTE (IMAGE COUNT) JSP T1,RTEMFE ;++MESSAGE FORMAT ERROR EVENT MOVE P1,T1 ;PRESERVE IT FOR A WHILE MOVE T1,MB ;POINT TO MESSAGE CALL DNLENG ;CALCULATE LENGTH CAMLE P1,T1 ;DOES IT LOOK LIKE A REASONABLE LENGTH? CALLRET RTEVRJ ;++VERIFICATION REJECT MOVX T1,RCS.RN ;IF WE GOT THIS FAR, STOR T1,RCSTA,(RC) ; WE DESERVE TO BE IN A GOOD STATE CALLRET FREMSG ;TOSS MESSAGE AND RETURN SUBTTL Control Message Processors -- RTCRTE - Routing Messages ;RTCRTE - Routine to handle incoming routing message ; ; Call: ; T1/ State of circuit ; AJ/ Pointer to adjacency block ; RC/ Pointer to circuit block ; MB/ Pointer to message block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T4 RTCRTE: TRACE RTR, CAIE T1,RCS.TT ;CHECK OUR STATE FOR EITHER TEST OR CAIN T1,RCS.RN ; OK STATE TRNA ;WE SEEM ALRIGHT JRST [ETRACE RTR, MOVX T1,RS.UPT ;EVENT REASON: UNEXPECTED PACKET RECEIVED CALLRET RTELDS] ;REPORT CIRCUIT DOWN - SOFTWARE FAULT EVENT SKIPN ENFLG ; Endnode? IFSKP. CALL DNG1BY ; Get reserved byte CALLRET FREMSG ; Forget any error LOAD T1,MBSRC,(MB) ; Get the source address LDB T2,[POINTR (T1,RN%ARE)] ; Get the area number LDB T3,[POINTR(T1,RN%NOD)] ; Get the node number LOAD T4,RCAJQ,(RC) LOAD T4,AJNAN,(T4) ; Get DSR low order address CAIE T3,(T4) ; Same as the sender of message? JRST FREMSG ; No, then don't bother processing SKIPN T2 ; Phase IV area number there? CALLRET FREMSG CAME T2,RTRHOM ; Is packet from our area CALLRET FREMSG LOAD AJ,RCAJQ,(RC) ; Get our only adjacency JUMPE AJ,FREMSG ELSE. JUMPE AJ,FREMSG ; If no adjacency, toss message CALL CK2WAY ;Do we have a known two-way adjacency? CALLRET FREMSG ;No, can't accept this message TMNN AJPH4,(AJ) ; Phase 4 node? IFSKP. LOAD T1,AJNTY,(AJ) ;Get type CAXE T1,ADJ.LN ;Is it non-routing? IFSKP. LOAD T1,AJNAN,(AJ) ;Get address and give a buginf BUG.(INF,ROURFN,ROUTER,SOFT,,<>,< Cause: We have received a routing message from a node we believe to be an endnode so we will have no vector to store it in. count. Action: Check the address of the node and then see if it thinks it is a routing/non-routing node. >,FREMSG) ENDIF. CALL DNG1BY ; Get expected reserved byte JSP T1,RTEMFE ;++Message format error ENDIF. LOAD T1,MBSRC,(MB) ;GET THE SOURCE ADDRESS LDB T2,[POINTR (T1,RN%ARE)] ;GET THE AREA NUMBER LDB T1,[POINTR(T1,RN%NOD)] ;GET THE NODE NUMBER SKIPN T2 ;Phase IV area number there? MOVE T2,RTRHOM ;No, then supply a default OPSTR ,AJNAN,(AJ) ;Is that the number we expected? CAME T2,RTRHOM ;Is packet from our area JRST [MOVX T1,RS.ANA ;EVENT REASON: ADJACENT NODE ADDRESS CHANGE CALLRET RTEADO] ;REPORT ADJACENCY DOWN - OPERATOR FAULT EVENT ENDIF. MOVE T1,MB ;POINT TO INPUT MESSAGE CALL DNLENG ;GET ITS LENGTH TXNE T1,1B35 ;SEE IF IT