Google
 

Trailing-Edge - PDP-10 Archives - BB-4170H-SM - sources/nspint.mac
There are 18 other files named nspint.mac in the archive. Click here to see a list.
;<4.MONITOR>NSPINT.MAC.60,  3-Jan-80 08:09:49, EDIT BY R.ACE
;UPDATE COPYRIGHT DATE
;<OSMAN.MON>NSPINT.MAC.1, 10-Sep-79 15:46:53, EDIT BY OSMAN
;TCO 4.2412 - Move definition of BUGHLTs, BUGCHKs, and BUGINFs to BUGS.MAC
;<4.MONITOR>NSPINT.MAC.58,  4-Mar-79 18:40:12, Edit by KONEN
;UPDATE COPYRIGHT FOR RELEASE 4
;<4.MONITOR>NSPINT.MAC.57, 21-Feb-79 21:47:04, EDIT BY KIRSCHEN
;ADD BUGINF FOR FREE SPACE EXHAUSTED CONDITION
;<4.MONITOR>NSPINT.MAC.56, 18-Feb-79 09:10:28, EDIT BY KIRSCHEN
;NSPINT.MAC.55 WAS EDIT TO FIX BACKGROUND TASK WAKEUP BUG
;<4.MONITOR>NSPINT.MAC.54, 15-Feb-79 16:43:47, EDIT BY ENGEL
;ADD CODE TO ALLOW ATS TO SET FLOW CONTROL
;<4.MONITOR>NSPINT.MAC.53,  8-Feb-79 17:53:41, EDIT BY MILLER
;IF CLZSDI FAILS, RELEASE LINK BLOCK ANYWAY
;<4.MONITOR>NSPINT.MAC.52, 30-Jan-79 09:38:01, EDIT BY KIRSCHEN
;CONVERT NSP ERROR CODE TO TOPS20 ERROR CODE IN XNSRLS
;<4.MONITOR>NSPINT.MAC.51, 30-Jan-79 09:04:20, EDIT BY KIRSCHEN
;ADD PERFORMANCE BREAKPOINT
;<4.MONITOR>NSPINT.MAC.50, 12-Jan-79 20:10:02, EDIT BY KIRSCHEN
;really don't clobber it this time !
;<4.MONITOR>NSPINT.MAC.49, 12-Jan-79 15:05:15, EDIT BY KIRSCHEN
;DO NOT CLOBBER SEGMENT SIZE IN XNSRSS
;<4.MONITOR>NSPINT.MAC.48,  3-Jan-79 15:35:56, EDIT BY KIRSCHEN
;RETURN ERROR CODE IN CLOSE FAILURE DUE TO BAD LINK ID
;<4.MONITOR>NSPINT.MAC.47, 28-Dec-78 14:38:50, EDIT BY KIRSCHEN
;REMOVE DEFENSIVE BUGCHK AT IFLUSH, NOT NEEDED
;<4.MONITOR>NSPINT.MAC.46,  9-Nov-78 08:58:08, EDIT BY KIRSCHEN
;ON FAILURE FROM CRTLNK, DELETE LINK BLOCK AND UNLOCK TREE
;<4.MONITOR>NSPINT.MAC.45,  8-Aug-78 16:16:28, Edit by KIRSCHEN
;RETURN FROM STORING BYTES IN XNSRIN
;<4.MONITOR>NSPINT.MAC.44,  8-Aug-78 16:14:17, Edit by KIRSCHEN
;INITIALIZE LLEOM EACH TIME THRU XNSOUT
;<4.MONITOR>NSPINT.MAC.43,  3-Aug-78 19:12:07, Edit by HALL
;ADD IFIW'S TO THE CLIDSP TABLE
;<4.MONITOR>NSPINT.MAC.42, 26-Jul-78 11:46:39, Edit by KIRSCHEN
;DO  NOT LOCK LINK BLOCK AT START OF CLOSE CODE (DRIVER WILL LOCK IT)
;<4.MONITOR>NSPINT.MAC.41, 28-Jun-78 13:37:53, Edit by KIRSCHEN
;RETURN ERROR CODE ON SUPERFLUOUS BUFFER
;<4.MONITOR>NSPINT.MAC.40, 26-Jun-78 16:42:59, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.39, 26-Jun-78 10:36:37, Edit by KIRSCHEN
;MORE CLEAN UP
;<4.MONITOR>NSPINT.MAC.38, 26-Jun-78 10:22:57, Edit by KIRSCHEN
;CLEAN UP, ADD ERROR CODES
;<4.MONITOR>NSPINT.MAC.37, 20-Jun-78 16:25:14, Edit by KIRSCHEN
;UNLOCK BLOCK WHEN ERROR IN CLOSE
;<4.MONITOR>NSPINT.MAC.36, 16-Jun-78 15:10:34, Edit by KIRSCHEN
;FIX TEST FOR ABORT CLOSE AT CLIDIR
;<4.MONITOR>NSPINT.MAC.35, 14-Jun-78 14:17:42, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.34, 14-Jun-78 08:21:11, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.33, 13-Jun-78 15:53:02, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.32, 13-Jun-78 09:01:41, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.31, 13-Jun-78 09:00:40, Edit by KIRSCHEN
;ADD OTHER CLOSE STATES
;<4.MONITOR>NSPINT.MAC.30, 12-Jun-78 14:50:47, Edit by KIRSCHEN
;MORE BUG FIXES TO OPNINT
;<4.MONITOR>NSPINT.MAC.29, 12-Jun-78 14:14:44, Edit by KIRSCHEN
;SUPPLY DEFAULT REASON IF NEEDED ON CLOSE
;<4.MONITOR>NSPINT.MAC.28, 12-Jun-78 11:39:11, Edit by KIRSCHEN
;SEND OPTIONAL DATA ON CLOSE
;<4.MONITOR>NSPINT.MAC.27,  8-Jun-78 15:29:55, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.26,  8-Jun-78 14:35:13, Edit by KIRSCHEN
;ADD SOME ERROR CODES
;<4.MONITOR>NSPINT.MAC.25,  8-Jun-78 12:18:08, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.24,  8-Jun-78 12:16:05, Edit by KIRSCHEN
;MORE CLOSE CODE
;<4.MONITOR>NSPINT.MAC.23,  8-Jun-78 09:16:02, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.22,  8-Jun-78 09:04:40, Edit by KIRSCHEN
;DO NOT USE ARG BLOCK ENTRIES NOT PRESENT IN OPNINT
;<4.MONITOR>NSPINT.MAC.21,  7-Jun-78 10:15:49, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.20,  7-Jun-78 10:14:32, Edit by KIRSCHEN
;YET MORE CLOSE CODE
;<4.MONITOR>NSPINT.MAC.19,  5-Jun-78 13:55:36, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.18,  5-Jun-78 13:53:43, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.17,  1-Jun-78 10:45:20, Edit by KIRSCHEN
;<4.MONITOR>NSPINT.MAC.16,  1-Jun-78 10:41:43, Edit by KIRSCHEN
;ADD MORE CLOSE CODE
;<4.MONITOR>NSPINT.MAC.15, 30-May-78 13:19:16, Edit by KIRSCHEN
;RETURN LINK ADDRESS IN T4 FROM CREATE LINK FUNCTION FOR DEBUGGING
;<4.MONITOR>NSPINT.MAC.14, 30-May-78 09:08:12, Edit by KIRSCHEN
;MAKE SOME ROUTINES INTERNAL
;<4.MONITOR>NSPINT.MAC.13, 26-May-78 11:48:07, Edit by KIRSCHEN
;BREAK INTERNAL INTERFACE CODE OUT OF NSPSRV

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976,1977,1978,1979,1980 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
	SEARCH NSPPAR,PROLOG,PROKL


	EXTN <FLUSH,DELNOD,CHKDCR,NSPERR>
	EXTN <SNDSEG,SNINT,RDSTS,MTRNCK,MOVSTR,CLZSDI>
	EXTN <STRSAV,OBJSRC,MOVSEG,TELOBE,SNDCHK,CHKEMP>
	EXTN <MAKTST,TSTLCL,TIMWAT,RDINT,LOKLL>
	EXTN <LLLKUP,LOKLL,ULOKLL,BLKLOK,BLKULK,OPNIWK,MAKMSG>
	EXTN <CRTLNK,DELNOD,MOVST1,MAKFLG,INTSET,GETRES>
	EXTN <ASGWDW,BLKASG,CMPLEN,DCNNAM,DCNSET,EXTSET,ITSID>
	EXTN <ITSNAM,ITSNUM,LASTSK,LLBIT,LLBITS,LLHEAD,LLLLCK>
	EXTN <MAXBLK,MAXEXP,MAXLNK,MCBDTE,MSGQ,NAKCNT,NETDIR>
	EXTN <NETSR1,NETSQ1,NETUIN,NETUOU,NODNUM,NSPLPB,NSPMAX>
	EXTN <OBJMAX,OBJTBL,OPNDNC,OPNSRC,OURCNT,OURNAM,OURNUM>
	EXTN <PRSNAM,RMSGQ,SMSGQ,SRCNAM,SRNSET,VERSET>

	TTITLE (NSPINT,,< - Network Services Protocol Internal Interface>)
;DEFINE LOCAL MACROS

	DEFINE LLLOCK
   <	CALL LOKLL		;;GO LOCK UP THE TREE
   >				;;END OF LLLOCK MACRO

	DEFINE LLLULK
   <	CALL ULOKLL		;;GO UNLOCK THE TREE
   >				;;DONE

   DEFINE ATTENT (VALUE,BIN,COUNT,EXCLU)
<	<BIN>B0+<COUNT>B17+EXCLU*1000+VALUE
>

DEFSTR (NTATR,,35,9)
DEFSTR (NTATC,,17,6)
DEFSTR (NTATE,,26,9)
DEFSTR (NTATB,,0,1)

	DEFAC (STS,P1)
	DEFAC (JFN,P2)
	DEFAC (DEV,P4)
	DEFAC (F1,P5)
SUBTTL	NSP Internal Interface


; NSP FUNCTION DISPATCH VECTOR

	SWAPCD

NSPVEC::PHASE 0			;INSURE NO SKEW IN DEFINITIONS OF OFFSETS

.NSCRT::!XNSCRT!IFIW		;CREATE AN INTERNAL LOGICAL LINK
.NSCLZ::!XNSCLZ!IFIW		;CLOSE AN INTERNAL LOGICAL LINK
.NSOUT::!XNSOUT!IFIW		;OUTPUT TO AN INTERNAL LOGICAL LINK
.NSINB::!XNSINB!IFIW		;DRIVER IS PROVIDING NSP WITH A BUFFER FOR INPUT
.NSRIN::!XNSRIN!IFIW		;READ INTERRUPT MESSAGE ON INTERNAL LOGICAL LINK
.NSSIN::!XNSSIN!IFIW		;SEND INTERRUPT MESSAGE ON INTERNAL LOGICAL LINK
.NSTRN::!XNSTRN!IFIW		;TRUNCATE THE CURRENT MESSAGE
.NSRLS::!XNSRLS!IFIW		;READ LINK STATUS
.NSRHN::!XNSRHN!IFIW		;READ HOST NAME
.NSRTN::!XNSRTN!IFIW		;READ TASK NAME
.NSRDA::!XNSRDA!IFIW		;READ OPTIONAL DATA
.NSRSS::!XNSRSS!IFIW		;READ LINK SEGMENT SIZE

	DEPHASE			;END OF SKEW CHECK

NSPVLN==.-NSPVEC		;LENGTH OF NSP DISPATCH VECTOR

XNSRTN::RETBAD (ARGX02)		;FUNCTION NOT IMPLEMENTED
XNSTRN::RETBAD (ARGX02)		;FUNCTION NOT IMPLEMENTED
SUBTTL	Internal Links - Temporary Test Routines

; LINK CREATION

MAKINT:	MOVX T1,NS%RD!NS%WRT	;LONG ARG FORMAT, READ AND WRITE
	MOVE T2,['DRIVER']	;DRIVER CORRELATION CODE IS SIXBIT "DRIVER"
	MOVEI T3,[ IFIW!R
		IFIW!R

		IFIW![	CALL ASGPAG
			 RET
			MOVEI T2,4000
			RETSKP ]

		IFIW![	MOVE T1,T2
			CALL RELPAG
			 JFCL
			RET ]
		IFIW!R
		IFIW!R
		IFIW!R
		IFIW!R
		IFIW!R
		IFIW!R
		IFIW!R ]
	MOVEI T4,[ EXP 13	;SIZE OF ARG BLOCK
		[ASCIZ/2136/]
		[ASCIZ/TASK/]	;OBJECT TYPE IS TASK
		[ASCIZ/DESCRIPTOR/]
		4		;OPTIONAL DATA BYTES
		[ BYTE (8) 1, 2, 3, 4 ]
		[ASCIZ /TSKNAM/]
		[ASCIZ /USERID/]
		5		;PASSWORD STRING COUNT
		[ BYTE (8) 10, 11, 12, 13, 14 ]
		[ASCIZ /CHARGE/]]
	CALL @NSPVEC+.NSCRT	;MAKE A LINK
	 RET			;PLACE FOR FAILURE BREAKPOINT
	RETSKP			;SUCCESS


; SEND OUTPUT TEST ROUTINE.   PLACE NSP LINK ID IN T1 BEFORE INVOKING...

SNDOUT:	MOVEI T2,NSPINI
	MOVE T3,[NS%EOM+<600*6>]
	CALL XNSOUT		;SEND THE DATA
	 RET			;FAIL
	RETSKP			;SUCCESS
SUBTTL	Internal Links - Create an Internal Link

XNSCRT::ACVAR <A1,A2,A3,A4>
	TRVAR <NTCNT,NTPNT,NTOBJ,NTDSC,NTDSS,NTHST,NTHSC,NTCIB>
	STKVAR <CRIFLG,CRICOD,CRIVEC,CRIARG,CRILLB,CRIERR>
	MOVEM T1,CRIFLG		;SAVE FLAGS
	MOVEM T2,CRICOD		;SAVE DRIVER CORRELATION CODE
	MOVEM T3,CRIVEC		;SAVE ADDRESS OF DRIVER VECTOR
	MOVEM T4,CRIARG		;SAVE ARGUMENT BLOCK ADDRESS

; CHECK FOR DUPLICATE DRIVER-CODE/VECTOR PAIRS


	MOVE T1,CRICOD		;GET DRIVER CORRELATION CODE
	MOVE T2,CRIVEC		;GET DRIVER FUNCTION VECTOR
	CALL DUPCHK		;GO CHECK FOR DUPLICATES IN OTHER LINKS
	 RETBAD ()		;FAILED, RETURN ERROR

; PARSE NAME OF REMOTE OBJECT TO WHICH CONNECTION IS DESIRED

	MOVE T1,CRIFLG		;GET FLAGS
	MOVE T2,CRIARG		;GET ADDRESS OF ARGUMENT BLOCK
	CALL PRSINT		;GO PARSE NAME FOR INTERNAL LINK
	 RETBAD ()		;FAILED, RETURN ERROR TO DRIVER
	DMOVE A1,T1		;COPY COUNTS AND HOST POINTER
	DMOVE A3,T3		;COPY DESCRIPTOR POINTER AND OBJECT ID

; CREATE LOGICAL LINK BLOCK AND INSERT INITIAL VALUES

	NOINT			;DO NOT PPEMIT INTERRUPTS WITH SPACE ASSIGNED
	MOVE T4,CRIARG		;GET ADDRESS OF DRIVER ARGUMENT BLOCK
	MOVE T1,.NSTSN(T4)	;GET ADDRESS OF TASK NAME STRING
	HRLI T1,(POINT 7,)	;FORM POINTER TO TASK NAME
	MOVX T2,10		;ALWAYS USE 8-BIT BYTES FOR INTERNAL LINKS
	CALL OPNIWK		;CALL WORK ROUTINE TO PERFORM OPEN FUNCTIONS
	 RETBAD (,<OKINT>)	;FAILED, RETURN ERROR TO DRIVER
	MOVEM T1,CRILLB		;SAVE LOIGICAL LINK BLOCK ADDRESS

; SET UP I/O DIRECTIONS IN LOGICAL LINK BLOCK

	MOVE T4,CRIFLG		;GET FLAGS PROVIDED BY DRIVER
	MOVE T1,CRILLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	TXNE T4,NS%RD		;READ WANTED ?
	JRST [	SETONE LLOPI,(T1) ;SET INPUT FLAG
		JRST .+1]	;CONTINUE
	TXNE T4,NS%WRT		;WRITE WANTED ?
	JRST [	SETONE LLOPW,(T1) ;SET OUTPUT FLAG
		JRST .+1]	;CONTINUE
	MOVE T4,CRIARG		;GET ADDRESS OF ARGUMENT BLOCK
	CALL STMAXQ		;SET MAXIMUM INPUT/OUTPUT QUEUED VALUES
	; ..
	; ..

; MOVE STRINGS FOR THIS LOGICAL LINK BLOCK

	MOVE T1,CRILLB		;GET LOGICAL LINK BLOCK ADDRESS
	MOVE T2,A1		;GET COUNTS FOR HOST AND DESCRIPTOR STRINGS
	MOVE T3,A2		;COPY POINTER TO HOST NAME STRING
	MOVE T4,A3		;COPY POINTER TO DESCRIPTOR STRING
	CALL STRSAV		;GO SAVE THE STRINGS IN PERMANENT AREAS
	 JRST [	MOVEM T1,CRIERR	;FAILED, SAVE ERROR CODE
		MOVE T1,CRILLB	;GET LOGICAL LINK BLOCK ADDRESS
		CALL CRTCLN	;GO RELEASE LL BLOCK AND OTHERWISE CLEAN UP
		MOVE T1,CRIERR	;RESTORE ERROR CODE
		RETBAD () ]	;RETURN ERROR TO DRIVER

; OPEN THE NETWORK CONNECTION FOR THE NEWLY CREATED LINK

	MOVE T1,CRIARG		;GET ADDRESS OF DRIVER ARGUMENT BLOCK
	MOVE T2,CRILLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	HRL T3,A4		;GET OBJECT ID
	HRR T3,A1		;GET COUNT OF BYTES IN DESCRIPTOR STRING
	MOVE T4,A3		;COPY POINTER TO DESCRIPTOR STRING
	CALL OPNINT		;GO OPEN INTERNAL LINK
	 JRST [	MOVEM T1,CRIERR	;FAILED, SAVE ERROR CODE
		MOVE T1,CRILLB	;GET LOGICAL LINK BLOCK ADDRESS
		CALL CRTCLN	;GO RELEASE LL BLOCK AND OTHERWISE CLEAN UP
		MOVE T1,CRIERR	;RESTORE ERROR CODE
		RETBAD () ]	;RETURN ERROR TO DRIVER

; SAVE THE DRIVER CORRELATION CODE AND FUNCTION VECTOR ADDRESS

	MOVE T4,CRIARG		;GET ADDRESS OF ARGUMENT BLOCK
	MOVE T3,CRILLB		;RESTORE LOGICAL LINK BLOCK ADDRESS
	MOVE T2,CRICOD		;GET DRIVER CORRELATION CODE
	STOR T2,LLDRV,(T3)	;SAVE IN LOGICAL LINK BLOCK
	MOVE T2,CRIVEC		;GET DRIVER FUNCTION VECTOR ADDRESS
	STOR T2,LLVEC,(T3)	;SAVE IN LOGICAL LINK BLOCK
	SETONE LLINT,(T3)	;NOTE THAT THIS IS AN INTERNAL LINK
	;..
	;..

; LOCK THE NEWLY CREATED LINK FOR THE DRIVER

CRT050:	MOVE T4,CRIFLG		;GET FLAGS FROM DRIVER
	TXNN T4,NS%LOK		;DRIVER WANT LINK LOCKED ?
	JRST CRT060		;NO, GO ON
	MOVE T1,CRILLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKLOK		;LOCK THE BLOCK FOR THE DRIVER
	 JRST [	BUG(NSPBAL)
		MDISMS		;WAIT FOR LINK TO FREE
		JRST CRT050 ]	;GO TRY LOCKING LINK AGAIN, SHOULD BE FREE NOW
	OKINT			;BLOCK LOCKED, PERMIT INTERRUPTS AGAIN

; RETURN LOGICAL LINK ADDRESS AS NSP IDENTIFIER FOR LINK

CRT060:	MOVE T4,CRILLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T1,LLLNK,(T4)	;GET LINK ID
	RETSKP			;DONE, RETURN TO DRIVER


;CRTCLN - ROUTINE TO CLEAN UP FROM FAILURE
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;		CALL CRTCLN
;RETURNS: +1 ALWAYS

CRTCLN:	DECR DCCUR		;ONE LESS LINK ON FAILURE
	CALL DELNOD		;FREE THE NODE
	LLLULK			;UNLOCK THE TREE
	OKINT			;PERMIT INTERRUPTS AGAIN
	RET			;AND FAIL
;STMAXQ - ROUTINE TO PUT MAXIMUM INPUT/OUTPUT QUEUED VALUES INTO LL BLOCK
;
;ACCEPTS IN T1/ LOGICAL LINK BLOCK ADDRESS
;	    T4/ ADDRESS OF ARGUMENT BLOCK 
;
;RETURNS: +1 ALWAYS

STMAXQ:	MOVE T2,.NSHDR(T4)	;GET NUMBER OF ITEMS IN ARGUMENT BLOCK
	CAILE T2,.NSMQI		;USER INCLUDE MAX INPUT IN BLOCK?
	SKIPN T2,.NSMQI(T4)	;YES - WAS A ZERO SPECIFIED?
	JRST [	CALL STMXDF	;YES - SET MAX DEFAULTS
		RET]
	STOR T2,LLMQI,(T1)	;SAVE VALUE
	MOVE T2,.NSHDR(T4)	;GET NUMBER OF ITEMS IN ARGUMENT BLOCK
	MOVEI T3,MAXSGQ		;DEFAULT OUTPUT QUEUE LENGTH
	CAIG T2,.NSMQO		;USER INCLUDE MAX OUTPUT IN BLOCK?
	JRST STMXQ1		;NO - TAKE DEFAULT
	SKIPN T3,.NSMQO(T4)	;YES - WAS A ZERO SPECIFIED?
	MOVEI T3,.NSMQO(T4)	;GET SPECIFIED VALUE
STMXQ1:	STOR T3,LLMQO,(T1)	;SAVE VALUE
	RET


;STMXDF - SET MAX INPUT/OUTPUT QUEUE DEFAULTS
;
;ACCEPTS:	T1/ ADDRESS OF LOGICAL LINK BLOCK
;
;RETURNS:	+1,ALWAYS
;
;DESTROYS T2

STMXDF::	MOVEI T2,MAXSEG		;ASSUME READ ONLY
	OPSTR <SKIPE>,LLOPW,(T1) ;OPEN FOR WRITE AS WELL?
	MOVEI T2,MAXSG1		;YES. USE A SMALLER NUMBER
	STOR T2,LLMQI,(T1)	;SAVE THE INPUT QUEUE LENGTH (ALSO FLOW CONTROL)
	MOVEI T2,MAXSGQ		;SET OUTPUT QUEUE LENGTH
	STOR T2,LLMQO,(T1)	;SAVE IN LINK BLOCK
	RET
;DUPCHK - ROUTINE TO CHECK FOR DUPLICATE DRIVER-CODE/VECTOR PAIRS
;
;ACCEPTS IN T1/	DRIVER CORRELATION CODE
;	    T2/	DRIVER FUNCTION VECTOR ADDRESS
;		CALL DUPCHK
;RETURNS: +1	 FAILED, DUPLICATE CODE/VECTOR PAIR ALREADY IN USE
;	  +2	SUCCESS, THIS IS ONLY SUCH PAIR

DUPCHK:	TRVAR <DCKCOD,DCKVEC>	;NOTE:	TRVAR'S ARE REQUIRED HERE BECAUSE THE
				;	COROUTINE OF OBJSRC, INTSRC, NEEDS TO
				;	ACCESS THIS INFORMATION.
	MOVEM T1,DCKCOD		;SAVE DRIVER CORRELATION CODE
	MOVEM T2,DCKVEC		;SAVE DRIVER FUNCTION VECTOR ADDRESS
	XMOVEI T1,INTSRC	;GET ADDRESS OF COROUTINE FOR OBJSRC
	SETOM T2		;INDICATE ALL LINKS SHOULD BE CHECKED
	CALL OBJSRC		;CHECK FOR DUPLICATES
	 RETSKP			;NONE FOUND, THIS CODE/VECTOR OK
	RETBAD (NSPX1)		;FAIL, THIS CODE/VECTOR ALREADY IN USE


;INTSRC - COROUTINE OF OBJSRC TO CHECK FOR DUPLICATE DRIVER-CODE/VECTOR PAIRS
;
;ACCEPTS IN TRVARS DCKCOD/ DRIVER CORRELATION CODE
;		   DCKVEC/ DRIVER FUNCTION VECTOR ADDRESS

INTSRC:	JE LLINT,(T1),R		;IS THIS AN INTERNAL LINK ?
	SAVET			;YES, SAVE ALL TEMPORARY AC'S
	LOAD T3,LLDRV,(T1)	;GET DRIVER CORRELATION CODE
	LOAD T4,LLVEC,(T1)	;GET DRIVER FUNCTION VECTOR ADDRESS
	CAMN T3,DCKCOD		;SAME CORRELATION CODE ?
	CAME T4,DCKVEC		; AND SAME DRIVER FUNCTION VECTOR ?
	RET			;NO, RETURN NOT FOUND
	RETSKP			;YES, RETURN FOUND
;OPNINT - ROUTINE TO OPEN AN INTERNAL LOGICAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF DRIVER ARGUMENT BLOCK
;	    T2/	ADDRESS OF LOGICAL LINK BLOCK
;	    T3/	OBJECT ID,,COUNT OF BYTES IN DESCRIPTOR STRING
;	    T4/	POINTER TO DESCRIPTOR STRING
;		CALL OPNINT
;RETURNS: +1	 FAILED, ERROR CODE IN T1
;	  +2	SUCCESS, CONNECT-INITIATE MESSAGE (CI) SENT OVER LINK

OPNINT:	STKVAR <OPIARG,OPIATR,OPILLB,OPIOBJ,OPIDSS,OPIDSC,OPIERR>
	MOVEM T1,OPIARG		;SAVE DRIVER ARGUMENT BLOCK ADDRESS
	MOVEM T2,OPILLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	HLRZM T3,OPIOBJ		;SAVE OBJECT ID
	HRRZM T3,OPIDSC		;SAVE COUNT OF DESCRIPTOR BYTES
	MOVEM T4,OPIDSS		;SAVE DESCRIPTOR STRING POINTER

; ASSIGN FREE SPACE FOR THE ATTRIBUTE LIST FOR THIS LINK

	MOVEI T1,0		;INITIALIZE SPACE NEEDED
	MOVE T4,OPIARG		;GET ADDRESS OF DRIVER ARGUMENT BLOCK
	MOVE T3,.NSHDR(T4)	;GET ARGUMENT BLOCK LENGTH
	CAILE T3,.NSODC		;OPTIONAL DATA COUNT PRESENT ?
	ADD T1,.NSODC(T4)	;YES, GET NUMBER OF BYTES IN OPTIONAL DATA
	CAILE T3,.NSPWC		;PASSWORD COUNT PROVIDED IN ARG BLOCK ?
	ADD T1,.NSPWC(T4)	;YES, ADD NUMBER OF BYTES IN PASSWORD STRING
	IDIVI T1,4		;COMPUTE NUMBER OF WORDS REQUIRED
	SKIPN T2		;ROUND UP IF
	ADDI T1,1		; NEEDED
	ADDI T1,MAXLC		;AND ACCOUNT FOR USER ID AND ACCOUNT STRINGS
	CALL ASGSWP		;ASSIGN SPACE
	 RETBAD (MONX01)	;FAILED, RETURN ERROR TO CALLER
	ADDI T1,1		;POINT TO START OF ATTRIBUTE LIST (SKIP HEADER)
	MOVEM T1,OPIATR		;SAVE ADDRESS OF START OF ATTRIBUTE LIST

; CREATE THE ATTRIBUTE LIST FOR THIS INTERNAL LINK

	MOVE T1,OPIARG		;GET ADDRESS OF DRIVER ARGUMENT BLOCK
	MOVE T2,OPIATR		;GET ADDRESS OF START OF ATTRIBUTE LIST
	CALL CREATR		;GO CREATE ATTRIBUTE LIST
	 JRST [	MOVEM T1,OPIERR	;FAILED, SAVE ERROR CODE
		MOVE T1,OPIATR	;GET ADDRESS OF ATTRIBUTE LIST
		CALL FREATR	;CLEAN UP AND RETURN ERROR TO CALLER
		MOVE T1,OPIERR	;RESTORE ERROR CODE
		RETBAD () ]	;RETURN ERROR CODE
	; ..
	; ..

; OPEN THE NETWORK CONNECTION

	MOVE T1,OPILLB		;GET LOGICAL LINK BLOCK ADDRESS
	MOVE T2,OPIATR		;GET ADDRESS OF START OF ATTRIBUTE LIST
	HRL T3,OPIOBJ		;GET OBJECT ID
	HRR T3,OPIDSC		;GET DESCRIPTOR STRING LENGTH
	MOVE T4,OPIDSS		;GET POINTER TO DESCRIPTOR STRING
	CALL CRTLNK		;CREATE NETWORK LINK
	 JRST [	MOVEM T1,OPIERR	;FAILED, SAVE ERROR CODE
		MOVE T1,OPIATR	;GET ADDRESS OF ATTRIBUTE LIST
		CALL FREATR	;CLEAN UP AND RETURN ERROR TO CALLER
		MOVE T1,OPILLB	;GET LOGICAL LINK BLOCK ADDRESS
		CALL DELNOD	;DELETE THE LINK BLOCK
		DECR DCCUR	;DECREMENT NUMBER OF EXTANT LINKS
		LLLULK		;UNLOCK THE LOGICAL LINK TREE
		MOVE T1,OPIERR	;RESTORE ERROR CODE
		RETBAD () ]	;RETURN ERROR CODE

; CLEAN UP FREE SPACE AND RETURN SUCCESS

	MOVE T1,OPIATR		;GET ADDRESS OF ATTRIBUTE LIST
	CALL FREATR		;CALL CLEANUP ROUTINE
	RETSKP			;DONE, RETURN SUCCESS.
;FREATR - ROUTINE TO RELEASE FREE SPACE USED TO HOLD THE ATTRIBUTE LIST
;
;ACCEPTS IN T1/	ADDRESS OF BLOCK USED FOR ATTRIBUTE LIST
;		CALL FREATR
;RETURNS: +1 ALWAYS

FREATR:	SUBI T1,1		;POINT TO START OF FREE BLOCK
	HRRZ T2,(T1)		;GET BLOCK SIZE
	CALLRET RELSWP		;RELEASE FREE SPACE AND RETURN
;INTNAM - ROUTINE TO SET UP POINTERS AND COUNTS FOR SEPARATE SPECIFICATION
;	  OF THE PORTIONS OF A DESTINATION TASK NAME.
;
;ACCEPTS IN T1/	ADDRESS OF ARGUMENT BLOCK FOR .NSCRT
;	    TRVARS:	NTHSC, NTHST, NTOBJ, NTDSS, NTDSC
;		CALL INTNAM
;RETURNS: +1	 FAILED, ERROR CODE IN T1
;	  +2	SUCCESS, WITH TRVARS FILLED IN

INTNAM:	ACVAR <AB>		;WORK AC TO HOLD ARGUMENT BLOCK ADDRESS
	MOVEM T1,AB		;SAVE ADDRESS OF ARGUMENT BLOCK

; CHECK MINIMUM LENGTH OF ARGUMENT BLOCK

	MOVE T4,.NSHDR(AB)	;GET ARGUMENT BLOCK SIZE
	CAIGE T4,.NSOBJ		;AT LEAST HOST AND OBJECT SPECIFIED ?
	RETBAD (ARGX04)		;NO, ARGUMENT BLOCK TOO SMALL

; SAVE HOST NAME POINTER AND BYTE COUNT

	MOVE T1,.NSHST(AB)	;GET ADDRESS OF HOST NAME STRING
	HRLI T1,(POINT 7,)	;FORM BYTE POINTER TO HOST NAME STRING
	MOVEM T1,NTHST		;SAVE POINTER TO HOST NAME STRING
	MOVX T3,MAXLC		;GET MAX CHARS IN HOST NAME
	CALL CMPLEN		;COMPUTE SIZE OF HOST NAME STRING
	SUBI T3,1		;ADJUST FOR NULL ON END OF STRING
	MOVEM T3,NTHSC		;SAVE HOST NAME STRING SIZE

; SAVE OBJECT NUMBER

	MOVE T1,.NSOBJ(AB)	;GET ADDRESS OF OBJECT STRING
	HRLI T1,(POINT 7,)	;FORM POINTER TO STRING
	CALL OBJLOK		;LOOK UP THE OBJECT IN TABLE
	 RETBAD (DCNX3)		;NO SUCH OBJECT
	MOVEM T1,NTOBJ		;SAVE OBJECT NUMBER

; SAVE DESCRIPTOR SIZE AND POINTER

	SETZM NTDSS		;INITIALIZE POINTER AND COUNT FOR
	SETZM NTDSC		; DESCRIPTOR IN CASE NOT SPECIFIED IN CALL
	SKIPN T1,.NSDSC(AB)	;ANY DESCRIPTOR GIVEN IN CALL ?
	RETSKP			;NO, DONE. RETURN SUCCESS
	HRLI T1,(POINT 7,)	;YES, FORM POINTER TO DESCRIPTOR STRING
	MOVEM T1,NTDSS		;SAVE BYTE POINTER TO DESCRIPTOR
	MOVX T3,MAXLC		;GET MAX NUMBER OF BYTES IN STRING
	CALL CMPLEN		;COMPUTE NUMBER OF BYTES IN DESCRIPTOR
	MOVEM T3,NTDSC		;SAVE COUNT
	RETSKP			;DONE. RETURN SUCCESS.
;PRSINT - ROUTINE TO PARSE A NAME FIELD FOR AN INTERNAL LINK
;
;ACCEPTS IN T1/	FLAGS AS IN CALL TO .NSCRT
;	    T2/	POINTER TO ARGUMENT BLOCK
;		CALL PRSINT
;RETURNS: +1	 FAILED, SYNTAX ERROR
;	  +2	SUCCESS, WITH FOLLOWING TRVARS SET UP:
;
;			NTHST,NTHSC,NTOBJ,NTDSC,NTDSS

PRSINT:	TXNN T1,NS%SHT		;SHORT FORM CALL ?
	JRST [	MOVE T1,T2	;NO, GET ADDRESS OF ARGUMENT BLOCK
		CALL INTNAM	;GO PARSE INDIVIDUAL ITEMS IN NAME
		 RETBAD ()	;FAILED, RETURN ERROR
		JRST PRS020 ]	;GO RETURN PARSED ITEMS
	MOVE T1,.NSSTR(T2)	;YES, GET ADDRESS OF NAME STRING
	HRLI T1,(POINT 7,)	;FORM POINTER TO STRING
	CALL CMPLEN		;GO GET LENGTH OF STRING
	CALL PRSNAM		;GO PARSE THE NAME FIELD

; HERE TO RETURN PARSED ITEMS

PRS020:	HRL T1,NTHSC		;GET COUNT OF BYTES IN HOST NAME STRING
	HRR T1,NTDSC		;GET COUNT OF BYTES IN DESCRIPTOR STRING
	MOVE T2,NTHST		;GET POINTER TO HOST NAME STRING
	MOVE T3,NTDSS		;GET POINTER TO DESCRIPTOR
	MOVE T4,NTOBJ		;GET OBJECT ID
	RETSKP			;DONE, RETURN
;CREATR - ROUTINE TO CREATE AN ATTRIBUTE LIST
;
;ACCEPTS IN T1/	ADDRESS OF DRIVER ARGUMENT BLOCK
;	    T2/	ADDRESS OF START OF ATTRIBUTE LIST
;		CALL CREATR
;RETURNS: +1	 FAILED, ERROR CODE IN T1
;	  +2	SUCCESS, WITH ATTRIBUTE LIST CREATED

CREATR:	ACVAR <BK,AL,LP>

	MOVEM T1,BK		;SAVE ADDRESS OF DRIVER ARGUMENT BLOCK
	MOVEM T2,AL		;SAVE ADDRESS OF START OF LIST
	MOVEI LP,0		;NO POINTER TO PREVIOUS ITEM YET

; ADD OPTIONAL DATA TO ATTRIBUTE LIST

	MOVE T1,.NSHDR(BK)	;GET NUMBER OF WORDS IN ARG BLOCK
	CAILE T1,.NSODC		;OPTIONAL DATA INCLUDED IN ARG BLOCK ?
	SKIPG .NSODC(BK)	;YES, ANY OPTIONAL DATA TO ADD ?
	JRST CRA010		;NO, GO DO PASSWORD
	MOVE T3,LP		;GET POINTER TO LAST ITEM ON LIST
	MOVE T2,AL		;ADDRESS OF CURRENT ITEM ON ATTRIBUTE LIST
	MOVE T1,BK		;ADDRESS OF DRIVER ARGUMENT BLOCK
	CALL ADDOPT		;ADD OPTIONAL DATA TO LIST
	MOVEM AL,LP		;SAVE NEW LAST ITEM IN LIST
	MOVEM T1,AL		;SAVE NEW CURRENT ITEM IN LIST

; ADD PASSWORD STRING TO ATTRIBUTE LIST

CRA010:	MOVE T1,.NSHDR(BK)	;GET NUMBER OF WORDS IN ARG BLOCK
	CAILE T1,.NSPWC		;PASSWORD INCLUDED ?
	SKIPG .NSPWC(BK)	;YES, ANY PASSWORD TO ADD ?
	JRST CRA020		;NO, GO DO USER ID
	MOVE T3,LP		;GET POINTER TO LAST ITEM ON LIST
	MOVE T2,AL		;ADDRESS OF CURRENT ITEM ON ATTRIBUTE LIST
	MOVE T1,BK		;ADDRESS OF DRIVER ARGUMENT BLOCK
	CALL ADDPSW		;ADD PASSWORD TO LIST
	MOVEM AL,LP		;SAVE NEW LAST ITEM IN LIST
	MOVEM T1,AL		;SAVE NEW CURRENT ITEM IN LIST
	; ..
	; ..

; ADD USER ID TO THE LIST

CRA020:	MOVE T1,.NSHDR(BK)	;GET NUMBER OF ITEMS IN ARG BLOCK
	CAILE T1,.NSUSR		;USER ID INCLUDED IN ARG BLOCK ?
	SKIPN .NSUSR(BK)	;YES, ANY USER ID TO ADD ?
	JRST CRA030		;NO, GO DO ACCOUNT
	MOVE T3,LP		;GET POINTER TO LAST ITEM ON LIST
	MOVE T2,AL		;ADDRESS OF CURRENT ITEM ON ATTRIBUTE LIST
	MOVE T1,BK		;ADDRESS OF DRIVER ARGUMENT BLOCK
	CALL ADDUSR		;ADD USER ID TO THE LIST
	MOVEM AL,LP		;SAVE NEW LAST ITEM IN LIST
	MOVEM T1,AL		;SAVE NEW CURRENT ITEM IN LIST

; ADD ACCOUNT TO ATTRIBUTE LIST

CRA030:	MOVE T1,.NSHDR(BK)	;GET NUMBER OF ITEMS IN ARG BLOCK
	CAILE T1,.NSCHG		;ACCOUNT INCLUDED IN ARG BLOCK ?
	SKIPN .NSCHG(BK)	;YES, ANY ACCOUNT TO ADD ?
	JRST CRA040		;NO, GO RETURN TO CALLER
	MOVE T3,LP		;GET POINTER TO LAST ITEM ON LIST
	MOVE T2,AL		;ADDRESS OF CURRENT ITEM ON ATTRIBUTE LIST
	MOVE T1,BK		;ADDRESS OF DRIVER ARGUMENT BLOCK
	CALL ADDACT		;ADD OPTIONAL DATA TO LIST

; HERE WHEN ALL ATTRIBUTES ARE IN LIST

CRA040:	RETSKP			;DONE, RETURN
;ADDOPT - ROUTINE TO ADD THE OPTIONAL DATA STRING TO THE ATTRIBUTE LIST
;
;ACCEPTS IN T1/	ADDRESS OF DRIVER ARGUMENT BLOCK
;	    T2/	CURRENT POINTER INTO ATTRIBUTE LIST
;	    T3/	ADDRESS OF PREVIOUS ITEM IN ATTRIBUTE LIST
;		CALL ADDOPT
;RETURNS: +1 ALWAYS, WITH T1/ UPDATED POINTER INTO ATTRIBUTE LIST

ADDOPT:	ACVAR <BK,AL>
	MOVEM T1,BK		;SAVE ARGUMENT BLOCK ADDRESS
	MOVEM T2,AL		;SAVE ATTRIBUTE POINTER

; ADD ATTRIBUTE TYPE AND PREVIOUS ITEM POINTER TO ATTRIBUTE LIST

	STOR T3,PRFXL,(AL)	;STORE POINTER TO LAST ITEM IN LIST
	MOVX T4,.PFOPT		;GET OPTIONAL DATA ATTRIBUTE TYPE CODE
	STOR T4,PRFXV,(AL)	;SAVE ATTRIBUTE TYPE IN ATTRIBUTE LIST

; ADD SIZE OF THIS ATTRIBUTE TO LIST

	MOVE T3,.NSODC(BK)	;GET COUNT OF BYTES IN OPTIONAL DATA
	IDIVI T3,4		;COMPUTE NUMBER OF WORDS
	SKIPN T4		;ROUND UP
	ADDI T3,1		;..
	STOR T3,PRFXS,(AL)	;SAVE SIZE IN ATTRIBUTE LIST

; ADD THE STRING TO THE ATTRIBUTE LIST

	MOVE T3,.NSODC(BK)	;GET BYTE COUNT AGAIN
	MOVE T2,.NSOPD(BK)	;GET ADDRESS OF OPTIONAL DATA STRING
	HRLI T2,(POINT 8,)	;FORM BYTE POINTER TO OPTIONAL DATA
	MOVEI T1,1(AL)		;GET DESTINATION ADDRESS
	CALL MOVST1		;ADD STRING TO LIST
	LOAD T4,PRFXS,(AL)	;GET SIZE OF THIS BLOCK
	ADDI AL,1(T4)		;POINT TO NEXT FREE ELEMENT ON LIST
	RET			;DONE, RETURN
;ADDPSW - ROUTINE TO ADD THE PASSWORD STRING TO THE ATTRIBUTE LIST
;
;ACCEPTS IN T1/	ADDRESS OF DRIVER ARGUMENT BLOCK
;	    T2/	CURRENT POINTER INTO ATTRIBUTE LIST
;	    T2/	CURRENT POINTER INTO ATTRIBUTE LIST
;		CALL ADDPSW
;RETURNS: +1 ALWAYS, WITH T1/ UPDATED POINTER INTO ATTRIBUTE LIST

ADDPSW:	ACVAR <BK,AL>
	MOVEM T1,BK		;SAVE ARGUMENT BLOCK ADDRESS
	MOVEM T2,AL		;SAVE ATTRIBUTE POINTER

; ADD ATTRIBUTE TYPE AND PREVIOUS ITEM POINTER TO ATTRIBUTE LIST

	STOR T3,PRFXL,(AL)	;STORE POINTER TO LAST ITEM IN LIST
	MOVX T4,.PFPWD		;GET PASSWORD ATTRIBUTE TYPE CODE
	STOR T4,PRFXV,(AL)	;SAVE ATTRIBUTE TYPE IN ATTRIBUTE LIST

; ADD SIZE OF THIS ATTRIBUTE TO LIST

	MOVE T3,.NSPWC(BK)	;GET COUNT OF BYTES IN PASSWORD
	IDIVI T3,4		;COMPUTE NUMBER OF WORDS
	SKIPN T4		;ROUND UP
	ADDI T3,1		;..
	STOR T3,PRFXS,(AL)	;SAVE SIZE IN ATTRIBUTE LIST

; ADD THE STRING TO THE ATTRIBUTE LIST

	MOVE T3,.NSPWC(BK)	;GET BYTE COUNT AGAIN
	MOVE T2,.NSPSW(BK)	;GET ADDRESS OF PASSWORD STRING
	HRLI T2,(POINT 8,)	;FORM BYTE POINTER TO PASSWORD
	MOVEI T1,1(AL)		;GET DESTINATION ADDRESS
	CALL MOVST1		;ADD STRING TO LIST
	LOAD T4,PRFXS,(AL)	;GET SIZE OF THIS BLOCK
	ADDI AL,1(T4)		;POINT TO NEXT FREE ELEMENT ON LIST
	RET			;DONE, RETURN
;ADDUSR - ROUTINE TO ADD THE USER STRING TO THE ATTRIBUTE LIST
;
;ACCEPTS IN T1/	ADDRESS OF DRIVER ARGUMENT BLOCK
;	    T2/	CURRENT POINTER INTO ATTRIBUTE LIST
;	    T2/	CURRENT POINTER INTO ATTRIBUTE LIST
;		CALL ADDUSR
;RETURNS: +1 ALWAYS, WITH T1/ UPDATED POINTER INTO ATTRIBUTE LIST

ADDUSR:	ACVAR <BK,AL>
	MOVEM T1,BK		;SAVE ARGUMENT BLOCK ADDRESS
	MOVEM T2,AL		;SAVE ATTRIBUTE POINTER

; ADD ATTRIBUTE TYPE AND PREVIOUS ITEM POINTER TO ATTRIBUTE LIST

	STOR T3,PRFXL,(AL)	;STORE POINTER TO LAST ITEM IN LIST
	MOVX T4,.PFUDT		;GET USER ID ATTRIBUTE TYPE CODE
	STOR T4,PRFXV,(AL)	;SAVE ATTRIBUTE TYPE IN ATTRIBUTE LIST

; ADD SIZE OF THIS ATTRIBUTE TO LIST

	MOVE T1,.NSUSR(BK)	;GET ADDRESS OF USER ID STRING
	HRLI T1,(POINT 7,)	;FORM BYTE POINTER TO USER ID STRING
	MOVX T3,MAXLC		;GET MAX SIZE OF USER ID STRING
	CALL CMPLEN		;GO GET LENGTH OF USER ID STRING
	STOR T3,PRFXS,(AL)	;SAVE SIZE IN ATTRIBUTE LIST

; ADD THE STRING TO THE ATTRIBUTE LIST

	MOVE T2,.NSUSR(BK)	;GET ADDRESS OF STRING AGAIN
	HRLI T2,(POINT 7,)	;AND POINT TO THE STRING
	MOVEI T1,1(AL)		;GET DESTINATION ADDRESS
	CALL MOVST1		;ADD STRING TO LIST
	LOAD T4,PRFXS,(AL)	;GET SIZE OF THIS BLOCK
	ADDI AL,1(T4)		;POINT TO NEXT FREE ELEMENT ON LIST
	RET			;DONE, RETURN
;ADDACT - ROUTINE TO ADD THE ACCOUNT STRING TO THE ATTRIBUTE LIST
;
;ACCEPTS IN T1/	ADDRESS OF DRIVER ARGUMENT BLOCK
;	    T2/	CURRENT POINTER INTO ATTRIBUTE LIST
;	    T2/	CURRENT POINTER INTO ATTRIBUTE LIST
;		CALL ADDACT
;RETURNS: +1 ALWAYS, WITH T1/ UPDATED POINTER INTO ATTRIBUTE LIST

ADDACT:	ACVAR <BK,AL>
	MOVEM T1,BK		;SAVE ARGUMENT BLOCK ADDRESS
	MOVEM T2,AL		;SAVE ATTRIBUTE POINTER

; ADD ATTRIBUTE TYPE AND PREVIOUS ITEM POINTER TO ATTRIBUTE LIST

	STOR T3,PRFXL,(AL)	;STORE POINTER TO LAST ITEM IN LIST
	MOVX T4,.PFACN		;GET ACCOUNT ATTRIBUTE TYPE CODE
	STOR T4,PRFXV,(AL)	;SAVE ATTRIBUTE TYPE IN ATTRIBUTE LIST

; ADD SIZE OF THIS ATTRIBUTE TO LIST

	MOVE T1,.NSCHG(BK)	;GET ADDRESS OF ACCOUNT STRING
	HRLI T1,(POINT 7,)	;FORM BYTE POINTER TO ACCOUNT STRING
	MOVX T3,MAXLC		;GET MAX SIZE OF ACCOUNT STRING
	CALL CMPLEN		;GO GET LENGTH OF ACCOUNT STRING
	STOR T3,PRFXS,(AL)	;SAVE SIZE IN ATTRIBUTE LIST

; ADD THE STRING TO THE ATTRIBUTE LIST

	MOVE T2,.NSCHG(BK)	;GET ADDRESS OF STRING AGAIN
	HRLI T2,(POINT 7,)	;AND POINT TO THE STRING
	MOVEI T1,1(AL)		;GET DESTINATION ADDRESS
	CALL MOVST1		;ADD STRING TO LIST
	LOAD T4,PRFXS,(AL)	;GET SIZE OF THIS BLOCK
	ADDI AL,1(T4)		;POINT TO NEXT FREE ELEMENT ON LIST
	RET			;DONE, RETURN
SUBTTL	Internal Links - Send Output on an Internal Link

XNSOUT::ASUBR <SNOLID,SNOBUF,SNOCNT,SNOLLB>
	STKVAR <SNOFLG>
	MOVEM T3,SNOFLG		;SAVE FLAGS

; LOCK LOGICAL LINK BLOCK

SNO001:	MOVE T1,SNOLID		;GET LINK ID
	CALL INTLOK		;GO CHECK LINK STATE
	 RET			;FAILED, RETURN ERROR
	MOVEM T1,SNOLLB		;SAVE LOGICAL LINK BLOCK ADDRESS

; CHECK THAT ANOTHER BUFFER IS NOT STILL BEING PROCESSED

SNO003:	MOVE T1,SNOLLB		;GET LOGICAL LINK BLOCK ADDRESS
	JE LLBFO,(T1),SNO005	;IS ANOTHER BUFFER NOW BEING PROCESSED ?
	MOVE T4,SNOFLG		;YES, GET FLAGS PROVIDED BY DRIVER
	JE NS%BLK,T4,[	SETONE LLNDO,(T1) ;DON'T BLOCK, NOTIFY DRIVER WHEN READY
			CALL BLKULK	  ;NOTIFY DRIVER THAT WE ARE STILL BUSY
			RETBAD (NSPX4)]	  ;ADVISE DRIVER OF PREVIOUS BUFFER
	LOAD T1,LLLNK,(T1)	;GET LINK ID
	HRLS T1			;FORM STANDARD SCHEDULER WAIT
	HRRI T1,SNOTST		; TEST WORD
	MOVE T2,SNOLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL INTWAT		;GO WAIT UNTIL DONE WITH THIS BUFFER
	 RETBAD ()		;FAIL, LINK NOT OK ANY MORE

; SAVE INPUT ARGUMENTS IN THE LOGICAL LINK

SNO005:	MOVE T2,SNOBUF		;GET BUFFER ADDRESS PROVIDED BY DRIVER
	STOR T2,LLBFO,(T1)	;STORE OUTPUT BUFFER ADDRESS
	HRLI T2,(POINT 8,)	;FORM POINTER TO START OF BUFFER
	STOR T2,LLBPO,(T1)	;SAVE IN LOGICAL LINK BLOCK
	HRRZ T4,SNOCNT		;GET JUST THE COUNT
NSIB01:	STOR T4,LLOCT,(T1)	;STORE INITIAL COUNT FOR OUTPUT
	MOVE T4,SNOFLG		;GET FLAGS
	TXNE T4,NS%BLK		;DRIVER WANT TO BLOCK ?
	JRST [SETONE LLWAT,(T1)	;YES, NOTE DRIVER ASKED TO WAIT
	      JRST .+1]		;CONTINUE
	SETZRO LLEOM,(T1)	;ASSUME NOT EOM
	TXNE T4,NS%EOM		;IS THIS A COMPLETE MESSAGE ?
	JRST [SETONE LLEOM,(T1)	;YES, NOTE THAT EOM SHOULD BE SET
	      JRST .+1]		;CONTINUE

; NOTE THAT END-OF-MESSAGE IS DESIRED IF REQUESTED BY THE DRIVER

	MOVE T4,SNOFLG		;GET FLAGS FROM DRIVER
	JN NS%EOM,T4,[	MOVE T1,SNOLLB	;GET LOGICAL LINK BLOCK ADDRESS
			SETONE LLFEM,(T1) ;SAY SHOULD GET EOM ON OUTPUT
			JRST .+1 ]	;CONTINUE IN MAINLINE CODE
	;..
	;..

; PROCESS ANY OUTSTANDING ACK'S FOR THIS LINK

SNO010:	MOVE T1,SNOLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	CALL MOVSEG		;PROCESS OUTSTANDING ACK'S
	 JRST [	MOVE T4,SNOFLG	;GET FLAGS PROVIDED BY DRIVER
		JE NS%BLK,T4,[	MOVE T1,SNOLLB ;GET LOGICAL LINK BLOCK ADDRESS
				CALL BLKULK    ;CLEAN UP LOCKED LL BLOCK
				RETSKP]        ;RETURN IF BLOCKING NOT REQUESTED
		MOVE T2,SNOLLB	;GET LOGICAL LINK BLOCK ADDRESS
		CALL INTWAT	;GO WAIT FOR CONDITION TO BE SATISFIED
		 RETBAD ()	;FAIL, LINK NOT OK ANY MORE
		JRST SNO010 ]	;TRY AGAIN TO PROCESS ACK'S

; SEND AS MUCH DATA AS POSSIBLE NOW

	MOVE T1,SNOLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	CALL SNDINT		;GO SEND AS MUCH OUTPUT AS POSSIBLE
	 RETBAD ()		;FAIL, LINK WENT AWAY OR NOT IN RUN STATE
	MOVE T1,SNOLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKULK		;CLEAN UP LOCKED LOGICAL LINK BLOCK
	RETSKP			;DONE, RETURN SUCCESS

; SCHEDULER TEST TO WAIT UNTIL PREVIOUS BUFFER IS COMPLETELY PROCESSED

	RESCD
SNOTST:	CALL CHKLNK		;GO CHECK STATE OF LINK
	 JRST 1(4)		;LINK NOT IN RUN STATE, WAKE UP
	JE LLBFO,(T1),1(4)	;WAKE UP IF DONE WITH BUFFER
	JRST 0(4)		;CONTINUE WAITING, STILL ON LAST BUFFER
	SWAPCD
;CHKLNK - ROUTINE TO CHECK THE STATE OF AN INTERNAL LINK
;
;ACCEPTS IN T1/	LINK ID
;		CALL CHKLNK
;RETURNS: +1	 FAILED, LINK DOES NOT EXIST OR IS NOT IN RUN STATE
;	  +2	SUCCESS, WITH T1/ ADDRESS OF LOGICAL LINK BLOCK

CHKLNK:	SETOM T2		;ANY LINK
	CALL LLLKUP		;GO FIND BLOCK
	 RETBAD (NSPX2)		;NOT THERE. SOMETHING TERRIBLE HAPPENED
	LOAD T2,LLSTA,(T1)	;GET STATE
	CAIE T2,LLSRUN		;IS IT RUNNING?
	RETBAD (NSPX3)		;NO, FAIL
	RETSKP			;YES. ALL FINE



;INTWAT - ROUTINE TO PERFORM A BLOCK FOR AN INTERNAL LINK
;
;ACCEPTS IN T1/	STANDARD SCHEDULER TEST WORD
;	    T2/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL INTWAT
;RETURNS: +1	 FAILED - LINK DOES NOT EXIST OR IS NOT IN RUN STATE ANY MORE
;	  +2	SUCCESS, WAIT OVER AND LINK IN RUN STATE

INTWAT:	ASUBR <IWTTST,IWTLLB,IWTLID>

	MOVE T1,IWTLLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T4,LLLNK,(T1)	;GET LINK ID
	MOVEM T4,IWTLID		;SAVE LINK ID
	CALL BLKULK		;UNLOCK THE LOGICAL LINK BLOCK
	MOVE T1,IWTTST		;GET SCHEDULER WAIT TEST
INTW10:	MDISMS			;WAIT FOR CONDITION TO BE SATISFIED
	MOVE T1,IWTLID		;GET LINK ID AGAIN
	CALL CHKLNK		;GO CHECK STATE OF LINK
	 RET			;FAIL, LINK NOT EXISTENT OR NOT IN RUN STATE
	MOVE T1,IWTLLB		;GET LOGICAL LINK BLOCK
	CALL BLKLOK		;LOCK THE LOGICAL LINK
	 JRST INTW10		;FAILED, WAIT THEN TRY AGAIN
	RETSKP			;DONE, WAIT SATISFIED AND LINK LOCKED AND OK
;SNDINT - ROUTINE TO SEND AS MUCH DATA AS POSSIBLE FOR AN INTERNAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL SNDINT
;RETURNS: +1 	 FAILED, LINK WENT AWAY OR NOT IN RUN STATE
;	  +2	SUCCESS, WITH LOGICAL LINK BLOCK ON THE BACKGROUND TASK'S
;			 "OUTPUT REMAINING" QUEUE (OUTQUE) IF NOT ALL
;			 DATA COULD BE SENT.

SNDINT:	STKVAR <SNDLLB>
	MOVEM T1,SNDLLB		;SAVE LOGICAL LINK BLOCK ADDRESS

; CHECK TO SEE IF THERE IS ANY MORE DATA TO SEND, DISPOSE OF BUFFER IF NOT

SND020:	MOVE T1,SNDLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	JN LLOCT,(T1),SND025	;IF DATA LEFT, GO TRY TO SEND IT
	MOVE T1,SNDLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL TELOBE		;GO TELL DRIVER THAT OUTPUT BUFFER IS EMPTY
	RETSKP			;DONE, RETURN

;CHECK TO SEE IF ANY SEGMENTS CAN BE SENT NOW

SND025:	MOVE T1,SNDLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL SNDCHK		;CAN ANY SEGMENTS BE SENT ?
	 JRST [	MOVE T1,SNDLLB	;NO, GET LOGICAL LINK BLOCK ADDRESS
		CALL QUECHK	;GO SEE IF LINK MUST BE QUEUED, OR WAIT FOR OK
		 RETBAD ()	;LINK WENT AWAY
		SKIPN T1	;HAVE WE WAITED UNTIL IT'S OK TO SEND DATA ?
		RETSKP		;NO, LINK WAS PUT ON Q, SO ALL DONE FOR NOW
		JRST SND025 ]	;YES, TRY AGAIN TO SEE IF A SEGMENT CAN BE SENT

; HERE TO SEND A SEGMENT

SND030:	MOVE T1,SNDLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL OUTSEG		;SEND THE SEGMENT
	 JRST [	MOVE T4,SNDLLB	;NO, GET LOGICAL LINK BLOCK ADDRESS
		JE LLWAT,(T4),SND050 ;IF BLOCKING NOT WANTED, GO QUEUE LL BLOCK
		MOVE T2,SNDLLB	;GET LOGICAL LINK BLOCK ADDRESS
		CALL INTWAT	;WAIT FOR CONDITION TO BE SATISFIED
		 RETBAD ()	;FAIL, LINK WENT AWAY OR NOT IN RUN STATE
		JRST SND030 ]	;TRY AGAIN TO SEE IF A SEGMENT CAN BE SENT
	JRST SND020		;CHECK TO SEE IF ANOTHER SEGMENT CAN BE SENT


; HERE WHEN MORE DATA REMAINS TO BE SENT - ADD THIS LOGICAL LINK BLOCK
; TO THE BACKGROUND TASK'S "OUTPUT REMAINING" QUEUE (OUTQUE).

SND050:	MOVE T1,SNDLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL ADDOUT		;GO ADD THIS BLOCK TO OUTQUE
	CALL SKDOUT		;NOTE BACKGROUND TASK ACTION NEEDED
	MOVE T1,SNDLLB		;GET LOGICAL LINK BLOCK ADDRESS
	SETONE LLNDO,(T1)	;NOTE DRIVER NOTIFICATION NEEDED
	CALLRET BLKULK		;UNLOCK THE BLOCK AND RETURN
;QUECHK - ROUTINE TO DETERMINE IF THIS LOGICAL LINK BLOCK SHOULD BE
;	  PLACED ON THE BACKGROUND TASKS'S "OUTPUT REMAINING" QUEUE
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;	    T2/	ADDRESS OF SCHEDULER TEST ROUTINE
;		CALL QUECHK
;RETURNS: +1	 FAILED, LINK WENT AWAY OR NOT IN RUN STATE
;	  +2	SUCCESS, LINK QUEUED IF NEEDED OR NOW OK TO SEND DATA

QUECHK:	ASUBR <QCKLLB>

	MOVE T4,QCKLLB		;NO, GET LOGICAL LINK BLOCK ADDRESS
	JE LLWAT,(T4),QCK050	;IF BLOCKING NOT WANTED, SEE IF LOCAL LINK
	CALL MAKTST		;GO MAKE A STANDARD SCHEDULER TEST
	MOVE T2,QCKLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL INTWAT		;WAIT FOR CONDITION TO BE SATISFIED
	 RETBAD ()		;LINK WENT AWAY OR NOT IN RUN STATE
	SETOM T1		;NOTE THAT CONDITION HAS BEEN SATISFIED
	RETSKP			;DONE, RETURN SUCCESS - OK TO SEND DATA NOW

; HERE IF BLOCKING NOT REQUESTED - SEE IF THIS IS A LOCAL LINK

QCK050:	MOVE T1,QCKLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL TSTLCL		;IS THIS A LOCAL LINK ?
	 CALL ADDOUT		;YES, PUT LINK ON BACKGROUND TASK'S QUEUE
	SETZM T1		;NOTE THAT DATA WILL BE SENT LATER
	RETSKP			;DONE, RETURN SUCCESS


;ADDOUT - ROUTINE TO ADD A LOGICAL LINK BLOCK TO THE BACKGROUND TASK'S
;	  "OUTPUT REMAINING" QUEUE (OUTQUE).
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;		CALL ADDOUT
;RETURNS: +1 ALWAYS

ADDOUT::JN LLQUE,(T1),R		;DONE IF ALREADY QUEUED
	LOCK OUTLOK		;PREVENT OTHER PROCESSES FROM HANDLING THE Q
	SKIPN T4,OUTQUE		;ANYTHING ON THE QUEUE YET ?
	JRST [	HRRM T1,OUTQUE	;NO, SAVE NEW HEAD OF QUEUE
		HRLM T1,OUTQUE	;SAVE INITIAL TAIL OF QUEUE
		JRST ADOUT2 ]	;GO CLEAR POINTER TO NEXT BLOCK ON CHAIN
	HLRZS T4		;KEEP JUST THE TAIL OF THE QUEUE
	STOR T1,LLOUT,(T4)	;MAKE TAIL POINT TO NEW BLOCK
	HRLM T1,OUTQUE		;SAVE NEW TAIL
ADOUT2:	SETZRO LLOUT,(T1)	;CLEAR POINTER TO NEXT BLOCK IN NEW TAIL
	SETONE LLQUE,(T1)	;NOTE THAT THIS BLOCK IS ON THE QUEUE
	UNLOCK OUTLOK		;PERMIT ACCESS TO QUEUE AGAIN
	RET			;RETURN
;OUTSEG - ROUTINE TO OUTPUT A SEGMENT FOR AN INTERNAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL OUTSEG
;RETURNS: +1	 FAILED, SCHEDULER TEST IN T1
;	  +2	SUCCESS, WITH SEGMENT AWAY

OUTSEG::STKVAR <OSGLLB,OSGSIZ,OSGBLK>
	MOVEM T1,OSGLLB		;SAVE LOGICAL LINK ADDRESS

; CHECK TO SEE IF A CLOSE IS IN PROGRESS

	MOVE T1,OSGLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	CALL CHKCIP		;SEE IF CLOSE IS IN PROGRESS

; COMPUTE SIZE OF SEGMENT AND ASSIGN SPACE

	MOVE T4,OSGLLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T3,LLOCT,(T4)	;GET NUMBER OF BYTES REMAINING TO BE SENT
	LOAD T4,LLSWG,(T4)	;GET MAXIMUM SEGMENT SIZE FOR THIS LINK
	CAILE T3,(T4)		;CAN ALL REMAINING DATA BE SENT ?
	MOVEI T3,(T4)		;NO, JUST SEND MAXIMUM AMOUNT FOR ONE SEGMENT
	MOVEM T3,OSGSIZ		;SAVE MESSAGE SIZE
	MOVEI T1,<<MSHDR+DTMLEN>*4+3>(T3) ;COMPUTE BYTES REQUIRED
	LSH T1,-2		;CONVERT TO WORDS
	CALL GETRES		;GET ONE
	 JRST [	BUG(NSPFRE)
		CALL TIMWAT	;FORM STANDARD SCHEDULER TEST WORD
		RET ]		;AND RETURN WITH WAIT TEST IN T1
	MOVEM T1,OSGBLK		;SAVE ADDRESS OF MESSAGE BLOCK

; SET UP COUNTS AND POINTERS IN MESSAGE HEADER

	MOVEI T2,MSHDR(T1)	;GET BEGINNING OF DATA STORAGE
	HRLI T2,(<POINT 8,>)	;FORM BYTE POINTER
	MOVE T1,OSGLLB		;GET BACK LL BLOCK
	MOVEM T2,LLBPTR(T1)	;SAVE WORK POINTER
	SETZM LLBPCT(T1)	;INIT COUNT
	MOVE T3,OSGSIZ		;GET # OF BYTES TO GO
	LOAD T2,LLOCT,(T1)	;GET # OF BYTES REMAINING IN BUFFER
	SUBI T2,0(T3)		;COMPUTE # LEFT
	STOR T2,LLOCT,(T1)	;SAVE FOR NEXT OUTPUT
	CALL MAKFLG		;GO MAKE FLAGS FOR THIS MESSAGE
	MOVE T3,OSGBLK		;GET MESSAGE BLOCK ADDRESS
	MOVE T4,OSGSIZ		;GET MESSAGE COUNT
	CALL MAKMSG		;GO ASSEMBLE NON-DATA PARTS OF MESSAGE

; ADD THE DATA TO THE MESSAGE

	MOVE T4,OSGLLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T1,LLBPO,(T4)	;GET CURRENT OUTPUT POINTER
	MOVE T2,LLBPTR(T4)	;GET DESTINATION POINTER
	MOVE T3,OSGSIZ		;GET COUNT
	CALL NETMOV		;ADD DATA BYTES TO THE MESSAGE
	MOVE T4,OSGLLB		;GET ADDRESS OF LOGICAL LINK BLOCK AGAIN
	STOR T1,LLBPO,(T4)	;STORE NEW OUTPUT POINTER TO REMAINDER OF BUFFER
	; ..
	; ..

; COMPUTE REMAINING QUANTITIES FOR MESSAGE HEADER AND SEND THE SEGMENT

	MOVE T2,OSGBLK		;GET ADDRESS OF SEGMENT AGAIN
	MOVX T3,MSDAT		;GET MESSAGE TYPE (DATA MESSAGE)
	STOR T3,MSTOM,(T2)	;STORE MESSAGE TYPE IN MESSAGE HEADER
	MOVE T1,OSGLLB		;GET LOGICAL LINK BLOCK ADDRESS
	MOVE T3,LLBPCT(T1)	;GET COUNT OF BYTES IN THE MESSAGE
	SUBI T3,5		;ACCOUNT FOR NSP OVERHEAD
	STOR T3,MSDTC,(T2)	;STORE COUNT INTO MESSAGE HEADER
	CALL SNDSEG		;SEND THE MESSAGE

; SEGMENT SENT. RETURN SUCCESS.

	RETSKP			;DONE.
;CHKCIP - ROUTINE TO CHECK TO SEE IF A CLOSE IS IN PROGRESS
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL CHKCIP
;RETURNS: +1 ALWAYS, WITH LLFEM SET IF NEEDED

CHKCIP:	ASUBR <CIPLLB>

	MOVE T1,CIPLLB		;GET LOGICAL LINK BLOCK ADDRESS
	JE LLCIP,(T1),R		;IF CLOSE NOT IN PROGRESS, DONE.
	LOAD T3,LLOCT,(T1)	;GET NUMBER OF BYTES REMAINING TO BE SENT
	LOAD T4,LLSWG,(T1)	;GET MAXIMUM SEGMENT SIZE FOR THIS LINK
	CAMLE T3,T4		;SENDING LAST SEGMENT FOR THIS BUFFER ?
	RET			;NO, WAIT FOR LAST SEGMENT TO SET EOM
	SETONE LLFEM,(T1)	;YES, SET END OF MESSAGE NEEDED
	RET			;AND DONE.
SUBTTL	Internal Links - Provide a Buffer for Input

XNSINB:	ASUBR <IBPLID,IBPBUF,IBPCNT,IBPLLB>

; LOCK LOGICAL LINK BLOCK

IBP001:	MOVE T1,IBPLID		;GET LINK ID
	CALL INTLOK		;GO CHECK LINK STATE
	 RET			;FAILED, RETURN ERROR
	MOVEM T1,IBPLLB		;SAVE LOGICAL LINK BLOCK ADDRESS

; CHECK THAT WE PREVIOUSLY REQUESTED A BUFFER AND DID NOT GET IT

	MOVE T1,IBPLLB		;GET LOGICAL LINK BLOCK ADDRESS
	JN LLDRB,(T1),IBP010	;DRIVER REFUSED BUFFER PREVIOUSLY ?
	BUG (NSPEXB)
	RETBAD (NSPX5)		;RETURN FAILURE TO DRIVER
IBP010:	SETZRO LLDRB,(T1)	;CLEAR "DRIVER REFUSED TO PROVIDE BUFFER" FLAG

; STORE NEW BUFFER ADDRESS, COUNT, AND FLAGS

	MOVE T1,IBPLLB		;GET LOGICAL LINK BLOCK ADDRESS
	MOVE T4,IBPBUF		;GET NEW BUFFER ADDRESS
	STOR T4,LLBFI,(T1)	;SAVE IN LINK BLOCK
	HRLI T4,(POINT 8,)	;FORM POINTER TO FIRST BYTE IN THIS BUFFER
	STOR T4,LLBPI,(T1)	;SAVE AS POINTER TO NEXT BYTE TO BE INPUT
	MOVE T4,IBPCNT		;GET COUNT AND FLAGS
	STOR T4,LLICT,(T1)	;STORE COUNT OF BYTES CURRENTLY LEFT IN BUFFER
	STOR T4,LLIIC,(T1)	;ALSO STORE AS INITIAL COUNT OF BYTES IN BUFFER
	TXNE T4,NS%TRN		;DRIVER WANT MESSAGES TRUNCATED IF TOO LONG ?
	JRST [	SETONE LLTRC,(T4) ;YES, NOTE TRUNCATION DESIRED
		JRST .+1 ]	;AND CONTINUE

; TRY TO DO INPUT NOW THAT A BUFFER IS AVAILABLE

	MOVE T1,IBPLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL INTSET		;DO AS MUCH INPUT AS POSSIBLE
	 JRST [	MOVE T1,IBPLLB	;FAILED, LINK WENT AWAY. GET BLOCK ADDRESS
		CALLRET BLKULK]	;UNLOCK THE BLOCK AND RETURN FAILURE

; DONE, UNLOCK LOGICAL LINK BLOCK AND RETURN

	MOVE T1,IBPLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKULK		;UNLOCK THE BLOCK
	RETSKP			;DONE
SUBTTL	Internal Links - Send and Receive Interrupt Messages


XNSRIN:	ASUBR <RIMLID,RIMBUF,RIMCNT,RIMLLB>

; LOCK LOGICAL LINK BLOCK

	MOVE T1,RIMLID		;GET LINK ID
	CALL INTLOK		;GO LOCK THE LINK
	 RET			;FAILED, RETURN ERROR
	MOVEM T1,RIMLLB		;SAVE LOGICAL LINK BLOCK

; READ THE INTERRUPT MESSAGE

	MOVE T1,RIMLLB		;GET LOGICAL LINK BLOCK ADDRESS
	MOVE T2,[IFIW+[IDPB T2,T3] ;GET ROUTINE TO STORE BYTES
		 RET]		;  AND RETURN
	MOVE T3,RIMBUF		;GET ADDRESS OF DRIVER'S BUFFER
	HRLI T3,(POINT 8,)	;FORM POINTER TO BUFFER
	CALL RDINT		;GO READ INTERRUPT MESSAGE
	 RET			;FAILED, RETURN ERROR
	MOVEM T3,RIMCNT		;SAVE NUMBER OF BYTES READ
	MOVE T1,RIMLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKULK		;UNLOCK THE BLOCK
	MOVE T1,RIMCNT		;RESTORE COUNT
	RETSKP			;DONE, RETURN



XNSSIN:	ASUBR <SINLID,SINBUF,SINCNT,SINLLB>

; LOCK THE LOGICAL LINK BLOCK

	MOVE T1,SINLID		;GET LINK ID
	CALL INTLOK		;GO LOCK THE LINK
	 RET			;FAILED, RETURN ERROR
	MOVEM T1,SINLLB		;SAVE LOGICAL LINK BLOCK ADDRESS

; SEND THE INTERRUPT MESSAGE

	MOVE T1,SINLLB		;GET LOGICAL LINK BLOCK ADDRESS
	MOVE T2,[IFIW![ILDB T2,T3]
		RET ]		;ROUTINE TO GET BYTES
	MOVE T3,SINBUF		;GET BUFFER ADDRESS
	HRLI T3,(POINT 8,)	;FORM POINTER TO INTERRUPT MESSAGE
	MOVE T4,SINCNT		;GET COUNT
	CALL SNINT		;SEND THE MESSAGE
	 RET			;FAILED, RETURN ERROR
	MOVE T1,SINLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKULK		;UNLOCK THE BLOCK
	RETSKP			;DONE, RETURN SUCCESS
SUBTTL	Internal Links - Read Link Status

XNSRLS:	ASUBR <RLSLID,RLSLLB,RLSSTS>

; LOCK THE LOGICAL LINK BLOCK

	MOVE T1,RLSLID		;GET LINK ID
	CALL INTLOK		;LOCK THE LOGICAL LINK
	 RET			;FAILED, RETURN ERROR TO CALLER
	MOVEM T1,RLSLLB		;SAVE LINK ADDRESS

; GET THE LINK STATUS

	MOVE T1,RLSLLB		;GET LOGICAL LINK ADDRESS
	CALL RDSTS		;GET THE STATUS
	MOVEM T3,RLSSTS		;SAVE STATUS

; UNLOCK THE LINK BLOCK AND CONVERT ERROR CODE

	CALL BLKULK		;UNLOCK THE LOGICAL LINK BLOCK
	HRRZ T1,RLSSTS		;GET NSP ERROR CODE
	CALL NSPERR		;CONVERT TO TOPS20 ERROR CODE
	 RETBAD ()		;FAILED
	HRR T3,T1		;COPY ERROR CODE
	HLL T3,RLSSTS		;COPY STATUS BITS
	RETSKP			;DONE, RETURN SUCCESS
SUBTTL	Internal Links - Read Maximum Link Segment Size

XNSRSS:	ASUBR <RSSLID,RSSLLB,RSSERR,RSSSIZ>

; LOCK THE LOGICAL LINK BLOCK

	MOVE T1,RSSLID		;GET LINK ID
	CALL INTLOK		;LOCK THE LINK BLOCK
	 RET			;FAILED, RETURN TO DRIVER
	MOVEM T1,RSSLLB		;SAVE LOGICAL LINK BLOCK ADDRESS

; CHECK LINK STATE AND GET SEGMENT SIZE

	MOVE T1,RSSLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL MTRNCK		;GO CHECK LINK STATE
	 JRST [	MOVEM T1,RSSERR	;BAD STATE, SAVE ERROR CODE
		MOVE T1,RSSLLB	;GET BLOCK ADDRESS
		CALL BLKULK	;UNLOCK THE LINK BLOCK
		MOVE T1,RSSERR	;RESTORE ERROR CODE
		RET ]		;RETURN ERROR TO DRIVER
	LOAD t4,LLSWG,(T1)	;GET MAX SEGMENT SIZE
	MOVEM t4,RSSSIZ		;SAVE SEGMENT SIZE
	CALL BLKULK		;UNLOCK THE LINK BLOCK
	MOVE T1,RSSSIZ		;RESTORE SEGMENT SIZE
	RETSKP			;AND DONE
SUBTTL	Internal Links - Read Optional Data

XNSRDA::ASUBR <RDALID,RDABUF,RDALLB,RDACNT>
	STKVAR <RDASRC,RDADST>

; LOOK UP THE LOGICAL LINK BLOCK

RDA001:	LLLOCK			;LOCK THE LOGICAL LINK TREE
	MOVE T1,RDALID		;GET LINK ID
	SETOM T2		;ANY LINK
	CALL LLLKUP		;GO FIND BLOCK
	 JRST [	LLLULK		;NOT IN RUN STATE, CANNOT DO ANY OUTPUT
		RET ]		;UNLOCK THE TREE AND RETURN FAILURE
	MOVEM T1,RDALLB		;SAVE LOGICAL LINK BLOCK ADDRESS

; LOCK THE BLOCK

	MOVE T1,RDALLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKLOK		;GO LOCK THE LOGICAL LINK BLOCK
	 JRST [	LLLULK		;CANNOT LOCK IT NOW, UNLOCK THE TREE
		MDISMS		;WAIT UNTIL CONDITION SATISFIED
		JRST RDA001 ]	;TRY AGAIN TO PROCESS ACK'S
	LLLULK			;BLOCK IS NOW LOCKED. UNLOCK THE TREE

; SET UP TO COPY OPTIONAL DATA

	MOVE T1,RDALLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T4,LLUCT,(T1)	;GET COUNT OF BYTES IN OPTIONAL DATA
	MOVEM T4,RDACNT		;SAVE COUNT OF BYTES TO BE MOVED
	LOAD T3,LLOPT,(T1)	;GET ADDRESS OF OPTIONAL DATA
	MOVE T2,RDABUF		;GET ADDRESS OF DESTINATION BUFFER
	MOVE T1,[POINT 8,(T2)]	;FORM POINTER TO DESTINATION STRING
	MOVEM T1,RDADST		;SAVE DESTINATION POINTER
	MOVE T1,[POINT 8,(T3)]	;FORM POINTER TO SOURCE STRING
	MOVEM T1,RDASRC		;SAVE SOURCE POINTER

; COPY THE OPTIONAL DATA TO THE DRIVER BUFFER

RDA010:	SOJL T4,RDA020		;IF NO MORE BYTES TO MOVE ALL DONE
	ILDB T1,RDASRC		;GET A BYTE
	IDPB T1,RDADST		;SAVE THE BYTE IN DRIVER'S BUFFER
	JRST RDA010		;GO DO THE NEXT BYTE

; HERE WHEN DONE MOVING THE STRING

RDA020:	MOVE T1,RDALLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKULK		;UNLOCK THE BLOCK
	MOVE T1,RDACNT		;RETURN COUNT TO DRIVER
	RETSKP			;DONE, RETURN SUCCESS
SUBTTL	Internal Links - Read Host Name

XNSRHN:	ASUBR <RHNLID,RHNBUF,RHNLLB,RHNERR>

; LOOK UP THE LOGICAL LINK BLOCK

RHN001:	LLLOCK			;LOCK THE LOGICAL LINK TREE
	MOVE T1,RHNLID		;GET LINK ID
	SETOM T2		;ANY LINK
	CALL LLLKUP		;GO FIND BLOCK
	 JRST [	LLLULK		;NOT IN RUN STATE, CANNOT DO ANY OUTPUT
		RET ]		;UNLOCK THE TREE AND RETURN FAILURE
	MOVEM T1,RHNLLB		;SAVE LOGICAL LINK BLOCK ADDRESS

; LOCK THE BLOCK

	MOVE T1,RHNLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKLOK		;GO LOCK THE LOGICAL LINK BLOCK
	 JRST [	LLLULK		;CANNOT LOCK IT NOW, UNLOCK THE TREE
		MDISMS		;WAIT UNTIL CONDITION SATISFIED
		JRST RHN001 ]	;TRY AGAIN TO PROCESS ACK'S
	LLLULK			;BLOCK IS NOW LOCKED. UNLOCK THE TREE

; GET HOST NAME AND PLACE INTO DRIVER BUFFER

	MOVE T1,RHNLLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T2,LLHST,(T1)	;GET FOREIGN HOST NAME
	CALL TSTLCL		;IS THIS A LOCAL CONNECTION ?
	 MOVEI T2,OURNAM	;YES, GET ADDRESS OF OUR NAME STRING
	MOVE T1,RHNBUF		;GET DRIVER BUFFER ADDRESS
	SETOM T3		;ASCIZ STRING, NO COUNT
	CALL MOVSTR		;COPY THE STRING

; UNLOCK THE LINK BLOCK AND RETURN

	MOVE T1,RHNLLB		;GET LOGICAL LINK BLOCK
	CALL BLKULK		;UNLOCK THE BLOCK
	RETSKP			;DONE, RETURN SUCCESS
SUBTTL	Internal Links - Close a link

XNSCLZ:	ASUBR <CLILID,CLIRSN,CLIBUF,CLICNT>
	STKVAR <CLILLB,CLIERR>

; LOOK UP THE LOGICAL LINK BLOCK

CLI001:	LLLOCK			;LOCK THE LOGICAL LINK TREE
	MOVE T1,CLILID		;GET LINK ID
	SETOM T2		;ANY LINK
	CALL LLLKUP		;GO FIND BLOCK
	 JRST [	LLLULK		;NOT IN RUN STATE, CANNOT DO ANY OUTPUT
		RETBAD (NSPX02) ] ;UNLOCK THE TREE AND RETURN FAILURE
	MOVEM T1,CLILLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	LLLULK			;BLOCK IS NOW LOCKED. UNLOCK THE TREE

; HANDLE ANY OUTSTANDING ACKS

	MOVE T1,CLILLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL MOVSEG		;HANDLE ACK'S
	 JFCL			;IGNORE FAILURE

; DISPATCH TO SPECIFIC ROUTINE BASED ON LINK STATE

	MOVE T1,CLILLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T2,LLSTA,(T1)	;GET LOGICAL LINK STATE
	JRST @CLIDSP-1(T2)	;DISPATCH TO PROCESSING ROUTINE

; TABLE OF ROUTINES TO DO A CLOSE FOR LINKS IN VARIOUS STATES

CLIDSP:	IFIW!CLIDON
	IFIW!CLIDON
	IFIW!CLIDI
	IFIW!CLIRUN
	IFIW!CLIWDC
	IFIW!CLIDIQ
	IFIW!CLIDIR
	IFIW!CLIABT
; HERE TO CLOSE AN INTERNAL LINK IN RUN STATE

CLIRUN:	MOVE T1,CLILLB		;GET LOGICAL LINK BLOCK ADDRESS
	SKIPN CLIRSN		;ABORT CLOSE ?
	CALL FRCOUT		;NO, GO FORCE OUT ANY REMAINING DATA

; STORE REASON CODE IN LOGICAL LINK BLOCK

	MOVE T4,CLIRSN		;GET REASON FROM DRIVER
	CAMN T4,[-1]		;WANT DEFAULT REASON ?
CLIDI:	MOVX T4,.DCX9		;YES, SUPPLY DEFAULT
	MOVE T1,CLILLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	STOR T4,LLRSN,(T1)	;STORE REASON CODE IN LOGICAL LINK

; SEND A DISCONNECT-INITIATE MESSAGE TO THE REMOTE NSP

CLIDIQ:
CLRN10:	MOVE T1,CLILLB		;GET LOGICAL LINK BLOCK ADDRESS
	SETZM T2		;ASSUME SYNCHRONOUS CLOSE
	SKIPE CLIRSN		;ABORT CLOSE ?
	SETOM T2		;YES, NOTE SO
	MOVE T3,CLICNT		;GET COUNT OF BYTES IN OPTIONAL DATA
	MOVE T4,CLIBUF		;GET ADDRESS OF BUFFER WITH DATA
	CALL CLZSDI		;GO SEND A DI
	 JRST [	SKIPE CLIRSN	;ABORT?
		JRST CLIABT	;YES. PROCEED AS IF CONFIRMED
		MDISMS		;CANNOT SEND IT, WAIT A WHILE
		JRST CLRN10 ]	;TRY TO SEND DI AGAIN
	; ..
	; ..

; IF ABORT CLOSE, KILL LINK QUEUES.  ELSE WAIT FOR DC FROM REMOTE NSP

CLIWDC:	MOVE T1,CLILLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	SKIPE CLIRSN		;ABORT CLOSE ?
	JRST [	SETONE LLSDE,(T1) ;YES, DISSOCIATE PROCESS FROM LINK
		CALL IFLUSH	;KILL ALL LINK QUEUES AND DISPOSE OF BUFFERS
		CALL BLKULK	;UNLOCK THE BLOCK
		JRST CLRN20 ]	;AND CONTINUE WITH CLEANUP
	MOVEI T2,CHKDCR		;GET TEST ADDRESS
	CALL MAKTST		;MAKE STANDARD SCHEDULER TEST WORD
	MOVE T2,CLILLB		;GET BACK LOGICAL LINK BLOCK ADDRESS
	CALL INTWAT		;WAIT FOR DC TO ARRIVE
	 JRST [	MOVEM T1,CLIERR	;SAVE ERROR CODE
		MOVE T1,CLILLB	;GET LINK BLOCK ADDRESS
		CALL BLKULK	;UNLOCK THE BLOCK
		MOVE T1,CLIERR	;RESTORE ERROR CODE
		RETBAD () ]	;FAILED, OTHER END MUST HAVE ABORTED LINK

; DC HAS ARRIVED - CHECK REASON CODE

CLIABT:
CLIDIR:	MOVE T4,CLILLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T1,LLRSN,(T4)	;GET REASON CODE
	CAIE T1,0		;NORMAL DISCONNECT, OR
	CAIN T1,.DCX42		; REPLY TO DI MESSAGE ?
	JRST CLRN15		;YES, GO ON
	SKIPN CLIRSN		;NO, WAS THIS AN ABORT CLOSE ?
	JRST [	CALL BLKULK	;NO, SYNCHRONOUS CLOSE FAILED.
		RETBAD (DCNX11) ] ;RETURN ERROR TO DRIVER

; KILL LINK QUEUES AND DELETE LINK BLOCK

CLIDON:
CLRN15:	MOVE T1,CLILLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	CALL IFLUSH		;KILL LINK QUEUES AND DISPOSE OF BUFFERS
	LLLOCK			;LOCK THE LOGICAL LINK TREE
	CALL DELNOD		;RELEASE THE LINK BLOCK
	LLLULK			;UNLOCK THE TREE
	OKINT			;IN LIEU OF OKINT IN BLKULK THAT'S NOT DONE

; ACCOUNT FOR REMOVAL OF A LINK

CLRN20:	DECR DCCUR		;DECREMENT LINK COUNT
	RETSKP			;DONE, RETURN
;FRCOUT - ROUTINE TO FORCE OUT ANY REMAINING DATA FOR AN INTERNAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK (LOCKED)
;		CALL FRCOUT
;RETURN: +1 ALWAYS, WITH ALL DATA SENT

FRCOUT:	ASUBR <FRCLLB>

; SEE IF ALL DATA HAS ALREADY BEEN SENT

	MOVE T1,FRCLLB		;GET LOGICAL LINK BLOCK ADDRESS
	JE LLBFO,(T1),FRC010	;IF ALL DATA SENT, WAIT TILL ALL ACK'ED

; DATA REMAINS TO BE SENT, SO THIS LINK MUST BE ON OUTQUE.  JUST
; WAIT UNTIL THE BACKGROUND PROCESS SENDS THE DATA.

	SETONE LLCIP,(T1)	;NOTE SYNCHRONOUS CLOSE IN PROGRESS
	LOAD T1,LLLNK,(T1)	;GET LINK ID
	HRLS T1			;FORM STANDARD SCHEDULER TEST
	HRRI T1,SNOTST		; WORD
	MOVE T2,FRCLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL INTWAT		;WAIT FOR ALL DATA TO BE SENT
	 RET			;LINK WENT AWAY, DONE.

; ALL DATA SENT - WAIT UNTIL ALL SEGMENTS HAVE BEEN ACK'ED

FRC010:	MOVE T2,FRCLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	JE LLQOU,(T2),R		;ALL ACK'D, SO DONE.
	LOAD T1,LLLNK,(T2)	;GET LINK ID
	HRLS T1			;FORM STANDARD SCHEDULER TEST
	HRRI T1,CHKEMP		; WORD
	CALL INTWAT		;WAIT FOR ALL DATA TO BE SENT
	 RET			;LINK WENT AWAY, DONE
	RET			;DONE, RETURN
;IFLUSH - ROUTINE TO FLUSH ALL BUFFERS AND QUEUES FOR INTERNAL LINKS
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL IFLUSH
;RETURNS: +1 ALWAYS

IFLUSH:	ASUBR <IFLLLB>

; DISPOSE OF ANY INPUT BUFFER STILL CONTROLLED BY NSP

	MOVE T4,IFLLLB		;GET LOGICAL LINK BLOCK ADDRESS
	JE LLBFI,(T4),IFL010	;IF NO INPUT BUFFER THEN GO CHECK OUTPUT BUFFER
	LOAD T1,LLDRV,(T4)	;GET DRIVER CORRELATION CODE
	LOAD T2,LLBFI,(T4)	;GET BUFFER ADDRESS
	LOAD T3,LLIIC,(T4)	;GET INITIAL COUNT OF BYTES
	OPSTR <SUB T3,>,LLICT,(T4) ;COMPUTE NUMBER OF BYTES IN BUFFER
	TXO T3,NS%ABT		;NOTE THAT LINK NOT USABLE
	LOAD T4,LLVEC,(T4)	;GET DRIVER VECTOR ADDRESS
	CALL @.NSDAT(T4)	;NOTIFY DRIVER OF LINK ABORT

; HERE TO DISPOSE OF OUTPUT BUFFER - NOTE THAT THERE SHOULD NOT BE
; AN OUTPUT BUFFER IF THIS IS A SYNCHRONOUS CLOSE.

IFL010:	MOVE T4,IFLLLB		;GET LOGICAL LINK BLOCK ADDRESS
	JE LLBFO,(T4),IFL020	;ALL SET IF NO OUTPUT BUFFER
	LOAD T1,LLDRV,(T4)	;GET DRIVER CORRELATION CODE
	LOAD T2,LLBFO,(T4)	;GET BUFFER ADDRESS
	LOAD T3,LLVEC,(T4)	;GET DRIVER VECTOR ADDRESS
	CALL @.NSOBE(T3)	;TELL DRIVER TO DISPOSE OF BUFFER

; HERE TO DISPOSE OF OTHER LINK QUEUES

IFL020:	MOVE T1,IFLLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALLRET FLUSH		;FLUSH THE QUEUES AND RETURN TO CALLER
;INTLOK - ROUTINE TO LOCK AN INTERNAL LOGICAL LINK
;
;ACCEPTS IN T1/	LINK IDENTIFIER
;		CALL INTLOK
;RETURNS: +1	 FAILED, COULD NOT LOCK THE LINK
;	  +2	SUCCESS, WITH T1/ ADDRESS OF LOGICAL LINK BLOCK

INTLOK:	ASUBR <ILKLID,ILKLLB>

; GET THE ADDRESS OF THE LOGICAL LINK BLOCK

ILK001:	LLLOCK			;LOCK THE LOGICAL LINK TREE
	MOVE T1,ILKLID		;GET LINK ID
	CALL CHKLNK		;GO CHECK LINK STATE
	 JRST [	LLLULK		;NOT IN RUN STATE, CANNOT DO ANY OUTPUT
		RET ]		;UNLOCK THE TREE AND RETURN FAILURE
	MOVEM T1,ILKLLB		;SAVE LOGICAL LINK BLOCK ADDRESS

; LOCK THE BLOCK

	MOVE T1,ILKLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKLOK		;GO LOCK THE LOGICAL LINK BLOCK
	 JRST [	LLLULK		;CANNOT LOCK IT NOW, UNLOCK THE TREE
		MDISMS		;WAIT UNTIL CONDITION SATISFIED
		JRST ILK001 ]	;TRY AGAIN TO PROCESS ACK'S
	LLLULK			;BLOCK IS NOW LOCKED. UNLOCK THE TREE

; RETURN THE ADDRESS OF THE LINK BLOCK

	MOVE T1,ILKLLB		;GET BLOCK ADDRESS
	RETSKP			;DONE, RETURN SUCCESS

	TNXEND
	END