	.TITLE	RTRRSX MA ROUTER RSX VERSION
	.IDENT	/1.6/
;
; This is the code for the MA_ROUTER RSX version.
;
; UPDATES:
;
;	03/12/87  D. LUECK   VERSION 1.1
;	Added support to translate a logical node name into 
;	an actual node name used for the service.
;
;	03/17/87  D. LUECK   VERSION 1.2
;	Added support to log all state changes (i.e. connect/disconnect)
;	to the queue (message id NET_STATUS).
;
;	05/18/87  D. LUECK   VERSION 1.3
;	Added support to reject a connect request if accept of the connect
;	request results in a bad I/O status.
;
;	06/08/87  D. LUECK   VERSION 1.4
;	Added additional support for V1.3 implementation.  The reject of
;	a connect request in V1.3 did not work properly.  A network message
;	buffer was added to each NRB defined in the database to save the connect
;	block received in the mail buffer by GND$.  The accept connection
;	AST routine did not have a valid temporary link address in the connect 
;	block to reject the connect request -- probably lost when GND$ dequeued 
;	another network message into the same mail buffer.
;
;	06/09/87  D. LUECK   VERSION 1.5
;	The invalid temporary link address mentioned in V1.4 change was caused 
;	by passing a connect block size of 0 to REJECT.  Although a save buffer
;	was not needed to save the connect block, it was retained to avoid 
;	any future problems.
;	
;	10/08/87  D. LUECK   VERSION 1.6
;	Added retry counter to 'read message from queue' function in routine
;	GETOUT.  The counter uses the last two bits (14 and 15) of word
;	NID.ST in the routing database.  This counter was added because
;	the test for messages in a queue (M.CNT offset in queue listhead)
;	indicated at least one message, but a 'no messages in queue' error
;	(IE.EOF) was returned from the QUEACP when a read was attempted.  No
;	reason for the error could be detected at this time and the affected
;	queue does not appear to be corrupted.
;	
;
; SYSTEM MACROS
;
	.MCALL	WTLO$	; WAIT FOR LOGICAL OR OF EVENT FLAGS
	.MCALL	SETF$	; SET SINGLE EVENT FLAG
	.MCALL	MRKT$	; MARK TIME 
	.MCALL	CMKT$S	; CANCEL MARK TIME REQUEST
	.MCALL	WTSE$S	; WAIT FOR SINGLE EVENT FLAG
	.MCALL	GTIM$	; GET SYSTEM TIME 
	.MCALL	SETF$S	; SET SINGLE EVENT FLAG
	.MCALL	RDAF$	; READ ALL EVENT FLAGS
	.MCALL	QIOSY$	; DEFINE ALL THE FUNCTION CODES
	.MCALL	WTSE$S	; WAIT FOR SINGLE EVENT FLAG
	.MCALL	CLEF$S	; CLEAR EVENT FLAG
	.MCALL	SRDA$S	; SPECIFY RECIEVE DATA AST
	.MCALL	DIR$	; DIRECTIVE CALL
	.MCALL	QIO$	; QIO CALL
	.MCALL	QIOW$	; QIO AND WAIT CALL
	.MCALL	ASTX$S	; AST EXIT
	.MCALL	SREX$S	; SPECIFY REQUESTED EXIT AST
	.MCALL	RQST$	; RUN A TASK
	.MCALL	ATRG$	; ATTACH TO REGION
	.MCALL	CRAW$	; CREATE ADDRESS WINDOW
	.MCALL	DTRG$S	; DETACH REGION
	.MCALL	SVTK$S	; SPECIFY SST VECTOR TABLE
	.MCALL	SNPBK$	; ALLOCATE SNAPSHOT DUMP CONTROL BLOCK
	.MCALL	SNAP$	; GENERATE SNAPSHOT DUMP
	.MCALL	EXIT$S	; TASK EXIT
	.MCALL	ALUN$	; ASSIGN LOGICAL UNIT NUMBER
	.MCALL	DSAR$S	; DISABLE AST RECOGNITION
	.MCALL	ENAR$S	; ENABLE AST RECOGNITION
;
; EQUATES
;
;DEBUG=1		; DEFINE SYMBOL TO PRINT DEBUG MESSAGES
;
ICO=1	; CONSOLE DEVICE
IZQ=2	; QUEUE DEVICE DRIVER
INET=3	; NETWORK MESSAGES 
;   LUNS 4... TO N+3 WHERE N= NUMBER OF NODES ARE THE
;		LUNS ASSIGNED TO THE TASK ON THE REMOTE NODES
;
; EVENT FLAGS
;
NETEFN=5	; EVENT FLAG TO SET WHEN NETWORK MESSAGE (NOT NORMAL
						; TASK TO TASK MESSAGE)
CONEFN=6	; EVENT FLAG TO SET WHEN CONSOLE I/O COMPLETE
SNPEFN=7	; EVENT FLAG TO SYNCHRONIZE SST HANDLER AND PMD
WAKEFN=8.	; WAKE UP EVENT FLAG
QUEEFN=9.	; USED FOR ACCESSING THE QUEUE
MRKEFN=10.	; USED BY MARK TIME DIRECTIVE
WATEFN=11.	; USED BY TASK FOR QIO'S THAT ARE TO COMPLETE SYNCHRONOUSLY
;
;
; QUEUE FILE MACROS (QUEUE.MLB)
;
	.MCALL	HDRDEF	; MESSAGE HEADER OFFSETS
	.MCALL	QHDDEF	; QUEUE HEADER OFFSETS
	.MCALL	MIDDEF	; MESSAGE ID LIST HEAD DEFINITIONS
	.MCALL	RTRHED	; ROUTER DATABASE HEADER DEFINITIONS
	.MCALL	NRBDEF	; DEFINE NRB OFFSETS
	.MCALL	OUTDEF	; OUTPUT BUFFER OFFSETS
	.MCALL	RSPDEF	; RESPONSE BUFFER OFFSETS
	.MCALL	EVTDEF	; EVENT QUEUE ENTRY DEFINITONS
	.MCALL	MGHDEF	; MESSAGE DEFINITION BETWEEN ROUTERS
	.MCALL	STADEF	; CONNECT/DISCONNECT MESSAGE OFFSETS
;
; NETWORK MACROS
;
	.MCALL 	CNBDF$	; CONNECT BLOCK DEFINITIONS
	.MCALL	SPAW$	; SPECIFY NETWORK MESSAGES AST
	.MCALL	GLNW$	; GET LOCAL NETWORK INFORMATION
	.MCALL	OPNW$	; OPEN LUN TO NETWORK
	.MCALL	GNDW$	; GET NETWORK DATA
	.MCALL	NETDF$	; NETWORK SYMBOLIC OFFSETS
	.MCALL	ACC$S	; ACCEPT CONNECT REQUEST
	.MCALL	REJ$S	; REJECT CONNECT REQUEST
	.MCALL	REC$	; RECEIVE DATA OVER NETWORK LOGICAL LINK
	.MCALL	SND$	; SEND DATA OVER NETWORK LOGICAL LINK
	.MCALL	CON$	; CONNECT REQUEST
	.MCALL	DSC$S	; DISCONNECT LOGICAL LINK
	.MCALL	DSC$
;
; INVOKE SOME OF THE MACROS TO DEFINE OFFSETS
;
	QIOSY$
	NETDF$
	CNBDF$
;
	.LIST	ME
	HDRDEF
	QHDDEF
	MIDDEF
	RTRHED
	NRBDEF
	OUTDEF
	RSPDEF
	EVTDEF
	MGHDEF
	STADEF
	.NLIST	ME
	.PAGE
	.PSECT	$DATA,D,CON,LCL,REL
;
; DIRECTIVES AND THE LIKE
;
;
; DPB'S TO CREATE AND MAP REGION FOR OUR QUEUE HEADER
;
CRWND:
	CRAW$	WDB	; CREATE ADDRESS WINDOW
;
; WINDOW DESCRIPTOR BLOCK
;
WDB:
	.BYTE	0	; UNUSED
	.BYTE	6	; W.NAPR APR (6)
	.WORD	0	; W.NBAS RETURN V. A. OR WINDOW
	.WORD	0	; W.NSIZ DESIRED SIZE OF WINDOW IN 32W BLOCKS
	.WORD	0	; W.NRID TASK REGION ID (FROM CREATE REGION)
	.WORD	0	; W.NOFF OFFSET TO START MAP
	.WORD	0	; W.NLEN LENGTH TO BE MAPPED IN 32W BLOCKS
	.WORD	WS.RED!WS.MAP!WS.UDS		; W.NSTS STATUS 
		; WS.MAP= IF WINDOW IS TO BE MAPPED
		; WS.RED= READ ACCESS
		; WS.UDS= CREATE WINDOW IN USER "D" SPACE
;
ATREG:
	ATRG$	RDB	; ATTACH REGION
;
; REGIONS DESCRIPTOR BLOCK
;
RDB:
	.WORD	0	; R.GID RETURNDED ID TO THE CREATED REGION
	.WORD	0	; R.GSIZ SIZE OF REGION TO CREATE IN 32W BLOCKS
	.RAD50	/QUEHED/ ; R.GNAM NAME OF REGION
	.WORD	0,0	; R.GPAR PARTITION NAME (0= OUR PARTITION)
	.WORD	RS.RED!RS.DEL			   ; R.GSTS STATUS
	.WORD	010400	; R.GPRO PROTECTION, ALLOW ONLY OWNER AND SYSTEM FULL
			; ACCESS, REST READ ACCESS
	.PAGE
;
; SST TRAP VECTOR FOR "SVTK$S" MACRO CALL
;
SSTVEC:
	.WORD	ODDSST	; ODD ADDRESS OR NONEXISTENT MEMORY
	.WORD	MEMSST	; MEMORY PROTECT VIOLATION
	.WORD	TBTSST	; T-BIT TRAP OR EXECUTION OF A BPT INSTRUCTION
	.WORD	IOTSST	; EXECUTION OF AN IOT INSTRUCTION
	.WORD	RESSST	; EXECUTION OF A RESERVED INSTRUCTION
	.WORD	EMTSST	; EXECUTION OF A NON-RSX EMT INSTRUCTION
	.WORD	TRPSST	; EXECUTION OF A TRAP INSTRUCTION
	.WORD	FLTSST	; FLOATING POINT EXCEPTION
;
;
; DEFINE AND ALLOCATE THE SNAPSHOT CONTROL BLOCK
;
SNPSHT:
	SNPBK$	LB,0,SC.HDR!SC.LUN!SC.STK!SC.WRD!SC.BYT,SNPEFN,100.

;
; THE FOLLOWING GLOBAL SYMBOL IS DEFINED BY THE ROUTING DATABASE
; AND  IS THEN LINKED IN WITH THIS IMAGE.  IT IS A SAVE GUARD 
; AGAINST INCOMPATABLE ROUTING DATABASES AND TASKBUILDS WITH
; THIS TASK.
;
DBSID:	.WORD	RTRDID	; SEE RTRDBS FOR RTRDID DEFINITIONS
;
; TELL NETWORK THAT WE WANT UNSOLICITED MESSAGES
;
SPAW:
	SPAW$	INET,NETEFN,NETSTA,CONAST,<SPAAST>
GLNW:
	GLNW$	INET,NETEFN,NETSTA,,<LOCAL,8.>
;
LOCAL:
	.BLKW	4	; LOCAL NODE NAME AND DEFAULT NSP SEGMENT SIZE
	.ASCII	/RTRRSX/	; RESPONSE BUFFER FOR A CONNECT
	.EVEN
;
NETSTA:	.WORD	0,0	; NETWORK STATUS
;
OPNW:			; OPEN LUN TO NETOWRK 
	OPNW$	INET,NETEFN,NETSTA,,<RTRHED+HD.NCT,3>	; 3 MINUTE DISCONECT
;
GNDW:
	GNDW$	INET,NETEFN,NETSTA,,<MAIL,MLEN,0>,NT.TYP ; GET ANY MESSAGE
REQEST:
	RQST$	FNDSRV		; RUN TASK 'FNDSRV'
RETRY:	
	MRKT$	WAKEFN,1,2	; MARK TIME FOR 1 SECOND
TIMER:
	MRKT$	WAKEFN,1,4,NRTAST  ; MARK TIME 1 HOUR
CONTIM:
	MRKT$	WAKEFN,15.,3,CNTAST ; MARK TIME 15 MINUTES
CONTM2:
	MRKT$	WAKEFN,2,3,CNTAST   ; MARK TIME 2 MINUTES
;
; NETWORK MAIL BUFFER
;
MAIL:
	.BLKB	N.CBL+30	; SIZE OF MAIL PLUS ROOM
				; FOR SOME OPTIONAL POOP
MLEN=.-MAIL
;
; CONNECT/DISCONNECT STATUS MESSAGE WRITTEN TO QUEUE
;
STAMSG:
	.BLKB	SM.LEN
STAFLG:
	.WORD	0		; STATUS MESSAGE MSG ID FOUND FLAG
STAMID:
	.ASCII	/NET_STATUS      /	
				; STATUS MESSAGE MSG ID NAME
STASTA:
	.WORD	0,0		; WRITE STATUS MESSAGE TO QUEUE QIO STATUS
;
; NETWORK MESSAGE TYPE TABLE AND JUMP TABLE
; FOR DISPOSEING OF EACH TYPE OF NETWORK MESSAGE
;
TYPTBL:
	.BYTE	NT.CON	; CONNECT
	.BYTE	NT.INT	; INTERRUPT
	.BYTE	NT.DSC	; DISCONNECT
	.BYTE	NT.ABT	; USER ABORT
	.BYTE	NT.ABO	; NETWORK ABORT
TYPCNT=.-TYPTBL
	.EVEN
;
; SUBROUTINE TO HANDLE EACH TYPE OF NETWORK MESSAGE
;	NOTE: THEY ARE IN REVERSE ORDER FROM ABOVE (BECAUSE OF JSR INSTRUCTION)
;
TYPJMP:
	.WORD	ABOMSG
	.WORD	ABTMSG
	.WORD	DSCMSG
	.WORD	INTMSG
	.WORD	CONMSG
;
ASTCNT:
	.WORD	0
;
; EVENT QUEUE DISPOSE TABLE
;
ENTTYP:
	.WORD 	EVTCON	; EVENT= CONNECTION COMPLETE
	.WORD	EVTRSP	; EVENT= RETRY ALLOCATING RESPONSE BUFFER AFTER
			;   MARK TIME COMPLETES
	.WORD	EVTNRT	; EVENT= MARK MSG ID'S AS ROUTABLE
	.WORD	CONFAL	; EVENT= CONNECTION FAILURE
	.WORD	CONTRY	; EVENT= TRY CONNECTING TO REMOTES
	.WORD	EVTDIS	; EVENT= DISCONNECT COMPLETE
ENTCNT=<.-ENTTYP>/2	; NUMBER OF EVENTS
	.EVEN
;
; SUBROUTINE LIST FOR EACH EVENT
;	NOTE: IN REVERSE ORDER FROM ABOVE (BECAUSE OF JSR INSTRUCTION)
;
ENTJMP:
	.WORD	DISCMP	; DISCONNECT COMPLETE
	.WORD	CONNOD	; TIME TO ATTEMT A CONNECT
	.WORD	CNFALS	; CONNECTION FAILURE
	.WORD	NRTENB	; TIME TO MARK MSG ID'S AS ROUTABLE
	.WORD	RERSP	; RETRY RESPONSE BUFFER ALLOCATION
	.WORD	CONCMP	; CONNECT COMPLETE
;
; READ DATA FROM NETWORK QIO
;
REDNET:
	REC$	,NETEFN,,REDAST,<MAIL,0> ; BUFFER, LENGTH, LUN, AND
					 ; BUFFER SIZE FILLED IN LATER
;
; WRITE DATA TO NETWORK QIO
;
WRTNET:
	SND$	,NETEFN,,WRRAST,<MAIL,0> ; BUFFER, LENGTH, LUN, AND
				   	 ;    BUFFER SIZE FILLED IN LATER
SNDNET:
	SND$	,NETEFN,,WROAST,<MAIL,0> ; BUFFER, LENGTH, LUN, AND
					 ;    BUFFER SIZE FILLED IN LATER
;
; CONNECT REQUEST
;
CONREQ:
	CON$	,NETEFN,,CNLAST,<,N.RQL>
	.PAGE
;
; QIOS TO THE QUEUE DRIVER/ACP
;
WRTQUE:			; WRITE TO THE QUEUE (ROUTER ENTRY)
	QIO$	IO.WVB+1,IZQ,QUEEFN,,,WRQAST,<>
REDQUE:			; READ FROM THE QUEUE
	QIOW$	IO.RVB,IZQ,WATEFN,,,<>
RNAQUE:			; BACKUP RNA
	QIO$	IO.RNA,IZQ,QUEEFN,,,RNAAST,<,16.>
ACKQUE:			; ACKNOWLEGE A READ FROM THE QUEUE
	QIO$	IO.ACW,IZQ,QUEEFN,,,ACKAST,<,16.>
;
; CONNECT A MESSAGE ID TO QUEUE
;
CONQUE:
	QIOW$	IO.ACR,IZQ,WATEFN,,QUESTA,,<,16.,WAKEFN>
;
QUESTA:	.BLKW	2	; CONNECT TO QUEUE STATUS
;
QINIT:
	QIO$	IO.DAC,IZQ,,,,,
;
RESID:
	QIOW$	IO.RNA,IZQ,WATEFN,,,,<,16.>  ; BACKUP RNA FOR ID AND WAIT
					     ; (USED WHEN NEW CONNECTION MADE)
DISCQ:
	QIO$	IO.KIL,IZQ,,,,,		     ; KILL ALL PENDING I/O TO ZQ0:
WRTSTA:
	QIOW$	IO.WVB,IZQ,WATEFN,,STASTA,,<STAMSG,SM.LEN,STAMID,,0>
					     ; QIO TO WRITE CONNECT/DISCONNECT
					     ;   STATUS MESSAGE TO QUEUE
	.PAGE
;
; LINKAGE TO THE ROUTING DATABASE COMMON
;
	.PSECT 	ARTRHD,RW,D,OVR,REL,GBL
RTRHED:
	.PSECT	NRBS,D,OVR,RW,REL,GBL
	.PSECT 	OUTBUF,D,RW,REL,OVR,GBL
	.PSECT 	RSPBUF,D,RW,REL,OVR,GBL
	.PSECT	UNSBUF,D,RW,REL,OVR,GBL
	.PAGE
;
; SET UP SST VECTOR
;
	.PSECT	$CODE,RO,I,CON,REL
START:
	SVTK$S	#SSTVEC,#8.	; DEFINE SST VECTOR 
	BCC	5$		; SST DIRECTIVE SUCCESSFUL
	MOV	#"01,ERRNUM	; STORE ERROR NUMBER
	CALL 	DSWMSG		; LOG STATUS
	EXIT$S			; CAN'T CONTINUE
;
; ATTACH TO THE REGION
;
5$:
	DIR$	#ATREG		; ATTACH TO THE REGION
	BCC	10$		; ATTACH OK?
	MOV	#"02,ERRNUM	; ERORR NUMBER, FOR OUTPUT MESSAGE
	CALL	DSWMSG		; LOG THE MESSAGE
	EXIT$S			; FATAL ERROR
10$:
	MOV	RDB+R.GSIZ,WDB+W.NSIZ  ; SET SIZE OF WINDOW
	MOV	RDB+R.GID,WDB+W.NRID   ; COPY REGION ID
	DIR$	#CRWND		; CREATE THE WINDOW
	BCC	20$		; EVERYTHING OK?
	MOV	#"03,ERRNUM	; ERROR NUMBER FOR OUTPUT MESSAGE
	CALL 	DSWMSG		; LOG ERROR
	EXIT$S			; FATAL ERROR
20$:
	MOV	#"04,ERRNUM	; LOG SUCCESSFUL STATUS
	MOV	RDB+R.GSIZ,ERRSTA	; STATUS TO BE ENCODED
	CALL	MESGW		; LOG ERROR
;
; VALIDATE OUR ROUTING DATABASE
;
	CMP 	DBSID,RTRHED+HD.ID	; DO DATABASES MATCH?
	BEQ	25$			; YES, GO LINK DBS WITH QUEUE
	MOV	#"05,ERRNUM		; LOG THE ERROR
	MOV	DBSID,ERRSTA		; COPY OUR VERSION
	CALL	MESGW			; LOG ERROR MESSAGE
	EXIT$S				; CAN'T CONTINUE
;
; MAKE SURE DATABASE HAS NOT BEEN ACCESSED SINCE INSTALLED FROM DISK
;
25$:
	TST	RTRHED+HD.STR		; WAS DATABASE ACCESSED?
	BEQ	30$			; NO, SO OK
	MOV	#"54,ERRNUM		; ERROR NUMBER
	CLR	ERRSTA			; NO STATUS
	CALL	MESGW			; LOG ERROR MESSAGE
	EXIT$S				; CAN'T CONTINUE
30$:
	INC	RTRHED+HD.STR		; MARK DATABASE AS HAVING BEEN ACCESSED
;
	DIR$	#QINIT		; SET UP EXIT POOP FOR QUEUE
	BCC	INIDS		; A-OK?
	MOV	#"50,ERRNUM	; ERROR NUMBER
	CALL	DSWMSG		; LOG ERROR
	EXIT$S
	.PAGE
;
; DATABASE INITIALIZATION FOR THE RTRRSX TASK.
; THE FOLLOWING ARE DONE:
;
;	1) SCAN ALL OF THE NRB'S AND CLEAR THE STATUS WORD
;
;	2) FOR ALL MESSAGE ID'S THAT ARE ROUTED TO THE 
;	   NODE SPECIFIED BY THIS NRB, FIND THE MESSAGE
;	   ID IN THE QUEUE.  IF NOT IN QUEUE, SIMPLY
;	   CLEAR THE LINK TO THE QUEUE MESSAGE ID LIST HEAD
;	   AND LOG THE ERROR.
;
;
; LOOP LOOKING AT EACH NRB
;
INIDS:
	MOV	RTRHED+HD.NCT,R1	; NUMBER OF NRB'S DEFINED
	MOV	RTRHED+HD.NRB,R5	; NRB BEGINNING THREAD
	MOV	#140000+Q.KSIZ,-(SP) 	; WHERE MESSAGE ID LIST HEADS START
					; (RIGHT AFTER THE QUEUE HEADER)
10$:
	MOV	N.IDS(R5),-(SP)		; NUMBER OF MESSAGE ID'S 
					; ROUTED TO THIS NODE
	BEQ	105$			; NONE ROUTED, ONLY RECEIVED
;
	MOV	R5,R3			; COPY NRB
	ADD	#N.IDXL,R3		; POINT TO MESSAGE ID LIST
	MOV	R3,-(SP)		; SAVE INDEX TO ID LIST
;
; SCAN THE QUEUE LOOKING FOR THE MESSAGE ID IN THE QUEUE
;
30$:
	MOV	@#<140000 ! Q.IDC>,R0	; GET NUMBER OF ID'S IN QUEUE
;
; LOOP FOR EACH ID IN QUEUE
;
40$:
	MOV	(SP),R3			; GET CURRENT NRB MESG. ID  LIST PTR.
	MOV	4(SP),R2		; ID LHD. TO COMPARE IN QUEUE
	ADD	#M.MID,R2		; POINT TO THE ID NAME IN LHD.
	MOV	#M.IDSIZ/2,R4		; SIZE OF A MESSAGE ID IN WORDS
	ADD	#NID.NM,R3		; POINT TO THE ACTUAL ASCII ID NAME
					; IN ID LIST HEAD
50$:
	CMP	(R3)+,(R2)+		; MATCH?
	BNE	80$			; NO
	SOB	R4,50$			; YES, SO FAR
;
; MATCH COMPLETELY, STORE ADDRESS TO MESSAGE ID LIST
; HEAD IN THE QUEUE
;
	MOV	(SP),R2			; GET MESSAGE ID NRB LIST PTR.
	MOV	4(SP),NID.IX(R2)	; STORE ADDRESS TO ENTRY IN  QUEUE
	CLR	NID.ST(R2)		; CLEAR STATUS WORD
;
; CONNECT THE MESSAGE IT TO THE QUEUE
;
	MOV	R2,CONQUE+Q.IOPL	; ADDRESS OF NRBID
	ADD	#NID.NM,CONQUE+Q.IOPL	; ADD OFFSET TO ACTUAL MESSAGE ID 
	DIR$	#CONQUE			; CONNECT MESSAGE ID TO QUEUE
	BCC	55$			; DIRECTIVE ACCEPTED
	MOV	#"34,ERRNUM		; NO
	CALL	DSWMSG			; LOG IT
	DIR$	#DISCQ			; KILL PENDING I/O
	EXIT$S				; EXIT
55$:
	CMPB	#IS.SUC,QUESTA		; STATUS GOOD?
	BEQ	60$			; YES
	MOVB	QUESTA,ERRSTA
	BIS	#177400,ERRSTA		; SIGN EXTEND STATUS
	MOV	#"35,ERRNUM		; ERROR
	CALL	MESGW			
	DIR$	#DISCQ			; KILL PENDING I/O
	EXIT$S				; EXIT
;
; FOUND OR NOT, POINT TO NEXT MESSAGE ID IN NRB ID LIST
;
60$:
	MOV	#140000+Q.KSIZ,4(SP) 	; RESET THE QUEUE SEARCH POINTER
	DEC	2(SP)			; DECREMENT NUMBER THAT HAVE TO LOOK FOR
	BEQ	100$			; THIS NRB, ALL DONE THIS NRB?
	ADD	#NID.LN,(SP)		; UPDATE NRB ID LIST POINTER
	BR	30$			; GO SEE IF WE CAN FIND THIS ID IN QUEUE
;
; MESSAGE ID'S DON'T MATCH, UPDATE TO NEXT MESSAGE ID IN QUEUE OR ELSE
; MESSAGE ID IS NOT IN THE QUEUE
;
80$:
	ADD	#M.LEN,4(SP)		; ADD SIZE OF A MESSAGE ID LISTHEAD
	DEC	R0
	BEQ	85$
	JMP	40$			; LOOP FOR NUMBER ID'S IN QUEUE
;
; CAN'T FIND THE MESSAGE ID IN THE QUEUE
;
85$:
	MOV	#M.IDSIZ/2,R4		; NUMBER WORDS IN MESSAGE ID
	MOV	#ASCXTA,R2		; BUFFER FOR LOGGING
	MOV	#NID.NM,R3		; OFFSET IN NBR ID LIST TO ID NAME
	ADD	(SP),R3			; ADD CURRENT ID LIST ELEMENT ADDR.
90$:
	MOV	(R3)+,(R2)+		; COPY ID THAT WASN'T FOUND FOR LOG
	SOB	R4,90$	
	CLR	ERRSTA
	MOV	#"26,ERRNUM		; MESSAGE ID NOT FOUND ERROR NUMBER
	CALL	MESGW			; LOG THE ERROR
	BR	60$			; GO CHECK NEXT ID IN NRB ID LIST
;
; DONE THIS NRB, CHECK NEXT
;
100$:
	TST	(SP)+			; POP OFF THE NRB ID LIST POINTER
105$:		; <--- if the NRB didn't have any id's at all
	MOV	N.LNK(R5),R5		; POINT TO NEXT NRB
	TST	(SP)+			; POP OFF NUMBER IDS THIS NRB
	DEC	R1
	BEQ	110$
	JMP	10$			; GO CHECK NEXT NODE
110$:
	TST	(SP)+			; POP OFF ADDRESS OF THE FIRST
					; MESSAGE ID LHD. IN THE QUEUE
;   ALL DONE
	.PAGE
;
; CONNECT A LUN FOR THE UNSOLICITED NETWORK MESSAGES
;
ININET:
	DIR$	#OPNW		; OPEN LUN TO NETWORK
	BCC	25$		; DIRECTIVE ACCEPTED?
	MOV	#"06,ERRNUM
	CALL	DSWMSG		; LOG THE ERROR
	DIR$	#DISCQ			; KILL PENDING I/O
	EXIT$S				; FATAL
25$:
	CMPB	#IS.SUC,NETSTA		; WAS STATUS SUCCESSFUL?
	BEQ	30$			; YES
	MOVB	NETSTA,R0		; GET STATUS
	MOV	R0,ERRSTA		; STORE FOR LOG
	MOV	#"11,ERRNUM		; ERROR NUMBER
	CALL	MESGW			; LOG MESSAGE
	DIR$	#DISCQ			; KILL PENDING I/O
	EXIT$S				; FATAL ERROR
30$:
	DIR$	#SPAW			; SPECIFY NETWORK MESSAGES AST'S
	BCC	40$			; DIRECTIVE ACCEPTED?
	MOV	#"07,ERRNUM
	CALL	DSWMSG			; LOG ERROR
	DIR$	#DISCQ			; KILL PENDING I/O
	EXIT$S
;
; SEE IF STATUS GOOD TOO
;
40$:
	CMPB	#IE.NDA,NETSTA		; NO DATA IN QUEUE?
	BEQ	50$			; OK
	CMPB	#IS.SUC,NETSTA		; WAS IT SUCCESSFUL?
	BEQ	50$			; YES
	MOVB	NETSTA,R0		; SIGN EXTEND
	MOV	#"08,ERRNUM
	MOV	R0,ERRSTA
	CALL	MESGW			; LOG ERROR
	DIR$	#DISCQ			; KILL PENDING I/O
	EXIT$S				; FATAL
;
; GET OUR LOCAL NODE INFORMATION
;
50$:
	DIR$	#GLNW			; GET LOCAL NODE INFORMATION
	BCC	60$			; DIRECTIVE ACCEPTED?
	MOV	#"09,ERRNUM
	CALL	DSWMSG			; LOG ERROR
	DIR$	#DISCQ			; KILL PENDING I/O
	EXIT$S				; FATAL
;
60$:
	TSTB	NETSTA			; GOOD I/O STATUS?
	BPL	70$			; YES
	MOVB	NETSTA,R0
	MOV	R0,ERRSTA
	MOV	#"10,ERRNUM
	CALL	MESGW			; LOG ERROR
	DIR$	#DISCQ			; KILL PENDING I/O
	EXIT$S				; FATAL
	.PAGE
;
; ALREADY TO GO
;
70$:
	MOV	LOCAL,ASCXTA		; COPY NODE NAME FOR OUR OUTPUT
	MOV	LOCAL+2,ASCXTA+2
	MOV	LOCAL+4,ASCXTA+4
;
	MOV	LOCAL,RTRHED+HD.NOD
	MOV	LOCAL+2,RTRHED+HD.NOD+2
	MOV	LOCAL+4,RTRHED+HD.NOD+4
	MOV	#"14,ERRNUM		; ERROR NUMBER
	CLR	ERRSTA			; NO STATUS
	CALL	MESGW			; MESSAGE WITH ASCII
;
; ATTEMPT TO CONNECT ALL REMOTE NODES WITH AN NRB. AST'S ARE DISABLED
; SINCE THE 'CONNOD' ROUTINE PUSHES STATUS MESSAGES INTO THE MESSAGE
; QUEUE WHICH MUST BE DONE AT AST LOCKOUT.
;
	DSAR$S			; DISABLE AST RECOGNITION 
	CALL	CONNOD
	ENAR$S			; ENABLE AST RECOGNITION
;
; THIS CODE PROCESSES OF ALL EVENTS THAT OCCURRED SINCE THE
; WAKEUP EVENT FLAG WAS SET.  AFTER FINISHING, IT WAITS FOR ANOTHER
; EVENT TO SET THE WAKEUP EVENT FLAG.  THIS CODE RUNS ENTIRELY IN
; AN AST LOCKOUT STATE.
;
80$:
	CLEF$S	#WAKEFN		; CLEAR WAKEUP EFN
	DSAR$S			; DISABLE AST RECOGNITION WHILE PROCESSING
				;   EVENTS THAT WERE QUEUED
	.IF DF,DEBUG
	MOV	#"99,-(SP)	; WAKEUP DEBUG MESSAGE
	MOV	ASTCNT,-(SP)
	CLR	-(SP)
	MOV	#WAKEUP,-(SP)	
	MOV	#6,-(SP)
	CALL	PSHERR		; QUEUE MESSAGE
	.ENDC
;
85$:
	CALL	REMQUE
	BCS	110$
	MOV	#ENTTYP,R3	; TABLE OF POSSIBLE ENTRIES
	MOV	#ENTCNT,R2	; NUMBER OF POSSIBLE ENTRIES
90$:
	CMP	(R3)+,R1	; IS IT THIS ENTRY?
	BNE	100$		; NO
;
; GO TAKE CARE OF THE DESIRED EVENT
;
	ASL	R2		; CHANGE FROM BYTE TO WORD INDEX
	JSR	PC,@ENTJMP-2(R2)	; GO HANDLE EVENT
	BR	85$		; GO SEE IF ANY MORE EVENTS
100$:
	SOB	R2,90$		; CHECK REST OF THE POSSIBLE EVENTS
110$:
	CALL	GETOUT		; GO SEE IF ANY MESSAGES FOR ROUTING
	ENAR$S			; ENABLE AST RECOGNITION, ALL EVENTS QUEUED
				;   WERE PROCESSED
	WTSE$S	#WAKEFN		; WAIT FOR SOMETHING TO HAPPEN
	BR	80$
	.page
;
; This subroutine connects each NRB if it is not 
; currently connected and a remote has not requested a
; connection.
;
; If neither the Primary or Secondary node is selected, 
; then the Primary node is selected and copied into 
; N.CUR.  If the primary node name is a logical node name, 
; the Secondary node is always selected.  The connect block 
; is constructed and an attempt to connect is made.
; 
;
CONNOD:
	MOV	RTRHED+HD.NCT,R0	; NUMBER OF NODES TO CONNECT
	MOV	RTRHED+HD.NRB,R5	; POINT TO FIRST NRB
5$:
	BIT	#NS.AVL ! NS.CPN ! NS.RCN, N.STS(R5) ; OK TO CONNECT
	BEQ	10$			; TRY TO CONNECT
	JMP	60$			; CAN'T CONNECT RIGHT NOW
;
; ATTEMPT TO BUILD THE CONNECT BLOCK
;
; CHECK IF PRIMARY NODE NAME IS A LOGICAL NODE NAME
;
10$:
	BIT	#NS.LND,N.STS(R5)	; IS PRIMARY NODE NAME A LOGICAL NODE
					;    NAME?
	BEQ	20$			; NO
	BIT	#NS.NOD,N.STS(R5)	; IS CURRENT ACTUAL (SERVICE) NODE 
					;    NAME PRESENT FOR LOGICAL NODE NAME
	BNE	30$			; YES, CONNECT TO SECONDARY
	DIR$	#REQEST			; RUN TASK 'FNDSRV'
	BCC	12$			; DIRECTIVE OK
	CMP	#IE.ACT,$DSW		; IS TASK ALREADY ACTIVE
	BNE	11$			; NO, LOG ERROR
	JMP	60$			; TASK ACTIVE, NO NEED TO RUN AGAIN
11$:
	MOV	#"55,-(SP)		; ERROR NUMBER
	MOVB	$DSW,-(SP)		; DIRECTIVE STATUS
	BIS	#177400,(SP)		; MAKE SURE NEGATIVE
	CLR	-(SP)			; NO SECOND STATUS			
	CLR	-(SP)			; NO NODE NAME DISPLAYED
	CLR	-(SP)
	CALL	PSHERR			; QUEUE MESSAGE
12$:
	TST	RTRHED+HD.CTM		; IS CONNECT TIMER ACTIVE
	BEQ	15$			; NO
	CMKT$S	,#CNTAST		; CANCEL CONNECT ATTEMPT MARK TIME
15$:
	DIR$	#CONTM2			; ISSUE MARK TIME
	BCC	17$			; DIRECTIVE OK
	MOV	#"49,-(SP)	; ERROR NUMBER
	MOVB	$DSW,-(SP)	; DIRECTIVE STATUS
	BIS	#177400,(SP)	; MAKE SURE NEGATIVE
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	; 
	ADD	#N.PRI,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	CLR	RTRHED+HD.CTM	; CLEAR CONNECT TIMER ACTIVE FLAG
	JMP	60$
17$:
	INC	RTRHED+HD.CTM	; SET CONNECT TIMER ACTIVE FLAG
	JMP	60$
20$:
	BIT	#NS.PRI,N.STS(R5)	; IS PRIMARY SELECTED?
	BNE	30$			; YES, THEN GO SELECT SECONDARY THIS TIME
;
; SELECT PRIMARY NODE
;
	BIC	#NS.SEC,N.STS(R5)	; CLEAR SECONDARY NODE
	BIS	#NS.CPN ! NS.PRI,N.STS(R5)	; SELECT AS PRIMARY
						; AND MARK LOCAL CONNECT
						; IN PROGRESS
	MOV	#N.PRI,R1		; POINT TO PRIMARY
	BR	50$			; GO TO COMMON CONNECT CODE
;
; SELECT SECONDARY NODE
;
30$:
	BIC	#NS.PRI,N.STS(R5)	; CLEAR PRIMARY NODE
	BIS	#NS.CPN ! NS.SEC, N.STS(R5)	; SELECT AS SECONDARY
						; AND MARK LOCAL CONNECT 
						; IN PROGRESS
	MOV	#N.SEC,R1		; POINT TO SECONDARY NODE NAME
	.PAGE
;
; CONNECT NODE
;
50$:
	ADD	R5,R1		; R1 NOW POINTS TO DESIRED NODE TO BUILD
				; NCB CONNECT BLOCK
	MOV	#N.CUR,R2	; FILL IN CURRENT NODE NAME
	ADD	R5,R2		; ADD START OF NRB
;
	MOV	#N.NCB+N.RND,R3	; NETWORK CONNECT BLOCK (REMOTE NODE NAME)
	ADD	R5,R3		; ADD START OF NRB
;
	MOV	(R1),(R3)+	; COPY TO NCB
	MOV	(R1)+,(R2)+	; COPY TO CURRENT NODE NAME
	MOV	(R1),(R3)+	; COPY TO NCB
	MOV	(R1)+,(R2)+	; COPY TO CURRENT NODE NAME
	MOV	(R1),(R3)+	; COPY TO NCB
	MOV	(R1)+,(R2)+	; COPY TO CURRENT NODE NAME
;
	MOV	N.LUN(R5),CONREQ+Q.IOLU	; COPY LOGICAL UNIT NAME
	MOV	N.ISAC(R5),CONREQ+Q.IOSB  ; I/O STATUS BLOCK ADDRESS
	MOV	#N.NCB,CONREQ+Q.IOPL
	ADD	R5,CONREQ+Q.IOPL	; NCB FOR CONNECT
	DIR$	#CONREQ			; REQUEST THE CONNECTION
	BCC	60$			; DIRECTIVE ACCEPTED?
	BIC	#NS.CPN,N.STS(R5)	; CLEAR LOCAL CONNECT IN PROGRESS
	MOV	#"45,-(SP)		; ERROR NUMBER
	MOVB	$DSW,-(SP)			; DIRECTIVE STATUS
	BIS	#177400,(SP)			; MAKE SURE NEGATIVE
	CLR	-(SP)			
	MOV	R5,-(SP)		; POINT TO NODE NAME IN NRB
	ADD	#N.CUR,(SP)		
	MOV	#6,-(SP)		; NBR BYTES IN NODE NAME
	CALL	PSHERR			; QUEUE MESSAGE
;
; START TIMER FOR LATER RETRY
;
	TST	RTRHED+HD.CTM	; IS CONNECT TIMER ACTIVE
	BNE	60$		; YES
	DIR$	#CONTIM		; ISSUE MARK TIME
	BCC	53$		; DIRECTIVE OK
	MOV	#"49,-(SP)	; ERROR NUMBER
	MOVB	$DSW,-(SP)	; DIRECTIVE STATUS
	BIS	#177400,(SP)	; MAKE SURE NEGATIVE
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	; 
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	BR	60$
53$:
	INC	RTRHED+HD.CTM	; SET CONNECT TIMER ACTIVE FLAG
60$:
	MOV	N.LNK(R5),R5		; NEXT NRB ADDRESS
	DEC	R0
	BEQ	65$			
	JMP	5$			; TRY TO CONNECT THIS NODE
65$:
	RETURN
	.PAGE
;
; CONNECTION AST.
;	If the connection was successful, then mark the
; NRB with link available status and push an event that
; denotes that.  This will also trigger a scan to see if 
; there is any work.
;
;	0(SP)= I/O STATUS BLOCK (MUST BE POPPED)
;
CNLAST:
	MOV	R5,-(SP)	; SAVE R5
	MOV	2(SP),R5	; GET I/O STATUS BLOCK ADDRESS
	SUB	#N.IOSC,R5	; NORMALIZE TO START OF NRB
	BIC	#NS.CPN,N.STS(R5)	; CLEAR LOCAL CONNECT IN PROGRESS
	TSTB	N.IOSC(R5)	; GOOD STATUS?
	BPL	10$		; YES
;
; BAD CONNECT STATUS
;
	BIS	#NS.DWN,N.STS(R5)	; FLAG AS DOWN 
	TST	RTRHED+HD.CTM	; IS CONNECT TIMER ACTIVE
	BNE	5$		; YES
	DIR$	#CONTIM		; ISSUE MARK TIME
	BCC	3$		; DIRECTIVE OK
	MOV	#"49,-(SP)	; ERROR NUMBER
	MOVB	$DSW,-(SP)	; DIRECTIVE STATUS
	BIS	#177400,(SP)	; MAKE SURE NEGATIVE
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	; 
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	BR	5$
3$:
	INC	RTRHED+HD.CTM	; SET CONNECT TIMER ACTIVE FLAG
5$:
	MOV	R5,-(SP)	; PASS NRB
	MOV	#CONFAL,-(SP)	; ERROR
	CALL 	PSHENT		; PUSH AN EVENT
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK
	ASTX$S			; EXIT AST
;
; CONNECT COMPLETE
;
10$:
	BIS	#NS.AVL,N.STS(R5)	; FLAG NODE AS AVAILABLE
	BIC	#NS.DWN,N.STS(R5)	; CLEAR DOWN FLAG
	MOVB	N.IOSC(R5),N.STAM(R5)	; SAVE CONNECT STATUS
	MOV	R5,-(SP)		; CONNECT COMPLETE
	MOV	#EVTCON,-(SP)		; PUSH ENTRY "CONNECT COMPLETE"
	CALL	PSHENT
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O  STATUS BLOCK	
	ASTX$S			; EXIT AST	
	.PAGE
;
; CONNECT FAILURE STATUS
;
; Simply log the error.
;
;	R5= NRB OF NODE
;	N.IOSC(R5) SHOULD PROBABLY STILL CONTAIN THE STATUS
;
;
CNFALS:
	MOV	#"46,-(SP)		; ERROR NUMBER
	MOVB	N.IOSC(R5),-(SP)	; I/O ERROR
	BIS	#177400,(SP)		; MAKE NEGATIVE
	MOVB	N.IOSC+2(R5),-(SP)	; SECOND STATUS WORD
	BIC	#177400,(SP)		; MAKE POSITIVE
	MOV	R5,-(SP)		; POINT TO NODE NAME IN NRB
	ADD	#N.CUR,(SP)		
	MOV	#6,-(SP)		; NBR BYTES IN NODE NAME
	CALL	PSHERR			; QUEUE MESSAGE
	RETURN		
	.PAGE
;
; CONNECT TIMER HAS EXPIRED.  QUEUE AN EVENT TO ATTEMPT CONNECTING
; TO ALL REMOTE NODES AGAIN.
;	0(SP)= EVENT FLAG NUMBER (MUST BE POPPED)
;
CNTAST:
	CLR	RTRHED+HD.CTM	; CLEAR CONNECT TIMER ACTIVE FLAG
	CLR	-(SP)		; NO PARAMETER TO SAVE
	MOV	#CONTRY,-(SP)	; PUSH ENTRY "ATTEMPT TO CONNECT"
	CALL	PSHENT
	TST	(SP)+		; POP EFN
	ASTX$S			; EXIT AST	
	.PAGE
;
; CONNECT TO NETWORK FOR NETWORK MAIL AST ROUTINE.  THIS OCURRS ONLY
; ONCE WHEN THE CONNECTION IS FIRST ATTEMPTED.
;	(SP)= I/O STATUS BLOCK ADDRESS
; SECOND WORD OF THE I/O STATUS BLOCK WILL CONTAIN THE NUMBER
; OF NETWORK MESSAGES ALREADY PENDING.
;
CONAST:
	.IF DF,DEBUG
	MOV	#"CA,-(SP)
	MOV	#-1,-(SP)
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	CLR	-(SP)		; NO ADDRESS
	CLR	-(SP)		; NO BYTE COUNT
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	.ENDC
;
	INC	ASTCNT
	MOV	R0,-(SP)	; SAVE A REGISTER
	MOV	2(SP),R0	; GET I/O STATUS BLOCK 
	TST	2(R0)		; ANY MESSAGES?
	BNE	10$		; YES
	MOV	(SP),2(SP)	; MOV SAVE R0 ON TOP OF I/O STATUS BLOCK
	TST	(SP)+		; POP EXTRA COPY OF R0
	MOV	(SP)+,R0	; RESTORE R0
	ASTX$S			; EXIT AST
10$:
	MOV	(SP),2(SP)	; MOVE SAVED R0 DOWN
	TST	(SP)+		; POP I/O STATUS BLOCK ADDRESS
	BR	SPAST2		; GO READ THE MESSAGES
	.page
;
; NETWORK MESSAGES AST ROUTINE
; 	When the network has a network message (not a message from some
; other router), then this routine is called.  The type of the 
; message is returned in the higher byte of the status block as follows:
;
;	.BLKB	1	(IS.SUC, have a network message
;			IE.NDA, if no more messages)
; 	.BLKB   type is:
; 			NT.CON= Network connection requested
; 			NT.INT= Interrupt message
; 			NT.DSC= User disconnect notice
; 			NT.ABT= User abort notice
; 			NT.ABO= Network abort notice
;
;	.BLKB	 1	; number of words in connect block if NT.CON
;			; number of bytes in optional message if NT.INT,
;						NT.DSC, or NT.ABT
;			; reason for network abort if NT.ABO
;
;	.BLKB	1	; access verification and priv code if NT.CON
;			; LUN if NT.INT, NT.DSC, NT.ABO, or NT.ABT
;
;
; NOTE: THERE IS NOTHING ON THE STACK WHEN THIS AST IS ENVOKED.
; 	THE STATUS IS ONLY AFTER DOING THE GET NETWORK DATA.
SPAAST:
	.IF DF,DEBUG
	MOV	#"SA,-(SP)
	MOV	#-1,-(SP)
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	CLR	-(SP)		; NO ADDRESS
	CLR	-(SP)		; NO BYTE COUNT
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	.ENDC
	INC	ASTCNT
	MOV	R0,-(SP)	; SAVE AT LEAST ONE REGISTER
SPAST2:
	DIR$	#GNDW	; GET NETWORK DATA (ANY MESSAGE TYPE)
	BCC	10$	; DIRECTIVE ACCEPTED?
	MOV	#"38,-(SP)	; PUSH ERROR NUMBER
	MOVB	$DSW,R0		; SIGN EXTEND ERROR
	MOV	R0,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	CLR	-(SP)		; NO ADDRESS
	CLR	-(SP)		; NO BYTE COUNT
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
5$:
	MOV	(SP)+,R0	; RESTORE R0
	ASTX$S			; EXIT AST
;
10$:
	TSTB	NETSTA	; IS STATUS CODE POSTIVE (IS.SUC or IS.DAO)?
	BPL	20$	; YES, THEN MUST BE A GOOD READ MESSAGE
	CMPB	#IE.NDA,NETSTA	; QUEUE EMPTY?
	BEQ	5$		; YES, THEN COMPLETE
	MOV	#"23,-(SP)	; ERROR NUMBER
	MOVB	NETSTA,R0	; SIGN EXTEND THE ERROR CODE
	MOV	R0,-(SP)	; STORE FOR A LOG
	CLR	-(SP)	
	CLR	-(SP)		; NO ADDRESS
	CLR	-(SP)		; NO BYTE COUNT
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	BR	SPAST2		; GO SEE IF ANY MORE MESSAGES
	.PAGE
;
; HAVE A VALID NETWORK MESSAGE, DISPOSE OF BY LOOKING AT THEY TYPE
;
20$:
	MOV	#70$,-(SP)	; FAKE RETURN ADDRESS
	CALL	$SAVAL		; SAVE ALL REGISTERS
	MOV	#TYPCNT,R1
	MOV	#TYPTBL,R2
30$:
	CMPB	(R2)+,NETSTA+1	; SEE IF MATCH ON TYPE
	BEQ	40$		; FOUND MATCH
	SOB	R1,30$		; SEE IF NEXT
;
; NOT A VALID TYPE, LOG AND IGNORE
;
	MOV	#"12,-(SP)	; ERROR NUMBER
	MOVB	NETSTA+1,R0	; PRINT THE MESSAGE TYPE
	MOV	R0,-(SP)	; STORE FOR LOG
	CLR	-(SP)		
	CLR	-(SP)		; NO ADDRESS
	CLR	-(SP)		; NO BYTE COUNT
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	BR 	50$		; DISPOSE OF AST
;
40$:
	ASL	R1		; MAKE OFFSET
	JSR	PC,@TYPJMP-2(R1) ; GO TO CORRECT MESSAGE TYPE
50$:
	RETURN			; RESTORE REGISTERS (WILL RETURN TO 70$ WITH
				; REGISTERS RESTORED)
70$:
	BR	SPAST2		; GO SEE IF ANY MORE NETWORK DATA
	.PAGE
;
; CONNECT MESSAGE
;
; Offset N.SND is the node that is requesting a connection with us in
; the MAIL buffer from the network.  If we can find the node in our
; routing database, accept the connection, else reject the connection.  
; Also if we are currently trying to connect, then also reject the 
; connection.
;
CONMSG:
	MOV	RTRHED+HD.NRB,R5	; GET THREAD TO NRB'S
	MOV	RTRHED+HD.NCT,R2	; NUMBER OF NRB'S TO SCAN
10$:
	CMP	MAIL+N.SND,N.PRI(R5)	; SEE IF PRIMARY NODE
	BNE	20$			; NOPE
	CMP	MAIL+N.SND+2,N.PRI+2(R5)
	BNE	20$
	CMP	MAIL+N.SND+4,N.PRI+4(R5)
	BEQ	60$			; NODE IS PRIMARY NODE
20$:
	CMP	MAIL+N.SND,N.SEC(R5)	; SEE IF SECONDARY NODE
	BNE	40$			; NOPE
	CMP	MAIL+N.SND+2,N.SEC+2(R5)
	BNE	40$
	CMP	MAIL+N.SND+4,N.SEC+4(R5)
	BEQ	70$			; NODE IS SECONDARY NODE
40$:
	MOV	N.LNK(R5),R5		; GET NEXT NRB IN THREAD
	SOB	R2,10$			; CHECK ALL NRB'S
;
; NRB NOT FOUND; SINCE NODE REQUESTING CONNECTION MAY HAVE A LOGICAL
; NODE NAME IN THE DATABASE, RUN TASK 'FNDSRV', SET CONNECT TIMER, AND
; REJECT CONNECTION.
;
	DIR$	#REQEST			; RUN TASK 'FNDSRV'
	BCC	45$			; DIRECTIVE OK
	CMP	#IE.ACT,$DSW		; IS TASK ALREADY ACTIVE
	BEQ	50$			; YES, NO NEED TO RUN AGAIN
	MOV	#"55,-(SP)		; ERROR NUMBER
	MOVB	$DSW,-(SP)		; DIRECTIVE STATUS
	BIS	#177400,(SP)		; MAKE SURE NEGATIVE
	CLR	-(SP)			; NO SECOND STATUS			
	CLR	-(SP)			; NO NODE NAME DISPLAYED
	CLR	-(SP)
	CALL	PSHERR			; QUEUE MESSAGE
45$:
	TST	RTRHED+HD.CTM		; IS CONNECT TIMER ACTIVE
	BEQ	47$			; NO
	CMKT$S	,#CNTAST		; CANCEL CONNECT ATTEMPT MARK TIME
47$:
	DIR$	#CONTM2			; ISSUE MARK TIME
	BCC	48$			; DIRECTIVE OK
	MOV	#"49,-(SP)	; ERROR NUMBER
	MOVB	$DSW,-(SP)	; DIRECTIVE STATUS
	BIS	#177400,(SP)	; MAKE SURE NEGATIVE
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	; 
	ADD	#N.PRI,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	CLR	RTRHED+HD.CTM	; CLEAR CONNECT TIMER ACTIVE FLAG
	BR	50$
48$:
	INC	RTRHED+HD.CTM	; SET CONNECT TIMER ACTIVE FLAG
;
; NRB NOT FOUND, DISALLOW THE CONNECTION AND LOG THE FACT
;
50$:
	MOV	#"24,-(SP)	; ERROR NUMBER
	CLR	-(SP)		; NO STATUS
	CLR	-(SP)
	MOV	#MAIL+N.SND,-(SP) ; POINTER TO NODE NAME WANTING
				  ;   CONNECTION
	MOV	#6,-(SP)	; NUMBER OF BYTES IN NODE NAME
	CALL	PSHERR		; STORE IN OUR EVENT QUEUE
;
; REJECT CONNECTION
;
55$:
	MOVB	NETSTA+2,R1	; NUMBER BYTES IN MAIL CONNECT BLOCK
	MOV	R5,R3		; COPY NRB
	ADD	#N.IOSU,R3	; POINT TO I/O STATUS BLOCK
	REJ$S	#INET,#NETEFN,R3,#RJAST1,<#MAIL,R1>
	BCC	58$		; DIRECTIVE ACCEPTED
	MOV	#"18,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R0		; SIGN EXTEND ERROR
	MOV	R0,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	#MAIL+N.SND,-(SP) ; POINTER TO NODE NAME WANTING
				  ;   CONNECTION
	MOV	#6,-(SP)	; NUMBER OF BYTES IN NODE NAME
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
58$:
	RETURN
	.PAGE
;
; FOUND NODE IN OUR DATABASE, ACCEPT UNLESS WE ARE ALREADY 
; ATTEMPTING TO CONNECT.
;
; PRIMARY NODE
;
60$:
	BIT	#NS.CPN,N.STS(R5)	; LOCAL CONNECT PENDING?
	BNE	55$			; YES, THEN DON'T ALLOW EITHER
	BIC	#NS.SEC,N.STS(R5)	; CLEAR SECONDARY NODE
	BIS	#NS.PRI,N.STS(R5)	; SET PRIMARY
	BR	80$
;
; SECONDARY NODE
;
70$:
	BIT	#NS.CPN,N.STS(R5)	; LOCAL CONNECT PENDING?
	BNE	55$			; YES, THEN DON'T ALLOW EITHER
	BIC	#NS.PRI,N.STS(R5)	; CLEAR PRIMARY NODE
	BIS	#NS.SEC,N.STS(R5)	; SET SECONDARY NODE
	BIT	#NS.LND,N.STS(R5)	; IS THE PRIMARY NODE NAME A LOGICAL
					;   NODE NAME?
	BEQ	80$			; NO
	BIS 	#NS.NOD,N.STS(R5)	; SET THE LOGICAL NAME TRANSLATED
					;   FLAG SINCE REMOTE REQUEST OK
80$:
;
; ACTUALLY ACCEPT THE CONNECTION
;
	MOV	MAIL+N.SND,N.CUR(R5)	; COPY ACTUAL CURRENT NODE NAME
	MOV	MAIL+N.SND+2,N.CUR+2(R5)
	MOV	MAIL+N.SND+4,N.CUR+4(R5)
	MOVB	NETSTA+2,R1		; NUMBER BYTES IN MAIL CONNECT BLOCK
	MOV	#MAIL,R2	; GET START ADDRESS OF NETWORK MAIL BUFFER
	MOV	R5,R3		; GET ADDRESS OF NRB
	ADD	#N.MBX,R3	; POINT TO START OF CONNECT BLOCK SAVE BUFFER
85$:
	MOVB	(R2)+,(R3)+	; SAVE CONNECT BLOCK 
	SOB	R1,85$		
	MOVB	NETSTA+2,R1	; GET NUMBER OF BYTES IN CONNECT BLOCK
	MOV	R5,R2		; COPY NRB
	ADD	#N.IOSU,R2	; POINT TO I/O STATUS BLOCK
	MOV	R5,R3		; GET ADDRESS OF SAVE BUFFER
	ADD	#N.MBX,R3
	.IF DF,DEBUG
	MOV	#"CR,-(SP)
	MOV	#-1,-(SP)
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE MESSAGE FOR LOGGING
	.ENDC
	ACC$S	N.LUN(R5),#NETEFN,R2,#ACCAST,<R3,R1>
	BCC	90$		; DIRECTIVE ACCEPTED?
	MOV	#"17,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R0		; SIGN EXTEND ERROR
	MOV	R0,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
90$:
	RETURN
	.PAGE
;
; INTERRUPT MESSAGE (DON'T EXPECT ANY)
;
INTMSG:
	MOV	#"19,-(SP)
	MOV	#-1,-(SP)
	CLR	-(SP)
	CLR 	-(SP)
	CLR	-(SP)
	CALL	PSHERR
	RETURN
;
; ANY TIME A DISCONNECT MESSAGE, ABORT MESSAGE, OR NETWORK ABORT MESSAGE
; IS RECEIVED, AN ATTEMPT WILL BE MADE TO DISCONNECT THE LOGICAL LINK
; (PROBABLY DISCONNECTED ALREADY BY REMOTE), THE NODE SENDING THE MESSAGE
; WILL BE MARKED 'NOT AVAILABLE', AND A TIMER WILL BE STARTED TO TRY 
; A LATER RECONNECT TO THE NODE.
;
; USER DISCONNECT MESSAGE
;
DSCMSG:
	CALL	NETMSG			; GET NODE NAME 
	MOV	#"20,-(SP)		; ERROR NUMBER
	CLR 	-(SP)			; NO STATUS
	CLR	-(SP)
	MOV	R5,-(SP)		; POINTER TO NODE NAME
	MOV	R2,-(SP)		; NUMBER BYTES IN NODE NAME
	CALL	PSHERR			; PUT IN MESSAGE QUEUE
	RETURN
;
; USER ABORT MESSAGE
;
ABTMSG:
	CALL	NETMSG			; GET NODE NAME 
	MOV	#"21,-(SP)		; ERROR NUMBER
	CLR 	-(SP)			; NO STATUS
	CLR	-(SP)
	MOV	R5,-(SP)		; POINTER TO NODE NAME
	MOV	R2,-(SP)		; NUMBER BYTES IN NODE NAME
	CALL	PSHERR			; PUT IN MESSAGE QUEUE
	RETURN
;
; NETWORK ABORT MESSAGE
;
ABOMSG:
	CALL	NETMSG			; GET NODE NAME 
	MOV	#"22,-(SP)		; ERROR NUMBER
	MOVB	NETSTA+2,-(SP)		; STATUS
	BIC	#177400,(SP)
	CLR 	-(SP)			; NO SECOND STATUS
	MOV	R5,-(SP)		; POINTER TO NODE NAME
	MOV	R2,-(SP)		; NUMBER BYTES IN NODE NAME
	CALL	PSHERR			; PUT IN MESSAGE QUEUE
	RETURN
;
; HANDLE USER DISCONNECT, USER ABORT, OR NETWORK ABORT MESSAGE 
; RECEIVED FROM REMOTE.  
;
NETMSG:
	MOV	RTRHED+HD.NRB,R5	; POINTER TO FIRST NRB
	MOV	RTRHED+HD.NCT,R2	; NUMBER OF NRB'S TO SCAN
	
	MOVB	NETSTA+3,R0		; MOVE LUN OVER WHICH THE NETWORK
5$:					;   MESSAGE WAS RECEIVED
	CMP	N.LUN(R5),R0		; SEE IF MATCH WITH LUN IN NRB
	BEQ	10$			; MATCH, NRB ADDRESS OF NODE 
					;   SENDING MESSAGE IN R5
	MOV	N.LNK(R5),R5		; POINT TO NEXT NRB
	SOB	R2,5$			; CHECK NEXT NRB
	CLR	R5			; DIDN'T FIND LUN IN ANY NRB
					;   DON'T LOG ANY NODE NAME
	CLR	R2			; NO BYTE COUNT 
	RETURN
10$:
	DSC$S	N.LUN(R5),#NETEFN	; ALSO TRY TO DISCONNECT FROM
					;   THIS END, DON'T CARE ABOUT STATUS
	BCC	20$			; DIRECTIVE ACCEPTED
	MOV	#"51,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R0		; SIGN EXTEND ERROR
	MOV	R0,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
20$:
	BIC	#NS.AVL ! NS.CPN ! NS.RCN ! NS.NOD,N.STS(R5)  
						     ; MARK NOT AVAILABLE
	BIS	#NS.DWN,N.STS(R5)	; MARK DOWN

	TST	RTRHED+HD.CTM	; IS CONNECT TIMER ACTIVE
	BNE	30$		; YES
	DIR$	#CONTIM		; ISSUE MARK TIME TO TRY CONNECT LATER
	BCC	25$		; DIRECTIVE OK
	MOV	#"49,-(SP)	; ERROR NUMBER
	MOVB	$DSW,-(SP)	; DIRECTIVE STATUS
	BIS	#177400,(SP)	; MAKE SURE NEGATIVE
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	; 
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	BR	30$
25$:
	INC	RTRHED+HD.CTM	; SET CONNECT TIMER ACTIVE FLAG
30$:
	MOV	#1,N.STAM(R5)	; SAVE CONNECT STATUS
	MOV	R5,-(SP)	; NRB ADDRESS
	MOV	#EVTDIS,-(SP)	; PUSH EVENT "DISCONNECT COMPLETE"
	CALL	PSHENT
	ADD	#N.CUR,R5	; POINT TO CURRENT NODE NAME IN NRB SO THAT
				;   IT CAN BE LOGGED
	MOV	#6,R2		; NUMBER BYTES TO LOG
	RETURN
	.PAGE
;
; THIS AST ROUTINE IS CALLED AFTER AN ACCEPT LOGICAL LINK HAS BEEN
; COMPLETED.
;
;	0(SP)= I/O STATUS BLOCK ADDRESS (MUST BE POPPED)
;
ACCAST:
	INC	ASTCNT
	MOV	R5,-(SP) 	; SAVE R5
	MOV	2(SP),R5	; GET I/O STATUS BLOCK ADDRESS
	SUB	#N.IOSU,R5	; CHANGE TO NRB ADDRESS
	.IF DF,DEBUG
	MOV	#"AA,-(SP)
	MOV	#-1,-(SP)
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE ERROR FOR LOGGING
	.ENDC
	TSTB	N.IOSU(R5)	; GOOD STATUS?
	BMI	20$		; NO.
	BIS	#NS.AVL,N.STS(R5)	; YES, FLAG AS AVAILABLE
	BIC	#NS.DWN,N.STS(R5)	; CLEAR POSSIBLE DOWN
	BIS	#NS.RCN,N.STS(R5)	; MARK AS REMOTE CONNECTING
	MOVB	N.IOSU(R5),N.STAM(R5)	; SAVE CONNECT STATUS
	MOV	R5,-(SP)		; STORE NRB
	MOV	#EVTCON,-(SP)		; EVENT IS NODE CONNECTED
	CALL	PSHENT
10$:
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK ADDRESS
	ASTX$S			; EXIT AST
;
; ERROR WHILE ACCEPTING THE CONNECTION.  ATTEMPT TO REJECT CONNECTION.
;
20$:
	MOV	R3,-(SP)	 ; SAVE R3,R2,R1
	MOV	R2,-(SP)
	MOV	R1,-(SP)
	MOV	#"16,-(SP)	 ; ERROR NUMBER
	MOVB	N.IOSU(R5),-(SP) ; I/O STATUS
	BIS	#177400,(SP)	 ; MAKE SURE NEGATIVE
	CLR	-(SP)		
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE FOR LOG
	MOV	#MLEN,R1	; DEFAULT SIZE OF NETWORK MAILBOX IN BYTES,
				;   COULD NOT USE SIZE IN BYTE 1 OF 'NETSTA'
				;   SINCE COULD HAVE BEEN DESTROYED.
	MOV	R5,R2		; COPY NRB
	ADD	#N.IOSU,R2	; POINT TO I/O STATUS BLOCK
	MOV	R5,R3		; GET ADDRESS OF CONNECT REQUEST SAVE BUFFER
	ADD	#N.MBX,R3
	REJ$S	#INET,#NETEFN,R2,#RJAST2,<R3,R1>
	BCC	21$		; DIRECTIVE ACCEPTED
	MOV	#"18,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R0		; SIGN EXTEND ERROR
	MOV	R0,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES IN NODE NAME
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
21$:
	MOV	(SP)+,R1	; RESTORE R1,R2,R3
	MOV	(SP)+,R2
	MOV	(SP)+,R3
	BR	10$		; GO TAKE CARE OF REST
	.PAGE
;
; THIS AST ROUTINE IS CALLED AFTER A REJECT OF A CONNECTION REQUEST
; BECAUSE THE NODE REQUESTING THE CONNECTION WAS NOT DEFINED IN THE 
; DATABASE.
;
;	0(SP)= I/O STATUS BLOCK ADDRESS (MUST BE POPPED)
;
RJAST1:
	MOV	R5,-(SP) 	; SAVE R5
	MOV	2(SP),R5	; GET I/O STATUS BLOCK ADDRESS
	SUB	#N.IOSU,R5	; CHANGE TO NRB ADDRESS
	MOV	#"15,-(SP)
	CLR	-(SP)		; NO STATUS 
	TSTB	N.IOSU(R5)	; STATUS GOOD
	BPL	10$
	MOV	N.IOSU(R5),(SP) ; BAD I/O STATUS
	BIS	#177400,(SP)	 ; MAKE SURE NEGATIVE
10$:
	CLR	-(SP)
	MOV	#MAIL+N.SND,-(SP) ; POINTER TO NODE NAME WANTING
				  ;   CONNECTION
	MOV	#6,-(SP)	; NUMBER OF BYTES IN NODE NAME
	CALL	PSHERR		; QUEUE ERROR FOR LOGGING
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK ADDRESS
	ASTX$S			; EXIT AST
	.PAGE
;
; THIS AST ROUTINE IS CALLED AFTER A REJECT OF A CONNECTION REQUEST
; BECAUSE AN ATTEMPT TO ACCEPT THE REQUEST RESULTED IN A BAD I/O
; STATUS.  IF THE BAD ACCEPT WAS CAUSED BY A LINK ALEADY ESTABLISHED
; ON THE LUN, A DISCONNECT IS ALSO DONE.  IF NOT, A TIMER IS SET
; SO THAT A LINK MAY BE ATTEMPTED LATER.
;
;	0(SP)= I/O STATUS BLOCK ADDRESS (MUST BE POPPED)
;
RJAST2:
	MOV	R5,-(SP) 	; SAVE R5
	MOV	2(SP),R5	; GET I/O STATUS BLOCK ADDRESS
	SUB	#N.IOSU,R5	; CHANGE TO NRB ADDRESS
	MOV	#"15,-(SP)
	CLR	-(SP)		; NO STATUS 
	TSTB	N.IOSU(R5)	; STATUS GOOD
	BPL	10$
	MOV	N.IOSU(R5),(SP) ; BAD I/O STATUS
	BIS	#177400,(SP)	 ; MAKE SURE NEGATIVE
10$:
	CLR	-(SP)
	MOV	R5,-(SP) 	  
	ADD	#N.CUR,(SP)	; ADDRESS OF NAME OF NODE WANTING CONNECTION
	MOV	#6,-(SP)	; NUMBER OF BYTES IN NODE NAME
	CALL	PSHERR		; QUEUE ERROR FOR LOGGING
	BIT	#NS.DPN ! NS.DWN,N.STS(R5)	; IS NODE AVAILABLE FOR
						;    DISCONNECT
	BNE	20$		; NO
	CALL	DISCNT		; DISCONNECT
15$:
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK ADDRESS
	ASTX$S			; EXIT AST
20$:
	TST	RTRHED+HD.CTM	; IS CONNECT TIMER ACTIVE
	BNE	25$		; YES
	DIR$	#CONTIM		; ISSUE MARK TIME
	BCC	23$		; DIRECTIVE OK
	MOV	#"49,-(SP)	; ERROR NUMBER
	MOVB	$DSW,-(SP)	; DIRECTIVE STATUS
	BIS	#177400,(SP)	; MAKE SURE NEGATIVE
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	BR	25$
23$:
	INC	RTRHED+HD.CTM	; SET CONNECT TIMER ACTIVE FLAG
25$:		
	BR 	15$		; EXIT AST
	.PAGE
;	
;
; CONNECTION COMPLETE TO A NODE
;	R1= EVTCON
;	R5= NRB ADDRESS
;
; LOG THE SUCCESSFUL EVENT, WRITE THE STATUS MESSAGE TO THE QUEUE,
; MARK THE NRB AS ON LINE, HANG A READ ON THE REMOTE NODE.   
;
CONCMP:
	MOV	#"25,-(SP)		; ERROR NUMBER
	CLR	-(SP)			; NO STATUS 
	CLR	-(SP)
	MOV	R5,-(SP)		; POINT TO NODE NAME IN NRB
	ADD	#N.CUR,(SP)		
	MOV	#6,-(SP)		; NBR BYTES IN NODE NAME
	CALL	PSHERR			; QUEUE MESSAGE
;
; WRITE CONNECT STATUS MESSAGE TO QUEUE
;
	TST	STAFLG			; DOES MESSAGE ID EXIST
	BNE	10$			; NO, DON'T ATTEMPT TO QUEUE
	MOV	#STAMSG,R0		; GET ADDRESS OF STATUS MESSAGE BUFFER
	MOV	#1,SM.UD(R0)		; FLAG AS CONNECT
	CALL	WRTSTS			; WRITE CONNECT STATUS TO QUEUE
;
; BACKUP ANY OUTSTANDING MESSAGE IDS THAT WERE TRANSMITTED TO
; THE REMOTE NODE BUT WE NEVER RECEIVED AN ACKNOWLEGE TO. WILL
; PUT THEM BACK ON THE QUEUE AND RESEND WHEN AVAILABLE.
;
10$:
	MOV	N.IDS(R5),R1	; NUMBER OF MESSAGE ID'S
	BEQ	35$		; NO MESSAGES ROUTED TO NODE CONNECTING
	MOV	R5,R4		; COPY NRB
	ADD	#N.IDXL,R4	; POINT TO THE NRB ID LIST
15$:
	TST	NID.RA(R4)	; OUTSTANDING RNA?
	BEQ	30$		; NO
	MOV	R4,RESID+Q.IOPL	; MESSAGE ID BUFFER
	ADD	#NID.NM,RESID+Q.IOPL ; OF ID TO DO THE BACKUP RNA ON
	DIR$	#RESID		; BACK UP THE RNA
	BCC	20$		; ALL OK? (ONLY CHECK DIRECTIVE AS THE
				; STATUS COULD BE BAD ANYWAY)
	MOV	#"13,ERRNUM	; ERROR NUMBER
	CALL	DSWMSG		; LOG ERROR
	DIR$	#DISCQ		; KILL PENDING I/O
	EXIT$S			; SHOULDN'T HAPPEN
20$:
	CLR	NID.RA(R4)	; NO LONGER ANY OUTSTANDING RNA
30$:
	ADD	#NID.LN,R4	; POINT TO NEXT RNA
	SOB	R1,15$		; LOOP UNTIL ALL HAVE BEEN RESET
;
; POST A READ ON THIS NODE
;
35$:
	CALL	POSRED
	RETURN
	.PAGE
;
; POST A READ ON THE NODE WHOSE NRB IS PASSED.
; THIS ROUTINE IS CALLED TO POST A READ ON THE NODE WHEN A
; CONNECTION IS FIRST MADE TO THAT NODE.  THE TASK IS NOT 
; PROCESSING AN AST.
;	R5 = NRB ADDRESS
;
;
POSRED:
	.IF DF,DEBUG
	MOV	#"PR,-(SP)
	MOV	#-1,-(SP)
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR			; QUEUE FOR LOG
	.ENDC
	BIT	#NS.AVL,N.STS(R5)	; IS THE NODE AVAILABLE?
	BNE	10$			; YES
	RETURN				; NO, THEN DONE
;
10$:
	MOV	R1,-(SP)		; SAVE R1
	MOV	N.LUN(R5),REDNET+Q.IOLU	; UNIT NUMBER
	MOV	N.IBSA(R5),REDNET+Q.IOSB ; I/O STATUS BLOCK
	MOV	N.ULNK(R5),R1		; ADDRESS OF UNSOLICITED BUFFER HEADER
	MOV	(R1)+,REDNET+Q.IOPL+2	; SIZE OF UNSOLICITED BUFFER
	MOV	R1,REDNET+Q.IOPL 	; READ BUFFER ADDRESS
	DIR$	#REDNET			; POST THE READ
	BCC	20$			; ALL A OK, LET AST HANDLE REST
	MOV	#"27,-(SP)		; ERROR NUMBER
	MOVB	$DSW,R1			; SIGN EXTEND ERROR
	MOV	R1,-(SP)		; STORE ERROR STATUS
	CLR	-(SP)			; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR			; PUT ERROR IN MESSAGE QUEUE
	BIT	#NS.DPN ! NS.DWN,N.STS(R5)  ; IS THE NODE AVAILABLE TO 
					    ;    DICONNECT? (COULD HAVE 
					    ;    ALREADY BEEN DICONNECTED)
	BNE	20$			; NO
	CALL	DISCNT			; DISCONNECT NODE
20$:
	MOV	(SP)+,R1		; RESTORE R1
	RETURN	
	.PAGE
;
; POST A READ ON THE NODE WHOSE NRB IS PASSED.
; THIS ROUTINE IS CALLED TO POST A READ WHENEVER THE TASK
; IS PROCESSING AN AST.
;	R5 = NRB ADDRESS
;
;
POSRD1:
	.IF DF,DEBUG
	MOV	#"P1,-(SP)
	MOV	#-1,-(SP)
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR			; QUEUE FOR LOG
	.ENDC
	BIT	#NS.AVL,N.STS(R5)	; IS THE NODE AVAILABLE?
	BNE	10$			; YES
	RETURN				; NO, THEN DONE
;
10$:
	MOV	R1,-(SP)		; SAVE R1
	MOV	N.LUN(R5),REDNET+Q.IOLU	; UNIT NUMBER
	MOV	N.IBSA(R5),REDNET+Q.IOSB ; I/O STATUS BLOCK
	MOV	N.ULNK(R5),R1		; ADDRESS OF UNSOLICITED BUFFER HEADER
	MOV	(R1)+,REDNET+Q.IOPL+2	; SIZE OF UNSOLICITED BUFFER
	MOV	R1,REDNET+Q.IOPL 	; READ BUFFER ADDRESS
	DIR$	#REDNET			; POST THE READ
	BCC	20$			; ALL A OK, LET AST HANDLE REST
	MOV	#"27,-(SP)		; ERROR NUMBER
	MOVB	$DSW,R1			; SIGN EXTEND ERROR
	MOV	R1,-(SP)		; STORE ERROR STATUS
	CLR	-(SP)			; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR			; PUT ERROR IN MESSAGE QUEUE
	BIT	#NS.DPN ! NS.DWN,N.STS(R5)  ; IS THE NODE AVAILABLE TO 
					    ;    DICONNECT? (COULD HAVE 
					    ;    ALREADY BEEN DICONNECTED)
	BNE	20$			; NO
	CALL	DISCNT			; DISCONNECT NODE
20$:
	MOV	(SP)+,R1		; RESTORE R1
	RETURN	
	.PAGE
;
; NETWORK READ AST
; This routine is called when a network read is complete.
; The information on the stack is:
;	 0(SP) I/O STATUS BLOCK (MUST BE POPPED)
;	 2(SP) DSW
;	 4(SP) PC PRIOR TO AST
;	 6(SP) PS PRIOR TO AST
;	10(SP) EVENT FLAG MASK WORD
;
; I/O STAUS BLOCK:
;	.BLKB	STATUS
;	.BLKB	Unused
;	.BLKW	TRANSFER COUNT
;
REDAST:
	TSTB	@(SP)	; GOOD STATUS?
	BPL	10$	; YES
;
; BAD I/O STATUS
;
	MOV	R5,-(SP)	; SAVE A REGISTER
	MOV	2(SP),R5	; GET I/O STATUS BLOCK
	SUB	#N.IOSB,R5	; POINT TO BEGINNING OF NRB
	MOV	#"28,-(SP)	
	MOV	N.IOSB(R5),-(SP)  ; I/O STATUS
	BIS	#177400,(SP)	  ; SIGN EXTEND
	CLR 	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE ERROR FOR LOG
	BIT	#NS.DPN ! NS.DWN,N.STS(R5)  ; IS THE NODE AVAILABLE TO 
					    ;    DICONNECT? (COULD HAVE 
					    ;    ALREADY BEEN DICONNECTED)
	BNE	5$			; NO
	CALL	DISCNT		; DISCONNECT NODE
5$:
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK
	ASTX$S
;
; GOOD READ STATUS
;	DEPENDING ON THE TYPE OF MESSAGE, THIS MESSAGE COULD
; EITHER BE A ROUTER TO ROUTER PROTOCOL MESSAGE OR A 
; DATA MESSAGE
;
10$:
	MOV	R5,-(SP)	; SAVE R5
	MOV	2(SP),R5	; GET I/O STATUS BLOCK
	SUB	#N.IOSB,R5	; POINT TO NRB
	.IF DF,DEBUG
	MOV	#"DD,-(SP)
	MOV	#-1,-(SP);	; JUST LOG IT FOR NOW
	MOV	N.IOSB+2(R5),-(SP)	; NUMBER OF BYTES RECEIVED
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE FOR LOG
	.ENDC
	MOV	#200$,-(SP)	; FAKE RETURN ADDRESS
	CALL	$SAVAL		; SAVE REGISTERS
	.PAGE
;
; CHECK LINK SEQUNCE NUMBER OF MESSAGE JUST RECEIVED
;
	MOV	N.ULNK(R5),R1	; GET ADDRESS OF INPUT BUFFER
	TST	(R1)+		; SKIP OVER BUFFER SIZE
	TST	N.SEQ(R5)	; ZERO, THEN MUST BE FIRST MESSAGE, ACCEPT
	BEQ	30$		; 	ANYTHING
	MOV	N.SEQ(R5),R2	; GET OLD LINK SEQUENCE NUMBER
	INC	R2		; SHOULD BE ONE MORE
	CMP	#10000.,R2	; TIME TO WRAP
	BNE	20$		; NO
	MOV	#1,R2		; YES, RESET TO ONE
20$:
	CMP	R2,MG.LSQ(R1)	; ARE THEY EQUAL
	BEQ	30$		; YES
;
; LOST A MESSAGE OR SOMETHING, OR ELSE REBOOT ON REMOTE SYSTEM, ETC.
;
; LOG FACT AND ACCEPT THE NEW LINK SEQUENCE NUMBER
;
	SUB	MG.LSQ(R1),R2	; GET DIFFERENCE
	BMI	25$		; ALREADY NEGATIVE?
	NEG	R2		; NO, THEN MAKE NEGATIVE
25$:
	MOV	#"29,-(SP)	; ERROR NUMBER
	MOV	R2,-(SP)	; DIFFERENCE IN LINK SEQUNCE NUMBER
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; STORE IN QUEUE FOR LATER LOGGING
30$:
	MOV	MG.LSQ(R1),N.SEQ(R5)	; NO MATTER WHAT ACCEPT NEW SEQ. NO.
;
; FIND OUT IF THE MESSAGE IS A ROUTER TO ROUTER MESSAGE OR A NEW
; MESSAGE TO BE QUEUED.
;
	TST	MG.SIZ+H.TYPE(R1)	; SEE IF ROUTER MESSAGE (IE: < 0)
	BMI	60$			; ROUTER MESSAGE
;
; NOT A ROUTER MESSAGE, THEN USE OUR SPECIAL ENTRY TO WRITE
; AN ENTRY INTO THE QUEUE VIA A QIO.  WE WILL USE THE SAME
; I/O STATUS BLOCK AS FOR A READ AS WE WON'T BE POSTING ANOTHER
; READ UNTIL WE FINISH WITH THE WRITE TO THE QUEUE ANYWAY.
;
	MOV	N.IBSA(R5),WRTQUE+Q.IOSB	; I/O STATUS BLOCK
	MOV	R1,WRTQUE+Q.IOPL		; MESSAGE BUFFER ADDRESS OF MESG
	ADD	#MG.SIZ,WRTQUE+Q.IOPL		; JUST RECIEVED. SKIP ROUTER INFO
	MOV	N.IOSB+2(R5),WRTQUE+Q.IOPL+2	; TOTAL SIZE OF MESSAGE
	SUB	#MG.SIZ,WRTQUE+Q.IOPL+2		; NOT WRITING HEADER
	MOV	R1,WRTQUE+Q.IOPL+4		; MESSAGE ID BUFFER
	ADD	#MG.MID,WRTQUE+Q.IOPL+4		; ADDRESS IN ROUTER HEADER
	MOV	MG.SIZ+H.TYPE(R1),WRTQUE+Q.IOPL+10  ; TYPE OF MESSAGE
	DIR$	#WRTQUE				; WRITE IT TO THE QUEUE
	BCC	40$				; WRITE OK?, IF YES WAIT FOR AST
	MOV	#"30,-(SP)			; ERROR NUMBER
	MOVB	$DSW,R2				; SIGN EXTEND ERROR
	MOV	R2,-(SP)			; STORE ERROR STATUS
	CLR	-(SP)				; CLEAR SECOND ERROR STATUS WORD
	MOV	R1,-(SP)	
	ADD	#MG.MID,(SP)		; ADDRESS OF MEG ID NAME
	MOV	#16.,-(SP)		; NUMBER OF BYTES TO MOVE
	CALL	PSHERR			; PUT ERROR IN MESSAGE QUEUE
	BIT	#NS.DPN ! NS.DWN,N.STS(R5)  ; IS THE NODE AVAILABLE TO 
					    ;    DICONNECT? (COULD HAVE 
					    ;    ALREADY BEEN DICONNECTED)
	BNE	40$			; NO
	CALL	DISCNT			; DISCONNECT NODE
40$:
	RETURN
	.PAGE
;
; ROUTER MESSAGE FROM REMOTE NODE, ONE OF THE FOLLOWING:
;	-1= ACKNOWLEGE
;	-2= REMOTE MESSAGE ID FULL
;	-3= REMOTE NODE DOES NOT KNOW OF THE MESSAGE ID
;
60$:
;
	CMP	#-1,MG.SIZ+H.TYPE(R1)	; IS THIS AN ACKNOWLEGE
	BNE	70$			; NO
;
; ACKNOWLEGE OF A PREVIOUSLY WRITTEN MESSAGE TO THE REMOTE. IE, THE
; REMOTE NODE HAS SUCCESSFULLY QUEUED THE MESSAGE AND NOW IS TELLING
; US THAT IT CAN BE REMOVED.  TO DO THIS:
; 
; DO A WRITE TO THE QUEUE WITH AN ACKNOWLEGE WITH THE RNA.
; (THE INDEX THAT WAS PASSED TO THE REMOTE ROUTER SHOULD
; POINT TO MESSAGE ID ENTRY IN THE NRB ID LIST FOLLOWED BY
; THE RNA THAT WAS RECEIVED FROM THE QUEUE).
;
	MOV	MG.IDX(R1),R3		; GET OUR INDEX (ADDRESS OF NRBID ENTRY)
	CMP	NID.RA(R3),MG.RNA(R1)	; DOES THE RNA IN MESSAGE MATCH OURS
	BEQ	65$			; YES
	MOV	#"32,-(SP)		; ERROR CODE
	MOV	MG.RNA(R1),-(SP)	; STORE FOR LOGGING
	CLR	-(SP)
	MOV	R1,-(SP)	
	ADD	#MG.MID,(SP)	; ADDRESS OF MSG ID NAME
	MOV	#16.,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR			; LOG ERROR LATER, IGNORE REST 
					; OF THE PROCESSING, MAYBE DISCONNECT??
	RETURN
65$:
	MOV	N.IBSA(R5),ACKQUE+Q.IOSB  ; I/O STATUS BLOCK
	MOV	R1,ACKQUE+Q.IOPL	; MESSAGE ID BUFFER
	ADD	#MG.MID,ACKQUE+Q.IOPL	; POINT TO MESSAGE ID
	MOV	2(R3),ACKQUE+Q.IOPL+4	; RNA 
	DIR$	#ACKQUE			; ACKNOWLEGE THE MESSAGE
	BCC	67$			; ALL OK.
	MOV	#"33,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R2		; SIGN EXTEND ERROR
	MOV	R2,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R1,-(SP)	
	ADD	#MG.MID,(SP)	; ADDRESS OF MSG ID NAME
	MOV	#16.,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
67$:
	RETURN
70$:
	CMP	#-2,MG.SIZ+H.TYPE(R1)	; IS THIS A REMOTE MESSAGE ID QUEUE FULL
	BEQ	80$			; YES
	CMP	#-3,MG.SIZ+H.TYPE(R1)	; IS THIS A REMOTE MESSAGE ID UNLNOWN
	BNE	90$			; NO
;
; REMOTE MESSAGE ID QUEUE IS FULL OR REMOTE NODE DOSEN'T KNOW OF 
; THIS MESSAGE ID.
; MARK THE MESSAGE ID AS NOT ROUTABLE, BACKUP THE
; RNA POINTER, AND START A TIMER FOR A LATER TRY.
; THE RNAAST WILL POST ANOTHER READ WHEN IT IS COMPLETE.
;
80$:
	.IF DF,DEBUG
	MOV	#"NR,-(SP)
	MOV	#-1,-(SP);		; JUST LOG IT FOR NOW
	CLR	-(SP)			
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR
	.ENDC
	MOV	MG.IDX(R1),R3		; GET OUR INDEX (ADDRESS OF NRBID ENTRY)
	BIS	#NIS.RT,NID.ST(R3)	; MARK AS NOT ROUTABLE
	TST	RTRHED+HD.NRT	; IS TIMER ACTIVE
	BNE	83$		; YES
	DIR$	#TIMER		; ISSUE MARK TIME
	BCC	82$		; DIRECTIVE OK
	MOV	#"49,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R2		; SIGN EXTEND ERROR
	MOV	R2,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R1,-(SP)	
	ADD	#MG.MID,(SP)	; ADDRESS OF MSG ID NAME
	MOV	#16.,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	BR	83$
82$:
	INC	RTRHED+HD.NRT	; SET NOT ROUTABLE TIMER ACTIVE FLAG
83$:
	MOV	N.IBSA(R5),RNAQUE+Q.IOSB ; I/O STATUS BLOCK
	MOV	R1,RNAQUE+Q.IOPL	; MESSAGE ID BUFFER
	ADD	#MG.MID,RNAQUE+Q.IOPL	; POINT TO MESSAGE ID
	DIR$	#RNAQUE			; PUT MESSAGE BACK ON QUEUE THE MESSAGE
	BCC	85$			; ALL OK.
	MOV	#"44,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R2		; SIGN EXTEND ERROR
	MOV	R2,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R1,-(SP)	
	ADD	#MG.MID,(SP)	; ADDRESS OF MSG ID NAME
	MOV	#16.,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
85$:
	RETURN	
;
90$:
	MOV	#"31,-(SP)		; INVALID ROUTER TYPE MESSAGE
	MOV	MG.SIZ+H.TYPE(R1),-(SP)	; STORE THE INVALID TYPE CODE
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR			; CALL TO PLACE IN QUEUE TO BE LOGGED
	RETURN
;
; AST EXIT  (REGISTERS RESTORED BY $SAVAL, ONLY 
;	SAVED R5 AND I/O STATUS BLOCK LEFT TO BE POPPED.
;
200$:
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+	; POP I/O STATUS BLOCK
	ASTX$S
	.PAGE
;
; MSG ID'S NOT ROUTABLE TIMER HAS EXPIRED.  QUEUE AN EVENT TO SET ALL
; MSG ID'S IN EACH NRB AS ROUTABLE.
; 	0(SP) = EVENT FLAG NUMBER (MUST BE POPPED)
;
NRTAST:
	CLR	-(SP)		; NO PARAMETER TO SAVE
	MOV	#EVTNRT,-(SP)	; PUSH ENTRY "ATTEMPT TO CONNECT"
	CALL	PSHENT
	TST	(SP)+		; POP EFN
	ASTX$S			; EXIT AST	
;
;
; MARK ALL MSG ID'S IN EACH NRB AS ROUTABLE.  CLEAR THE NOT ROUTABLE
; TIMER FLAG SO THAT A TIMER CAN BE STARTED WHEN A MSG ID BECOMES NOT
; ROUTABLE.
;
NRTENB:
	.IF DF,DEBUG
	MOV	#"ER,-(SP)		; DEBUG
	MOV	#-1,-(SP)
	CLR	-(SP)
	CLR	-(SP)
	CLR	-(SP)
	CALL	PSHERR
	.ENDC
	MOV	RTRHED+HD.NCT,R1	; NUMBER OF NRB'S DEFINED
	MOV	RTRHED+HD.NRB,R5	; NRB BEGINNING THREAD
10$:
	MOV	N.IDS(R5),R2		; NUMBER OF MSG ID'S THIS NRB
	BEQ	50$			; NO MSG ID'S THIS NRB
	MOV	R5,R3			; COPY NRB ADDRESS
	ADD 	#N.IDXL,R3		; POINT TO FIRST MSG ID LIST
20$:
	BIC	#NIS.RT,NID.ST(R3)	; MARK AS ROUTABLE
	ADD	#NID.LN,R3		; POINT TO NEXT MSG ID LIST
	SOB	R2,20$			; NEXT MSG ID IN NRB
50$:
	MOV	N.LNK(R5),R5		; GET LINK TO NEXT NRB
	SOB	R1,10$			; NEXT NRB
	CLR	RTRHED+HD.NRT		; INDICATE MARK TIME EXPIRED AND
					;   ALL MSG ID'S MARKED ROUTABLE
	RETURN				
	.PAGE
;
; A MESSAGE FROM A REMOTE NODE HAS BEEN QUEUED.
; THE QIO FOR THIS AST WAS CAUSED WHEN A READ COMPLETED
; FROM THE REMOTE NODE AND IT WAS A DATA MESSAGE AND NOT
; A ROUTER MESSAGE (IE: THE MESSAGE HAD TO BE QUEUED).  IF
; ALL IS WELL, THEN SEND BACK A ROUTER RESPONSE MESSAGE TO THE 
; REMOTE NODE AND POST ANOTHER READ FOR THAT NODE.  IF A RESPONSE
; BUFFER IS NOT AVAILABLE, AN EVENT IS QUEUED AND A TIMER IS STARTED.
; WHEN THE TIMER EXPIRES, THIS ROUTINE WILL NOT BE ENTERED AT
; AST LEVEL.
;
;	AT AST LEVEL:  0(SP) = I/O STATUS BLOCK ADDRESS (MUST BE POPPED)
;
WRQAST:
	MOV	R5,-(SP)	; SAVE R5
	MOV	2(SP),R5	; ADDRESS OF NRB I/O STATUS BLOCK
	SUB	#N.IOSB,R5	; POINT TO START OF NRB
	MOV	#RETN,-(SP)	; FAKE RETURN ADDRESS
	CALL	$SAVAL		; SAVE ALL REGISTERS
;
; ENTER HERE WHEN TIMER (ISSUED WHEN A RESPONSE BUFFER WAS NOT 
; AVAILABLE) EXPIRES.
;
RERSP:
	TSTB	N.IOSB(R5)	; WAS QUEUE SUCCESSFUL
	BPL	50$		; YES
	.IF DF,DEBUG
	MOV	#"NQ,-(SP)	; DEBUG
	MOV	N.IOSB(R5),-(SP)
	BIS	#177400,(SP)	; SIGN EXTEND
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR
	.ENDC
	CALL 	ALLRSP		; ALLOCATE RESPONSE BUFFER
	BCC	40$		; ABLE TO ALLOCATE
	JMP	NOALL		; COULD NOT ALLOCATE A BUFFER
40$:
	MOV	#-3,R.BUF+MG.SIZ+H.TYPE(R4) ; PUT TYPE IN RESPONSE BUFFER
	CMPB	#IE.NDR,N.IOSB(R5)	    ; QUEUE FULL ERROR?
	BNE	60$			    ; NO
	MOV	#-2,R.BUF+MG.SIZ+H.TYPE(R4) ; PUT TYPE IN RESPONSE BUFFER
	BR	60$
50$:
	.IF DF,DEBUG
	MOV	#"WQ,-(SP)	; DEBUG
	MOV	#-1,-(SP)
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE FOR LOG
	.ENDC
	CALL 	ALLRSP		; ALLOCATE RESPONSE BUFFER
	BCS	NOALL
	MOV	#-1,R.BUF+MG.SIZ+H.TYPE(R4) ; PUT TYPE IN RESPONSE BUFFER
;
; FILL IN RESPONSE BUFFER AND ISSUE THE QIO TO SEND THE RESPONSE TO
; THE REMOTE NODE.
;
60$:
	MOV	N.OSEQ(R5),R1	; GET OUTBOUND LINK SEQ. NUMBER
	INC	R1		; INCREMENT IT
	MOV	R1,N.OSEQ(R5)	; UPDATE IT
	CMP	#9999.,R1	; TIME TO WRAP?
	BNE	62$		; NO
	CLR	N.OSEQ(R5)	; YES, RESET SO WILL BE ONE AGAIN NEXT TIME
62$:
	MOV	R1,R.BUF+MG.LSQ(R4)	; STORE IN ROUTER MESSAGE PORTION
	MOV	N.ULNK(R5),R1	; POINT TO INPUT BUFFER
	TST	(R1)+		; SKIP OVER THE BYTE COUNT OF THE BUFFER
	MOV     MG.RNA(R1),R.BUF+MG.RNA(R4) 	; RNA
	MOV	MG.IDX(R1),R.BUF+MG.IDX(R4) 	; INDEX
;
; MESSAGE ID
;
	MOV	#MG.MID,R3		; OFFSET TO MESSAGE ID IN RECV. BUFFER
	ADD	R1,R3			; RELOCATE BY ADDING RECV. BUFFER 
	MOV	#R.BUF+MG.MID,R2	; OFFSET TO MESSAGE ID IN RESP. BUFFER
	ADD	R4,R2			; RELOCATE BY ADDING RESPONSE BUF ADDR.
	MOV	R4,-(SP)	      	; SAVE R4
	MOV	#M.IDSIZ/2,R4	      	; MSG ID SIZE IN WORDS
65$:
	MOV	(R3)+,(R2)+		; FILL MSG ID IN RSP BUFFER
	SOB	R4,65$			; LOOP UNTIL ENTIRE MSG IN IN BUFFER
	MOV	(SP)+,R4		; RESTORE RSP BUFFER PTR IN R4
;
; SOURCE NODE NAME
;
	MOV	RTRHED+HD.NOD,R.BUF+MG.SIZ+H.SNM(R4)	    
	MOV	RTRHED+HD.NOD+2,R.BUF+MG.SIZ+H.SNM+2(R4)
	MOV	RTRHED+HD.NOD+4,R.BUF+MG.SIZ+H.SNM+4(R4)
;
; DESTINATION NODE NAME
;
	MOV	MG.SIZ+H.SNM(R1),R.BUF+MG.SIZ+H.DNM(R4)     
	MOV	MG.SIZ+H.SNM+2(R1),R.BUF+MG.SIZ+H.DNM+2(R4) 
	MOV	MG.SIZ+H.SNM+4(R1),R.BUF+MG.SIZ+H.DNM+4(R4)  
;
; OFF QUEUE TIME
;
	MOV	MG.SIZ+H.OFQT(R1),R.BUF+MG.SIZ+H.OFQT(R4)   
	MOV	MG.SIZ+H.OFQT+2(R1),R.BUF+MG.SIZ+H.OFQT+2(R4)   
	MOV	MG.SIZ+H.OFQT+4(R1),R.BUF+MG.SIZ+H.OFQT+4(R4)   
	MOV	MG.SIZ+H.OFQT+6(R1),R.BUF+MG.SIZ+H.OFQT+6(R4)   
;
; SETUP FOR SEND QIO
;
	MOV	N.LUN(R5),WRTNET+Q.IOLU	 ; UNIT NUMBER
	MOV	R4,WRTNET+Q.IOSB	
	ADD	#R.IOSB,WRTNET+Q.IOSB 	 ; RSP BUFFER I/O STATUS BLOCK
	MOV	R4,WRTNET+Q.IOPL	 
	ADD	#R.BUF,WRTNET+Q.IOPL	; ADDRESS OF RESPONSE BUFFER
	MOV	RTRHED+HD.RSZ,WRTNET+Q.IOPL+2	; SIZE OF RESPONSE BUFFER
	DIR$	#WRTNET			; DO THE WRITE TO THE NETWORK
	BCC	68$			; ALL A OK, LET AST HANDLE REST
	MOV	#"48,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R1		; SIGN EXTEND ERROR
	MOV	R1,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	CALL	DEARSP		; DEALLOCATE RESPONSE BUFFER
	BIT	#NS.DPN ! NS.DWN,N.STS(R5)  ; IS THE NODE AVAILABLE TO 
					    ;    DICONNECT? (COULD HAVE 
					    ;    ALREADY BEEN DICONNECTED)
	BNE	68$			; NO
	CALL	DISCNT		; DISCONNECT NODE
	RETURN			; IF REGISTERS SAVED, RESTORE REGISTERS AND
				;   RETURN AT RETN
68$:
	CALL	POSRD1		; POST ANOTHER READ ON THIS NODE
	RETURN			; IF REGISTERS SAVED, RESTORE REGISTERS AND
				;   RETURN AT RETN
RETN:
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK
	ASTX$S
;
; COULD NOT ALLOCATE A RESPONSE BUFFER.  PUSH ENTRY IN QUEUE AND ISSUE 
; A MARK TIME TO TRY AGAIN.
;
NOALL:		
	.IF DF,DEBUG
	MOV	#"NA,-(SP)	; DEBUG
	MOV	#-1,-(SP)
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR
	.ENDC
	MOV	R5,-(SP)	; SAVE NRB ADDRESS
	MOV	#EVTRSP,-(SP)	; EVENT IS RETRY ALLOCATING RSP BUFFER
	CALL 	PSHET2		; QUEUE EVENT BUT DON'T WAKEUP
	DIR$	#RETRY		; ISSUE MARK TIME
	BCC	110$		; DIRECTIVE OK
	MOV	#"49,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R1		; SIGN EXTEND ERROR
	MOV	R1,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
110$:
	RETURN			; IF REGISTERS SAVED, RESTORE REGISTERS AND
				;   RETURN AT RETN
	.PAGE
;
; This subroutine scans the routing database to see
; if there are any messages that can be routed.  The
; criteria that is used is:
;	1) There are output buffers available
;	   (HD.BFR .NE. 0)
;	2) The Message ID existed when the router
;	   was started up (done during database 
;	   initialization).
;	3) The node that the message is to be routed
;	   to is available ((IE: N.STS .AND. N.AVL) .NE. 0)
;	4) The message count is for the message id is
;	   non zero and there is not an outstanding 
;	   RNA message.
;
; If a message is selected, then a read and wait from the Queue
; is performed and the RNA pointer is stored in the 
; NRBID  NB.RNA.  The message header and is filled in
; and the message is transmitted to the network.
;
; This routine is called with ast's disabled.
;
GETOUT:
	MOV	RTRHED+HD.NBL,R5	; GET NRB TO LOOK FOR
	MOV	RTRHED+HD.NCT,R0	; NUMBER OF NODES
10$:
	MOV	N.OIDS(R5),R1	; START SCAN WHERE WE LEFT OFF LAST TIME
	MOV	N.IDS(R5),R4	; NUMBER OF ID'S
	BEQ	35$		; NO MESAGES ROUTED TO THIS NODE
;
; LOOP HERE FOR EACH MESSAGE ID ROUTED TO THIS NODE
;
15$:
	TST	RTRHED+HD.BFR	; ANY OUTPUT BUFFERS?
	BNE	20$		; YES
	MOV	R5,RTRHED+HD.NBL ; SAVE LAST SCANNED NODE
	MOV	R1,N.OIDS(R5)	; SAVE LAST SCANNED MESSAGE ID
	RETURN
;
20$:
	BIT	#NS.AVL,N.STS(R5)	; IS LINK AVAILABLE
	BEQ	35$			; NO, THEN SKIP THIS NODE
;
; LOOP HERE FOR EACH ID IN THE NRB
;
30$:	
	TST	(R1)			; TIME TO RECYCLE THE NRBID LIST
					; ID LIST TERMINATED WITH A NULL ENTRY
	BNE	31$			; NO
	MOV	R5,R1			; POINTER TO NRBID LIST
	ADD	#N.IDXL,R1		; STARTS RIGHT AFTER THE NRB
31$:
	MOV	NID.IX(R1),R2		; DID WE FIND THIS ID DURING
					; DATABASE INITITIALZATION
	BEQ	33$			; NO.
;
	TST	M.RNA(R2)		; IS THERE AN OUTSTANDING RNA
	BNE	33$			; YES, THEN DON'T NEED TO LOOK FURTHER
	TST	M.CNT(R2)		; ARE THERE ANY MESSAGES
	BEQ	33$			; NO
	BIT	#NIS.RT,NID.ST(R1)	; IS THIS MSG ID MARKED ROUTABLE
	BEQ	39$			; YES, GO TRY TO OUTPUT IT
	.PAGE
;
; DONE WITH A NRBID
;
33$:
	ADD	#NID.LN,R1		; POINT TO NEXT NRBID
	SOB	R4,15$			; LOOP UNTIL DONE WITH ALL NRBIDS
	MOV	R5,R1			; SCANNED WHOLE NRB, POINT TO 
	ADD	#N.IDXL,R1		; BEGINNING OF LIST AGAIN
	MOV	R1,N.OIDS(R5)		; SAVE FOR NEXT SCAN THROUGH
;
; DONE WITH A NRB
;
35$:
	MOV	N.LNK(R5),R5		; GET FORWARD POINTER
	SOB	R0,10$			; LOOP UNTIL ALL HAVE BEEN SCANNED
	MOV	R5,RTRHED+HD.NBL	; SAVE LAST SCANNED NODE
	RETURN
;
; WE HAVE A NODE WITH MESSAGES AND WE HAVE BUFFERS AVAILABLE
; TO OUTPUT THE MESSAGE.
;
39$:
	MOV	R4,-(SP)		; SAVE NRBID COUNTER
	CALL	ALLBUF			; ALLOCATE A BUFFER
	BCC	40$			; IT SHOULD ALLOCATE!!!
	MOV	#"40,ERRNUM		; ERROR NUMBER
	CLR	ERRSTA			; NO STATUS
	CALL	MESGW			; WE WANT TO LOG
	IOT				; DO AN IOT SO WILL FAULT AND GET PMD
	.PAGE
;
; R4= BUFFER TO WRITE INTO
;
40$:
	MOV	R4,REDQUE+Q.IOSB		; I/O STATUS BLOCK ADDRESS
	ADD	#O.IOSB,REDQUE+Q.IOSB		; IN BUFFER JUST ALLOCATED
	MOV	R4,REDQUE+Q.IOPL
	ADD	#O.BUF+MG.SIZ,REDQUE+Q.IOPL	; SKIP OVER LINKS AND RTR HDR.
	MOV	R1,REDQUE+Q.IOPL+4		; NRBID ADDRESS 
	ADD	#NID.NM,REDQUE+Q.IOPL+4		; POINT TO MESSAGE ID NAME
	MOV	RTRHED+HD.OSZ,REDQUE+Q.IOPL+2	; SIZE OF THE BUFFERS
	SUB	#MG.SIZ,REDQUE+Q.IOPL+2		; NEED SPACE FOR ROUTER INFO.
	DIR$	#REDQUE				; DO THE READ
	BCC	55$				; DIRECTIVE OK?
	MOV	#"41,-(SP)			; ERROR NUMBER
	MOVB	$DSW,-(SP)			; DIRECTIVE STATUS
	BIS	#177400,(SP)			; MAKE SURE NEGATIVE
	CLR	-(SP)			
	MOV	R1,-(SP)		; POINT TO MSG ID NAME IN NRB
	ADD	#NID.NM,(SP)		
	MOV	#16.,-(SP)		; NBR BYTES IN MSG ID NAME
	CALL	PSHERR			; QUEUE MESSAGE
50$:			
	CALL	DEABUF			; DEALLOCATE THE BUFFER
	ADD	#40000,NID.ST(R1)	; INCREMENT RETRY COUNTER,
					;   LAST TWO BITS OF NID.ST (V1.6)
	BCC	52$			; NO CARRY OUT OF BIT 15,
					;   TRY NEXT TIME (V1.6)
	CLR	NID.IX(R1)		; WON'T TRY THIS MESSAGE
					;   AGAIN!!!
52$:
	MOV	(SP)+,R4		; RESTORE NRBID COUNTER
	BR	33$			; GO HANDLE REST FOR THIS NODE
55$:
	CMPB	#IS.SUC,O.IOSB(R4)		; GOOD STATUS?
	BEQ	60$				; YES
	MOV	#"42,-(SP)			; NO, LOG THE ERROR
	MOVB	O.IOSB(R4),-(SP)		; GET ERROR CODE FOR LOGGING
	BIS	#177400,(SP)			; EXTEND THE ERROR CODE
	CLR	-(SP)			
	MOV	R1,-(SP)		; POINT TO MSG ID NAME IN NRB
	ADD	#NID.NM,(SP)		
	MOV	#16.,-(SP)		; NBR BYTES IN MSG ID NAME
	CALL	PSHERR			; QUEUE MESSAGE
	BR	50$				; COMMON ERROR PROCESSING
	.PAGE
;
; WRITE THE MESSAGE TO THE NETWORK, FILLING THE 
; ROUTING DATABASE HEADER AND THE NORMAL HEADER
;
; R5= NRB
; R4= OUTPUT BUFFER
;
60$:
	BIC	#140000,NID.ST(R1)	; CLEAR RETRY COUNTER BITS (V1.6)
	MOV	R1,-(SP)
	MOV	N.OSEQ(R5),R1	; GET OUTBOUND LINK SEQ. NUMBER
	INC	R1		; INCREMENT IT
	MOV	R1,N.OSEQ(R5)	; UPDATE IT
	CMP	#9999.,R1	; TIME TO WRAP?
	BNE	70$		; NO
	CLR	N.OSEQ(R5)	; YES, RESET SO WILL BE ONE AGAIN NEXT TIME
70$:
	MOV	R1,O.BUF+MG.LSQ(R4)	; STORE IN ROUTER MESSAGE PORTION
	MOV	(SP),R1			; GET SAVED NRBID ADDRESS
	MOV	R1,O.BUF+MG.IDX(R4)	; STORE NRBID INDEX
	MOV	O.IOSB+2(R4),O.BUF+MG.RNA(R4)	; STORE RNA
	MOV	O.IOSB+2(R4),NID.RA(R1)	; STORE IN NRBID TOO
;
; MOVE IN THE MESG ID
;
	MOV	NID.NM(R1),O.BUF+MG.MID(R4)
	MOV	NID.NM+2(R1),O.BUF+MG.MID+2(R4)
	MOV	NID.NM+4(R1),O.BUF+MG.MID+4(R4)
	MOV	NID.NM+6(R1),O.BUF+MG.MID+6(R4)
	MOV	NID.NM+10(R1),O.BUF+MG.MID+10(R4)
	MOV	NID.NM+12(R1),O.BUF+MG.MID+12(R4)
	MOV	NID.NM+14(R1),O.BUF+MG.MID+14(R4)
	MOV	NID.NM+16(R1),O.BUF+MG.MID+16(R4)
;
; MOVE IN OUR NODE NAME
;
	MOV	RTRHED+HD.NOD,O.BUF+MG.SIZ+H.SNM(R4)
	MOV	RTRHED+HD.NOD+2,O.BUF+MG.SIZ+H.SNM+2(R4)
	MOV	RTRHED+HD.NOD+4,O.BUF+MG.SIZ+H.SNM+4(R4)
;
; MOVE IN TARGET NODE NAME
;
	MOV	N.CUR(R5),O.BUF+MG.SIZ+H.DNM(R4)
	MOV	N.CUR+2(R5),O.BUF+MG.SIZ+H.DNM+2(R4)
	MOV	N.CUR+4(R5),O.BUF+MG.SIZ+H.DNM+4(R4)
;
; NOW DO A QIO TO THE NETWORK WITH THE MESSAGE
; THE BYTE COUNT OF THE MESSAGE IS IN THE MESSAGE
; HEADER PLUS OUR ROUTER HEADER SIZE (MG.SIZ) AND
; H.LEN.
;
	MOV	O.BUF+MG.SIZ+H.LEN(R4),R1   ; GET SIZE OF MESSAGE PART
	ADD	#H.SIZ+MG.SIZ,R1	; TOTAL SIZE TO BE WRITTEN TO NETWORK
	MOV	R1,SNDNET+Q.IOPL+2	; STORE IN QIO
	MOV	R4,SNDNET+Q.IOPL	; BUFFER ADDRESS
	ADD	#O.BUF,SNDNET+Q.IOPL	; ADD OFFSET TO START OF BUFFER
	MOV	N.LUN(R5),SNDNET+Q.IOLU ; LOGICAL UNIT NUMBER
	MOV	#O.IOSB,SNDNET+Q.IOSB 	; I/O STATUS BLOCK OFFSET 
	ADD	R4,SNDNET+Q.IOSB	; RELOCATE TO AN ADRESS
	DIR$	#SNDNET			; DO THE OUTPUT
	BCC	80$			; A OK?
	MOV	#"43,-(SP)		; ERROR NUMBER
	MOVB	$DSW,-(SP)		; DIRECTIVE STATUS
	BIS	#177400,(SP)		; MAKE SURE NEGATIVE
	CLR	-(SP)			
	MOV	R5,-(SP)		; POINT TO NODE NAME IN NRB
	ADD	#N.CUR,(SP)		
	MOV	#6,-(SP)		; NBR BYTES IN NODE NAME
	CALL	PSHERR			; QUEUE MESSAGE
	CALL 	DEABUF			; DEALLOCATE THE BUFFER
	BIT	#NS.DPN ! NS.DWN,N.STS(R5)  ; IS THE NODE AVAILABLE TO 
					    ;    DICONNECT? (COULD HAVE 
					    ;    ALREADY BEEN DICONNECTED)
	BNE	75$			; NO
	CALL	DISCNT		; DISCONNECT NODE
75$:
	MOV	(SP)+,R1	; RESTORE R1
	MOV	(SP)+,R4	; RESTORE R4
	JMP	35$		; GO HANDLE NEXT NRB
80$:
	MOV	(SP)+,R1	; RESTORE R1
	MOV	(SP)+,R4	; RESTORE R4
	JMP	33$
	.PAGE
;
; A READ BUT NOT ACKNOWLEGED POINTER HAS BEEN REPLACED ON THE
; QUEUE.  THE QIO FOR THIS READ WAS PROBABLY ENVOKED WHEN
; A RESPONSE FROM THE REMOTE COMPUTER SHOWED THAT THE REMOTE
; COMPUTER WAS FULL, OR DIDN'T KNOW OF THE MESSAGE ID
;
; SINCE WE COULDN'T HAVE THE NETWORK POOPING ON OUR BUFFER,
; WE HAD TO WAIT UNTIL THE QUEACP FINISHED WITH THE BACKUP RNA
; BEFORE WE POST ANOTHER READ.  WHICH IS WHAT WE HAVE TO DO
; HERE.
;
;	0(SP) = I/O STATUS BLOCK ADDRESS (MUST BE POPPED)
;
RNAAST:
	MOV	R5,-(SP)	; SAVE R5
	MOV	2(SP),R5	; I/O STATUS BLOCK ADDRESS
	SUB	#N.IOSB,R5	; POINT TO NRB
	TSTB	N.IOSB(R5)	; RNA SUCCESSFUL?
	BPL	10$		; YES
	MOV	R1,-(SP)	; SAVE R1
	MOV	#"36,-(SP)	; FLAG BAD STATUS
	MOV	N.IOSB(R5),-(SP)
	BIS	#177400,(SP)	; SIGN EXTEND
	CLR	-(SP)
	MOV	N.ULNK(R5),R1	; INPUT BUFFER ADDRESS
	TST	(R1)+		; SKIP BUFFER SIZE
	MOV	R1,-(SP)	
	ADD	#MG.MID,(SP)	; ADDRESS OF MSG ID NAME
	MOV	#16.,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE FOR LATER LOGGING
	CALL	POSRD1		; POST ANOTHER READ 
	MOV	(SP)+,R1	; RESTORE R1
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP IOSB ADDRESS
	ASTX$S
;
10$:
	.IF DF,DEBUG
	MOV	#"RN,-(SP)	; DEBUG
	MOV	#-1,-(SP)
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEU FOR LATER LOGGING
	.ENDC
	CALL	POSRD1		; POST ANOTHER READ 
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK ADDRESS
	SETF$S	#WAKEFN		; WAKE UP MAINLINE TO SEE IF MORE 
				; MESSAGES CAN GO OUT
	ASTX$S

	.PAGE
;
; A remote computer liked what we sent it and we were 
; acknowleging the message to the queue.  But we couldn't
; allow the network to destroy our read buffer until
; the QUEACP finished acknowleging the message.   All
; we have to do here is post another read.
;
;	0(SP) = I/O STATUS BLOCK ADDRESS (MUST BE POPPED)
;
ACKAST:
	MOV	R5,-(SP)	; SAVE R5
	MOV	2(SP),R5	; I/O STATUS BLOCK ADDRESS
	SUB	#N.IOSB,R5	; POINT TO NRB
	TSTB	N.IOSB(R5)	; RNA SUCCESSFUL?
	BPL	10$		; YES
	MOV	R1,-(SP)	; SAVE R1
	MOV	#"37,-(SP)	; FLAG BAD STATUS
	MOV	N.IOSB(R5),-(SP)
	BIS	#177400,(SP)	; SIGN EXTEND
	CLR	-(SP)
	MOV	N.ULNK(R5),R1	; INPUT BUFFER ADDRESS
	TST	(R1)+		; SKIP BUFFER SIZE
	MOV	R1,-(SP)	
	ADD	#MG.MID,(SP)	; ADDRESS OF MSG ID NAME
	MOV	#16.,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE FOR LATER LOGGING
	CALL	POSRD1		; POST ANOTHER READ 
	MOV	(SP)+,R1	; RESTORE R1
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP IOSB ADDRESS
	ASTX$S
;
10$:
	.IF DF,DEBUG
	MOV	#"AK,-(SP)	; DEBUG
	MOV	#-1,-(SP)
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEU FOR LATER LOGGING
	.ENDC
	CALL	POSRD1		; POST ANOTHER READ 
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK ADDRESS
	SETF$S	#WAKEFN		; ALL DONE, SEE IF MORE TO GO OUT
	ASTX$S

	.PAGE
;
; WRITE TO NETWORK QIO AST
;
; Deallocate the response buffer.  If there was a QIO error, push
; an entry for later logging.  Also, post another read on this node.
;
;	0(SP) = I/O STATUS BLOCK ADDRESS (MUST BE POPPED)
;
WRRAST:
	MOV	R5,-(SP)	; SAVE R5
	MOV	R4,-(SP)	; SAVE R4
	MOV	4(SP),R4	; GET I/O STAUS BLOCK ADDRESS
	SUB	#R.IOSB,R4	; CHANGE TO RESPONSE BUFFER STARTING ADDRESS
	MOV	R.NRB(R4),R5	; GET THE NRB ADDRESS
	CMPB	#IS.SUC,R.IOSB(R4)  ; GOOD STATUS
	BEQ	20$		; YES
	MOV	#"47,-(SP)	; ERROR NUMBER
	MOVB	R.IOSB(R4),-(SP)
	BIS	#177400,(SP)	; SIGN EXTEND STATUS
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE SO WILL LOG 
	BIT	#NS.DPN ! NS.DWN,N.STS(R5)  ; IS THE NODE AVAILABLE TO 
					    ;    DICONNECT? (COULD HAVE 
					    ;    ALREADY BEEN DICONNECTED)
	BNE	20$			; NO
	CALL	DISCNT		; DISCONNECT NODE
20$:
	CALL	DEARSP		; DEALLOCATE RESPONSE BUFFER
	MOV	(SP)+,R4	; RESTORE R4
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK ADDRESS
	ASTX$S			; EXIT THE AST 	
	.PAGE
;
; WRITE TO NETWORK QIO AST
;
; Deallocate the output buffer.  If there was a QIO error, push
; an entry for later logging.
;
;	0(SP) = I/O STATUS BLOCK ADDRESS (MUST BE POPPED)
;
WROAST:
	MOV	R5,-(SP)	; SAVE R5
	MOV	R4,-(SP)	; SAVE R4
	MOV	4(SP),R4	; GET I/O STATUS BLOCK ADDRESS
	SUB	#O.IOSB,R4	; CHANGE TO OUTPUT BUFFER STARTING ADDRESS
	MOV	O.NRB(R4),R5	; GET THE NRB ADDRESS
	CMPB	#IS.SUC,O.IOSB(R4)  ; GOOD STATUS
	BEQ	20$		; YES
	MOV	#"39,-(SP)	; ERROR NUMBER
	MOVB	O.IOSB(R4),-(SP)
	BIS	#177400,(SP)	; SIGN EXTEND STATUS
	CLR	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE SO WILL LOG 
	BIT	#NS.DPN ! NS.DWN,N.STS(R5)  ; IS THE NODE AVAILABLE TO 
					    ;    DICONNECT? (COULD HAVE 
					    ;    ALREADY BEEN DICONNECTED)
	BNE	20$			; NO
	CALL	DISCNT		; DISCONNECT NODE
20$:
	CALL	DEABUF
	MOV	(SP)+,R4	; RESTORE R4
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP I/O STATUS BLOCK ADDRESS
	ASTX$S			; EXIT THE AST 	
	.PAGE
;
;
; DISCONNECT THE LOGICAL LINK TO NODE 
; R5 = NRB ADDRESS OF NODE TO DISCONNECT
;
DISCNT:
	MOV	R0,-(SP)		; SAVE R0
	MOV	R5,R0			; NRB ADDRESS
	ADD	#N.IOSC,R0		; ADDRESS OF I/O STATUS BLOCK
	BIS	#NS.DPN,N.STS(R5)	; MARK DISCONNECT PENDING
	DSC$S	N.LUN(R5),#NETEFN,R0,#DISAST   ; DICONNECT LOGICAL LINK
	BCC	20$			; DIRECTIVE ACCEPTED
	BIC	#NS.DPN,N.STS(R5)	; CLEAR DISCONNECT PENDING
	MOV	#"51,-(SP)	; ERROR NUMBER
	MOVB	$DSW,R0		; SIGN EXTEND ERROR
	MOV	R0,-(SP)	; STORE ERROR STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
20$:
	MOV	(SP)+,R0	; RESTORE R0
	RETURN
	.PAGE
;
; DISCONNECT COMPLETE AST
;     0(SP) = I/O STATUS BLOCK ADDRESS
;
DISAST:
	MOV	R5,-(SP)	; SAVE R5
	MOV	2(SP),R5	; GET IOSB ADDRESS
	SUB	#N.IOSC,R5	; POINT TO START OF NRB
	TSTB	N.IOSC(R5)	; GOOD STATUS?
	BPL	10$		; YES
	BIC	#NS.DPN,N.STS(R5)   ; CLEAR DISCONNECT PENDING
	MOV	#"52,-(SP)	; ERROR NUMBER
	MOVB	N.IOSC(R5),-(SP); STATUS
	BIS	#177400,(SP)	; MAKE SURE NEGATIVE
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	; 
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP IOSB ADDRESS
	ASTX$S	
10$:
	BIC	#NS.AVL ! NS.CPN ! NS.RCN ! NS.NOD,N.STS(R5)  
						     ; MARK NOT AVAILABLE
	BIS	#NS.DWN,N.STS(R5)	; MARK DOWN
	BIC	#NS.DPN,N.STS(R5)       ; CLEAR DISCONNECT PENDING
	
	TST	RTRHED+HD.CTM	; IS CONNECT TIMER ACTIVE
	BNE	30$		; YES
	DIR$	#CONTIM		; ISSUE MARK TIME TO TRY CONNECT LATER
	BCC	25$		; DIRECTIVE OK
	MOV	#"49,-(SP)	; ERROR NUMBER
	MOVB	$DSW,-(SP)	; DIRECTIVE STATUS
	BIS	#177400,(SP)	; MAKE SURE NEGATIVE
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	; 
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
	BR	30$
25$:
	INC	RTRHED+HD.CTM	; SET CONNECT TIMER ACTIVE FLAG
30$:
	MOVB	N.IOSC(R5),N.STAM(R5)	; SAVE DISCONNECT STATUS
	MOV	R5,-(SP)	; NRB ADDRESS
	MOV	#EVTDIS,-(SP)	; PUSH EVENT "DISCONNECT COMPLETE"
	CALL	PSHENT
	MOV	(SP)+,R5	; RESTORE R5
	TST	(SP)+		; POP IOSB ADDRESS
	ASTX$S	
	.PAGE
;
;
; DISCONNECT FROM NODE COMPLETE
;	R1 = EVTDIS
;	R5 = NRB ADDRESS
;
; LOG THE EVENT AND WRITE THE STATUS MESSAGE 
; TO THE QUEUE.
;
DISCMP:
	MOV	#"53,-(SP)	; SUCCESSFUL DISCONNECT
	CLR	-(SP)		; NO STATUS
	CLR	-(SP)		; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	; 
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; PUT ERROR IN MESSAGE QUEUE
;
; WRITE CONNECT STATUS MESSAGE TO QUEUE
;
	TST	STAFLG			; DOES MESSAGE ID EXIST
	BNE	10$			; NO, DON'T ATTEMPT TO QUEUE
	MOV	#STAMSG,R0		; GET ADDRESS OF STATUS MESSAGE BUFFER
	CLR	SM.UD(R0)		; FLAG AS DISCONNECT
	CALL	WRTSTS			; WRITE DISCONNECT STATUS TO QUEUE
10$:
	RETURN
	.PAGE
;
; WRITE CONNECT/DISCONNECT MESSAGE TO 'NET_STATUS' MSG ID IN QUEUE
;	R0 = ADDRESS OF CONNECT/DISCONNECT MSG BUFFER
;	R5 = ADDRESS OF NRB
;
WRTSTS:
	MOV	N.PRI(R5),SM.PRI(R0)	; MOVE IN PRIMARY NODE NAME
	MOV	N.PRI+2(R5),SM.PRI+2(R0)	
	MOV	N.PRI+4(R5),SM.PRI+4(R0)	
	MOV	N.SEC(R5),SM.SEC(R0)	; MOVE IN SECONDARY NODE NAME
	MOV	N.SEC+2(R5),SM.SEC+2(R0)	
	MOV	N.SEC+4(R5),SM.SEC+4(R0)	
	MOV	N.STAM(R5),SM.IOS(R0)	; MOVE IN THE STATUS
	MOV	N.STS(R5),SM.STS(R0)	; MOVE IN NRB STATUS WORD
	CLR	SM.STS+2(R0)		; CLEAR SECOND WORD (NOT USED)
	DIR$	#WRTSTA			; DO THE QIO
	BCC	5$			; DIRECTIVE OK
	MOV	#"56,-(SP)		; ERROR NUMBER
	MOVB	$DSW,R1			; SIGN EXTEND ERROR
	MOV	R1,-(SP)		; STORE ERROR STATUS
	CLR	-(SP)			; CLEAR SECOND ERROR STATUS WORD
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)		; ADDRESS OF NODE NAME
	MOV	#6,-(SP)		; NUMBER OF BYTES TO MOVE
	CALL	PSHERR			; PUT ERROR IN MESSAGE QUEUE
	INC	STAFLG		; SET FLAG SO THAT NO MORE ATTEMPTS
				;   TO QUEUE STATUS WILL BE MADE	
	RETURN
5$:
	TSTB	STASTA			; CHECK QIO STATUS
	BPL	10$			; STATUS OK
	MOV	#"57,-(SP)	; ERROR NUMBER
	MOV	STASTA,-(SP)  	; I/O STATUS
	BIS	#177400,(SP)	; SIGN EXTEND
	CLR 	-(SP)
	MOV	R5,-(SP)	
	ADD	#N.CUR,(SP)	; ADDRESS OF NODE NAME
	MOV	#6,-(SP)	; NUMBER OF BYTES TO MOVE
	CALL	PSHERR		; QUEUE ERROR FOR LOG
	INC	STAFLG		; SET FLAG SO THAT NO MORE ATTEMPTS
				;   TO QUEUE STATUS WILL BE MADE	
10$:
	RETURN
	.PAGE

	.PSECT	$DATA,D,CON,LCL,REL
;
; EVENT QUEUE
;
INSPTR:	.WORD	QUEUE	; INSERT POINTER
REMPTR:	.WORD	QUEUE	; REMOVAL POINTER
QUECNT:	.WORD	0	; NUMBER OF ENTRIES IN QUEUE
QUESIZ=20.	; NUMBER OF ENTRIES
;
QUEUE:
	.REPT	QUESIZ
	.BLKW	2	; TWO WORDS PER ENTRY
	.ENDR
QUEEND=.
;
;
; This subroutine is responsible for pushing a single 
; event into our event queue.
;
; calling sequence is:
;
;	  (sp)= return address
;	02(sp)= Entry type
;	04(sp)= entry parameter
;
; NOTE:  AST MUST BE DISABLED OR CALLED FROM AN AST ROUTINE
;
; return is with the stack cleaned up and all registers preserved.
;
	.PSECT	$CODE,RO,I,CON,REL
PSHENT:
	SETF$S	#WAKEFN 	; SET NETWORK WAKE UP EVENT FLAG
PSHET2:				; ENTRY TO NOT CAUSE A WAKEUP
	CMP	#QUESIZ,QUECNT	; ROOM STILL LEFT IN QUEUE?
	BLE	40$		; NO
;
; STORE ENTRY IN QUEUE
;
	MOV	R0,-(SP)	; SAVE REGISTERS
	MOV	R1,-(SP)
	MOV	INSPTR,R0	; WHERE TO INSERT
	CMP	#QUEEND,R0	; TIME TO WRAP QUEUE
	BNE	20$		; NO
	MOV	#QUEUE,R0	; RESET TO BEGINNING OF QUEUE
;
20$:
	MOV	6(SP),(R0)+	; MOVE ENTRY TYPE
	MOV	10(SP),(R0)+	; MOVE ENTRY PARAMETER
	MOV	R0,INSPTR	; UPDATE INSERT POINTER
	INC	QUECNT		; UPDATE COUNTER
	MOV	(SP)+,R1	; RESTORE OUR REGISTERS
	MOV	(SP)+,R0
40$:
	MOV	(SP),4(SP)	; MOVE RETURN ADDRESS DOWN OVER ENTRY PARMETER
	CMP	(SP)+,(SP)+	; OLD RETURN ADDR. AND ENTRY TYPE
	RETURN
	.PAGE
;
; This subroutine is responsible for removing an entry from the
; event queue.  The calling sequence is:
;
;  CALL REMQUE
;
; On return, if carry is clear, then have an entry.  
;	R0= destroyed
;	R1= entry type
;	R5= entry parameter
; 
; else carry is set in which case the queue was empty.
;	
REMQUE:
	TST	QUECNT
	BNE	10$	; HAVE AN ENTRY
	SEC		; NO ENTRY
	RETURN
;
10$:
	MOV	REMPTR,R0	; GET REMOVAL POINTER
	MOV	(R0)+,R1	; TYPE
	MOV	(R0)+,R5	; ENTRY PARAMETER
	CMP	#QUEEND,R0	; PAST END OF QUEUE?
	BNE	20$		; NO
	MOV	#QUEUE,R0	; YES, RESET TO BEGINNING
20$:
	DEC	QUECNT		; DECREMENT NUMBER IN QUEUE
	MOV	R0,REMPTR	; POINT TO NEXT AVAILABLE
	CLC
	RETURN
	.PAGE
	.PSECT	$DATA,D,CON,LCL,REL
;
; MESSAGE QUEUE
;
INSPTE:	.WORD	ERRQUE	; INSERT POINTER
REMPTE:	.WORD	ERRQUE	; REMOVAL POINTER
EQUECT:	.WORD	0	; NUMBER OF ENTRIES IN QUEUE
EQUESZ=20.	; NUMBER OF ENTRIES
;
ERRQUE:
	.REPT	EQUESZ
	.BLKB	22.	; 22 BYTES PER ENTRY
	.ENDR
EQUEEN=.
;
;
; This subroutine is responsible for pushing a status message
; into our message queue if the console QIO busy flag is set.
; If the busy flag is not set, the message is logged without 
; being queued.
;
; calling sequence is:
;
;	  (sp)= return address
;	02(sp)= status type
;	04(sp)= error status word 1 (0 if no status)
;	06(sp)= error status word 2 (0 if no status)
;	10(sp)= address of extra ASCII to log (0 if none to log)
;	12(sp)= number of extra ASCII characters to log (0 if none to log)
;
; NOTE:  AST MUST BE DISABLED OR CALLED FROM AN AST ROUTINE
;
; return is with the stack cleaned up and all registers preserved.
;
	.PSECT	$CODE,RO,I,CON,REL
PSHERR:				
;
; STORE ENTRY IN QUEUE
;
	MOV	R0,-(SP)	; SAVE REGISTERS
	MOV	R1,-(SP)
	MOV	R2,-(SP)
	TST	BUSY		; IS A CONSOLE QIO STILL PENDING?
	BNE	10$		; YES, QUEUE MESSAGE
	JMP	LOGMSG		; LOG MESSAGE WITHOUT QUEUEING
10$:
	CMP	#EQUESZ,EQUECT	; ROOM STILL LEFT IN QUEUE?
	BLE	37$		; NO, CLEAN STACK AND EXIT
	MOV	INSPTE,R0	; WHERE TO INSERT
	CMP	#EQUEEN,R0	; TIME TO WRAP QUEUE
	BNE	20$		; NO
	MOV	#ERRQUE,R0	; RESET TO BEGINNING OF QUEUE
20$:
	MOV	20(SP),(R0)+	; MOVE TYPE
	MOV	16(SP),(R0)+	; MOVE STATUS WORD 1	
	MOV	14(SP),(R0)+	; MOVE STATUS WORD 2
	MOV	12(SP),R2	; ADDRESS OF EXTRA ASCII TO BE QUEUED
	BEQ	32$		; ZERO, NOTHING TO MOVE
	MOV	10(SP),R1	; NUMBER OF BYTES TO MOVE
30$:
	MOVB	(R2)+,(R0)+	; MOVE EXTRA ASCII TO QUEUE
	SOB	R1,30$
32$:
	MOV	10(SP),R1	; CALCULATE NUMBER BYTES TO FILL
	SUB	#16.,R1		;   WITH SPACES
	NEG	R1
	BEQ	36$		; NOTHING TO FILL WITH SPACES
35$:
	MOVB	#' ,(R0)+	; FILL REST WITH SPACES
	SOB	R1,35$
36$:
	MOV	R0,INSPTE	; UPDATE INSERT POINTER
	INC	EQUECT		; UPDATE COUNTER
37$:
	MOV	(SP)+,R2	; RESTORE OUR REGISTERS
	MOV	(SP)+,R1	
	MOV	(SP)+,R0
	MOV	(SP),12(SP)	; MOVE RETURN ADDRESS DOWN OVER TYPE
	ADD	#12,SP		; POP STACK TO RETURN ADDRESS
	RETURN
;
; CONSOLE QIO IS NOT PENDING.  LOG MESSAGE WITHOUT QUEUEING.
;
LOGMSG:
	INC	BUSY		; SET CONSOLE QIO PENDING FLAG
	MOV	#ASCXTA,R0	; PLACE FOR EXTRA ASCII
	MOV	20(SP),ERRNUM	; MOVE TYPE
	MOV	16(SP),ERRSTA	; MOVE STATUS WORD 1	
	MOV	14(SP),ERRSTA+2	; MOVE STATUS WORD 2
	MOV	12(SP),R2	; ADDRESS OF EXTRA ASCII TO BE QUEUED
	BEQ	32$		; ZERO, NOTHING TO MOVE
	MOV	10(SP),R1	; NUMBER OF BYTES TO MOVE
30$:
	MOVB	(R2)+,(R0)+	; MOVE EXTRA ASCII TO QUEUE
	SOB	R1,30$
32$:
	MOV	10(SP),R1	; CALCULATE NUMBER BYTES TO FILL
	SUB	#16.,R1		;   WITH SPACES
	NEG	R1
	BEQ	36$		; NOTHING TO FILL WITH SPACES
35$:
	MOVB	#' ,(R0)+	; FILL REST WITH SPACES
	SOB	R1,35$
36$:
	CALL	MESG		; LOG MESSAGE
	MOV	(SP)+,R2	; RESTORE OUR REGISTERS
	MOV	(SP)+,R1	
	MOV	(SP)+,R0
	MOV	(SP),12(SP)	; MOVE RETURN ADDRESS DOWN OVER TYPE
	ADD	#12,SP		; POP STACK TO RETURN ADDRESS
	RETURN
	.PAGE
;
; This subroutine is responsible for removing an entry from the
; status message queue.  The calling sequence is:
;
;  CALL REMERR
;
REMERR:
	TST	EQUECT		; IS THERE A MESSAGE IN QUEUE?
	BNE	10$		; YES, SEE IF MESSAGE CAN BE SENT TO CONSOLE
	RETURN			
10$:
	INC	BUSY		; SET QIO PENDING FLAG
	MOV	REMPTE,R0	; GET REMOVAL POINTER
	MOV	#ASCXTA,R2	; EXTRA ASCII ADDRESS IN R2
	MOV	(R0)+,ERRNUM	; STATUS TYPE
	MOV	(R0)+,ERRSTA	; STATUS WORD 1
	MOV	(R0)+,ERRSTA+2	; STATUS WORD 2
	MOV	#8.,R1		; NUMBER OF WORDS IN EXTRA ASCII
15$:
	MOV	(R0)+,(R2)+	; MOVE WORD
	SOB	R1,15$
	CMP	#EQUEEN,R0	; PAST END OF QUEUE?
	BNE	20$		; NO
	MOV	#ERRQUE,R0	; YES, RESET TO BEGINNING
20$:
	DEC	EQUECT		; DECREMENT NUMBER IN QUEUE
	MOV	R0,REMPTE	; POINT TO NEXT AVAILABLE
	CALL	MESG		; LOG MESSAGE
	RETURN
	.PAGE
;
;
; SUBROUTINE 'ALLBUF' WILL ALLOCATE AN OUTPUT BUFFER.  
;
;   RECEIVES:	R5 -- ADDRESS OF NRB
;   RETURNS:	R4 -- ADDRESS OF OUTPUT BUFFER
;		C=0 IF OUTPUT BUFFER WAS ALLOCATED
;		C=1 IF ALLOCATION FAILED
;
ALLBUF:
	TST	RTRHED+HD.BFR		; SEE IF THERE IS A FREE BUFFER
	BNE	10$			; THERE IS
	SEC				; SET CARRY TO INDICATE ALLOCATION
					;   FAILURE
	RETURN
;
10$:
	MOV	RTRHED+HD.OCT,R3	; TOTAL NUMBER OF BUFFERS AVAILABLE
	MOV	RTRHED+HD.BLS,R4	; ADDRESS OF FIRST BUFFER TO CHECK
15$:
	TST	O.NRB(R4)		; SEE IF THE POINTER TO THE NRB IS
					;   ZERO INDICATING A FREE BUFFER
	BEQ	20$			; NOT IN USE
	MOV	O.LNK(R4),R4		; LOAD POINTER TO NEXT BUFFER
	SOB	R3,15$			; CHECK NEXT BUFFER
	SEC				; SET CARRY TO INDICATE ALLOCATION
					;   FAILURE (SHOULD NOT HAPPEN SINCE
					;   FREE COUNTER WAS NOT ZERO)
	RETURN
;
20$:
	MOV	R5,O.NRB(R4)		; STORE POINTER TO NRB TO ALLOCATE
					;   BUFFER
	DEC	RTRHED+HD.BFR		; DECREMENT FREE COUNTER
	CLC				; CLEAR CARRY TO INDICATE SUCCESS
	RETURN
;
;
;
;
; SUBROUTINE 'DEABUF' WILL DEALLOCATE AN OUTPUT BUFFER.  
;
;   RECEIVES:	R4 -- ADDRESS OF BUFFER TO DEALLOCATE
;
DEABUF:
	CLR	O.NRB(R4)		; ZERO POINTER TO NRB TO FREE BUFFER
	MOV	R4,RTRHED+HD.BLS	; POINT NEXT POSSIBLE FREE BUFFER TO
					;   THIS BUFFER
	INC	RTRHED+HD.BFR		; INCREMENT FREE COUNTER
	CMP 	#1,RTRHED+HD.BFR	; DID FREE COUNT GO FROM 0 TO 1
	BNE	10$			; NO
	SETF$S	#WAKEFN			; HAVE 1 FREE OUTPUT BUFFER NOW,
					;   SET WAKEUP EFN TO SCAN FOR 
					;   MORE WORK TO SEND
10$:
	RETURN
;
;
;
;
; SUBROUTINE 'ALLRSP' WILL ALLOCATE A RESPONSE BUFFER.  
;
;   RECEIVES:	R5 -- ADDRESS OF NRB
;   RETURNS:	R4 -- ADDRESS OF RESPONSE BUFFER
;		C=0 IF RESPONSE BUFFER WAS ALLOCATED
;		C=1 IF ALLOCATION FAILED
;
ALLRSP:
	TST	RTRHED+HD.RFR		; SEE IF THERE IS A FREE BUFFER
	BNE	10$			; THERE IS
	SEC				; SET CARRY TO INDICATE ALLOCATION
					;   FAILURE
	RETURN
;
10$:
	MOV	RTRHED+HD.RCT,R3	; TOTAL NUMBER OF BUFFERS AVAILABLE
	MOV	RTRHED+HD.RLS,R4	; ADDRESS OF FIRST BUFFER TO CHECK
15$:
	TST	R.NRB(R4)		; SEE IF THE POINTER TO THE NRB IS
					;   ZERO INDICATING A FREE BUFFER
	BEQ	20$			; NOT IN USE
	MOV	R.LNK(R4),R4		; LOAD POINTER TO NEXT BUFFER
	SOB	R3,15$			; CHECK NEXT BUFFER
	SEC				; SET CARRY TO INDICATE ALLOCATION
					;   FAILURE (SHOULD NOT HAPPEN SINCE
					;   FREE COUNTER WAS NOT ZERO)
	RETURN
;
20$:
	MOV	R5,R.NRB(R4)		; STORE POINTER TO NRB TO ALLOCATE
					;   BUFFER
	DEC	RTRHED+HD.RFR		; DECREMENT FREE COUNTER
	CLC				; CLEAR CARRY TO INDICATE SUCCESS
	RETURN
;
;
;
;
; SUBROUTINE 'DEARSP' WILL DEALLOCATE A RESPONSE BUFFER.  
;
;   RECEIVES:	R4 -- ADDRESS OF BUFFER TO DEALLOCATE
;
DEARSP:
	CLR	R.NRB(R4)		; ZERO POINTER TO NRB TO FREE BUFFER
	MOV	R4,RTRHED+HD.RLS	; POINT NEXT POSSIBLE FREE BUFFER TO
					;   THIS BUFFER
	INC	RTRHED+HD.RFR		; INCREMENT FREE COUNTER
	RETURN
	.PAGE
	.PSECT	$DATA,D,CON,LCL,REL
;
; QIO'S TO WRITE TO CONSOLE DEVICE
;
CONSWT:
	QIOW$	IO.WLB,ICO,CONEFN,,CONSTS,,<LGMESG,CSMGL>	
CONSOL:
	QIO$	IO.WLB,ICO,CONEFN,,CONSTS,LOGAST,<LGMESG,CSMGL>
CONSTS:
	.WORD	1,0	; CONSOLE QIO STATUS
BUSY:
	.WORD	0	; I/O IN PROGRESS FLAG
;
; DPB TO GET THE CURRENT SYSTEM TIME
;
TIME:
	GTIM$	TIMBUF
TIMBUF:
	.BLKW	8.	; BUFFER TO GET CURRENT TIME AND DATE
WAKEUP:
	.ASCII	/WAKEUP/	; FOR DEBUG WAKEUP MESSAGE
	.EVEN
;
; CONSOLE DEVICE MESSAGE
;
LGMESG:
	.BYTE	012,015		; SOME CARRIAGE RETURNS
	.BYTE	006		; A BELL
	.EVEN
MSGTIM:		; TIME STAMP TO MESSAGE
	.ASCII	/YY-MM-DD /
	.ASCII	/HH:MM:SS /
	.ASCII	/ RTRRSX ROUTER ERROR: /
	.EVEN
ERRNUM:
	.WORD	0	; ASCII ERROR NUMBER
	.ASCII	/ STATUS: /
	.EVEN
ASCSTA:
	.ASCII	/  /	; WORD 0 OF STATUS BLOCK
	.ASCII	/  /
	.ASCII 	/  /
	.ASCII	/  /	; SEPARATE STATUS BLOCK WORDS
	.EVEN
ASCST2:
	.ASCII	/  /	; WORD 1 OF STATUS BLOCK
	.ASCII	/  /
	.ASCII 	/  /
	.EVEN
ASCXTA:
	.ASCII	/    /	; SOME EXTRA ASCII IF DESIRED
	.ASCII	/    /	; SOME EXTRA ASCII IF DESIRED
	.ASCII	/    /	; SOME EXTRA ASCII IF DESIRED
	.ASCII	/    /	; SOME EXTRA ASCII IF DESIRED
	.BYTE	012,015,006,006  ; LINE FEEDS, CARRIAGE RETURNS, BELLS
	.EVEN
CSMGL=.-LGMESG

	.PAGE
;
; MESSAGE OUTPUT SUBROUTINE
;
;    ERROR	DESCRIPTION
;
;	01	Unable to set up SST vector
;	02	Unable to attach to QUEHED region
;       03	Unable to map the QUEHED region
;	04	Successful map to QUEHED, status= size
;	05	Routing database not consistent with one linked with task
;	06	Assign lun to network failure
;	07	Specify network AST directive failure
;	08	Specify network AST I/O status failure
;	09	Get local node information directive failure
;	10	Get local node information status failure
;	11	Assign lun to network bad i/o status
;	12	Unknown network message type received (type is status)
;	13	Bad directive status while backing up RNA when link est.
;	14	Good connect to the network. Local node name is printed
;	15	Connection requested by remote node was rejected by this node
;	16      Node connection accept attempt failed for a remote node
;	17	Bad directive status while attempting to accept connection
;	18	Bad directive status while attempting to reject connection
;	19	Interupt network message received
;	20	User disconnect network message received
;	21	User abort network message received
;	22	Network abort network message received
;	23	Get network data bad I/O status 
;	24	Remote request for a node not in routing database
;	25	Connect complete to node printed
;	26	Mesg. ID was not found in Queue,  Mesg. ID will not be routed
;	27	Bad directive status while posting a read for node
;	28	Read from network with bad I/O status
;	29	Link sequence number in error by delta value
;	30	Write to queue directive status error
;	31	Invalid router to router type message received
;	32	RNA received from the remote computer does not match ours
;	33	Bad directive status on ACK Write QIO to the Queue
;	34	Bad directive status while connecting to msg id in queue.
;	35	Bad I/O status while connecting to msg id in queue
;	36	Backup RNA to queue I/O status error
;	37	Ack message to queue I/O status error
;	38	Get network data bad directive status
;	39	Write to network with bad status (output buffer)
;	40	Unable to allocate an output buffer, IOT will be issued
;	41	Directive error while reading a message id from queue
;	42	Bad I/O status while reading from queue, message marked not
;		routable
;	43	Bad directive status while writing to network
;	44	Bad directive status on RNA QIO to the Queue
;	45 	Connect request bad directive status
;	46	Connect request failure for node, possible network status:
;	47	Write to network with bad status (response buffer)
;	48	Bad directive status while writing response to network
;	49	Bad directive status issuing mark time
;	50	Bad directive status while initing queue access
;	51	Bad directive status while disconnecting
;	52	Bad I/O status while disconnecting
;	53	Disconnect complete, disconnected node logged
;	54	Routing database wasn't initialized properly (i.e. was accessed
;		since last installed from disk)
;	55	Bad directive status while attempting to activate task
;	56	Bad directive status while writing connect/disconnect status
;		message to queue
;	57	Bad I/O status while writing connect/disconnect status message
;		to queue
;
;
;    DEBUG	DESCRIPTION
;
;	CA	Connect to network for network mail ast routine
;	SA	Receive network mail (AST)
;	CR	Accept connect request from remote node
;	AA	Accept connect request QIO from remote node complete
;	PR	Post a read on remote node when connect just made
;	P1	Post a read on remote node when in AST state
;	DD	Received a message from remote node
;	NR	Message not routable to remote node; remote responded that
;		it could not queue message.
;	ER	Not routable timer expired; mark all msg ids routable
;	NQ	Message received from remote node could not be queued; send
;		response to remote.
;	WQ	Message received from remote node was queued successfully;
; 		send response to remote.
;	NA	Response buffer could not be allocated
;	RN	A message read but not acknowledged by remote has been requeued.
;	AK	A message has been acknowledged successfully by the remote.
;%%%%%%%%%%%
;
; ERROR STATUS TO BE ENCODED INTO THE MESSAGE BEFORE OUTPUT
;
ERRSTA:
	.WORD	0,0
;
	.PSECT	$CODE,RO,I,CON,REL
;
; THIS ROUTINE WILL ISSUE A QIO TO THE CONSOLE AND WAIT FOR IT TO COMPLETE.
; IT IS ONLY USED TO LOG FATAL ERROR MESSAGES SINCE THE TASK MUST WAIT
; FOR THE QIO TO COMPLETE BEFORE IT EXITS.
;
DSWMSG:				; ENTRY WHERE DSW IS THE STATUS, R0 
				;    IS DESTROYED
	MOVB	$DSW,R0		; SIGN EXTEND THE ERROR CODE
	MOV	R0,ERRSTA	; STORE STATUS
MESGW:				
	MOV	R0,-(SP)	; SAVE REGISTERS
	MOV	R1,-(SP)
	MOV	R2,-(SP)
	CALL	FORMAT		; FORMAT MESSAGE
	DIR$	#CONSWT		; OUTPUT MESSAGE TO CONSOLE DEVICE AND WAIT
	MOV	#16.,R1		; BLANK OUT ASCII EXTENSION (16 BYTES)
	MOV	#ASCXTA,R2
10$:
	MOVB	#' ,(R2)+	; BLANK OUT ASCII EXTENSION
	SOB	R1,10$	
	MOV	(SP)+,R2	; RESTORE OUR REGISTERS
	MOV	(SP)+,R1	
	MOV	(SP)+,R0
	RETURN
;
; THIS ROUTINE WILL ISSUE A QIO TO THE CONSOLE AND CONTINUE.  ALL NON-FATAL
; ERRORS MUST USE THIS ROUTINE SO THAT THE TASK DOES NOT WAIT FOREVER IF
; THE QIO DOESN'T COMPLETE (CONSOLE OUT OF PAPER, ETC.)
;
MESG:
	CALL	FORMAT		; FORMAT MESSAGE
	DIR$	#CONSOL		; OUTPUT MESSAGE TO CONSOLE DEVICE AND WAIT
	RETURN
;
;
; QIO TO THE CONSOLE PRINTER HAS COMPLETED.  RESET THE BUSY FLAG AND
; CHECK FOR MORE MESSAGES TO LOG.
;	
;	0(SP) = ADDRESS OF I/O STATUS BLOCK
;
LOGAST:
	MOV	R0,-(SP)	; SAVE REGISTERS
	MOV	R1,-(SP)
	MOV	R2,-(SP)
	CLR	BUSY		; RESET BUSY FLAG
	CALL	REMERR		; CHECK FOR ANOTHER MESSAGE IN QUEUE TO LOG
	MOV	(SP)+,R2	; RESTORE OUR REGISTERS
	MOV	(SP)+,R1	
	MOV	(SP)+,R0
	TST	(SP)+		; POP IOSB ADDRESS OFF STACK
	ASTX$S
;
;
; THIS ROUTINE FORMATS THE MESSAGE LOGGED ON THE CONSOLE
;
FORMAT:
	DIR$	#TIME		; GET CURRENT SYSTEM TIME
	MOV	#TIMBUF,R1	; DATE PARAMETERS
	MOV	#MSGTIM,R0	; WHERE TO ENCODE TIME
	CALL 	$DAT		; COVNERT DATE
	MOVB	#' ,(R0)+	; STORE INTERVENING SPACE
	MOV	#TIMBUF+6,R1	; TIME PARAMETERS
	MOV	#3,R2		; WANT HH:MM:SS
	CALL 	$TIM		; CONVERT TIME
;
	MOV	#"  ,ASCSTA	; BLANK OUT 
	MOV	#"  ,ASCSTA+2
	MOV	#"  ,ASCSTA+4
	TST	ERRSTA		; IS STATUS ZERO?
	BEQ	2$		; YES, NO STATUS TO LOG
	MOV	#ASCSTA,R0	; PLACE FOR ASCII
	MOV	ERRSTA,R1	; BINARY TO CONVERT
;
;
	MOV	#<10.!400!020000>,R2	; CONVERSION PARAMETERS
	CALL	$CBTA	; CALL TO CONVERT BINARY ASCII
;
;
2$:
	MOV	#"  ,ASCST2	; BLANK OUT 
	MOV	#"  ,ASCST2+2
	MOV	#"  ,ASCST2+4
	TST	ERRSTA+2	; IS SECOND STATUS WORD=0 
	BEQ	5$		; DON'T LOG IT
	MOV	#ASCST2,R0	; PLACE FOR ASCII
	MOV	ERRSTA+2,R1	; BINARY TO CONVERT
;
;
	MOV	#<10.!400!020000>,R2	; CONVERSION PARAMETERS
	CALL	$CBTA		; CALL TO CONVERT BINARY ASCII
	CLR	ERRSTA+2	; CLEAR STATUS
;
5$:
	RETURN
	.PAGE
;
; SYNCHRONOUS SYSTEM TRAP ROUTINES
;
; THE COMMON SST ROUTINE CREATES A SNAP DUMP OF THE TASK STACK
; AND THE ROUTER DATABASE REGION.  THE EXACT 
; SST IS IDENTIFIED BY AN ERROR CODE THAT APPEARS ON THE STACK
; ALONG WITH SST DEPENDENT PARAMETERS.
;
; THE STACK IN THE SNAP DUMP CONTAINS THE FOLLOWING
;	  (SP) = R5 WHEN SST OCCURRED
;	 2(SP) = R4 WHEN SST OCCURRED
;	 4(SP) = R3 WHEN SST OCCURRED
;	 6(SP) = R2 WHEN SST OCCURRED
;	10(SP) = R1 WHEN SST OCCURRED
;	12(SP) = R0 WHEN SST OCCURRED
;	14(SP) = SST CODE
;	
;
; ODD ADDRESS OR NONEXISTENT MEMORY
;	14(SP) = SST CODE 'OD'
;	16(SP) = PC WHEN SST OCCURRED
;	20(SP) = PSW WHEN SST OCCURRED
;
ODDSST:
	MOV	#"OD,-(SP)	; PUSH ODD ADDRESS CODE 'OD' ON STACK
	JMP	COMSST		; ENTER COMMON ROUTINE
;
; MEMORY PROTECT VIOLATION
;	14(SP) = SST CODE 'ME'
;	16(SP) = MMR1 (INSTRUCTION BACKUP REGISTER)
;	20(SP) = MMR2 (VIRTUAL PC OF FAULTY INSTRUCTION) 
;	22(SP) = MMR0 (MEMORY PROTECT STATUS) 
;	24(SP) = PC WHEN SST OCCURRED
;	26(SP) = PSW WHEN SST OCCURRED
MEMSST:
	MOV	#"ME,-(SP)	; PUSH MEMORT PROTECT CODE 'ME' ON STACK
	JMP	COMSST		; ENTER COMMON ROUTINE
;
; T-BIT TRAP OR EXECUTION OF A BPT INSTRUCTION
;	14(SP) = SST CODE 'TB'
;	16(SP) = PC WHEN SST OCCURRED
;	20(SP) = PSW WHEN SST OCCURRED
TBTSST:
	MOV	#"TB,-(SP)	; PUSH T-BIT CODE 'TB' ON STACK
	JMP	COMSST		; ENTER COMMON ROUTINE
;
; EXECUTION OF AN IOT INSTRUCTION
;	14(SP) = SST CODE 'IO'
;	16(SP) = PC WHEN SST OCCURRED
;	20(SP) = PSW WHEN SST OCCURRED
IOTSST:
	MOV	#"IO,-(SP)	; PUSH IOT CODE 'IO' ON STACK
	JMP	COMSST		; ENTER COMMON ROUTINE
;
; EXECUTION OF A RESERVED INSTRUCTION
;	14(SP) = SST CODE 'RE'
;	16(SP) = PC WHEN SST OCCURRED
;	20(SP) = PSW WHEN SST OCCURRED
RESSST:
	MOV	#"RE,-(SP)	; PUSH RESERVED INSTRUCTION CODE 'RE' ON STACK
	JMP	COMSST		; ENTER COMMON ROUTINE
;
; EXECUTION OF A NON-RSX EMT INSTRUCTION
;	14(SP) = SST CODE 'EM'
;	16(SP) = EMT CODE TIMES 2
;	20(SP) = PC WHEN SST OCCURRED
;	22(SP) = PSW WHEN SST OCCURRED
EMTSST:
	MOV	#"EM,-(SP)	; PUSH EMT CODE 'EM' ON STACK
	JMP	COMSST		; ENTER COMMON ROUTINE
;
; EXECUTION OF A TRAP INSTRUCTION
;	14(SP) = SST CODE 'TR'
;	16(SP) = TRAP CODE TIMES 2
;	20(SP) = PC WHEN SST OCCURRED
;	22(SP) = PSW WHEN SST OCCURRED
TRPSST:
	MOV	#"TR,-(SP)	; PUSH TRAP CODE 'TR' ON STACK
	JMP	COMSST		; ENTER COMMON ROUTINE
;
; FLOATING POINT EXCEPTION
;	14(SP) = SST CODE 'FL'
;	16(SP) = PC WHEN SST OCCURRED
;	20(SP) = PSW WHEN SST OCCURRED
FLTSST:
	MOV	#"FL,-(SP)	; PUSH FLOAT EXCEPTION CODE 'FL' ON STACK
;
COMSST:
	MOV	R0,-(SP)	; SAVE STATE OF REGISTERS WHEN SST
	MOV	R1,-(SP)	;   OCCURRED
	MOV	R2,-(SP)
	MOV	R3,-(SP)
	MOV	R4,-(SP)
	MOV	R5,-(SP)
	MOV	RDB+R.GSIZ,R1	; GET 'QUEHED' SIZE IN 32 WORD BLOCKS
	ASH	#6,R1		; CHANGE TO NUMBER OF BYTES
	ADD	#137776,R1	; MERGE IN APR6 MAPPING
	MOV	#117776,R2	; ROUTING DATABASE MAPPED BY APRS 2,3,4
	SNAP$	,,,#140000,R1,#40000,R2
				; GENERATE SNAP DUMP; QUEUE HEADER AND DATABASE
	EXIT$S			; EXIT TASK
	.END	START	
