Google
 

Trailing-Edge - PDP-10 Archives - BB-X116A-BB_1984 - router.mac
There are 25 other files named router.mac in the archive. Click here to see a list.
;DNET:ROUTER.MAC[10,36,MON,NEW], 30-Oct-1983 03:16:14, Edit by TARL
;MCO 11027(a) - Teach RTEEXN to pick up adjacent node in circuit block
;DNET:ROUTER.MAC[10,36,MON,NEW], 30-Oct-1983 02:26:14, Edit by TARL
;MCO 11027 - Teach RTNEVT how to find router header on output messages.
;DNET:ROUTER.MAC[10,36,MON,NEW], 29-Oct-1983 05:33:42, Edit by TARL
;MCO 11025 - Add code to talk with non-routing phase III nodes.
;DNET:ROUTER.MAC[10,36,MON,NEW], 23-Oct-1983 17:14:35, Edit by TARL
;MCO 11016 - ROUBCD's caused by RTRRCR getting called at interrupt level,
;	     by RTIDWN and friends. SETOM RTRRCF instead
;DNET:ROUTER.MAC[10,36,MON,NEW], 05-Oct-1983 05:26:52, Edit by TARL
;MCO 10994 - Fix loop node stuff
;TITLE ROUTER - Routing Layer Service for DECnet-36
  	SUBTTL V. Brownell/Tarl/AJR

	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.
;
IFN FTOPS10,<
.CPYRT<
COPYRIGHT (C) 1984 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
>
> ;END IFN FTOPS10

IFN FTOPS20,<
	SEARCH PROLOG,PROKL
	TTITLE ROUTER,,< - Routing Layer Service for DECnet-36>
	>

IFN FTOPS10,<
	SEARCH F,S
	TITLE ROUTER - Routing Layer Service for DECnet-36
>;END OF IFN FTOPS10

	D36SYM			;SET UP D36 SPECIFIC PARAMETERS

	$RELOC
	$HIGH			;RELOC TO HIGHSEG (RSCOD PSECT ON TOPS-20)
	SUBTTL	Table of Contents


;		Table of Contents for ROUTER
;
;
;			   Section			      Page
;   1. Table of Contents. . . . . . . . . . . . . . . . . . .    2
;   2. Definitions
;        2.1.   External References . . . . . . . . . . . . .    3
;        2.2.   Accumulators. . . . . . . . . . . . . . . . .    5
;        2.3.   Macros. . . . . . . . . . . . . . . . . . . .    6
;        2.4.   Packet Route Header . . . . . . . . . . . . .    7
;        2.5.   Router Control Message. . . . . . . . . . . .    8
;        2.6.   Phase II Messages . . . . . . . . . . . . . .    9
;        2.7.   Routing Vectors . . . . . . . . . . . . . . .   10
;        2.8.   Miscellaneous . . . . . . . . . . . . . . . .   11
;   3. RTRINI - Initialize Router User. . . . . . . . . . . .   12
;   4. RTRON - Turn Router (and DECnet) On. . . . . . . . . .   13
;   5. RTROFF - Turn Router (and DECnet) Off. . . . . . . . .   14
;   6. RTRSEC - Once a second processing for Router . . . . .   15
;   7. RTRJIF - Once a jiffy processing for Router. . . . . .   16
;   8. RTRXMT - NSP's Entry in Router . . . . . . . . . . . .   18
;   9. RTRFWD - Perform Routing of Message. . . . . . . . . .   19
;  10. RTR2RM - Send Message to Remote Node . . . . . . . . .   22
;  11. R2NODN - Return Output Done to NSP . . . . . . . . . .   25
;  12. R2NRTN - Return Message to NSP . . . . . . . . . . . .   26
;  13. R2NRCV - Pass Recieved Message to NSP. . . . . . . . .   27
;  14. R2KINI - Initialize a Kontroller's Circuit . . . . . .   28
;  15. R2KHLT - Halt the Kontroller's Circuit . . . . . . . .   29
;  16. CALKON - Call the Kontroller . . . . . . . . . . . . .   30
;  17. CALQOB - Call CALKON for queued output.. . . . . . . .   31
;  18. RTRRCR - Recompute Routing . . . . . . . . . . . . . .   32
;  19. RTRSRM - Send routing messages if needed . . . . . . .   37
;  20. RTRTMR - Routine to perform timer functions. . . . . .   40
;  21. Circuit Interface
;       21.1.   RTRDSP - Circuit Drivers Entry. . . . . . . .   43
;       21.2.   RTIOPN - Open a new circuit . . . . . . . . .   45
;       21.3.   RTICLS - Close a Circuit. . . . . . . . . . .   46
;       21.4.   RTIPRU - Process Protocol Up. . . . . . . . .   47
;       21.5.   RTIDWN - Process Protocol Down. . . . . . . .   49
;       21.6.   RTIMMR - Process Maintainence Message . . . .   50
;       21.7.   RTISMR - Process Start Message. . . . . . . .   51
;       21.8.   RTIBRQ - Process the Buffer Request . . . . .   52
;       21.9.   RTIOTC - Process Output Complete. . . . . . .   53
;       21.10.  RTIOTI - Process Output Incomplete. . . . . .   54
;       21.11.  RTIINC - Process Input Complete . . . . . . .   55
;  22. Control Message Processors
;       22.1.   RTCINI - Init Messages. . . . . . . . . . . .   58
;       22.2.   RTCVER - Verification Messages. . . . . . . .   61
;       22.3.   RTCRTE - Routing Messages . . . . . . . . . .   62
;       22.4.   RTCTST - Test or Hello Messages . . . . . . .   64
;  23. RTRHDP - Parse a Input Router Message Header . . . . .   65
;  24. RTRPH2 - Handle Phase II Messages. . . . . . . . . . .   67
;  25. Network Management Interface
;       25.1.   RTNSNT - Set node type. . . . . . . . . . . .   75
;       25.2.   RTNRNT - Read node's type . . . . . . . . . .   76
;       25.3.   RTNSLS - Set Circuit State. . . . . . . . . .   77
;       25.4.   RTNGLS - Circuit state routine. . . . . . . .   79
;       25.5.   RTNGLB - Circuit substate . . . . . . . . . .   80
;       25.6.   RTNLID - Give the line id . . . . . . . . . .   81
;       25.7.   RTRNMX - Do circuit functions . . . . . . . .   82
;       25.8.   Router Event Types. . . . . . . . . . . . . .   83
;       25.9.   Reason Definitions. . . . . . . . . . . . . .   85
;       25.10.  RTNEVT - Event Reporter . . . . . . . . . . .   86
;       25.11.  Event Parameter Processors. . . . . . . . . .   87
;       25.12.  Event Processor Subroutines . . . . . . . . .   89
;       25.13.  Miscellaneous Event Processors. . . . . . . .   90
;  26. Miscellaneous Routines
;       26.1.   RTRZCB - Zap Circuit Block. . . . . . . . . .   92
;       26.2.   RTRMCB - Make a Circuit Block . . . . . . . .   93
;       26.3.   RTRGCB - Get Circuit Block Pointer. . . . . .   94
;       26.4.   CPYMSG - Copy all MSDs together . . . . . . .   95
;       26.5.   FREMSG - Toss a Message . . . . . . . . . . .   96
;       26.6.   CKSNRM - Normalize Checksum . . . . . . . . .   97
;  27. Local Router Storage . . . . . . . . . . . . . . . . .   98
;  28. End of ROUTER. . . . . . . . . . . . . . . . . . . . .   99
	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 DNPEBY		;PUT AN EXTENSIBLE BYTE IN MESSAGE

	EXT DNG1BY		;GET ONE BYTE FROM MESSAGE
	EXT DNG2BY		;GET TWO 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 DNGEBF		;ADD EMERGENCY BUFFER TO FREE LIST
	EXT DNGEMS		;GET EMERGENCY 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 DNLMSS		;LINK MESSAGE SEGMENT INTO MESSAGE BLOCK
	EXT DNCPMS		;COPY MESSAGE BLOCKS

	EXT DNGTIM		;RETURN CURRENT UPTIME (IN MS)

;These are external data locations.

	EXT DCNSTA		;THE STATE VARIABLE OF DECNET
	EXT TIMBAS		;UNITS TO CONVERT FROM DNGTIM TO SECONDS.

;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 %RTMXV		;MAXIMUM VISITS COUNT
IFN FTOPS10,EXT %RTADR		;DEFAULT LOCAL ADDRESS
	EXT %RTTM1		;LONG TIMER
	EXT %RTTM3		;HELLO MESSAGE TIMER
	EXT %RTTM4		;NODE LISTENER TIMEOUT VALUE
	EXT %RTITM		;TI TIMER
	EXT %RTCST		;DEFAULT CIRCUIT COST
	EXT %RTBSZ		;DEFAULT BLOCK SIZE
	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 KONDSP		;KONTROLLER DISPATCH

	EXT RTN			;NON-SKIP RETURN
	EXT RSKP		;SKIP RETURN

;Interlock management

IFN FTOPS10,<
	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

	PURGE FREE1		;LOSE THIS SYMBOL

	SUBTTL Definitions -- Macros

;Event Logging Macro

DEFINE EVENT(TYPE,TEXT,MSGBLK),<
	CALL [
IFN FTTRACE,<
	      ETRACE RTR,<RTR Event: 'TEXT>
>
	      MOVX T1,TYPE	;;PUT EVENT TYPE IN T1
IFNB <MSGBLK>,MOVE T4,'MSGBLK	;;IF HE GAVE MB POINTER, GIVE IT
IFB <MSGBLK>, SETZ T4,		;;IF NOT, GIVE RTNEVT A ZERO
	      CALLRET RTNEVT]	;;CALL THE EVENT PROCESSOR AND RETURN
>


	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 XCT.TI,0		;ROUTER INIT
	XP XCT.TV,1		;ROUTER VERIFICATION
	XP XCT.TT,2		;ROUTER TEST
	XP XCT.RM,3		;ROUTER ROUTING MESSAGE


;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,37_3		; RESERVED
	FIELDM VER,1_2		; VERIFY FLAG
	FIELDM NTY,3		; NODE TYPE
ENDSTR

	XP TI.MXL,^D10		;MAX LENGTH OF TRANSPORT INIT MSG

;These are the possible types of nodes that can be at the other end
;of a circuit (in FIELD TINTY).

	XP RNT.XX,0		;RESERVED
	XP RNT.X1,1		;RESERVED FOR PHASE IV
	XP RNT.RT,2		;ROUTING
	XP RNT.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 HEL.LO,^O252		;CONSTANT FOR HELLO AND TEST MESSAGES
	SUBTTL Definitions -- Phase II Messages

;The First Byte of the "router" message may have the "evolution bit"
;turned on.  If it is turned on, the first byte is actually either the
;RTFLG byte of a Phase II RTHDR (routing header) or the MSGFLG field of
;a Phase II NSP message.

;The MSGFLG field of Phase II messages.

BEGSTR MF			;MSGFLG
	FIELDM TYP,3_2		; TYPE MESSAGE
	FIELDM SUB,7_4		; SUBTYPE OF MESSAGE
ENDSTR

;Types of Phase II messages (field MFTYP).

	XP MFT.DA,0		;DATA MESSAGE
	XP MFT.AK,1		;ACKNOWLEDGE
	XP MFT.CT,2		;CONTROL MESSAGE
	XP MFT.RS,3		;RESERVED

;The only SUBTYPE we are concered about is the STARTUP type.

	XP MFC.ST,5		;STARTUP CONTROL MESSAGE

;STARTTYPE field.

	XP STT.NI,1		;NODE INITIALIZATION
	XP STT.NV,2		;NODE VERIFICATION

;These are the lengths of the various START messages.

	XP NI.MXL,^D56		;NODE INITIALIZATION
	XP NV.MXL,^D11		;NODE VERIFICATION


;Node Initialization Message fields.

;REQUESTS field

BEGSTR RE
	FIELDM RIN,3_1		;REQUEST INTERCEPT TYPE
				;**MUST BE ZERO (NO INTERCEPT)**
	FIELDM VER,1		;VERIFICATION REQUIRED
ENDSTR

	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,3		;FLAGS
	  BIT RCH		;IF SET, NODE IS REACHABLE
	  BIT LCL		;NODE IS LOCL NSP USER
	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 -- Miscellaneous

;Here is the definitions for the node type vector.  This is used presently,
;only to see if a node is defined as a "Phase II" node.

	XP NT.WID,2		;WIDTH OF EACH NODE'S ENTRY IN VECTOR

	XP NTV.P2,1		;NODE IS PHASE II+ OR PHASE II
	XP NTV.P3,0		;NODE IS A PHASE III NODE
	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.

RTRINI::TRACE RTR,<Initializing Router>

;Here to allocate the "normal" and "scratch" routing vectors.

	MOVE T1,RTRMXN		;GET THE MAXIMUM NODE NUMBER
	ADDI T1,1		;ONE EXTRA FOR EASY INDEXING
	ASH T1,1		;MAKE IT TWICE AS LONG (HALF FOR RCH VECTOR
				; HALF FOR OUTPUT CIRCUIT VECTOR)
	CALL DNGWDZ		;GET THAT MANY WORDS
	 RET			;COULD NOT INITIALIZE
	MOVEM T1,RTRNRV		;SAVE POINTER TO NORMAL ROUTING VECTOR
	MOVE T2,RTRMXN		;GET OUR CURRENT MAX-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
	ADDI T1,1		;NODE NUMBERS START AT ONE
	MOVX T3,RNHOP!RNCST	;SMEAR WITH MAXIMUM COST AND HOPS
	CALL DNSWDS		;SPRAY THE BLOCK WITH MAXS

	MOVE T1,RTRMXN		;GET MAXIMUM NODE NUMBER
	ADDI T1,1		;ONE MORE
	ASH T1,1		;MULT BY TWO (ONE FOR SRV, ONE FOR SOV)
	CALL DNGWDZ		;GET THE WORDS FOR SCRATCH VECTOR
	 RET			;OOPS, GIVE BAD RETURN
	MOVEM T1,RTRSRV		;SAVE THE SCRATCH ROUTING VECTOR POINTER
	ADD T1,RTROFS		;CALCULATE START OF SOV
	MOVEM T1,RTRSOV		;SAVE SOV FOR LATER USERS

;Set up the node type vector.

	MOVE T1,RTRMXN		;GET MAX-NODES
	IMULI T1,NT.WID		;EACH ONE IS THIS WIDE
	IDIVI T1,^D36		;HOW MANY WORDS
	ADDI T1,1		;ONE MORE FOR REMAINDER
	CALL DNGWDZ		;GET THAT MANY WORDS
	 RET			;OOPS, WE'VE GOT A PROBLEM
	MOVEM T1,RTRNTV		;SAVE THE POINTER TO THE VECTOR
	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.

RTRON::	SAVEAC RC
	SKIPN DCNSTA		;IS DECNET TURNED ON?
	SKIPN T1,RTRADR		;AND DO WE HAVE AN ADDRESS FOR TRANSPORT?
	RET			;NO, CANNOT TURN DECNET ON YET

	ADD T1,RTRNRV		;FIND THE ENTRY IN THE NORMAL REACH VECTOR
	D36OFF			;TURN ON INTERLOCK

	SETONE <RNLCL,RNRCH>,(T1) ;MAKE IT LOCAL AND REACHABLE
	SETZRO <RNCST,RNHOP>,(T1) ;ZERO THE HOPS AND COST FOR THIS NODE

	XMOVEI T2,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

;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

	LOAD RC,RCNXT,(RC)	;STEP THROUGH TO NEXT ONE
	JUMPN RC,RTRON1		; AND INITIALIZE IF ANY MORE
	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 RC

;Now go through all the circuits, halting each one.

	SKIPN RC,RTRCBQ		;PICK UP FIRST CIRCUIT BLOCK
	 JRST RTROF2		;NONE THERE, RETURN SUCCESS

RTROF1:	CALL R2KHLT		;HALT THIS CIRCUIT

	LOAD RC,RCNXT,(RC)	;STEP THROUGH TO NEXT ONE
	JUMPN RC,RTROF1		; AND HALT IF ANY MORE

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

RTRSEC::
IFN FTOPS20,<			;ON TOPS-20 RTRSEC IS CALLED EVERY 100 MS
	MOVEI T1,^D1000		;GET MILLISECONDS IN RTRSEC INTERVAL
	MOVEM T1,RTRTIM		;INITIALIZE COUNT-DOWN IN STG
>;END IFN FTOPS20
	SKIPN DCNSTA		;IS DECnet TURNED 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
	SEC1			;RUN IN EXTENDED SECTIONS
	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 <MB,MS,RC,CX,T5,T6> ;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 RTRSRM		;SEND ROUTING MESSAGES IF NEEDED
				;CLEAR OWNER OF INTERLOCK
	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.

RTRJIF::
IFE FTMP,<RET>			;IF NOT SMP, THIS DOESN'T EXIST.
IFN FTMP,<
	SEC1			;RUN IN SECTION ONE

	SAVEAC <RC,MB>		;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 RCHLT,(RC),RTRJI3	;IF NO HALT REQUESTED, SKIP THIS CODE
	MOVEI T1,KF.HLT		;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 RCINI,(RC),RTRJI4	;IF NO INITIALIZE REQUESTED, SKIP THIS CODE
	MOVEI T1,KF.INI		;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:	SETZRO <RCINI,RCHLT>,(RC) ;CLEAR BITS INDICATING KONTROLLER FUNCTIONS
	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

	SUBTTL RTRXMT - NSP's Entry in Router

;RTRXMT - Routine to forward Phase III messages from NSP
;
; Call:
;	MB/ Ptr to Message Block
;	T1/ RQR flag (RT%RQR)
;	    ODN flag (RT%ODN)
; 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.

RTRXMT::SAVEAC <MB,MS,RC>	;SAVE A FEW FOR NSP

	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

	SETZRO RMICP,(MB)	;THERE'S NO INPUT CIRCUIT BLK PTR
	SETZRO RMOCP,(MB)	;THERES NO OUTPUT CIRCUIT BLK PTR
	SETZRO RMVST,(MB)	;ZERO VISITS COUNT
	SETONE RMMB1,(MB)	;BIT THAT MUST BE ONE IN FIRST BYTE

	SKIPN DCNSTA		;IS DECNET RUNNING?
	CALLRET FREMSG		;NO, PUNT THE MESSAGE CORRECTLY AND LEAVE

	LOAD T1,MBDST,(MB)	;GET DESTINATION NODE NUMBER
	CAMLE T1,RTRMXN		;IS NUMBER REASONABLE?
	CALLRET FREMSG		;NO, PUNT IT.
	LOAD T1,MBSRC,(MB)	;GET SOURCE NODE NUMBER
	ADD T1,RTRNRV		;ADD OFFSET TO NORMAL ROUTING VECTOR
	TMNN RNLCL,(T1)		;IS THIS A LOCAL NODE?
	BUG.(CHK,ROUBSN,ROUTER,SOFT,<Bad source node in message from NSP>,,<

Cause:	This BUG is not documented yet.

>,FREMSG)

	LOAD T1,MBCHN,(MB)	;GET CHANNEL NUMBER
	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,<Illegal Circuit Specified in NSP msg>,,<

Cause:	This BUG is not documented yet.

>,FREMSG)
	STOR RC,RMOCP,(MB)	;STORE IT AS OUTPUT CIRCUIT
	CALLRET RTRFWD		;LOOKS REASONABLE, FORWARD MESSAGE
	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)	;GET THE POINTER TO THE ROUTER MSD
	CALL DNPINI		;AND DNPINI IT
	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
	CALL DNP2BY		;STORE IT AWAY
	LOAD T1,MBSRC,(MB)	;GET THE SOURCE
	CALL DNP2BY		;PUT IN MESSAGE
	LOAD T1,RMVST,(MB)	;GET VISITS BYTE
	CALL DNP1BY		;AND PUT THAT IN, TOO

	MOVE T1,MB		;GET POINTER TO THE MESSAGE BLOCK
	CALL DNRPOS		;GET CURRENT POSITION IN THE BLOCK
	STOR T1,RMMK1,(MB)	;AND SET MARK IN BLOCK

RTRFW1:	JN RMOCP,(MB),RTR2RM	;IF OUTPUT CIRCUIT WAS SPEC'D, FORWARD IT

	LOAD T1,MBDST,(MB) 	;GET THE DSTNODE ADDRESS
	SKIPLE T1		;RANGE CHECK THE DESTINATION
	CAMLE T1,RTRMXN		;GREATER THAN THE MAX NODE ADDRESS?
	JRST RTRFOR		;DEST IS OUT OF RANGE
	ADD T1,RTRNRV		;GET OFFSET INTO NORMAL ROUTING VECTOR
	TMNN RNRCH,(T1)		;IS IT REACHABLE?
	JRST RTRFUR		;NODE IS UNREACHABLE
	TMNE RNLCL,(T1)		;IS THIS A LOCAL MESSAGE?
	JRST RTRFLC		;YES, FORWARD TO LOCAL NSP (OR WHATEVER)
	ADD T1,RTROFS		;POINT TO OUTPUT CIRCUIT VECTOR ENTRY
	MOVE T1,(T1)		;GET THE OUTPUT CIRCUIT
	STOR T1,RMOCP,(MB)	;STORE OUTPUT CIRCUIT ADDRESS FOR NEXT TIME
	CALLRET RTRFW1		;TRY TO FORWARD THE MESSAGE

;Here when destination node is out-of-range.

RTRFOR:	TMNE RMRQR,(MB)		;WAS RETURN REQUESTED
	JRST RTRFRT		;YES, RETURN IT

	OPSTR <SKIPN T2,>,RMICP,(MB) ;GET THE CIRCUIT IT CAME IN ON.
	BUG.(CHK,ROUNSO,ROUTER,SOFT,<NSP sent out-of-range packet>,,<
Cause:	This bug is not documented yet
>,FREMSG)
	LOAD T2,RCLID,(T2)	;GET THE LINE ID
	EVENT RE.NOR,<Node out-of-range packet loss>,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 <SKIPE T2,>,RMICP,(MB) ;GET THE CIRCUIT IT CAME IN ON
	LOAD T2,RCLID,(T2)	;GET THE LINE ID FOR IT
	EVENT RE.NUR,<Node unreachable packet loss>,MB
	AOS RTRCNU		;INCREMENT EXECUTOR NODE COUNTER
	CALLRET FREMSG		;GIVE THE MESSAGE BACK AND RETURN

;Here to return message to sender due to unreachability.

RTRFRT:	ETRACE RTR,<Returning message due to unreachability>
	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:	OPSTR <SKIPGE RC,>,RMICP,(MB) ;SEE WHERE MSG CAME FROM
	JRST RTRF2N		;IF ICP IS NEG, MSG HAS BEEN TURNED
				; AROUND FROM NSP
	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 R2NRTN		;YUP, DO SO.
	CALLRET R2NRCV		;NO, THIS IS GOOD OLDE RECEIVED DATA

RTRLTR::			;LABEL FOR DNSNUP TO FIND LOCAL MESSAGES
RTRF2C:	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 THE NEW 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)	;AND THE ADDRESS OF THE ROUTER MSD
	CAME T1,T2		;DOES IT AGREE?
	 RET			;RETURN TO CALLER
	LOAD T1,MDNXT,+RM.MSD(MB) ; GET THE POINTER TO THE NEXT MSD
	STOR T1,MBFMS,(MB)	;SAVE AS FIRST MSD POINTER
	RET			;RETURN TO CALLER



	SUBTTL RTR2RM - Send Message to Remote Node

;RTR2RM - Queue Out Message to Remote through the DLL
;
; Call:
;	MB/ Ptr to message block
;
; Return:
;	RET			;ALWAYS
;
; Uses: P1-P2, T1-T3

RTR2RM:	LOAD RC,RMOCP,(MB)	;SET UP RC WITH OUTPUT CIRCUIT PTR
	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
	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 AND AGED PACKET LOSS

;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).

	INCR RCCTR,(RC)		;NO, INCREMENT THE TRANSIT PACKETS RECEIVED
	LOAD RC,RMOCP,(MB)	;GET THE CIRCUIT BLOCK POINTER
	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 <CAMLE T1,>,RCCMQ,(RC) ;COMPARE WITH THE NUMBER OF MSG BLKS QUEUED
	JRST RTR2R0		;WE DON'T HAVE TO FLUSH IT

;Here to discard a message that has execeded the "square-root" limit.

	TRACE RTR,<Congestion Loss on output>
	INCR RCCTL,(RC)		;INCREMENT THE CONGESTION LOSS COUNTER
	CALLRET FREMSG		;FREE THE MESSAGE AND RETURN
;Check the visit field for a over-aged message.

RTR2R0:	LOAD T1,RMFST,(MB)	;GET THE FIRST BYTE OF MESSAGE
	OPSTRM <AOS T2,>,RMVST,(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 COMING BACK?
	ASH T3,2		;GIVE IT TWICE AS MANY HOPS
	CAMG T2,T3		;IS IT AGED TO FAR?
	JRST RTR2R1		;NO, PUT HEADER ON MSG

;Here to report a aged packet loss event.

	SETZ T2,		;THIS EVENT HAS NO ENTITY ASSOCIATED WITH IT
	EVENT RE.APL,<Aged packet loss event>,MB
	AOS RTRCAP		;INCREMENT THE AGED PACKET COUNTER
	CALLRET FREMSG		;FREE THE MESSAGE AND RETURN

;All packets to be sent come through here.

RTR2R1:	LOAD T1,RCNTY,(RC)	;GET THE NODE TYPE
	CAIN T1,RCT.P2		;IS IT A PHASE II NODE?
	JRST RTR2R3		;YES, DON'T PUT ON A RTR HDR

;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 TRANSPORT MSD
	STOR T1,MBFMS,(MB)	;STORE IN FIRST MSD SLOT


RTR2R3:	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 kontroller call and queue it out.

RTR2R4:	INCR RCCMQ,(RC)		;INCREMENT NUMBER OF MESSAGES QUEUED
	MOVX T1,KF.QOB		;GET QUEUE OUTPUT BUFFER FUNCTION CODE
	LOAD T2,RMOCP,(MB)	;GET OUTPUT CIRCUIT
	MOVE T3,MB		;POINT TO MB
	CALL CALKON		;CALL THE KONTROLLER
	 CALL [CALL RTIDWN	;SAY THE LINE IS NOW DOWN
	       MOVE T3,MB	;SET UP MESSAGE BLOCK POINTER FOR RTIOTC
	       CALLRET RTIOTC]	;FREE UP THE MESSAGE BLOCK
	RET			;GIVE A GOOD RETURN TO CALLER
 	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
	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:	MOVX T3,NV.RTS		;GET THE RETURNING TYPE
	CALLRET R2NCAL		;MERGE WITH THE OTHER CODE
	SUBTTL R2NRCV - Pass Recieved Message to NSP

;R2NRCV - Pass recieved 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:	MOVX T3,NV.RCV		;GIVE RECIEVED MESSAGE ENTRY TYPE
R2NCAL:	SKIPN T4,MB		;HE WANTS THE MESSAGE BLOCK PTR IN T4
	BUG.(CHK,ROUXNZ,ROUTER,SOFT,<R2NCAL called with MB=0>,,<

Cause:	This BUG is not documented yet.

>,RTN)
	LOAD T1,MBDST,(MB)	;GET THE DESTINATION OF THIS MESSAGE
	SKIPLE T1		;RANGE CHECK THE
	CAMLE T1,RTRMXN		; FOR REASONABLENESS
	BUG.(CHK,ROUNOR,ROUTER,SOFT,<Node number out of range>,,<

Cause:	This BUG is not documented yet.

>,R2NCLE)

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,<Trying to return msg to non-local NSP>,,<

Cause:	This BUG is not documented yet.

>,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
	SKIPN T1,(T1)		;GET THE CORRECT ENTRY
	BUG.(CHK,ROUCNL,ROUTER,SOFT,<Trying to call non-existant NSP>,,<

Cause:	This BUG is not documented yet.

>,R2NCLE)
	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:	MOVX T1,RCS.WT		;SAY THAT WE ARE IN
	STOR T1,RCSTA,(RC)	;WAIT STATE
	MOVX T1,KF.INI		;KONTROLLER FUNCTION IS INITIALIZE
	MOVE T2,RC		;POINTER TO CIRCUIT BLOCK
	CALL CALKON		;CALL THE KONTROLLER
	 CALLRET RTIDWN		;CIRCUIT IS DOWN
	RET			;GIVE GOOD RETURN ABOVE
	SUBTTL R2KHLT - Halt the Kontroller's Circuit

;R2KHLT - Halt 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 wait state.

R2KHLT:	MOVX T1,RCS.OF		;WE ARE IN "OFF" STATE
	STOR T1,RCSTA,(RC)	;STORE THIS STATE
	MOVX T1,KF.HLT		;FUNCTION IS HALT
	MOVE T2,RC		;POINTER TO CIRCUIT BLOCK
	CALL CALKON		;CALL THE KONTROLLER
	 CALLRET RTIDWN		;CIRCUIT IS DOWN
	RET			;RETURN TO CALLER GOOD
	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)
;
; 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
;on TOPS-10 SMP), CALKON will queue the request to be serviced
;at once-a-jiffy service on the correct CPU.

CALKON:	SAVEAC <RC,P1>		;SAVE A COUPLE ACS
	MOVE RC,T2		;SET UP THE CIRCUIT BLOCK POINTER

IFN FTMP,<
	LOAD T4,LIDEV,+RC.LID(RC) ;GET THE DEVICE TYPE
	CAIN T4,LD.DDP		;IS IT NOT 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,KF.QOB		;QUEUED OUTPUT?
	JRST CALKO4		;YES, QUEUE UP THE MESSAGE BLOCK.
	CAIE T1,KF.INI		;IS THIS AN INITIALIZE FUNCTION?
	JRST CALKO1		;NO, TRY FOR SOMETHING ELSE
	SETONE RCINI,(RC)	;FLAG INITIALIZE TO BE DONE AT JIFFY LEVEL.
	RETSKP			;SAY WE DID IT.
CALKO1:	CAIE T1,KF.HLT		;IS THIS A HALT KONTROLLER FUNCTION?
	BUG.(CHK,ROUIKF,ROUTER,SOFT,<Illegal Kontroller function>,,<

Cause:	CALKON was called with an illegal function code. The only allowed
	values are KF.QOB, KF.INI, and KF.HLT.
>,RTN)
	SETONE RCHLT,(RC)	;FLAG HALT TO BE DONE AT JIFFY LEVEL.
	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
	RETSKP			; AND RETURN TO SENDER
CALKO5:
>;End of IFN FTMP

	LOAD T2,RCKBA,(RC)	;GET THE KONTROLLER'S BLOCK ADDRESS
	LOAD P1,LIDEV,+RC.LID(RC) ;GET THE DEVICE TYPE
	SKIPL P1		;RANGE CHECK THE DEVICE TYPE
	CAILE P1,LD.MAX		; FOR REASONABLENESS
	BUG.(CHK,ROUNSD,ROUTER,SOFT,<Tried to call non-existant device driver>,,<

Cause:	This BUG is not documented yet.

>,RTN)
RTROTR::			;LABEL FOR DNSNUP TO FIND OUTPUT MESSAGES
IFN FTOPS10, MOVX T4,DD.DEC	;WE ARE DECNET TALKING
	CALL @KONDSP(P1)	;DISPATCH TO KONTROLLER BASED ON LINE TYPE
	 RET			;GIVE ERROR RETURN
	RETSKP			;GOOD RETURN

	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
; Return:
;	+1, Always. If the output fails, it calls RTIDWN and then
;		RTIOTI for the message block in MB.
;
;This routine is a jacket around CALKON to make the code sending messages
;simpler and easier to read.

CALQOB:
	MOVEI T1,KF.QOB		;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
	 TRNA			;FAILED, DO EXTRA WORK
	 RET			;RETURN SUCCESS
	CALL RTIDWN		;KILL THE CIRCUIT
	MOVE T3,MB		;POINTER TO THE MESSAGE BLOCK
	CALLRET RTIOTC		;RETURN MESSAGE BLOCK AND RETURN.
	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 RTRSRV points to a scratch routing vector.
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T6
;
; AC Usage:
;	RC/ Ptr to circuit block
;	MB/ Ptr to message block used for routing message
;	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 RTRSRV is a scratch
;routing vector which this routine uses to compute the new routing
;vector.

RTRRCR:	TRACE RTR,<Recomputing network topology>
	SAVEAC <P1,P2,RC,MB>
	SETZM RTRRCF		;CLEAR THE "RECOMPUTE-ROUTING" FLAG

	MOVE T2,RTRSRV		;POINT TO THE SCRATCH ROUTING VECTOR
	XMOVEI T1,1(T2)		;START AT FIRST NODE
	ADD T2,RTRMXN		;ADD MAX NODE NUMBER FOR END OF SMEAR
	MOVX T3,RNHOP!RNCST	;SMEAR WITH MAXIMUM HOPS AND COST
	CALL DNSWDS		;SMEAR SCRATCH VECTOR WITH MAX

	MOVE RC,RTRCBQ		;GET PTR TO FIRST CIRCUIT BLOCK

RTRRC1:	JUMPE RC,RTRRC5		;IF NO MORE CIRCUIT BLOCKS, CHECK LOCAL
	LOAD T1,RCSTA,(RC)	;GET THE CIRCUIT STATE
	CAIE T1,RCS.RN		;ARE WE IN RUN STATE
	CAIE T1,RCS.TT		; OR MAINT STATE?
	TRNA			;YES, CHECK THIS CIRCUITS ROUTING MESSAGE
	JRST RTRRC4		;NO, CHECK THE NEXT CIRCUIT
;Now check to see if the neighbor on this circuit is a Phase II node.  If
;he is, just set the RNRCH bit in the routing vector and leave the hops
;and cost infinite, so that we won't tell anybody about him in our
;routing messages.

	LOAD T1,RCNTY,(RC)	;GET THE NODE TYPE
	CAIN T1,RCT.3F		;IS HE A FULL ROUTING NODE?
	JRST RTRRC9		;YES, PROCESS AS A PHASE III

	LOAD T2,RCNAD,(RC)	;YES, GET HIS NODE NUMBER
	ADD T2,RTRSRV		;POINT TO ENTRY IN THE SCRATCH VECTOR
	SETONE RNRCH,(T2)	;HE IS NOW REACHABLE
	CAIE T1,RCT.3S		;IS THIS A SMALL (NONROUTING) PHASE III?
	JRST RTRR1A		;NO, JUST PHASE II

;FOR PHASE III NON-ROUTING
	LOAD T1,RCCST,(RC)	;GET COST TO NODE
	STOR T1,RNCST,(T2)	;STORE IN ROUTING VECTOR
	MOVEI T1,1		;GET HOPS TO NODE (ACROSS THIS CIRCUIT, 1)
	STOR T1,RNHOP,(T2)	;STORE IN ROUTING VECTOR

RTRR1A:	ADD T2,RTROFS		;NOW FIND THE OUTPUT CIRCUIT ENTRY
	MOVEM RC,(T2)		;STORE CIRCUIT POINTER IN VECTOR
;Here to re-use the last routing message.

RTRRC9:

;Note that we do not use OPSTR for the following exchange, as OPSTR
;may expand to a multi-word sequence.  The EXCH is used so that we do
;not have to get the interlock.  Interrupt level code that deals with
;LRM will not see the LRM pointer, and thus will not free it.

IFN RCLRM+1,<PRINTX ?RCLRM must be a full word pointer>

	SETZ MB,		;ZERO THE LAST ROUTING MSG PTR IN
	EXCH MB,RC.LRM(RC)	; THE CIRCUIT BLOCK AND PICK UP THE NEW ONE

	JUMPE MB,RTRRC4		;IF NONE, GO TO NEXT CIRCUIT
	MOVE T1,MB		;POINT TO THE MESSAGE BLOCK
	CALL DNGINI		;GET UP TO GET BYTES
	LOAD T1,RMMK2,(MB)	;GET THE ROUTING DATA'S POSITION
	CALL DNGPOS		; AND GO TO IT
	MOVE T1,MB		;POINT TO MESSAGE BLOCK AGAIN
	CALL DNLENG		;GET THE LENGTH OF THE MESSAGE

	SUBI T1,2		;ACCOUNT FOR CHECKSUM
	ASH T1,-1		;MAKE IT AN ENTRY (NODE) COUNT
	SKIPLE T1		;CHECK LENGTH OF STORED ROUTING MESSAGE
	CAMLE T1,RTRMXN		;OF REASONABLE LENGTH?
	BUG.(CHK,ROURML,ROUTER,SOFT,<Stored routing message format error in RTRRCR>,,<

Cause:	This BUG is not documented yet.

>,RTRRC4)
	MOVE T3,T1		;GET COUNT OF ENTRYS
	MOVE P1,RTRSRV		;GET POINTER TO SCRATCH VECTOR
	ADDI P1,1		;OFFSET FROM FIRST NODE
;RTRRCR - Continued from last page

RTRRC2:	CALL DNG2BY		;GET THE BYTE FOR A NODE
	 BUG.(CHK,ROUUER,ROUTER,SOFT,<Unexpected end of routing message>,,<

Cause:	This BUG is not documented yet.

>,RTRRC4)
	LOAD T2,RGCST,+T1	;GET THE COST FROM THE BYTE
	OPSTR <ADD T2,>,RCCST,(RC) ; ADD THE CIRCUIT COST
	LOAD T1,RGHOP,+T1	;GET THE HOP COUNT
	ADDI T1,1		;ADJUST IT BY US
	CAMG T2,RTRMXC		;IS THE COST WITHIN THE MAX?
	CAMLE T1,RTRMXH		; HOW ABOUT THE HOPS?
	JRST RTRRC3		;NO, LEAVE IT AT THE MAX
	LOAD T4,RNCST,(P1)	;GET THE BEST COST SO FAR
	CAMLE T2,T4		;SEE IF IT'S AS GOOD AS NEW COST
	JRST RTRRC3		; IT'S NOT, DON'T BOTHER CHANGING IT
	STOR T1,RNHOP,(P1)	;IT'S BETTER, STORE THE HOPS
	STOR T2,RNCST,(P1)	; AND THE COST

	SETONE RNRCH,(P1)	;SAY WE CAN REACH HIM
	MOVE T1,P1		;GET A COPY OF ENTRY POINTER FOR NRV
	ADD T1,RTROFS		;FIND OUTPUT CIRCUIT ENTRY POINTER
	MOVEM RC,(T1)		;STORE THE OUTPUT CIRCUIT

RTRRC3: AOJ P1,			;INCREMENT THE POINTER
	SOJG T3,RTRRC2		; AND LOOP UNTIL FINISHED WITH THEM ALL

RTRRC4:	D36OFF			;TURN OFF INTERRUPTS FOR A MOMENT
	LOAD T1,RCLRM,(RC)	;GET THE POSSIBLY NEW MB POINTER
	JUMPN T1,[D36ON		;IF GOT A NEW ROUTING MSG, WE'LL HAVE
		  CALL FREMSG	; TO GET RID OF THE OLD ONE
		  JRST RTRR11]	; AND MERGE WITH OTHER CODE
	STOR MB,RCLRM,(RC)	;PUT PTR BACK TO THE WAY IT WAS
	D36ON			;TURN INTERRUPTS BACK ON

RTRR11:	LOAD RC,RCNXT,(RC)	;GET THE NEXT CIRCUIT
	JUMPN RC,RTRRC1		; UNTIL WE GET THEM ALL
;Here to go through and compare the two routing vectors.  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.

RTRRC5:	MOVE T3,RTRMXN		;GET THE COUNT OF NODES
	MOVE P1,RTRSRV		;POINTER TO SCRATCH ROUTING VECTOR
	ADDI P1,1		;START WITH NODE 1
	MOVE P2,RTRNRV		;POINTER TO NORMAL ROUTING VECTOR
	ADDI P2,1		;START WITH FIRST NODE
	SETZB T2,T4		;T2 := CHECKSUM, T4:= # OF UPDATES

RTRRC6:	MOVE T1,(P2)		;GET THE NORMAL ENTRY FOR NODE
	JN RNLCL,+T1,[MOVEM T1,(P1) ;IF ITS A LOCAL NODE,
		      MOVE T1,P2    ;GET COPY OF NRV ENTRY
		      ADD T1,RTROFS ;FIND THE OUTPUT VECTOR ENTRY
		      MOVE T1,(T1)  ;GET THE OUTPUT CIRCUIT
		      ADD P1,RTROFS ;FIND THE OUTPUT VECTOR ENTRY
		      MOVEM T1,(P1) ;STORE THE OUTPUT CIRCUIT
		      SUB P1,RTROFS ;POINT BACK TO THE OUTPUT VECTOR
		      JRST RTRRC7]  ; JUST UPDATE THE LOCAL ENTRY IN SCRATCH
	CAME T1,(P1)		;COMPARE IT TO THE SCRATCH ENTRY
	AOJ T4,			;IF THEY ARE DIFFERENT, INCREMENT COUNT
	LDB T1,[POINTR ((P1),<RNHOP!RNCST>)] ;HOP AND COST MUST BE ADJACENT
	ADD T2,T1		;SUM THE CHECKSUM

RTRRC7:	AOJ P1,			;LOOK AT NEXT "SCRATCH" ENTRY
	AOJ P2,			; AND NEXT "NORMAL" ENTRY
	SOJG T3,RTRRC6		;LOOP OVER ALL ENTRIES

	MOVE T1,T2		;GET COPY OF CHECKSUM
	CALL CKSNRM		;FIXUP THE CHECKSUM
	MOVEM T1,RTRCKS		;DONE, STORE THE CHECKSUM
	JUMPE T4,RTN		;IF NO CHANGES, JUST RETURN

	TRACE RTR,<Network topology change occured - changing routing vector>
	D36OFF			;NO INTERRUPTS
	MOVE T1,RTRSRV		;GET POINTER TO SCRATCH REACHABILITY VECTOR
	EXCH T1,RTRNRV		;SWITCH THE SCRATCH AND THE NORMAL
	MOVEM T1,RTRSRV		;USE THE OLD NORMAL VECTOR AS THE SCRATCH

	MOVE T1,RTRSOV		;GET POINTER TO SCRATCH OUTPUT-CIRC VECTOR
	EXCH T1,RTRNOV		;SWITCH THE SCRATCH AND NORMAL
	MOVEM T1,RTRSOV		;USE THE OLD NORMAL VECTOR AS THE SCRATCH
	D36ON			;GIVE UP INTERLOCK

IFN FTOPS20,<CALL NTCIN>	;INVOKE NETWORK TOPOLOGY CHANGE INTERRUPT
	MOVE RC,RTRCBQ		;GET PTR TO FIRST CIRCUIT BLOCK
	JUMPE RC,RTN		;NO CIRCUITS?  JUST RETURN
RTRRC8:	SETONE RCSRM,(RC)	;SET THE "SEND ROUTING MESSAGE" FLAG
	LOAD RC,RCNXT,(RC)	;GET THE NEXT CIRCUIT
	JUMPN RC,RTRRC8		;GO SET SRM, IF ANOTHER ONE IS THERE
	RET			;RETURN
	SUBTTL RTRSRM - Send routing messages if needed

;RTRSRM - Routine to send routing messages out on a circuit if needed
;
; 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-T5

;We go through all the circuit blocks and see if the long timer has
;expired (T2). 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 build 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.

RTRSRM:	SAVEAC P1		;SAVE AN PEA
	SKIPA RC,RTRCBQ		;GET THE FIRST CIRCUIT POINTER

RTRSR1:	LOAD RC,RCNXT,(RC)	;GET THE NEXT CIRCUIT BLOCK
	JUMPE RC,RTN		;IF NONE LEFT, JUST LEAVE

	LOAD T1,RCNTY,(RC)	;GET THE NODE TYPE
	CAIE T1,RCT.3S		;PHASE III NON-ROUTING NODES DON'T GET THEM
	CAIN T1,RCT.P2		;IS THE NEIGHBOR A PHASE II?
	JRST RTRSR1		;YES, TRY NEXT CIRCUIT

	CALL DNGTIM		;GET CURRENT TIME
	MOVE T2,RTRTM1		;ASSUME THE LONG TIME
	TMNE RCSRM,(RC)		;IS THE "SEND ROUTING MSG" FLAG ON?
	IDIVI T2,^D30		;YES, USE THE SHORT TIMER (%RTTM2)
	OPSTR <ADD T2,>,RCTLR,(RC) ;ADD IN THE LAST TIME WE SEND ONE
	CAMLE T2,T1		;SEE IF ITS TIME TO SEND ONE
	JRST RTRSR1		;NOT ON THIS CIRCUIT, TRY NEXT ONE

	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 RTRSR1		;NO, LOOK AT NEXT CIRCUIT
;Here when we are about to send a routing message out on a circuit.

	MOVE T1,RTRMXN		;USE MAX NODE NUMBER TO CALCULATE SIZE OF MSG
	LSH T1,1		;MAKE IT INTO BYTES
	ADDI T1,2		;SPACE FOR CHECKSUM
	CALL DNGMSG		;GET A MESSAGE BLOCK AND STUFF
	 JRST RTRSR1		;COULDN'T GET MESSAGE BLOCK, TRY NEXT CIRCUIT
	MOVE MB,T1		;GET POINTER TO MESSAGE BLOCK
	XMOVEI T1,UD.MSD(MB)	;GET POINTER TO USER DATA MSD
	CALL DNPINI		;INITIALIZE THE MSD AND HEADER
	MOVE T3,RTRMXN		;COUNT TO USE FOR GOING THROUGH RTRNRV
	MOVE P1,RTRNRV		;POINTER TO "NORMAL" ROUTING VECTOR
	ADDI P1,1		;START WITH NODE ONE
	SETZ T4,		;MAKE UP CHECKSUM IN THIS WORD

;Now put the hops and cost bytes for each node in the database in the
;message.

RTRSR2:	LDB T1,[POINTR((P1),<RNHOP!RNCST>)] ;GET THE HOP!COST
	ADD T4,T1		;SUM THE CHECKSUM
	CALL DNP2BY		;PLACE BYTES IN ROUTING MESSAGE
	AOJ P1,			;LOOK AT NEXT ENTRY IN NRV
	SOJG T3,RTRSR2		;KEEP GOING OVER ALL ENTRIES

	MOVE T1,T4		;GET COPY OF CHECKSUM
	CALL CKSNRM		;NORMALIZE THE CHECKSUM
	CAME T1,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,<Bad Checksum detected when building routing msg>,,<

Cause:	This means that something got trashed. Look at P1, it point to the
	end of the normal routing vector [RTRNRV]+[RTRMXN]. Look at the
	vector itself (pointed to by RTRNRV) and see if the topology looks
	reasonable. Look at RTRCKS and make sure it is less than 16 bits.
>,RTN)
	MOVEM T1,RTRCKS		;STORE THE CHEKSUM
	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,XCT.RM		;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
	CALL DNP2BY		;PUT ADDRESS IN MESSAGE

	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,<Sending routing message>
	INCR RCCMQ,(RC)		;INCREMENT NUMBER OF MESSAGES QUEUED
	CALL CALQOB		;OUTPUT THE MESSAGE

	SETZRO RCSRM,(RC)	;INDICATE WE HAVE SENT ROUTING MESSAGE
	CALL DNGTIM		;GET THE CURRENT TIME
	STOR T1,RCTLR,(RC)	;STORE IT IN CIRCUIT BLOCK AS TIME LAST SENT
				; ROUTING MESSAGE
	JRST RTRSR1		;ALL DONE WITH THIS CIRCUIT, TRY NEXT ONE
	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
;
;The hello process will periodically send a hello (test) message to a
;neighbor that has not sent us any messages in time T3.  The listener process
;checks to see if a neighboring node has sent anything to us in time T4.
;If T4 expires, we declare the circuit down.  Both T3 and T4 are checked based
;and RCTLM, which is the time that any sort of message was received from the
;neighbor.

RTRTMR:	SKIPA RC,RTRCBQ		;GET THE FIRST CIRCUIT BLOCK

RTRTR1:	LOAD RC,RCNXT,(RC)	;GET NEXT CIRCUIT BLOCK
	JUMPE RC,RTN		;PUNT IF NO MORE

	LOAD T4,RCSTA,(RC)	;GET THE STATE OF LINK
	LOAD T1,RCNTY,(RC)	;GET THE NEIGHBOR'S NODE TYPE
	CAIN T1,RCT.P2		;IS IT A PHASE II?
	JRST RTRTR1		;YES, DON'T BOTHER SENDING OR LISTENING FOR
				; HELLO/TEST MESSAGES
	CAIE T4,RCS.TI		;IS LINK IN TI WAIT?
	CAIN T4,RCS.TV		;IS IT IN TV WAIT?
	TRNA			;YES, CHECK OUT TI TIMER
	JRST RTRTR2		;NO, CHECK OUT OTHER TIMERS

	JE RCTIN,(RC),RTRTR2	;IS INIT TIMER RUNNING?

	CALL DNGTIM		;GET THE CURRENT TIME
	OPSTR <SUB T1,>,RCTIN,(RC) ;SUBTRACT WHEN WE GOT THE PROTOCOL UP

	CAMGE T1,RTRITM		;HAS TIME EXPIRED?
	JRST RTRTR2		;NO, JUST CONTINUE ON

;Here when the time allowed for the response to the TI we sent has expired.

	ETRACE RTR,<Initialization timer expired and is restarting the circuit>
	MOVX T1,RS.VRT		;EVENT REASON: VERIFICATION RECEIVE TIMEOUT
	CALL RTEINL		;REPORT INITIALIZATION FAILURE EVENT
	CALL RTRZCB		;CLEAN THE CIRCUIT BLOCK UP
	CALL R2KINI		;INITIALIZE THE KONTROLLER
	SETOM RTRRCF		;RECOMPUTE ROUTING LATER
	JRST RTRTR1		; AND TRY THE NEXT CIRCUIT
;Now check the hello and listener timers.

RTRTR2:	CAIE T4,RCS.TT		;IS IT IN TEST?
	CAIN T4,RCS.RN		;IS IT RUNNING?
	TRNA			;YES, OK TO DO THINGS
	JRST RTRTR1		;NO, CHECK OUT THE NEXT CIRCUIT

	CALL DNGTIM		;GET THE CURRENT TIME
	OPSTR <SUB T1,>,RCTLM,(RC) ;SUBTRACT TIME OF LAST MESSAGE RECEIVED
	OPSTR <CAMGE T1,>,RCTM4,(RC) ;DID THE LISTENER TIMER EXPIRE?
	JRST RTRTR3		;NO, CHECK THE HELLO TIMER

;Here when the listener timer has been exceeded.  The circuit is declared
;down and re-initialization is tried.

	ETRACE RTR,<Node listener timed out and is rejecting circuit>
	MOVX T1,RS.ALT		;EVENT REASON: ADJACENT NODE LISTENER TIMEOUT
	CALL RTELDL		;REPORT CIRCUIT DOWN - CIRCUIT FAULT EVENT
	CALL RTRZCB		;CLEAR THE CIRCUIT BLOCK UP
	CALL R2KINI		;TELL THE KONTROLLER TO INITIALIZE
	SETOM RTRRCF		;RECOMPUTE ROUTING LATER
	JRST RTRTR1		; AND TRY THE NEXT CIRCUIT


;Check to see if the hello message timer has expired (T3) and if so,
;send out an hello message on the circuit.

RTRTR3:	CALL DNGTIM		;GET THE CURRENT TIME
	OPSTR <SUB T1,>,RCTLS,(RC) ;SUBTRACT BY THE TIME LAST MESSAGE WAS SENT
	OPSTR <CAMGE T1,>,RCTM3,(RC) ;HAVE WE EXCEEDED THE HELLO TIMER?
	JRST RTRTR1		;NO, TRY THE NEXT CIRCUIT

;Build the data portion of the hello message.

	MOVX T1,NO.HEL+1	;LENGTH OF DATA SEGMENT
	CALL DNGMSG		;GET THAT MANY BYTES
	JRST RTRTR1		;RESOURCE FAILURE, TRY NEXT TIME
	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
RTRTR4:	MOVX T1,HEL.LO		;WORD THAT GOES IN HELLO MESSSAGE
	CALL DNP1BY		;PUT ONE IN
	SOJG T3,RTRTR4		; 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,XCT.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
	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,<Sending hello message>
	INCR RCCMQ,(RC)		;INCREMENT NUMBER OF MESSAGES QUEUED
	CALL CALQOB		;SEND THE MESSAGE
	JRST RTRTR1		; AND DO IT ALL AGAIN FOR THE NEXT CIRCUIT
	SUBTTL Circuit Interface -- RTRDSP - Circuit Drivers Entry

;RTRDSP - Entry to Router from DLL
;
; Call:
;	T1/ Function Code
;	T2/ Router Circuit Block Address
;	T3/ Data (ususally pointer to message block)
;	T4/ More Data (used only with RTIOPN)
;
; 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.

RTRDSP::CAXL T1,KI.PRU		;RANGE CHECK THE
	CAXLE T1,KI.CLS		; FUNCTION CODE
	BUG.(CHK,ROUILF,ROUTER,SOFT,<Illegal function code from Kontroller>,,<

Cause:	This BUG is not documented yet.

>,RTN)
	SEC1			;DO OUR STUFF IN SECTION 1
	SAVEAC <MB,MS,RC,P1,P2,T5,T6>    ;SAVE SOME AC'S
	MOVE T1,RTRDTB(T1)	;GET BITS AND DISPATCH FOR THIS FUNCTION.
	TXZN T1,RD.CRC		;DID I GET AN RC?
	JRST RTRDS2		;NO
	SKIPN RC,T2		;USE RC TO HOLD CIRCUIT BLOCK ADDRESS
RTRDS1:	BUG.(CHK,ROUBCB,ROUTER,SOFT,<Bad circuit block pointer>,,<

Cause:	A Kontroller has called RTRDSP with a function requiring a circuit
	block pointer and supplied a pointer (in t2) which failed the range
	check.

Action:	Find which Kontroller is supplying us with a bad circuit block pointer.

>,RTRDS9)
RTRDS2:	TXZN T1,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,<Bad message block pointer>,,<

Cause:	A Kontroller has called RTRDSP with a function requiring a message
	block, and the pointer supplied (in T3) is either 0 or out of
	range.

Action:	Determine why the Kontroller gave us 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 T1,RD.CKS		;SHOULD WE CHECK DECNET/CIRCUIT STATE?
	JRST RTRDS6		;DON'T WORRY ABOUT STATE
	SKIPN DCNSTA		;IS DECNET UP?
	JRST RTRDS9		;NO, RETURN NOW.
	LOAD T2,RCSTA,(RC)	;GET THE CIRCUIT STATE
	CAXE T2,RCS.OF		;IS THE CIRCUIT STATE OFF?
RTRDS6:	CALLRET (T1)		;NO, CALL APPROPRIATE ROUTINE AND RETURN
	ETRACE RTR,<RTRDSP called by circuit that should be dead>
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+RTIPRU	;PROTOCOL "UP"
	RD.CRC+RD.CKS+RTIDWN	;PROTOCOL "DOWN"
	RD.CRC+RD.CKS+RTIMMR	;MAINT MESSAGE RECEIVED
	RD.CRC+RD.CKS+RTISMR	;START MESSAGE RECEIVED
	RD.CRC+RD.CMB+RTIOTC	;OUTPUT COMPLETE
	RD.CRC+RD.CMB+RTIOTI	;OUTPUT INCOMPLETE
	RD.CRC+RD.CMB+RTIINC	;INPUT COMPLETE
	RD.CRC+RD.CKS+RTIBRQ	;BUFFER REQUEST
		      RTIOPN	;OPEN CIRCUIT
	RD.CRC+	      RTICLS	;CLOSE CIRCUIT

	SUBTTL Circuit Interface -- RTIOPN - Open a new circuit

;RTIOPN - Open a new circuit
;
; Call:
;	T3/ Kontroller Block Address
;	T4/ Line-ID
;
; Return:
;	RET			;ALWAYS, RETURNS WITH T1 CONTAINING CIRCUIT
;				; BLOCK ADDRESS OR ZERO IF IT COULDN'T
;				; ALLOCATE A NEW ONE
;
; Uses: T1-T4
;
;Note that this call has a different format that the other kontroller
;interrupt calls.  Since we don't have a circuit block address yet,
;T2 doesn't mean anything.

RTIOPN:	DMOVE P1,T3		;SAVE KBA AND LINE-ID
	MOVE T1,P2		;GET THE LINE-ID
	CALL RTRGCB		;FIND THE MATCHING CIRCUIT BLOCK
	 TRNA			;NO CIRCUIT BLOCK, CREATE IT
	JRST RTIOP1		;WE HAVE A CIRCUIT BLOCK, TRY TO SET THE STATE

	CALL RTRMCB		;MAKE UP THE CIRCUIT BLOCK
	 JRST [	SETZ T1,	;RETURN NO CIRCUIT-BLOCK PTR
		RET]		; AND RETURN

	MOVE RC,T1		;CIRCUIT BLOCK POINTER WE GOT.
	ENDQUE RC,RTRCBQ,RC.NXT,T1 ;ADD CIRCUIT BLOCK TO LIST

RTIOP1:	STOR P1,RCKBA,(RC)	;STORE THE KONTROLLER DISPATCH ADDRESS
	STOR P2,RCLID,(RC)	; AND THE LINE-ID

	MOVX T1,RCS.WT		;PUT INTO WAIT STATE TO
	STOR T1,RCSTA,(RC)	; TO BEGIN WITH

	MOVE T1,RC		;RETURN PTR TO NEW CKT-BLK TO KONTROLLER
	RET			; AND RETURN TO SENDER
	SUBTTL Circuit Interface -- RTICLS - Close a Circuit

;RTICLS - Close a Circuit
;
; Call:
;	RC/ Circuit Block Pointer
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T2
;
;Note that we don't free the circuit block.  We simply clear portions of
;the block out and declare it down.  If we later get a OPN from a
;kontroller which gives the same line-id, we will use the block again.

RTICLS:	CALL RTRZCB		;ZERO IMPORTANT PARTS OF THE BLOCK

	MOVX T1,RCS.OF		;DECLARE IT AS
	STOR T1,RCSTA,(RC)	; DOWN
	RET			; AND RETURN (THAT WAS EASY)
	SUBTTL Circuit Interface -- RTIPRU - Process Protocol Up

;RTIPRU - Handle the "protocol up" interrupt from the kontroller
;
; Call:
;	RC/ Circuit block address
;	T2/ State of circuit
;
; Return:
;	RET			;ALWAYS
;
; Uses:


RTIPRU:	TRACE RTR,<Received "protocol-up" from kontroller>
	LOAD T2,RCSTA,(RC)	;GET CIRCUIT STATE
	CAIE T2,RCS.WT		;MAKE SURE WE'RE IN WAITING STATE
	JRST [ETRACE RTR,<Protocol Up rcvd in wrong state>
	      CALLRET R2KINI]	;TRY TO REINITIALIZE THE CIRCUIT
	MOVX T1,RCS.TI		;NEW STATE = TRANSPORT INITIALIZATION WAIT
	STOR T1,RCSTA,(RC)	;STORE THE NEW CIRCUIT STATE
	MOVX T1,TI.MXL		;MAX LENGTH OF A TI MESSAGE
	CALL DNGMSG		; USER MESSAGE AREA
	 CALLRET R2KINI		;CAN'T DO IT, GO INTO INI STATE
	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
	MOVX T2,XCT.TI		;TYPE IS ROUTER INIT
	STOR T2,CMTYP,+T1	;AND STORE THAT IN THE TYPE FIELD
	CALL DNP1BY		;WRITE THE FIRST BYTE

	MOVE T1,RTRADR		;GET OUR ADDRESS
	CALL DNP2BY		;STORE THE NODE ADDRESS

;Build TLINFO.

	SETZ T1,		;START BUILDING TLINFO FIELD
	MOVX T2,RNT.RT		;WE ARE A ROUTING NODE
	STOR T2,TINTY,+T1	;STORE THE NODE TYPE
	TMNE RCVRQ,(RC)		;IS VERIFICATION REQUIRED?
	TXO T1,TIVER		;YES, TELL HIM ABOUT IT
	CALL DNP1BY		;PUT THE BYTE IN

;Give him the useless blocksize.

	MOVE T1,RTRBSZ		;GET THE BLOCKSIZE (USELESS)
	CALL DNP2BY		; AND TELL HIM NOTHING

;Fill in version, etc.

	MOVE T1,RTRVER		;VERSION OF RTR
	CALL DNP1BY		;PUT IT IN MESSAGE
	MOVE T1,RTRECO		;EDIT NUMBER OF RTR
	CALL DNP1BY		;PUT IT IN, ALSO
	MOVE T1,RTRCUS		;CUSTOMER ARGUMENT NUMBER
	CALL DNP1BY		;AND STORE THAT ALSO

;Now fill in one reserved byte (supposedly a image count)

	SETZ T1,		;USE A ZERO
	CALL DNP1BY		;PUT IN THE BYTE

;Here we give the message to the DLL to send.

	TRACE RTR,<Sending Router Init message>
	INCR RCCMQ,(RC)		;INCREMENT NUMBER OF MESSAGES QUEUED
	CALL CALQOB		;OUTPUT THE MESSAGE

	CALL DNGTIM		;GET THE CURRENT TIME
	STOR T1,RCTIN,(RC)	;REGISTER THE TIME THAT WE SENT THE TI
	RET			;RETURN TO SENDER
	SUBTTL Circuit Interface -- RTIDWN - Process Protocol Down

;RTIDWN - Routine to process a protocol down interrupt
;
; Call:
;	RC/ Circuit block address
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1

RTIDWN:	TRACE RTR,<Received "protocol-down" from DLL>
	MOVX T1,RS.LSL		;EVENT REASON: CIRCUIT SYNCHRONIZATION LOST
	CALL RTELDL		;REPORT CIRCUIT DOWN - CIRCUIT FAULT EVENT
	CALL RTRZCB		;CLEAN OUT THE CIRCUIT BLOCK
	MOVX T1,RCS.WT		;GET "WAIT" STATE CODE
	STOR T1,RCSTA,(RC)	;STORE AS CURRENT STATE FOR THIS CIRCUIT
	SETOM RTRRCF		;FLAG RTRRCR TO BE CALLED NEXT TIC
	RET
	SUBTTL Circuit Interface -- RTIMMR - Process Maintainence Message

;RTIMMR - Routine to process a recieved maintanence message
;
; Call:
;	RC/ Circuit block address
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1

RTIMMR:	TRACE RTR,<Received maintainance message>
	MOVX T1,RS.LSL		;EVENT REASON: CIRCUIT SYNCHRONIZATION LOST
	CALL RTELDL		;REPORT CIRCUIT DOWN - CIRCUIT FAULT EVENT
	CALL RTRZCB		;CLEAN UP CIRCUIT BLOCK
	CALL R2KHLT		;HALT THE CIRCUIT
	BUG.(INF,ROUMMR,ROUTER,SOFT,<Maintainence Message recieved>,,<

Cause:	This BUG is not documented yet.

>)
	SETOM RTRRCF		;FLAG FOR RTRRCR TO RUN
	RET			;AND RETURN
	SUBTTL Circuit Interface -- RTISMR - Process Start Message

;RTISMR - Routine to process a recieved start message
;
; Call:
;	RC/ Circuit block address
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1

RTISMR:	TRACE RTR,<Start message received>
	MOVX T1,RS.LSL		;EVENT REASON: CIRCUIT SYNCHRONIZATION LOST
	CALL RTELDL		;REPORT CIRCUIT DOWN - CIRCUIT FAULT EVENT
	CALL RTRZCB		;CLEAN UP CIRCUIT BLOCK
	CALL R2KHLT		;HALT THE CIRCUIT
	BUG.(INF,ROUSMR,ROUTER,SOFT,<Start Message recieved>,,<

Cause:	This BUG is not documented yet.

>)
	SETOM RTRRCF		;FLAG FOR RTRRCR TO BE CALLED NEXT TIC
	RET
	SUBTTL  Circuit Interface -- RTIBRQ - Process the Buffer Request

;RTIBRQ - Process the input buffer request
;
; Call:
;	RC/ Circuit Block Address
;	T3/ Length of Buffer wanted
;
; Return:
;	RET			;ALWAYS WITH T1 POINTING TO MESSAGE BLOCK
;				; OR T1 SET TO ZERO ON ALLOCATION FAILURE
;
; Uses: T1-T3

RTIBRQ:	TRACE RTR,<Recieved buffer request from DLL>
	MOVE P1,T3		;SAVE THE SIZE OF MSG WANTED IN BYTES
	CAMLE P1,RTRBSZ		;IS BUFFER WITHIN OUR RANGE?
	JRST [LOAD T2,RCLID,(RC)	;GET THE ENTITY ID (FOR CIRCUIT)
	      EVENT RE.OPL,<Oversized packet loss event>
	      AOS RTRCOP	;INCREMENT THE OVERSIZED PACKET COUNTER
	      MOVE P1,RTRBSZ	;USE MAX BUFFER SIZE
	      SETZ T1,		;GIVE ALLOCATION FAILURE TO DLL
	      RET]		; AND RETURN

	MOVE T1,P1		;SET UP ARG TO DNGMSG
	CALL DNGMSG		;GET THE MESSAGE BLOCK WITH T1 BYTES OF USER
				; DATA AREA
	  CALL RTIBR1		;COULDN'T ALLOCATE USE EMERGENCY BUFFER
	JUMPE T1,RTN		;JUST RETURN IF WE'RE STARVING THE DLL
	XMOVEI T2,IN.MSD(T1)	;POINT TO THE INPUT MSD
	STOR T2,MBFMS,(T1)	;STORE IN FIRST MSD SLOT
	RET			;TO SENDER

;Here when we couldn't get a buffer from the memory manager. If our neighbor
;isn't a Phase II node, use the per-circuit emergency buffer, in case it's a
;important control message.  Otherwise, return a zero in T1 for the DLL.

RTIBR1:	SETZ T1,		;START OFF WITH NOTHING FOR THE DLL
	LOAD T2,RCNTY,(RC)	;GET THE NEIGHBORING NODE'S TYPE
	CAIN T2,RCT.P2		;A REAL PHASE II NODE?
	RET			;GIVE DLL ZERO TO INDICATE RESOURCE FAILURE

	TMNE RCEBU,(RC)		;IS THE BUFFER IN USE?
	BUG.(CHK,ROUEBI,ROUTER,SOFT,<Emergency circuit buffer already in use>,,<

Cause:	This BUG is not documented yet.

>,RTN)
				;USE IT ANYWAY
	MOVE T1,P1		;GET THE LENGTH TO USE
	CALL DNGEMS		;GET ONE OF THE EMERGENCY MESSAGE BLOCKS
	 BUG.(CHK,ROUDGE,ROUTER,SOFT,<Didn't get reserved emergency msg blk>,,<

Cause:	We should never run out of emergency blocks, ROUTER should
	sign up for enough blocks and then use no more than signed up for.

Cure:	Either ROUTER hasn't signed up for enough emergency blocks or
	has used too many.  If too many, they are probably in some
	input queue.  Find all calls to DNGEMS and DNMINP and find who
	used too many.
>,RTN)
	XMOVEI T2,IN.MSD(T1)	;POINT TO THE INPUT MSD
	STOR T2,MBFMS,(T1)	;STORE IN FIRST MSD SLOT
	SETONE RCEBU,(RC)	;SET THE INUSE BIT FOR THIS CIRCUIT
	RET			; AND RETURN WITH T1 POINTING TO EMERGENCY AREA
	SUBTTL Circuit Interface -- RTIOTC - Process Output Complete

;RTIOTC - Routine to process output complete interrupt
;
; Call:
;	RC/ Circuit block address
;	T3/ Message block address
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T3

RTIOTC:	TRACE RTR,<Output Complete>
	MOVE MB,T3		;GET THE MESSAGE BLOCK ADDRESS
	MOVE T1,MB		;ARG FOR DNLENG
	CALL DNLENG		;FIGURE OUT THE LENGTH OF THE MESSAGE
	OPSTRM <ADDM T1,>,RCBYS,(RC) ;UPDATE BYTES SENT
	INCR RCDBS,(RC)		;INCREMENT THE NUMBER OF BLOCKS SENT
	DECR RCCMQ,(RC)	 	;DECREMENT MESSAGES QUEUED COUNT

	CALL DNGTIM		;GET CURRENT TIME
	STOR T1,RCTLS,(RC)	;SAVE AS TIME LAST MESSAGE SENT

	JN RMCTL,(MB),FREMSG	;IF IT'S A CONTROL MESSAGE, JUST
				; FREE THE MESSAGE

	JN RMICP,(MB),[INCR RCCTS,(RC)	;IF THE MESSAGE IS NOT FROM A LOCAL
		       CALLRET FREMSG]	; NODE, INCREMENT THE TRANSIT COUNT
					; AND DISCARD THE PACKET

	INCR RCCLC,(RC)		;OTHERWISE, INCREMENT THE LOCAL COUNT
	CALLRET FREMSG		;GIVE PACKET TO BACK TO NSP, OR FREE IT
	SUBTTL Circuit Interface -- RTIOTI - Process Output Incomplete

;RTIOTI - Process the output incomplete interrupt
;
; Call:
;	RC/ Pointer to circuit block
;	T3/ Pointer to message block
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T3

RTIOTI:	TRACE RTR,<Output not done>
	CALLRET RTIOTC		;JUST CALL OUTPUT COMPLETE
	SUBTTL Circuit 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,<Input Complete>
	MOVE MB,T3		;GET POINTER TO MESSAGE BLOCK
RTRITR::			;LABEL FOR DNSNUP TO FIND INPUT MESSAGES
	STOR RC,RMICP,(MB)	;STORE THE INPUT CIRCUIT ADDRESS

	MOVE T1,MB		;COPY POINTER TO MESSAGE BLOCK
	CALL DNLENG		;SIZE OF THIS MESSAGE
	OPSTRM <ADDM T1,>,RCBYR,(RC) ;UPDATE TOTAL BYTES RECEIVED
	INCR RCDBR,(RC)		;INCREMENT TOTAL DATA BLOCKS RECEIVED

	CALL DNGTIM		;GET THE CURRENT TIME
	STOR T1,RCTLM,(RC)	;STORE TIME WE LAST HEARD FOR NEIGHBOR

	CALL RTRHDP		;PARSE THE HEADER
	 CALLRET RTEMFE		;REPORT THE MESSAGE FORMAT ERROR EVENT

	JN RMPH2,(MB),RTRPH2	;IF IT'S A PHASE II MESSAGE, PROCESS IT

	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
	SETZRO RCEBU,(RC)	;EMERGENCY BUFFER IS NO LONGER IN USE
	RET			;RETURN TO SENDER

RTIIND:	IFIW RTCINI		;ROUTER INITIALIZATION (0)
	IFIW RTCVER		;ROUTER VERIFICATION (1)
	IFIW RTCTST		;ROUTER TEST MESSAGE (2)
	IFIW RTCRTE		;ROUTER ROUTING MESSAGE (3)
;Here with a data message.

RTIIN1:	TMNE MBEBF,(MB)		;IS THIS MESSAGE IN AN EMERGENCY BUFFER?
	JRST RTIINE		;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,<Circuit in wrong state for forwarding>
	      CALLRET FREMSG]
	CALLRET RTRFWD		;FORWARD THE MESSAGE

;At this point we have a data message in an emergency buffer.  If it is
;from a Phase II node, we cannot throw the message away.  We therefore
;check the node type vector to see if the source was a Phase II node,
;and if it was we forward the message normally.

RTIINE:	LOAD T1,MBSRC,(MB)	;YES, LET'S CHECK IF
	CALL RTNRNT		; FROM A PHASE II NODE
	CAIE T1,NTV.P2		;IS IT PHASE II?
	JRST RTIINF		;NO, WE MUST PUNT MESSAGE
	SETONE MBPH2,(MB)	;YES, CALL IT A PHASE2 MESSAGE
	JRST RTIIN2		; AND FORWARD IT NORMALLY, AS WE
				;ARE NOT ALLOWED TO PUNT PHASE II
				;MESSAGES
;Here to discard an arriving phase III packet due to congestion.

RTIINF:	OPSTR <SKIPL T2,>,MBDST,(MB) ;GET THE DESTINATION
	CAMLE T2,RTRMXN		;RANGE CHECK IT
	CALLRET RTRFOR		;DESTINATION IS OUT-OF-RANGE
	ADD T2,RTRNRV		;GET THE NODE'S ROUTING VECTOR ENTRY
	JE RNLCL,(T2),[INCR RCCAL,(RC) ;IF IT WAS SUPPOSED TO COME TO US
		       JRST RTIIN3] ;REPORT IT AS ARRIVIED CONGESTION LOSS
	INCR RCCTL,(RC)		;INCREMENT THE TRANSIT CONGESTION LOSS
RTIIN3:	SETZRO RCEBU,(RC)	;EBUF ALLOCATED TO CIRCUIT NO LONGER IN USE
				;COULDN'T DO IT, LETS PUNT THE MESSAGE
	CALLRET FREMSG		;FREE MSG BLK & RETURN
	SUBTTL Control Message Processors -- RTCINI - Init 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,<Processing Router Init message>
	CAIE T1,RCS.TI		;ARE WE IN RTR INIT WAIT STATE?
	JRST [ETRACE RTR,<RTR Init message rcvd in wrong state>
	      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
	CAIL T1,1		;CHECK NODE ADDRESS
	CAMLE T1,RTRMXN		; FOR REASONABLENESS
	JRST [MOVX T1,RS.ANO	;REASON: ADJACENT NODE ADDRESS OUT OF RANGE
	      CALLRET RTEINO]	;REPORT THE INITIALIZATION FAILURE EVENT
	STOR T1,RCNAD,(RC)	;STORE IT

	MOVE T1,MB		;POINT TO INPUT MESSAGE
	CALL DNLENG		;CALCULATE THE LENGTH
	CAIGE T1,^D6		;IS IT THE CORRECT LENGTH FOR RTR INIT MSGS?
	CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT

;Check the first byte of the init message (TLINFO)

	CALL DNG1BY		;GET THE INITINFO FIELD
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR
	TXNE T1,TIRSV		;IS THE RESERVED FIELD ZERO?
	CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT

	MOVX T2,RCVRQ		;GET THE VERFIFY REQUIRED BIT
	ANDCAM T2,RC.VRQ(RC)	;ASSUME THAT VERIFICATION ISN'T REQUIRED
	TXNE T1,TIVER		;IS IT REALLY REQUIRED?
	IORM T2,RC.VRQ(RC)	;YES, SET IT

	LOAD T2,TINTY,+T1	;GET NODE TYPE FROM BYTE
	SETZ T1,		;USE T1 TO HOLD NODE TYPE FOR CIRCUIT BLOCK
	CAIN T2,RNT.RT		;IS IT A ROUTING NODE?
	MOVX T1,RCT.3F		;YUP, MUST BE A PHASE III FULL NODE
	CAIN T2,RNT.NR		;IS IT A NON-ROUTING NODE?
	MOVX T1,RCT.3S		;YES, WELL ITS A PHASE III END NODE
	SKIPN T1		;DID WE GET ONE?
	CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	STOR T1,RCNTY,(RC)	;STORE THE NODE TYPE IN CIRCUIT BLOCK
;Get the blocksize (which is quite useless).

	CALL DNG2BY		;GET TWO BYTES OF GARBAGE
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
;	CAMGE T1,RTRBSZ		;IS THE BLOCKSIZE REASONABLE
;	JRST [MOVX T1,RS.VSK	;EVENT REASON: VERSION SKEW
;	      CALLRET RTEINO]	;REPORT THE INITIALIZATION FAILURE EVENT
	STOR T1,RCBSZ,(RC)	; AND STORE IT FOR WHATEVER REASON

;Next comes the Version number, ECO number and Customer args.

	CALL DNG1BY		;GET THE VERSION NUMBER
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	STOR T1,RCVER,(RC)	;STORE IN IN CIRCUIT BLOCK
	CALL DNG1BY		;GET THE ECO NUMBER
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	STOR T1,RCECO,(RC)	;STORE IT
	CALL DNG1BY		;ALSO THE CUSTOMER ARGUMENT
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	STOR T1,RCCUS,(RC)	;STORE IT ALSO

;Now we have read the whole message, next send a verification if necessary.

	TMNE RCVRQ,(RC)		;DOES HE WANT VERIFICATION?
	JRST RTCIN1		;YES.
	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
	CAXN T1,RCS.RN		;DID WE END UP IN RUN STATE?
	CALL RTELUP		;YES, SIGNAL CIRCUIT UP EVENT
	SETOM RTRRCF		;FLAG THE NEED FOR A TOPOLOGY RECOMPUTE
	SETZRO RCTIN,(RC)	;ZERO THE TIME WE SENT TI TIMER
	CALLRET FREMSG		; FREE MESSAGE AND RETURN

RTCIN1:	MOVE T1,MB		;PASS PTR TO MSG BLK TO DNMINI
	SETZ T2,		;ZERO LENGTH USER DATA SPACE FOR PSWD
	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,XCT.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
	CALL DNP2BY		;STORE THAT
;Put a zero length password at the end of the verification msg

	SETZ T1,		;MAKE A ZERO COUNT FIELD
	CALL DNP1BY		;TELL MSG ABOUT IT

	TRACE RTR,<Sending Router Verification message>
	INCR RCCMQ,(RC)		;INCREMENT NUMBER OF MESSAGES QUEUED
	CALL CALQOB		;OUTPUT THE MESSAGE.

	CALL DNGTIM		;GET CURRENT TIME
	STOR T1,RCTIN,(RC)	;REGISTER THE TIME THAT WE SENT THE TV

	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
	CALLRET RTELUP		;SIGNAL CIRCUIT UP EVENT 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,<Processing Router Verification message>
	SAVEAC <P1,P2>		;SAVE 2 PEAS
	CAIE T1,RCS.TV		;ARE WE WAITING FOR A VERIFICATION
	JRST [ETRACE RTR,<RTR Verification message rcvd in wrong state>
	      MOVX T1,RS.UPT	;EVENT REASON: UNEXPECTED PACKET
	      CALLRET RTELDS]	;REPORT CIRCUIT DOWN - SOFTWARE ERROR EVENT
	CALL DNG1BY		;GET FIRST BYTE (IMAGE COUNT)
	 CALLRET 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
	CALL RTELUP		;SIGNAL CIRCUIT UP EVENT
	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
;	RC/ Pointer to circuit block
;	MB/ Poiner to message block
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T4

RTCRTE:	TRACE RTR,<Processing Routing message>
	CAIE T1,RCS.TT		;CHECK OUR STATE FOR EITHER TEST OR
	CAIN T1,RCS.RN		; OK STATE
	TRNA			;WE SEEM ALRIGHT
	JRST [ETRACE RTR,<Routing message rcvd in wrong state>
	      MOVX T1,RS.UPT	;EVENT REASON: UNEXPECTED PACKET RECEIVED
	      CALLRET RTELDS]	;REPORT CIRCUIT DOWN - SOFTWARE FAULT EVENT
	LOAD T1,MBSRC,(MB)	;GET THE SOURCE ADDRESS
	OPSTR <CAME T1,>,RCNAD,(RC) ;IS THAT THE ADDRESS WE EXPECTED?
	JRST [MOVX T1,RS.ANA	;EVENT REASON: ADJACENT NODE ADDRESS CHANGE
	      CALLRET RTELDO]	;REPORT CIRCUIT DOWN - OPERATOR FAULT EVENT
	MOVE T1,MB		;POINT TO INPUT MESSAGE
	CALL DNLENG		;GET ITS LENGTH
	TXNE T1,1B35		;SEE IF IT'S AN EVEN LENGTH
	CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	SUBI T1,2		;GET COUNT WITHOUT CHECKSUM
	ASH T1,-1		;MAKE IT ENTRY COUNT
	SKIPLE T1		;RANGE CHECK THE LENGTH
	CAMLE T1,RTRMXN		; OF THE MESSAGE
	CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	CAME T1,RTRMXN		;IT'S A ROUTING UPDATE LOSS IF MESSAGE ISN'T
				;  EXACTLY THE LENGTH THAT WE ARE EXPECTING
	CALL RTCRTF		; SO REPORT THE LOSS AND COME BACK
	MOVE T4,T1		;GET COPY OF ENTRY COUNT
	CALL DNRPOS		;READ THE POSTION IN MESSAGE
	STOR T1,RMMK2,(MB)	;STORE THE ROUTING MESSAGE POSITION

;Here to read the message, while summing the checksum.

	SETZ T3,		;A PLACE FOR THE CHECKSUM
RTCRT1:	CALL DNG2BY		;GET A BYTE OF THE ROUTING MESSAGE
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	ADD T3,T1		;SUM THE CHECKSUM
	SOJG T4,RTCRT1		;SKIM THROUGH IT
;Get the checksum in the message and verify it.

	CALL DNG2BY		;GET THE CHECKSUM FROM THE MESSAGE
	 JRST [MOVX T1,RS.RUC	;EVENT ERROR: CHECKSUM ERROR DETECTED
	       CALLRET RTELDS]	;REPORT THE CIRCUIT DOWN - SOFTWARE ERROR EVENT
	EXCH T1,T3		;EXCHANGE THE CHECKSUMS
	CALL CKSNRM		;NORMALIZE THE ONE WE FIGURED OUT
	CAME T1,T3		;BETTER BE THE SAME
	CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT

;Free the old message and link in the new one.

	LOAD T1,RCLRM,(RC)	;GET POINTER TO LAST ROUTING MESSAGE SENT
	STOR MB,RCLRM,(RC)	;STORE THIS MESSAGE THAT WE GOT
	JUMPE T1,RTCRT3		;IF NONE THERE, DON'T TRY TO FREE IT
	TMNE MBEBF,(MB)		;IS THIS MESSAGE IN AN EMERGENCY BUFFER?
	JRST RTCRT2		;NO, JUST FREE IT UP NORMALLY

	SETONE MBEBF,(T1)	;MAKE OLD MESSAGE INTO A "EMERGENCY" BUFFER
	SETZRO MBEBF,(MB)	; AND MAKE THE NEW ONE A REGULAR BUFFER
RTCRT2:	CALL DNFMSG		; FREE IT UP
RTCRT3:	SETOM RTRRCF		;LET PEOPLE KNOW WE HAVE TO RECOMPUTE TOPOLOGY
	RET			;TO SENDER

;Here to report the partial routing update loss.

RTCRTF:	SAVEAC <T1,T2,T3,T4>	;WE'RE RELYING ON THESE ACS
	MOVE T3,T1		;SET UP THE NODE NUMBER
	LOAD T2,RCLID,(RC)	;GET THE ENTITY ID
	EVENT RE.PRL,<Partial routing update loss event>,MB
	AOS RTRCPR		;INCREMENT THE COUNTER
	RET			;RETURN
	SUBTTL Control Message Processors -- RTCTST - Test or Hello Messages

;RTCTST - Routine to handle the hello and test messages
;
; Call:
;	T1/ State of Circuit
;	RC/ Pointer to Circuit Block
;	MB/ Pointer to Message Block
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T4
;
;Router Hello and Test messages consist of a image count followed by that
;count of bytes filled with some constant (HEL.LO).

RTCTST:	TRACE RTR,<Processing test or hello message>
	CAIE T1,RCS.TT		;ARE WE IN TEST OR
	CAIN T1,RCS.RN		; OK MODE?
	TRNA			;YES
	JRST [ETRACE RTR,<Test or Hello message rcvd in wrong state>
	      MOVX T1,RS.UPT	;REASON: UNEXPECTED PACKET RECEIVED
	      CALLRET RTELDS]	;REPORT CIRCUIT DOWN - CIRCUIT FAULT EVENT
	LOAD T1,MBSRC,(MB)	;GET THE SOURCE ADDRESS
	OPSTR <CAME T1,>,RCNAD,(RC) ;IS IT WHAT WE EXPECTED?
	JRST [MOVX T1,RS.ANA	;REASON: ADJACENT NODE ADDRESS CHANGED
	      CALLRET RTELDO]	;REPORT CIRCUIT DOWN - OPERATOR FAULT EVENT
	CALL DNG1BY		;GET THE IMAGE COUNT OF TEST MESSAGE
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	CAILE T1,^D128		;IS THE LENGTH WITHIN REASON
	BUG.(INF,ROUBTF,ROUTER,SOFT,<Bad Test message format>,,<

Cause:	This BUG is not documented yet.

>,FREMSG)

;Check to see if the test data is ok.

	MOVE T4,T1		;PRESERVE IT SORT OF
	SOJGE T4,[CALL DNG1BY	;GET A BYTE OF THE TEST
		   JRST [MOVX T1,RS.ALI ;REASON: INVALID TEST DATA
			 CALLRET RTELDS] ;REPORT THE CIRCUIT DOWN EVENT
		  CAIE T1,HEL.LO ;IS IT EQUAL TO THE MAGIC NUMBER
		  BUG.(INF,ROUBTM,ROUTER,SOFT,<Bad Hello or Test message>,,<

Cause:	This BUG is not documented yet.

>,FREMSG)
		  JRST .]	;LOOK AT ALL THE BYTES
	CALLRET FREMSG		;FREE THE MESSAGE AND RETURN

	SUBTTL RTRHDP - Parse a Input Router Message Header

;RTRHDP - Parse Router Header on Incoming Message
;
; Call:
;	MB/ Pointer to Input message
;
; Return:
;	RET			;IF BAD HEADER
;	RETSKP			;ON SUCCESS
;
; Uses: T1-T2
;
;Note that DNGINI is called here and should not be recalled afterwards
;for the Router MSD.

RTRHDP:	MOVE T1,MB		;POINT TO THE MESSAGE BLOCK
	CALL DNGINI		;SET UP FOR CALLS TO DNGXBY
	CALL DNRPOS		;GET OUR POSITION
	STOR T1,RMMK1,(MB)	;STORE IT FOR EVENT PROCESSING

	CALL DNG1BY		;GET THE FIRST BYTE
	 RET			;RAN OUT, GIVE ERROR RETURN
	STOR T1,RMFST,(MB)	;STORE IT FOR PEOPLE TO USE
	TXNE T1,RM%EVL		;IS THE EVOLUTION BIT SET?
	JRST RTRHD1		;YES, IT HAS A PHASE II ROUTING HEADER

	TXNE T1,RM%CTL		;IS THIS A CONTROL MESSAGE?
	JRST RTRHDC		;YES, GO HANDLE IT

;Check all the fields in the packet route header and store pertinent fields
;in the message block.

	TXNN T1,RM%MB1		;IF LOW TWO ORDER BYTES ARE 00, THIS
				; MESSAGE IS A PHASE II WITHOUT A ROUTING
				; HEADER
	JRST RTRHD1		;IT IS, RETURN, INDICATING PHASE II MESSAGE

	TXNE T1,RM%MZ1!RM%MZ2!RM%ALM ;MAKE SURE THESE FIELDS ARE ZERO
	RET			;THEY'RE NOT, GIVE ERROR RETURN

	TXNE T1,RM%RQR		;IS RQR ON?
	TXNN T1,RM%RTS		; AND RTS
	TRNA			;NO, OK
	RET			;YES, THAT'S A PROBLEM
;Now parse the source, destination and visits fields of packet route header.

	CALL DNG2BY		;GET THE DESTINATION ADDRESS
	 RET			;OUT OF BYTES, GIVE BAD RETURN
	STOR T1,MBDST,(MB)	;STORE IT

	CALL DNG2BY		;GET THE SOURCE ADDRESS
	 RET			;RAN OUT, GIVE BAD RETURN
	STOR T1,MBSRC,(MB)	;STORE THAT, TOO

	CALL DNG1BY		;GET THE "FORWARD" BYTE
	 RET			;RAN OUT, GIVE BAD RETURN
	TXNE T1,^-FWVST		;MAKE SURE IT'S NOT TOO BIG
	RET			;IT'S TOO BIG

	STOR T1,RMVST,(MB)	;STORE IT IN THE MESSAGE BLOC
	RETSKP			;LOOKS GOOD, RETURN

;Here we have a Phase II message.  Set the Phase II flag in the message
;block and return.

RTRHD1:	SETONE RMPH2,(MB)	;SAY THIS IS A PHASE II MESSAGE
	RETSKP			; AND GIVE GOOD RETURN

;Here with a control message. Check the type and return.

RTRHDC:	TXNE T1,^-<CMTYP!CMCTL>	;MAKE SURE THE RESERVED BITS ARE ZERO
	RET			;NOPE, GIVE BAD RETURN

	LOAD T2,CMTYP,+T1	;GET THE CONTROL MESSAGE TYPE
	STOR T2,RMCTY,(MB)	;STORE THAT IN MESSAGE BLOCK

	CALL DNG2BY		;GET THE ADDRESS
	 RET			;RAN OUT OF MESSAGE, GIVE ERROR RETURN
	STOR T1,MBSRC,(MB)	;AND STORE IT IN PUBLIC SECTION
	RETSKP			;RETURN TO SENDER WITH GOOD RETURN
	SUBTTL RTRPH2 - Handle Phase II Messages

;RTRPH2 - Process Phase II messages
;
; Call:
;	RC/ Pointer to circuit block
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1,T3
;
;RTRPH2 handles all of the Phase II messages that we get.  We check to see
;if the message is either a Node Initialization or a Node Verification message,
;if it is then we handle them in a similar manner to the Router
;Initialization and the Router Verification messages respectively.  All
;types of messages are known to NSP and are passed to the "PHASE2" NSP.  Note
;that that it can only be passed to the NSP which we believe is prepared to
;handle Phase II messages and that there can be only one of these nodes. (This
;is a hole in the multi-NSP sceme).

RTRPH2:
IFE FTPHA2, BUG PH2,CHK,<Shouldn't have gotten Phase II Message>,RTN
	SAVEAC <P1,P2,FREE0>	;SAVE A PEA
	LOAD T1,RMFST,(MB)	;GET THE FIRST BYTE OF THE MESSAGE
	TXNN T1,RM%MB1		;IF MUST BE ONE BIT IS OFF, WE ARE AT MSGFLG
	JRST RTRP2N		; SO THERE IS NO ROUTING HEADER

;Here we eat the RTHDR of the message.

	CALL DNG1BY		;GET THE DSTNODE IMAGE COUNT
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	CALL DNSKBY		;SKIP THAT MANY BYTES
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR

	CALL DNG1BY		;GET THE SRCNODE IMAGE COUNT
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	CALL DNSKBY		;SKIP THESE BYTES
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT

	CALL DNGEBY		;GET THE MSGFLG FIELD
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
;Now we have the MSGFLG in T1.  Check to see if it is either a Node Init (NI)
;message or a Node Verification (NV) message and if it is not, just forward
;the message to NSP.

RTRP2N:	LOAD T2,MFSUB,+T1	;GET THE SUBTYPE OF MESSAGE
	LOAD T3,MFTYP,+T1	;GET THE TYPE OF MESSAGE
	CAIN T3,MFT.CT		;IS IT A CONTROL MESSAGE?
	CAIE T2,MFC.ST		; OR THE START TYPE CONTROL MESSAGE?
	JRST RTRP2F		;NO, BACK UP ONE BYTE AND FORWARD TO NSP

;Here to check out the STARTTYPE field.

	CALL DNG1BY		;GET THE STARTTYPE FIELD
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	CAIN T1,STT.NV		;IS IT A NODE VERIFICATION MESSAGE?
	JRST RTRP2V		;YES, GO HANDLE IT
	CAIE T1,STT.NI		;IS IT A NODE INITIALIZATION MESSAGE?
	CALLRET RTEMFE		;++MESSAGE FORMAT ERROR

;Here with a Phase II Node Initialization message.  We simply go through
;the message and store the relavent parameters in the circuit block.

	TRACE RTR,<Phase II Node Init message being processed>
	LOAD T1,RCSTA,(RC)	;GET OUR CIRCUIT'S STATE
	CAIE T1,RCS.TI		;IS IT IN TI WAIT?
	BUG.(CHK,ROUWSP,ROUTER,SOFT,<Phase II Node Init received in wrong state>,,<

Cause:	This BUG is not documented yet.

>,FREMSG)

;Get the address of the neighbor.

	CALL DNGEBY		;GET THE SOURCE NODE NUMBER
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	SKIPLE T1		;RANGE CHECK IT
	CAMLE T1,RTRMXN		; DOES IT LOOK OK?
	BUG.(INF,ROUBNA,ROUTER,SOFT,<Bad node address in Phase II NI message>,,<

Cause:	This BUG is not documented yet.

>,FREMSG)
	STOR T1,RCNAD,(RC)	;STORE IT IN THE CIRCUIT BLOCK

;Skip the ASCII node name.

	CALL DNG1BY		;GET THE IMAGE COUNT OF NODE NAME
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	CAILE T1,6		;IS LENGTH OK?
	CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT

	CALL DNSKBY		;SKIP THOSE BYTES
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT

;Skip the FUNCTION field.

	CALL DNGEBY		;READ THE FUNCTION FIELD
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT

;Check out the REQUEST field.

	CALL DNGEBY		;GET THE REQUEST FIELD
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	MOVX T2,RCVRQ		;VERFICATION REQUEST BIT IN MESSAGE BLOCK
	ANDCAM T2,RC.VRQ(RC)	;ASSUME IT'S NOT REQUIRED
	TXNE T1,REVER		;IS IT REQUIRED?
	IORM T2,RC.VRQ(RC)	;YES, SET IT

;Get and store useless BLOCKSIZE.

	CALL DNG2BY		;GET THE BLOCKSIZE
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	STOR T1,RCBSZ,(RC)	;STORE IT FOR NOTHING

;Skip MAXLINKS field

	CALL DNG2BY		;IGNORE MAXLINK
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT

;Get and store the version, eco level and customer args

	CALL DNG1BY		;GET THE VERSION
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	STOR T1,RCVER,(RC)	;STORE IT
	CALL DNG1BY		;GET THE ECO LEVEL
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	STOR T1,RCECO,(RC)	;STORE IT
	CALL DNG1BY		;GET THE CUSTOMER ARGUMENT
	 CALLRET RTEMFE		;++MESSAGE FORMAT ERROR EVENT
	STOR T1,RCCUS,(RC)	;STORE THIS ALSO

;The rest of the NI message is useless for us.  Just set the node type
;to a Phase II node and build the verification message if needed.

	MOVX T1,RCT.P2		;NODE TYPE = PHASE II
	STOR T1,RCNTY,(RC)	;STORE IN CIRCUIT BLOCK
	MOVX T1,NTV.P2		;ALSO PUT IT IN NODE TYPE VECTOR
	CALL RTNSNT		; AS A PHASE II NODE

	TMNN RCVRQ,(RC)		;IS VERIFICATION REQUIRED?
	JRST RTRP2M		;NOT NEEDED

	MOVX T2,4		;WE NEED FOUR BYTES FOR MSGLFG AND COUNT
	MOVE T1,MB		;RE-USE THE MESSAGE WE JUST GOT IN
	CALL DNMINI		;RE-INITIALIZE IT
	 RET			;COULDN'T GET MESSAGE BLOCK, RETURN
	XMOVEI T1,UD.MSD(MB)	;POINT TO THE MESSAGE SEGMENT WE GOT
	CALL DNPINI		;SET UP THE BYTE POINTERS

	SETZ T1,		;START MAKING UP THE BYTE
	MOVX T2,MFT.CT		;TYPE IS CONTROL MESSAGE
	STOR T2,MFTYP,+T1	;STORE THE TYPE FIELD
	MOVX T2,MFC.ST		;SUB-TYPE IS START MESSAGE
	STOR T2,MFSUB,+T1	;STORE THE SUB-TYPE FIELD
	CALL DNPEBY		;WRITE THE EXTENSIBLE BYTE

	MOVX T1,STT.NV		;STARTTYPE IS NODE VERIFICATION
	CALL DNP1BY		;WRITE THE BYTE

	MOVX T2,^D8		;PASSWORD FIELD FOR PHASE II IS ALWAYS 8 BYTES
	SOJGE T2,[SETZ T1,	;WRITE THE NULL BYTES
		  CALL DNP1BY	;PUT IN MESSAGE SEGMENT
		  JRST .]	;KEEP IT GOING TILL DONE

;All done, set the state to Verification Wait and queue the message to the
;DLL.

	MOVX T1,RCS.TV		;NEW STATE WILL BE "TV" WAIT
	STOR T1,RCSTA,(RC)	;STORE IT IN CIRCUIT BLOCK

	TRACE RTR,<Sending Phase II Node Verification message>
	INCR RCCMQ,(RC)		;INCREMENT NUMBER OF MESSAGES QUEUED
	CALL CALQOB		;OUTPUT THE MESSAGE
	SETZ MB,		;SAY THAT WE USED THE OLD MESSAGE ALREADY
;Merge here when we don't have to send a Node Verification Message.

;Now that we know the neighbor is a Phase II node, we must send him
;a NI message in return.

RTRP2M:	SKIPE T1,MB		;IF WE HAVE AN OLD MESSAGE BLOCK
	JRST [MOVX T2,NI.MXL	; LET'S USE IT
	      CALL DNMINI	; BY RE-INITIALIZING IT
	       RET		;OOPS, CAN'T DO IT
	      JRST RTRPM1]	;MERGE WITH OTHER CODE
	MOVX T1,NI.MXL		;GET ROOM FOR MAX NI MESSAGE
	CALL DNGMSG		;GET THAT BIG OF A MESSAGE BLOCK
	 RET			;COULDN'T GET IT, JUST RETURN

	MOVE MB,T1		;SET UP MB
RTRPM1:	XMOVEI T1,UD.MSD(MB)	;WE WILL PUT BYTES IN THE USER DATA SEGMENT
	CALL DNPINI		;SET UP TO DO THAT

	SETZ T1,		;START MAKING UP THE BYTE
	MOVX T2,MFT.CT		;TYPE IS CONTROL MESSAGE
	STOR T2,MFTYP,+T1	;STORE THE TYPE FIELD
	MOVX T2,MFC.ST		;SUB-TYPE IS START MESSAGE
	STOR T2,MFSUB,+T1	;STORE THE SUB-TYPE FIELD
	CALL DNPEBY		;WRITE THAT EXTENSIBLE BYTE

	MOVX T1,STT.NI		;TYPE IS NODE INIT
	CALL DNP1BY		;WRITE THE BYTE

	MOVE T1,RTRADR		;GET OUR LOCAL ADDRESS
	CALL DNPEBY		;PLACE IN NI MESSAGE

	MOVE T1,RTRADR		;GET OUR LOCAL ADDRESS
	CALL SCTA2N		;GET LOCAL NODE NAME FROM THAT
	TDZA P1,P1		;COULDN'T FIND IT, DON'T SEND A NAME
	MOVE P1,T1		;SAVE NAME
	SETZ P2,		;ZERO BYTES AS OF YET.
	MOVE T3,[POINT 6,P1]	;POINTER TO NODE NAME
	MOVEI T4,6		;MAXIMUM NUMBER OF BYTES TO LOOK AT
	SOJG T4,[ILDB T2,T3	;GET A BYTE
		JUMPE T2,.+1	;IF ZERO, DONE.
		AOJA P2,.]	;LOOK AT NEXT BYTE.
	MOVE T1,P2		;NUMBER OF BYTES IN THE NODE NAME
	CALL DNP1BY		;PLACE THE COUNT IN THE MESSAGE
	MOVE FREE0,[POINT 6,P1]	;BYTE POINTER TO THE NODE NAME
	SOJGE P2,[ILDB T1,FREE0	;GET A BYTE FROM THE NAME
		  ADDI T1,^O40	;MAKE IT ASCII (FROM SIXBIT)
		  CALL DNP1BY	;PLACE IT IN THE MESSAGE
		  JRST .]	; AND CONTINUE UNTIL DONE

	SETZ T1,		;WE DON'T PERFORM ANY FUNCTIONS
	CALL DNPEBY		;WRITE THE FUNCTIONS BYTE
;RTRPH2 - Continued from last page

	SETZ T1,		;SET UP THE REQUESTS BYTE
	SKIPE RTRVRQ		;IS VERIFICATION REQUIRED?
	TXO T1,REVER		;YES, SET THE BIT IN REQUEST BYTE
	CALL DNPEBY		;WRITE THE REQUESTS BYTE

	MOVE T1,RTRBSZ		;GET OUR BLOCKSIZE
	CALL DNP2BY		;WRITE THE BLKSIZE
	MOVE T1,RTRBSZ		;GET OUR BLOCKSIZE
	CALL DNP2BY		;USE IT AS NSPSIZ ALSO (IS THIS OK?)

	SETZ T1,		;NEXT IS NSPVER, AND I DON'T CARE
	CALL DNP2BY		;SO, I'LL SEND THREE ZEROES
	SETZ T1,		;ANOTHER ONE
	CALL DNP1BY		;WRITE IT

	MOVX T1,^D4095		;PUT IN A MAX MAXLINKS
	CALL DNP2BY		;WRITE THE BYTES

	MOVE T1,RTRVER		;GET OUR VERSION
	CALL DNP1BY		;PUT IT IN AS COMVER (VERSION)
	MOVE T1,RTRECO		;GET OUR ECO LEVEL
	CALL DNP1BY		;PUT IT IN AS COMVER (ECO LEVEL)
	MOVE T1,RTRCUS		;GET OUR CUSTOMER ARGUMENT
	CALL DNP1BY		;PUT IT IN AS COMVER (CUSTOMER ARGUMENT)

IFN FTOPS20,<
	SETZ T1,		;IF WE ARE TOPS20, WE WON'T SEND A NAME
	CALL DNP1BY		; SO WRITE A ZERO COUNT
>
IFN FTOPS10,<
	MOVX T1,^D25		;WE'LL SEND ALL OF THE CONFIG TEXT
	CALL DNP1BY		;WRITE THE IMAGE COUNT
	MOVE P1,[POINT 7,CONFIG##] ;POINT TO CONFIGURATION TEXT
	MOVX P2,^D25		;SET UP A COUNT

	SOJGE P2,[ILDB T1,P1	;GET A BYTE FROM CONFIG
		  CALL DNP1BY	;PLACE IT IN THE MESSAGE
		  JRST .]	; AND CONTINUE UNTIL WE USED 32 BYTES
>

;Now send the message

	TRACE RTR,<Sending Phase II Node Init message>
	INCR RCCMQ,(RC)		;INCREMENT NUMBER OF MESSAGES QUEUED
	CALL CALQOB		;SEND IT OUT.
;Now set the reachable bit in the routing vector for the Phase II
;neighbor.

	D36OFF			;TURN OFF INTERRUPTS FOR A BIT
	MOVE P1,RTRNRV		;POINT TO THE NORMAL ROUTING VECTOR
	OPSTR <ADD P1,>,RCNAD,(RC) ;FIND THE PHASE II NEIGHBOR'S ENTRY
	SETONE RNRCH,(P1)	;SAY THAT IT'S REACHABLE
	ADD P1,RTROFS		;CALCULATE OUTPUT VECTOR POINTER
	MOVEM RC,(P1)		; AND STORE THE PTR TO CIRCUIT TO REACH IT ON
	SETZM RTRCKS		;RECALCULATE THE CHECKSUM LATER
	D36ON			;END INTERLOCKED CODE

	MOVX T1,RCS.RN		;NEW STATE WILL BE OK
	STOR T1,RCSTA,(RC)	;STORE IT

	CALLRET RTELUP		;TO SENDER

;Here to back up one byte (over MSGFLG) and forward the Phase II message
;to NSP.

RTRP2F:	LOAD T1,RCNAD,(RC)	;GET THE NEIGHBORS ADDRESS
	STOR T1,MBSRC,(MB)	;IT MUST HAVE COME FROM HIM
	MOVE T1,RTRADR		;GET THE ADDRESS OF US
	STOR T1,MBDST,(MB)	;STORE THAT IN MESSAGE FOR NSP

	MOVX T1,^D1		;MOVE BACK ONE BYTE
	CALL DNBKBY		;GO BACK

	MOVX T3,NV.RCV		;GIVE THE RECIEVED DATA ENTRY
	MOVE T4,MB		;POINT TO MESSAGE WHICH CAME IN
	CALLRET NSPRTR		;CALL NSP
;Here to handle the Phase II Node Verification Message.

RTRP2V:	TRACE RTR,<Phase II Node Verification Message being processed>
	LOAD T1,RCSTA,(RC)	;GET THE CIRCUIT STATE
	CAIE T1,RCS.TV		;ARE WE WAITING FOR THIS NODE VERIFICATION?
	BUG.(CHK,ROUWPV,ROUTER,SOFT,<Phase II Node Verif recieved in wrong state>,,<

Cause:	This BUG is not documented yet.

>,FREMSG)
	CALLRET RTRP2M		;SET OUR ENTRY IN ROUTING VECTOR AND
				; SET STATE TO RUN
	SUBTTL Network Management Interface -- RTNSNT - Set node type

;RTNSNT - Set a node's type in the node type vector
;
; Call:
;	T1/ Node number
;	T2/ Node type (NTV.xx)
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T3
;
;The node type vector is presently used only for one purpose; that is to
;define which nodes in the network are Phase II.  Because messages may
;come from a phase II+ node, looking like Phase III messages, we must have
;some way of knowing that we cannot through them away on a resource
;failure.

RTNSNT::MOVE T3,[POINT NT.WID,RTRNTV] ;MAKE UP BYTE POINTER TO VECTOR
	ADJBP T1,T3		;FIND THE RIGHT ENTRY
	DPB T2,T3		;PLACE THE NEW ONE IN
	RET			; AND RETURN TO USER

	SUBTTL Network Management Interface -- RTNRNT - Read node's type

;RTNRNT - Read a node's type from the node type vector
;
; Call:
;	T1/ Node number
; Return:
;	RET			;ALWAYS, WITH T1 CONTAINING THE NODE TYPE
;
; Uses: T1-T3

RTNRNT::MOVE T3,[POINT NT.WID,RTRNTV] ;MAKE UP THE BYTE POINTER
	ADJBP T1,T3		;FIND THE ENTRY
	LDB T1,T3		;GET THE NODE'S TYPE
	RET			; AND RETURN

	SUBTTL Network Management Interface -- RTNSLS - Set Circuit State

;RTNSLS - Network Management call to set circuit state
;
; Call:
;	T1/ Line id
;	T2/ State to set the circuit to
;
; Return:
;	RET			;COULDN'T PERFORM FUNCTION
;	RETSKP			;NORMAL RETURN
;
; Uses: T1-T4
;
;Note that a circuit does not exist until it has been set on for the first
;time with network management.

RTNSLS::SAVEAC <P1,RC>		;SAVE FOR CIRCUIT STATE, AND RTRGCB
	MOVE P1,T2		;SAVE THE STATE WE WANT
	CALL RTRGCB		;LOAD UP RC WITH CIRCUIT BLOCK
	 RET			;COULDN'T FIND BLOCK

	MOVE T2,P1		;GET STATE WE WANT
	CAXL T2,NCK.ON		;IS THE FUNCTION LESS THAN LOWEST?
	CAXLE T2,NCK.SR		;OR GREATER THAN HIGHEST?
	BUG.(CHK,ROUSOR,ROUTER,SOFT,<Setting state out of range>,,<

Cause:	This BUG is not documented yet.

>,RTN)
	JRST @[IFIW RTNSS1	;DO SET STATE ON
	       IFIW RTNSS3	;DO SET STATE OFF
	       IFIW RTNSS5](T2)	;DO SET STATE SERVICE
;Set the circuit state to ON.

RTNSS1:	LOAD T1,RCSTA,(RC)	;GET THE CURRENT CIRCUIT STATE
	CAIE T1,RCS.TT		;IS IT IN TEST MODE
	CAIN T1,RCS.RN		; OR RUNNING OK?
	RET			;SHOULDN'T BE DOING THIS THEN

	MOVX T1,RCS.WT		;NOW IT'S IN WAIT STATE
	STOR T1,RCSTA,(RC)	;STORE IT
	CALL R2KINI		;RE-START THE DLL
	RETSKP			; AND GIVE GOOD RETURN

;Set the circuit state to OFF.

RTNSS3:	CALL R2KHLT		;TRY TO HALT THIS CIRCUIT
	CALL RTRZCB		;ZAP THE CIRCUIT BLOCK
	SETOM RTRRCF		;FLAG FOR RECOMPUTING
	RETSKP			;AND RETURN

;Set the circuit state to SERVICE.

RTNSS5:	LOAD T1,RCSTA,(RC)	;GET CURRENT STATE
	CAXN T1,RCS.RN		;IS IT RUNNING?
	RET			;YES, TELL HIM WHERE TO GO.
	MOVX T1,RCS.TT		;TEST STATE (SERVICE)
	STOR T1,RCSTA,(RC)	;STORE.
	RETSKP			;AND TELL HIM IT WORKED
	SUBTTL	Network Management Interface -- RTNGLS - Circuit state routine

;RTNGLS - Circuit state routine for NMX
;
;Call
;	T1/ Line-id
;Return
;	RET		;Invalid line-id
;	RETSKP		;T1 contains circuit state in NCK.xx number

RTNGLS::SAVEAC RC		;SAVE CIRCUIT BLOCK POINTER
	CALL RTRGCB		;LOAD UP C WITH CIRCUIT BLOCK
	 RET			;NO SUCH CIRCUIT
	LOAD T1,RCSTA,(RC)	;GET RTR'S VERSION OF CIRCUIT STATE
	CAXL T1,RCS.OF		;IS LESSER THAN MINUMUM
	 CAXLE T1,RCS.RN	;OR GREATER THAN MAX
	  BUG.(CHK,ROUIVL,ROUTER,SOFT,<Invalid circuit state>,,<

Cause:	This BUG is not documented yet.

>,RTN)
	MOVE T1,<-RCS.OF>+[NCK.OF ;RCS.OF
		 NCK.ON		;RCS.WT
		 NCK.ON		;RCS.TI
		 NCK.ON		;RCS.TV
		 NCK.SR		;RCS.TT
		 NCK.ON](T1)	;RCS.RN
	RETSKP
	SUBTTL	Network Management Interface -- RTNGLB - Circuit substate

;RTNGLB - Circuit substate for NMX
;
;Call
;	T1/ Line-id
;Return
;	RET		;no substate for this state
;	RETSKP		;T1 contains substate in NCB.xx number

RTNGLB::SAVEAC RC		;SAVE CIRCUIT BLOCK POINTER
	CALL RTRGCB		;LOAD UP RC WITH CIRCUIT BLOCK
	 RET			;NO SUCH CIRCUIT (SHOULDN'T HAPPEN)
	SETO T1,		;START WITH ILLEGAL SUBSTATE
	LOAD T2,RCSTA,(RC)	;GET RTR'S VERSION OF CIRCUIT STATE
	CAXN T2,RCS.WT		;IS IT WAITING (SYNCHRONIZING)?
	MOVX T1,NCB.SN		; SUBSTATE SYNCH
	CAXE T2,RCS.TI		;SENDING TI'S?
	CAXN T2,RCS.TV		;OR WAITING FOR A VERIFICATION?
	MOVX T1,NCB.ST		; SUBSTATE STARTING
	JUMPL T1,RTN		;IF NO SUBSTATE GIVE NON-SUCCESS RETURN
	RETSKP			;SAY WE HAVE A SUBSTATE.
	SUBTTL Network Management Interface -- RTNLID - Give the line id

;RTNLID - Give the line id for a given node
;
;Call
;	T1/ Node address
;Return
;	RET		;node unreachable
;	RETSKP		;T1 contains line-id

RTNLID::CAMG T1,RTRMXN		;OUT OF RANGE?
	JUMPG T1,RTNLI1	;BELOW RANGE, MAYBE?
	BUG.(CHK,ROUNMR,ROUTER,SOFT,<NMX out of range>,,<

Cause:	This BUG is not documented yet.

>,RTN)
RTNLI1:	ADD T1,RTRNRV		;ADD IN THE VECTOR ADDRESS
	TMNN RNRCH,(T1)		;IS NODE REACHABLE?
	RET			;NOPE, TELL CALLER.
	ADD T1,RTROFS		;NOW POINT TO OUTPUT CIRCUIT VECTOR
	MOVE T1,(T1)		;GET THE OUTPUT CIRCUIT POINTER
	LOAD T1,RCLID,(T1)	;GET LINE ID FROM CIRCUIT BLOCK
	RETSKP			;SUCCESS.

	SUBTTL	Network Management Interface -- RTRNMX - Do circuit functions

;RTRNMX - Do circuit functions for NMX
;
;Call
;	T1/ Line id
;	T2/ 18 bit local pointer to byte pointer withing RC begstr
;	T3/ Pointer to NX block
;Return
;	RET		;
;	RETSKP		;Value in NXVAL,(NX)

RTRNMX::SAVEAC <P1,P2,RC>	;WORK AREA
	SKIPE P1,T2		;IF SECONDS SINCE LAST ZEROED, LEAVE ZERO
	MOVE P1,(T2)		;GET BYTE POINTER
	MOVE P2,T3		;SAVE POINTER TO NX BLOCK
	CALL RTRGCB		;GET CIRCUIT BLOCK POINTER
	 RET			;NO SUCH CIRCUIT
	JUMPE P1,RTNNM3		;SECONDS SINCE LAST ZEROED IS SPECIAL CASED.
	LOAD T2,NXVAL,(P2)	;GET VALUE IN CASE NEEDED
	TMNN NXWRM,(P2)		;ARE WE WRITING ON THE MONITOR?
	JRST RTNNM2		;NOPE, WE ARE ONLY READING
	LDB T1,P1		;GET CURRENT VALUE
	DPB T2,P1		;STORE OUR VALUE ON TOP OF ANYTHING THERE
	RETSKP			;WE FINISHED

RTNNM2:	LDB T1,P1		;GET VALUE FROM CIRCUIT BLOCK
	RETSKP			;RETURN WITH ANSWER IN CORRECT SPOT

RTNNM3:	CALL DNGTIM		;GET CURRENT TIME STAMP.
	TMNE NXZMC,(P2)		;ARE WE ZEROING SECONDS SINCE LAST ZEROED?
	JRST RTNNM4		;YES, GET CURRENT TIME.
	OPSTR <SUB T1,>,RCSLZ,(RC);SUBTRACT LAST TIME STAMP
	IDIVI T1,TIMBAS		;CONVERT TO SECONDS.
	RETSKP			;RETURN SUCCESS.

RTNNM4:	LOAD T2,RCSLZ,(RC)	;GET PREVIOUS TIME
	STOR T1,RCSLZ,(RC)	;STORE CURRENT TIME STAMP.
	SUB T1,T2		;SUBRACT TIME STAMPS
	IDIVI T1,TIMBAS		;AND CONVERT TO SECONDS
	RETSKP			;RETURN SUCCESS, WE DID IT.

RTLBSZ::POINTR(RC.BSZ(RC),RCBSZ)
RTLCST::POINTR(RC.CST(RC),RCCST)
RTLTM3::POINTR(RC.TM3(RC),RCTM3)
RTLTM4::POINTR(RC.TM4(RC),RCTM4)
RTLNAD::POINTR(RC.NAD(RC),RCNAD)
RTLCAP::POINTR(RC.CAP(RC),RCCAP)
RTLCDP::POINTR(RC.CDP(RC),RCCDP)
RTLCAL::POINTR(RC.CAL(RC),RCCAL)
RTLCTR::POINTR(RC.CTR(RC),RCCTR)
RTLCTS::POINTR(RC.CTS(RC),RCCTS)
RTLCTL::POINTR(RC.CTL(RC),RCCTL)
RTLCCD::POINTR(RC.CCD(RC),RCCCD)
RTLCIF::POINTR(RC.CIF(RC),RCCIF)
RTLBYR::POINTR(RC.BYR(RC),RCBYR)
RTLBYS::POINTR(RC.BYS(RC),RCBYS)
RTLDBR::POINTR(RC.DBR(RC),RCDBR)
RTLDBS::POINTR(RC.DBS(RC),RCDBS)

RTNRCH::POINTR(RN.RCH(T2),RNRCH)
RTNLCL::POINTR(RN.LCL(T2),RNLCL)
RTNCST::POINTR(RN.CST(T2),RNCST)
RTNHOP::POINTR(RN.HOP(T2),RNHOP)

	SUBTTL Network Management Interface -- Router Event Types

;These are the various events that occur in router which are reported
;to network management.

DEFINE EVENTS,<
	RE APL,0, NON,RTEPKH	;AGED PACKET LOSS
	RE NUR,1, CKT,RTEPKH	;NODE UNREACHABLE PACKET LOSS
	RE NOR,2, CKT,RTEPKH	;NODE OUT-OF-RANGE PACKET LOSS
	RE OPL,3, CKT,RTEPKH	;OVERSIZED PACKET LOSS
	RE PFE,4, CKT,RTEPKB	;PACKET FORMAT ERROR
	RE PRL,5, CKT,<RTEPKH,RTEHIA> ;PARTIAL ROUTING UPDATE LOSS
	RE VRJ,6, CKT,RTENOD	;VERIFICATION REJECT
	RE LDL,7, CKT,RTEREA	;CIRCUIT DOWN, CIRCUIT FAULT
	RE LDS,8, CKT,<RTEREA,RTEPKH> ;CIRCUIT DOWN, SOFTWARE FAULT
	RE LDO,9, CKT,<RTEREA,RTEPKH,RTEEXN> ;CIRCUIT DOWN, OPERATOR FAULT
	RE LUP,10,CKT,RTENOD	;CIRCUIT UP
	RE IFL,11,CKT,RTEREA	;INITIALIZATION FAILURE, CIRCUIT FAULT
	RE IFS,12,CKT,<RTEREA,RTEPKH> ;INITIALIZATION FAILURE, SOFTWARE FAULT
	RE IFO,13,CKT,<RTEREA,RTEPKH> ;INITIALIZATION FAILURE, OPERATOR FAULT
	RE NRC,14,NOD,RTESTA	;NODE REACHABILITY CHANGE
>


DEFINE RE(EVENT,TYPE,ENTTYP,PARAMS),<
	RE.'EVENT==^D<TYPE>>	;DEFINE THE RE MACRO

;Now expand the symbols.

	EVENTS
;Now define the processor macro.

DEFINE RE(PREFIX,VALUE,ENTTYP,PARAMS),<
	IFIW [MOVX T1,.NT'ENTTYP
	      STOR T1,NEETP,(P1)
	      SETZ T4,		;;INITIALIZE THE COUNT
	IRP <PARAMS>,<
	      CALL PARAMS	;;STICK ON THE PARAMETER DATA
	>
	      STOR T4,NEDLN,(P1) ;;GIVE ARG BLOCK THE LENGTH
	      RET]
>

;Make a table of event processors.

RTETAB:	EVENTS
	RET.LN==.-RTETAB
	RET.MX==<.-RTETAB>-1

	SUBTTL Network Management Interface -- Reason Definitions

;These are the various reasons which may be put in the reason field of
;events that include REASON as a event parameter.

	DEFINE REASON(SUFFIX,VALUE),<
	XP RS.'SUFFIX,^D'VALUE>

	REASON LSL,0		;CIRCUIT SYNCHRONIZATION LOST
	REASON DTE,1		;DATA ERRORS
	REASON UPT,2		;UNEXPECTED PACKET TYPE
	REASON RUC,3		;ROUTING UPDATE CHECKSUM ERROR
	REASON ANA,4		;ADJACENT NODE ADDRESS CHANGE
	REASON VRT,5		;VERIFICATION RECIEVE TIMEOUT
	REASON VSK,6		;VERSION SKEW
	REASON ANO,7		;ADJAGE
	REASON ABS,8		;ADJACENT NODE BLOCK SIZE TOO SMALL
	REASON IVS,9		;INVALID VERIFICATION SEED VALUE
	REASON ALT,10		;ADJACENT NODE LISTENER RECEIVE TIMEOUT
	REASON ALI,11		;ADJACENT NODE LISTENER RECEIVED INVALID DATA

	PURGE REASON

	SUBTTL Network Management Interface -- RTNEVT - Event Reporter

;RTNEVT - Report Router event
;
; Call:
;	T1/ Event type
;	T2/ Entity ID (we know the entity type from RTETAB)
;	T3/ Event specific word (REASON, STATUS, etc.)
;	T4/ Message Block Pointer or zero if none given
;		(Message Block must be DNGINIized before this is called)
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T4
;
;This calls something which will call network management to log this event
;which has taken place.  This routine is called by the EVENT macro.

	XP EVTMLN,^D15		;MAXIMUM LENGTH OF EVENT PARAMETER DATA (BYTES)

RTNEVT:	SAVEAC <P1,P2,MB,MS>	;SAVE SOME ACS
	SKIPL P2,T1		;RANGE CHECK THE
	CAILE P2,RET.MX		;EVENT TYPE
	BUG.(CHK,ROUUET,ROUTER,SOFT,<Unknown event type in RTNEVT>,,<

Cause:	This BUG is not documented yet.

>,RTN)

	MOVE P1,T2		;SAVE THE ENTITY-ID
	MOVEM T3,RTREVW		;SAVE THE EVENT ARGUMENT [**FIX THIS**]
	SKIPN MB,T4		;SET UP MESSAGE BLOCK (IF ANY)
	JRST RTNEV1		;NOT THERE, DON'T TRY TO SET POSITION
	JE RMMK1,(MB),RTNEV1	;IF NO ROUTER HEADER, THEN SKIP THIS

	MOVE T1,MB		;PASS POINTER TO MESSAGE BLK TO DNGINI
	XMOVEI MS,RM.MSD(MB)	;POINT AT THE ROUTER MSD
	TMNE RMICP,(MB)		;WAS THIS FROM THE LOCAL NSP?
	XMOVEI MS,IN.MSD(MB)	;NO, POINT AT INPUT MSD
	MOVX T1,<POINT 8,(T6)>	;VGNPTR. START AT BEGINNING OF MSD
	STOR T1,MDPTR,(MS)	;STORE AS CURRENT POSITION IN MSD.
	LOAD T1,RMMK1,(MB)	;GET ROUTER MARK
	STOR T1,MDBYT,(MS)	;SAVE AS NUMBER OF BYTES LEFT TO DO.

RTNEV1:	MOVX T1,NE.LEN+<<EVTMLN+3>/4> ;GET ENOUGH FOR ARG BLOCK AND
				; MAXIMUM AMOUNT OF EVENT PARAMETER DATA
	CALL DNGWDZ		;GET THE WORDS
	 BUG.(CHK,ROUCGV,ROUTER,SOFT,<Couldn't get memory for event arg block>,,<

Cause:	This BUG is not documented yet.

>,RTN)
	STOR P1,NEEID,(T1)	;PUT ENTITY-ID IN EVENT BLOCK
	MOVE P1,T1		;SAVE THE POINTER TO THE BLOCK
	STOR P2,NECTY,(P1)	;PUT THE EVENT TYPE IN THE ARG BLOCK
	MOVX T1,.NCRTR		;THE EVENT CLASS IS ROUTER
	STOR T1,NECCL,(P1)	;PUT IN NE ARG BLOCK
	XMOVEI T1,NE.LEN(P1)	;MAKE A FULLWORD POINTER TO DATA
	STOR T1,NEDAT,(P1)	;STORE POINTER TO IT IN ARG BLOCK
	MOVE T1,[POINT 8,NE.LEN(P1)] ;MAKE UP BYTE POINTER TO PARAMETER DATA
	EXCH T1,P2		;SWITCH FUNCTION AND POINTER
	CALL @RTETAB(T1)	;CALL THE PARAMETER PROCESSOR
	JN NEEID,(P1),RTNEV2	;IF THERE IS AN ENTITY ID, GIVE IT TO NTMAN
	SETONE NEETP,(P1)	;BE NICE TO SPEAR. IF NO ENTITY, SAY NONE.

RTNEV2:	MOVE T1,P1		;POINT TO THE ARG BLOCK
	CALL NMXEVT		;GIVE THE EVENT
	 JFCL			;SO WHAT IF THE EVENT GETS LOST
	MOVE T1,P1		;GET POINTER TO BLOCK
	CALLRET DNFWDS		;RETURN THE BLOCK OF CORE

	SUBTTL Network Management Interface -- Event Parameter Processors

;Put a packet header in the NE argument block string.  This corresponds to
;parameter 0 for circuit events.


RTEPKH:	SKIPN MB		;MUST HAVE A MESSAGE BLOCK HERE
	BUG.(CHK,ROUEHM,ROUTER,SOFT,<No Message Block for Event data>,,<

Cause:	This BUG is not documented yet.

>,RTN)
	JE RMMK1,(MB),RTEPKB	;NO ROUTER HEADER, THEN DON'T PUT A BLOCK 0 ON
	MOVEI T1,0		;GET PARAMETER NUMBER
	MOVEI T2,2		;GET NUMBER OF BYTES
	CALL PUTNBT		;INSTALL THE BYTES SWAPPED

	CALL DNG1BY		;GET THE "FIRST" BYTE FROM RTR MESSAGE
	 RET			;COULND'T GET IT, JUST RETURN
	PUSH P,T1		;SAVE MESSAGE FLAGS FOR LATER
	TXNE T1,RM%CTL		;WAS IT A CONTROL MESSAGE?
	SKIPA T1,[302]		;YES, CODED MULTIPLE, TWO FIELDS
	MOVEI T1,304		; NO, CODED MULTIPLE, FOUR FIELDS
	CALL PUTBYT		;INSTALL DATA TYPE
	MOVEI T1,041		;NOT CODED, HEX NUMBER OF 1 BYTE
	CALL PUTBYT		;INSTALL IT
	MOVE T1,0(P)		;GET BACK THE REAL DATA
	CALL PUTBYT		;OUTPUT IT

	TXNE T1,RM%CTL		;IS IT A CONTROL MESSAGE???
	JRST RTEPK1		;YES, SKIP THIS
	MOVEI T1,002		;DECIMAL UNSIGNED, TWO BYTES
	CALL PUTBYT		;OUTPUT THE DATA TYPE
	MOVEI T2,2		;NUMBER OF BYTES TO TRANSFER
	CALL PUTNBY		;PUT DESTINATION NODE ADDRESS INTO DATA STRING

RTEPK1:	MOVEI T1,002		;DECIMAL UNSIGNED, TWO BYTES
	CALL PUTBYT		;STUFF IT
	MOVEI T2,2		;NUMBER OF BYTES TO TRANSFER
	CALL PUTNBY		;INSTALL FOURCE NODE ADDRESS

	POP P,T1		;GET BACK MESSAGE HEADER
	TXNE T1,RM%CTL		;IS IT A CONTROL MESSAGE
	JRST RTN		;YES, SKIP THIS ONE TOO
	MOVEI T1,041		;NOT CODED, HEX NUMBER OF 1 BYTE
	CALL PUTBYT		;STUFF IT
	MOVEI T2,1		;TRANSFER ONE BYTE
	CALL PUTNBY		;DO THE TRANSFER
	RET			;WE RETURN ANYWAY
;Put a packet beginning in the NE argument block string.

RTEPKB:	SKIPN MB		;MUST HAVE A MESSAGE BLOCK HERE
	BUG.(CHK,ROUEHB,ROUTER,SOFT,<No Message Block for Event data>,,<

Cause:	This BUG is not documented yet.

>,RTN)
	MOVEI T1,1		;GET PARAMETER NUMBER
	MOVEI T2,2		;GET NUMBER OF BYTES
	CALL PUTNBT		;INSTALL THE BYTES SWAPPED

	MOVEI T1,040		;NOT CODED, HEX IMAGE
	CALL PUTBYT		;INSTALL DATA TYPE
	MOVEI T1,6		;LENGTH OF DATA IS ALWAYS 6 BYTES
	CALL PUTBYT		;INSTALL LENGTH OF DATA
	MOVX T2,6		;WE ALWAYS WANT SIX BYTES
	CALL PUTNBY		; PUT THEM IN THE NE BLOCK
	 JFCL			;DON'T REALLY CARE
	RET			; AND RETURN

;Put the Highest Address in the NE argument block string.

RTEHIA:	MOVEI T1,2		;GET PARAMETER NUMBER
	MOVEI T2,2		;GET NUMBER OF BYTES
	CALL PUTNBT		;INSTALL THE BYTES SWAPPED

	MOVEI T1,002		;DECIMAL UNSIGNED, TWO BYTES
	CALL PUTBYT		;OUTPUT IT
	MOVEI T2,2		;MOVE TWO BYTES
	CALLRET PUTNBY		;COPY HIGHEST ADDRESS

;Put a node address in the NE argument block string.

RTENOD:	MOVEI T1,3		;GET PARAMETER NUMBER
RTEEX1:	MOVEI T2,2		;GET NUMBER OF BYTES
	CALL PUTNBT		;INSTALL THE BYTES SWAPPED

	MOVEI T1,301		;CODED MULTIPLE, ONE FIELD
	CALL PUTBYT		;INSTALL DATA TYPE
	MOVEI T1,002		;DECIMAL UNSIGNED, TWO BYTES
	CALL PUTBYT		;INSTALL SUB-DATA TYPE
	MOVE T1,RTREVW		;GET THE NODE NUMBER [**FIX THIS**]
	MOVEI T2,2		;NODE NUMBER IS TWO BYTES
	CALLRET PUTNBT		;PUT THE NUMBER IN THE MESSAGE

;Put the Expected Node in the NE argument block string.

RTEEXN:	LOAD T1,RCNAD,(RC)	;GET THE ADJACENT NODE
	MOVEM T1,RTREVW		;SAVE FOR RTEEX1 [**FIX THIS**]
	MOVEI T1,4		;GET PARAMETER NUMBER
	JRST RTEEX1		;OTHEWISE, SAME AS NODE

;Put the REASON type in the NE argument block string.

RTEREA:	MOVEI T1,5		;GET PARAMETER NUMBER
RTEST1:	MOVEI T2,2		;GET NUMBER OF BYTES
	CALL PUTNBT		;INSTALL THE BYTES SWAPPED

	MOVEI T1,201		;CODED, SINGLE FIELD, LENGTH 1 BYTE
	CALL PUTBYT		;STUFF IT

	MOVE T1,RTREVW		;GET THE REASON [**FIX THIS**]
	CALLRET PUTBYT		;STUFF IT AND RETURN

;Put the status in the NE argument block.  This is a one byte field
;which we have in RTREVW, so just use RTEREA.

RTESTA:	MOVEI T1,7		;GET PARAMETER NUMBER
	JRST RTEST1		;STATUS PARAM IS JUST LIKE REASON


	SUBTTL Network Management Interface -- Event Processor Subroutines

;Put n (in T2) bytes in the string pointed to by the NE argument block.
;It also updates T4, which is the count of bytes put in so far.

PUTNBY:	JUMPE T2,RTN		;RETURN IF NO MORE BYTES LEFT
	CALL DNG1BY		;GET ONE BYTE FROM THE MESSAGE BLOCK
	 RET			;PROPAGATE FAILURE
	IDPB T1,P2		;STORE THE BYTE IN SOME SPACE
	ADDI T4,1		;UPDATE THE GLOBAL COUNT
	SOJA T2,PUTNBY		;SEE IF WE HAVE TO PUT IN MORE

;Put n (in T2) bytes of the number in T1.

PUTNBT:	JUMPE T2,RTN		;RETURN IF NOTHING LEFT
	IDPB T1,P2		;PUT THE BYTE IN THE MESSAGE
	LSH T1,-^D8		;SHIFT OVER TO THE NEXT BYTE
	ADDI T4,1		;UPDATE THE COUNT
	SOJA T2,PUTNBT		;DO THE REST

;Put one byte (in T1) into the data string for network management

PUTBYT:	IDPB T1,P2		;INSTALL THE BYTE
	AOJA T4,RTN		;INCREMENT THE NUMBER OF BYTES
	SUBTTL Network Management Interface -- Miscellaneous Event Processors

;These are a bunch of routines to report different events.  The events
;here are common to more than one routine, so they are collected
;together in this section.

;RTEMFE - Report Message Format Error Event

RTEMFE:	LOAD T2,RCLID,(RC)	;GET THE LINE ID FOR ENTITY ID
	EVENT RE.PFE,<Packet format error event>,MB
	CALLRET FREMSG		;FREE MSG BLK AND RETURN


;RTEVRJ - Report Verficiation Reject Event

RTEVRJ:	LOAD T2,RCLID,(RC)	;GET THE ENTITY ID (CIRCUIT)
	LOAD T3,RCNAD,(RC)	; AND THE NEIGHBOR'S ADDRESS
	EVENT RE.VRJ,<Verification reject event>
	CALLRET FREMSG		;FREE MSG BLK AND RETURN

;RTELDL - Report Circuit Down, Hard Circuit Fault Event

RTELDL:	MOVE T3,T1		;GET THE REASON
	LOAD T2,RCLID,(RC)	;GET THE LINE ID
	EVENT RE.LDL,<Circuit down, circuit fault>
	INCR RCCCD,(RC)		;INCREMENT THE CIRCUIT DOWN COUNTER
	RET			;RETURN, NO MSG TO FREE HERE

;RTELDS - Report Circuit Down, Software Fault Event

RTELDS:	MOVE T3,T1		;GET THE REASON
	LOAD T2,RCLID,(RC)	;GET THE LINE ID
	EVENT RE.LDS,<Circuit down, software fault>,MB
	INCR RCCCD,(RC)		;INCREMENT THE CIRCUIT DOWN COUNTER
	CALLRET FREMSG		;FREE MSG BLK AND RETURN

;RTELDO - Report Circuit Down, Operator Fault Event

RTELDO:	MOVE T3,T1		;GET THE REASON
	LOAD T2,RCLID,(RC)	;GET THE LINE ID
	EVENT RE.LDO,<Circuit down, operator fault>,MB
	INCR RCCCD,(RC)		;INCREMENT THE CIRCUIT DOWN COUNTER
	CALLRET FREMSG		;FREE MSG BLK AND RETURN
;Event Processors - Continued from last page

;RTELUP - Report circuit up
RTELUP:	LOAD T2,RCLID,(RC)	;GET THE ENTITY ID (CIRCUIT)
	LOAD T3,RCNAD,(RC)	; AND THE NEIGHBOR'S ADDRESS
	EVENT RE.LUP,<Circuit Up>
	RET			;AND RETURN


;RTEINL - Report Initialization Failure, Hard Circuit Fault Event

RTEINL:	MOVE T3,T1		;GET THE REASON
	LOAD T2,RCLID,(RC)	;GET THE LINE ID
	EVENT RE.IFL,<Initialization failure, circuit fault>
	INCR RCCCD,(RC)		;INCREMENT THE CIRCUIT DOWN COUNTER
	RET			;RETURN, NO MSG BLK TO FREE HERE

;RTEINS - Report Initialization Failure, Software Fault Event

RTEINS:	MOVE T3,T1		;GET THE REASON
	LOAD T2,RCLID,(RC)	;GET THE LINE ID
	EVENT RE.IFS,<Initialization failure, software fault>,MB
	INCR RCCCD,(RC)		;INCREMENT THE CIRCUIT DOWN COUNTER
	CALL FREMSG		;FREE MSG BLK AND RETURN
	CALLRET R2KINI		;RE-INITIALIZE THE DLL

;RTEINO - Report Initialization Failure, Operator Fault Event

RTEINO:	MOVE T3,T1		;GET THE REASON
	LOAD T2,RCLID,(RC)	;GET THE LINE ID
	EVENT RE.IFO,<Initialization failure, operator fault>,MB
	INCR RCCCD,(RC)		;INCREMENT THE CIRCUIT DOWN COUNTER
	CALL FREMSG		;FREE MSG BLK AND RETURN
	CALLRET R2KINI		;RE-INITIALIZE THE DLL
	SUBTTL Miscellaneous Routines -- RTRZCB - Zap Circuit Block

;RTRZCB - Zap circuit block and report circuit down event
;
; Call:
;	RC/ Pointer to circuit block
;
; Return:
;	RET			;ALWAYS
;
;This routine clears out a circuit block (usually when it goes down),
;and returns any messages which may have been queued up on it.

RTRZCB:	LOAD T1,RCLRM,(RC)	;POINTER TO LAST ROUTING MESSAGE
	SKIPE T1		;IF WE HAVE ONE
	CALL DNFMSG		;FREE IT

RTRZC1:	D36OFF			;RETURN ALL BUFFERS ON THE QUEUE.
	DEQUE T3,RC.JSQ(RC),MB.NXT,RTRZC2
	D36ON
	CALL RTIOTC		;CALL OUTPUT INCOMPLETE.
	JRST RTRZC1		;AND LOOP

RTRZC2:	D36ON			;CANCEL D36OFF FROM RTRZC1

	SETZRO <RCNAD,RCLRM,RCTLR,RCFLG>,(RC) ;CLEAR A BUNCH OF FIELDS:
				;  NEIGHBOR,
				;  LAST ROUTING MESSAGE,
				;  TIME OF LAST ROUTING MESSAGE,
				;  AND FLAGS.

	RET			;RETURN TO SENDER
	SUBTTL Miscellaneous Routines -- RTRMCB - Make a Circuit Block

;RTRMCB - Make a new circuit block and store the defaults
;
; Call:
;	T1/ Line id
;
; Return:
;	RET			;COULDN'T ALLOCATE BLOCK
;	RETSKP			;EVERYTHING WORKED, T1 CONTAINING CIRCUIT BLOCK
;				; POINTER
; Uses: T1-T4

RTRMCB:	SAVEAC P1		;SAVE A PEA
	MOVE P1,T1		;SAVE THE LINE ID
	MOVX T1,RC.LEN		;GET THE LENGTH OF A CIRCUIT BLOCK
	CALL DNGWDZ		;GET THAT MANY WORDS
	 RET			;RETURN A FAILURE

	STOR P1,RCLID,(T1)	;STORE THE LINE ID

	MOVX T2,%RTTM3		;GET THE DEFAULT HELLO MESSAGE TIMER VALUE
	STOR T2,RCTM3,(T1)	;STORE IT IN THE CIRCUIT BLOCK
	MOVX T2,%RTTM4		;GET THE DEFAULT LISTENER TIME-OUT VALUE
	STOR T2,RCTM4,(T1)	;STORE IT IN THE CIRCUIT BLOCK
	MOVX T2,%RTCST		;GET DEFAULT COST FOR A CIRCUIT
	STOR T2,RCCST,(T1)	;STORE IT IN THE CIRCUIT BLOCK
	MOVX T2,RCS.OF		;INITIAL STATE WILL BE "OFF"
	STOR T2,RCSTA,(T1)	;STORE STATE CODE

	MOVE P1,T1		;SAVE THE CIRCUIT BLOCK POINTER
	AOS RTRNLN		;INCREMENT THE NUMBER OF CIRCUITS
	MOVX T1,2		;GET NEW EMERGENCY BUFFERS FOR THIS CIRCUIT
	CALL DNGEBF		;1 FOR KEPT ROUTING MSG, 1 FOR ROUTE-THROUGH
	 BUG.(CHK,ROUCGE,ROUTER,SOFT,<Couldn't get emergency buffer for circuit>,,<

Cause:	ROUTER requires that the memory manager save at least 2 buffers
	per link for ROUTER, one for the routing message ROUTER keeps for
	each circuit and one to guarantee some level of route-through ability.
	ROUTER was asked to open a circuit, but the memory manager could
	not guarantee the buffers.

Cure:	Allocate more memory or settle for fewer circuits.

>)
	CALL DNGTIM		;GET CURRENT TIME OF DAY
	STOR T1,RCSLZ,(P1)	;STORE FOR USE BY SECONDS SINCE LAST ZEROED
	MOVE T1,P1		;RETURN THE CIRCUIT BLOCK POINTER IN T1
	RETSKP			;RETURN SUCCESS
	SUBTTL Miscellaneous Routines -- RTRGCB - Get Circuit Block Pointer

;RTRGCB - Get circuit block pointer from line id
;
; Call:
;	T1/ Line id
;
; Return:
;	RET			;WHEN WE COULDN'T FIND A MATCH
;	RETSKP			;WHEN SUCCESSFUL, WITH C POINTING TO THE
;				; CIRCUIT BLOCK
;
; Uses: T1,T2
;
;There aren't that many circuits, so a simple search is not too bad.

RTRGCB:	SKIPN RC,RTRCBQ		;START LOOKING AT FIRST CIRCUIT
	RET			;NONE THERE, JUST RETURN
RTRGC1:	LOAD T2,RCLID,(RC)	;GET IT'S LINE ID
	CAMN T1,T2		;IS IT THE ONE WE'RE LOOKING FOR?
	RETSKP			;GOOD RETURN (I SKIP OVER RETSKPS
				; IF YOU DON'T LIKE THAT CHANGE IT)
	LOAD RC,RCNXT,(RC)	;GET THE NEXT CIRCUIT BLOCK
	JUMPN RC,RTRGC1		;GO CHECK IT OUT
	RET			;COULDN'T FIND IT, OH WELL

;Routine used by network management to load up RCKBA before calling KONDSP
RTRKBA::SAVEAC RC		;PRESERVE
	CALL RTRGCB		;FIND THE CIRCUIT BLOCK
	 RET			;FAILED
	LOAD T2,RCKBA,(RC)	;GET THE KONTROLLER BLOCK ADDRESS
	RETSKP

	SUBTTL Miscellaneous Routines -- CPYMSG - Copy all MSDs together

;CPYMSG - Gather all the MSDs into one (IN.MSD) in a new message block
;
; Call:
;	MB/ Pointer to message block to make a copy of
;
; Return:
;	RET			;ON FAILURE
;	RETSKP			;DONE, WITH T1 POINTING TO THE NEW MESSAGE
;
; Uses: T1-T4
;
;Only the portions of the message block which are relavent to Router
;are copied, because the copied message will be sent to NSP, which
;believes that the message has come in over the network.

CPYMSG:	CALL DNCPMS		;COPY MB'S MSDs INTO A NEW BLOCK
	  RET			;PROPOGATE ERROR
				;T1 POINTS TO NEW MSG BLK

;Now copy all the relavent fields.

	LOAD T2,RMFST,(MB)	;GET THE FIRST BYTE
	STOR T2,RMFST,(T1)	; AND COPY IT
	LOAD T2,RMOCP,(MB)	;GET THE OUTPUT CIRCUIT
	STOR T2,RMOCP,(T1)	; AND COPY IT
	LOAD T2,RMICP,(MB)	;GET THE INPUT CIRCUIT
	STOR T2,RMICP,(T1)	; AND COPY IT (MONOTONOUS, ISN'T IT)
	LOAD T2,MBSRC,(MB)	;GET SOURCE NODE ADDRESS
	STOR T2,MBSRC,(T1)	; AND COPY IT INTO THE NEW COPY
	LOAD T2,MBDST,(MB)	;GET THE DESTINATION NODE ADDRESS
	STOR T2,MBDST,(T1)	; AND COPY IT INTO THE NEW COPY
	RETSKP			;RETURN SUCCESS, T1 PTS TO NEW MSG BLK

	SUBTTL Miscellaneous Routines -- FREMSG - Toss a Message

;FREMSG - Return an unwanted message to rightful sink
;
; Call:
;	MB/ Pointing to Message Block
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T6

FREMSG:	SKIPN T1,MB		;GET POINTER TO MESSAGE BLOCK
	BUG.(CHK,ROUZXT,ROUTER,SOFT,<Tried to free msg with MB=0>,,<

Cause:	This BUG is not documented yet.

>,RTN)

	TMNE RMODN,(MB)		;DOES NSP WANT THIS BACK?
	CALLRET R2NODN		;YES, GO GIVE "OUTPUT DONE"
				;NO, GIVE MSG TO MEMORY MANAGER
	TRASH MB,		;JUST CAREFUL
	CALLRET DNFMSG		;FREE MESSAGE T1 POINTS TO
	SUBTTL Miscellaneous Routines -- CKSNRM - Normalize Checksum

;CKSNRM - Make full word checksum into 16 bit checksum
;
; Call:
;	T1/ Full word checksum
;
; Return:
;	RET			;WITH T1 CONTAINING THE 16 BIT CHECKSUM
;
; Uses: T1-T2

CKSNRM:	MOVE T2,T1		;GET A COPY OF THE CHECKSUM
	TDZE T2,[EXP ^-177777]	;IF ANY OVERFLOW, CLEAR IT
	JRST [LSH T1,-^D16	;ADD OVERFLOW BACK INTO
	      ADDB T2,T1	; THE LOW ORDER BYTES
	      JRST .-1]		;LOOP UNTIL DONE
	RET			;RETURN

	SUBTTL Local Router Storage

	$LOW			;IMPURE STORAGE

RTRNRV::BLOCK 1			;"NORMAL" ROUTING VECTOR
RTRNOV::BLOCK 1			;"NORMAL" OUTPUT-CIRCUIT VECTOR
RTROFS::BLOCK 1			;OFFSET FROM NRV TO NOV
RTRSRV:	BLOCK 1			;"SCRATCH" ROUTING VECTOR
RTRSOV:	BLOCK 1			;"SCRATCH" OUTPUT-CIRCUIT VECTOR
RTRNTV:	BLOCK 1			;NODE TYPE VECTOR
RTRMXN::%RTMXN			;MAXIMUM NODE NUMBER
RTRCBQ::BLOCK QH.LEN		;CIRCUIT BLOCK QUEUE HEADER
RTRNLN::BLOCK 1			;NUMBER OF CIRCUITS IN USE
RTRMXC::%RTMXC			;MAXIMUM CIRCUIT COST
RTRMXH::%RTMXH			;MAXIMUM HOPS
RTRMXV::%RTMXV			;MAXIMUM VISITS
RTRRCF:	BLOCK 1			;RECOMPUTE ROUTING FLAG
RTRVRQ::BLOCK 1			;VERIFICATION REQUIRED FLAG
IFN FTOPS10,RTRADR::%RTADR	;OUR LOCAL ADDRESS
IFN FTOPS20,RTRADR::EXP 0	;OUR LOCAL ADDRESS, SET AT RUN TIME
RTRCKS: BLOCK 1			;CHECKSUM OF ROUTING MESSAGE
RTRTYP::EXP 0			;OUR TYPE OF NODE IS ROUTING.
RTRTM1::%RTTM1			;"SHORT" TIMER
RTRITM::%RTITM			;MAX TIME ALLOWED FROM PROTOCOL UP AND TI RCVD
RTRBSZ::%RTBSZ			;OUR BLOCKSIZE
RTRVER::%RTVER			;VERSION OF OUR ROUTER
RTRECO::%RTECO			;EDIT LEVEL OF RTR
RTRCUS::%RTCUS			;CUSTOMER ARGUMENT
RTRRSQ: BLOCK QH.LEN		;RESEND QUEUE HEADER
RTRSSV:	BLOCK 1			;ONCE-A-SEC SERVICE NEEDED FLAG
RTREVW: BLOCK 1			;EVENT WORD (PLACE TO KEEP REASON, NODE, ETC.)
				;[**FIX THIS**]. THIS CAN'T BE AN UNINTERLOCKED
				;[**FIX THIS**]  WORD. MOVE TO STACK.
				;NODE COUNTERS:
RTRCAP::BLOCK 1			; (900) AGED PACKET LOSS
RTRCNU::BLOCK 1			; (901) NODE UNREACHABLE PACKET LOSS
RTRCNO::BLOCK 1			; (902) NODE OUT-OF-RANGE PACKET LOSS
RTRCOP::BLOCK 1			; (903) OVERSIZED PACKET LOSS
RTRCPF::BLOCK 1			; (910) PACKET FORMAT ERROR
RTRCPR::BLOCK 1			; (920) PARTIAL ROUTING UPDATE LOSS
RTRCVR::BLOCK 1			; (930) VERIFICATION REJECT

	$HIGH			;BACK TO THE PURE SEGMENT
	SUBTTL End of ROUTER

IFN FTOPS10, .XCMSY             ;.XCREF SOME MACSYM SYMBOLS
IFN FTOPS20, TNXEND		;TOPS-20 ENDING

	END