Google
 

Trailing-Edge - PDP-10 Archives - BB-J098B-SB_1980 - tskser.mac
There are no other files named tskser.mac in the archive.
TITLE TSKSER -TASK TO TASK COMMUNICATION SERVICE ROUTINE - V100
SUBTTL	W. E. MATSON/WEM  08 JAN 80
	SEARCH	F,S,NETPRM
	$RELOC
	$HIGH
                           Comment @

                         End Comment @


;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
; COPYRIGHT (C) 1978,1979,1980 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VTSKSER,100	;PUT VERSION NUMBER IN GLOB AND LOADER MAP

NETTSK::ENTRY	NETTSK	;LOADING IF IN LIBRARY SEARCH MODE

;TSK. ERROR CODES
	TK%TNL==ECOD1##		; 1 = TSKSER NOT LOADED.
	TK%ATS==ECOD2##		; 2 = ARG LIST TOO SHORT
	TK%UNP==ECOD3##		; 3 = USER NOT PRIVLEDGED
	TK%ILF==ECOD4##		; 4 = ILLEGAL FUNCTION
	TK%ILC==ECOD5##		; 5 = ILLEGAL CHANNEL (OR NOT TASK)
	TK%ILN==ECOD6##		; 6 = ILLEGAL NPD
	TK%NTS==ECOD7##		; 7 = NPD TOO SHORT
	TK%ILS==ECOD10##	; 10 = ILLEGAL FUNCTION WHILE IN THIS STATE
	TK%NFC==ECOD11##	; 11 = NO MONITOR FREE CORE
	TK%NFL==ECOD12##	; 12 = NO FREE LINKS
	TK%NXN==ECOD13##	; 13 = ATTEMPT TO CONNECT TO A NONEXISTANT NODE
	TK%UDW==ECOD14##	; 14 = UUO (IN OR OUT) DIDN'T SKIP

;TSK. FUNCTION CODES
	.TKFRS==1		; 1 = RETURN STATUS
	.TKFEP==2		; 2 = ENTER PASSIVE STATE
	.TKFEA==3		; 3 = ENTER ACTIVE STATE
	.TKFEI==4		; 4 = ENTER IDLE STATE
	.TKFWT==5		; 5 = WAIT
	.TKFOT==6		; 6 = OUTPUT WITH CONTROL OF TYPE/E-O-R
	.TKFIN==7		; 7 = INPUT WITH NOTIFICATION OF TYPE/E-O-R

;TSK. STATE VALUES
	.TKSID==0		; 0 = LINE IS IDLE
	.TKSCI==1		; 1 = WAITING FOR CONNECT INITIATE
	.TKSCC==2		; 2 = WAITING FOR CONNECT CONFIRM
	.TKSOK==3		; 3 = LINK IS OPERATIONAL
	.TKSDC==4		; 4 = WAITING FOR A DISCONNECT CONFIRM
				COMMENT @

The first NPD in the UUO argument list is the Right-hand one (RH(DEVNPD))
The second NPD is the Left-hand one (LH(DEVNPD))

For the passive task.

    1)	The enter passive state uuo
	-   NPD1 := Name we wish to be identified as (our process name)
	-   NPD2 := The "pattern" we wish to match
    2)	After a successful connection,
	-   NPD1 := The "actual" that the pattern successfully matched
	-   NPD2 := The name of the remote process that sent the connect.

For the active task.

    1)	The enter active state uuo
	-   NPD1 := The name we want to return as "ours" on the confirm
	-   NPD2 := The the "actual" we try to connect to.
    2)	After a successful connection,
	-   NPD1 := The name the remote thinks we are.
	-   NPD2 := The name he gave us as "his"

				    @
TSK.::	PUSHJ	P,SAVE4##	;WE USE A LOT OF P'S
	HLRZ	P4,T1		;P4 := LENGTH OF ARG LIST
	HRRZ	P3,T1		;P3 := ADDRESS OF ARG LIST
	CAIGE	P4,2		;MAKE SURE AT LEAST FCN & CHAN ARE THERE
	PJRST	TK%ATS		;ERROR: ARG LIST TOO SHORT
	HRRI	M,(P3)		;SET "M" UP TO READ FUNCTION CODE
	PUSHJ	P,GETWDU##	;READ FUNCTION
	SKIPG	P2,T1		;P2 := FUNCTION CODE
	PJRST	TK%ILF		;ILLEGAL FUNCTION CODE
	PUSHJ	P,GETWD1##	;GET THE CHANNEL NUMBER
	MOVE	P1,T1		;P1 := CHANNEL NUMBER
	PUSHJ	P,SETUF##	;SET UP F WITH ADDRESS OF DDB
	  PJRST	TK%ILC		;ERROR: ILLEGAL CHANNEL
	HRLM	P1,.UPMP+.UPCTA	;SET UP THE EXTENDED CHANNEL NUMBER
	LDB	T1,PDVTYP##	;GET THE DEVICE TYPE
	CAIE	T1,<.TYTSK/.TYEST> ;MAKE SURE THAT THIS IS A TASK DEVICE
	PJRST	TK%ILC		;ERROR: ILLEGAL CHANNEL
	CAILE	P2,TSKMX	;IS THIS A LEGAL FUNCTION CODE
	PJRST	TK%ILF		;ILLEGAL FUNCTION
	JRST	@.(P2)		;DISPATCH TO SUBFUNCTION
	JRST	TSKRS		; 1 = RETURN TASK STATUS
	JRST	TSKEP		; 2 = ENTER PASSIVE TASK STATE
	JRST	TSKEA		; 3 = ENTER ACTIVE TASK STATE
	JRST	TSKEI		; 4 = ENTER IDLE TASK STATE
	JRST	TSKWT		; 5 = WAIT FOR CONNECT INITIATE/CONFIRM/REJECT
	JRST	TSKOU		; 6 = OUT WITH CONTROL OF E-O-R.
	JRST	TSKIN		; 7 = IN WITH NOTIFICATION OF E-O-R.
	TSKMX=7			; 7 = MAXIMUM LEGAL FUNCTION.
;SUB-FUNCTION #1 = RETURN STATUS
TSKRS:	PUSHJ	P,GETSTA	;GET THE CONNECTION STATE
	CAIGE	P4,3		;IF WE CAN'T STORE THE STATUS
	JRST	TK%ATS		;ERROR: ARG LIST TOO SHORT
	HRRI	M,2(P3)		;GET THE ADDRESS OF THE RETURN VALUE AREA
	PUSHJ	P,PUTWDU##	;RETURN THE STATE
	CAIN	T1,LAT.ID	;SKIP IF WE HAVE TO RETURN NPD'S
	JRST	[LDB T1,NETRSN##;GET REASON FOR LAST DISCONNECT
		 PUSHJ P,PUTWD1## ;RETURN THAT AS SECOND ARG
		 RETSKP]	;GIVE GOOD RETURN

	CAIGE	P4,4		;IF THE LIST IS ONLY 3 WDS LONG
	JRST	CPOPJ1		; THEN WE'RE DONE
	HRRI	M,3(P3)		;GET ADDRESS OF THE FIRST NPD POINTER
	HRRZ	J,DEVNPD(F)	;GET THE POINTER TO THE LOCAL NPD
	PUSHJ	P,WRTNPD	;STORE THE NPD IN THE USER'S AREA
	  POPJ	P,		;PROPAGATE THE ERROR RETURN
	CAIGE	P4,5		;IF THE LIST ISN'T LONG ENOUGH
	JRST	CPOPJ1		; THEN RETURN
	HRRI	M,4(P3)		;GET THE ADDRESS OF THE SECOND NPD POINTER
	HLRZ	J,DEVNPD(F)	;GET THE POINTER TO THE REMOTE NPD
	PUSHJ	P,WRTNPD	;STORE THE NPD
	  POPJ	P,		;PROPAGATE THE ERROR RETURN
	RETSKP			;ALL DONE, GOOD RETURN

;SUB-FUNCTION #2 = ENTER PASSIVE STATE.  (WAITING FOR CONNECT INITIATE)
TSKEP:	PUSHJ	P,GETSTA	;GET AND RANGE CHECK THE STATE
	CAIE	T1,LAT.ID	;THIS FUNCTION IS ONLY LEGAL IN IDLE STATE
	PJRST	TK%ILS		;ERROR: ILLEGAL STATE
	PUSHJ	P,RD2NPD	;READ THE TWO NPD'S (ARG'S 1 & 2)
	  POPJ	P,		;NPD WAS BAD, PROPAGATE THE ERROR RETURN
	NETDBJ			;GET THE NETSER INTERLOCK
	PUSHJ	P,T.PSIV	;ENTER PASSIVE STATE.
	  JRST	[PUSHJ P,GV2NPD## ;NO FREE LAT'S, FIRST RETURN THE NPD'S
		 PJRST TK%NFL]	;  THEN GIVE "NO FREE LINK ADDRESSES" ERROR
	RETSKP			;GIVE GOOD RETURN. STATE = LAT.CI

;SUB;SUB-FUNCTION #3 = ENTER ACTIVE STATE. (SEND CONNECT INITIATE)
TSKEA:	PUSHJ	P,GETSTA	;GET AND RANGE CHECK THE STATE
	CAIE	T1,LAT.ID	;THIS FUNCTION IS ONLY LEGAL IN IDLE STATE
	PJRST	TK%ILS		;ERROR: ILLEGAL STATE
	PUSHJ	P,RD2NPD	;READ THE TWO NPD'S (ARG'S 1 & 2)
	  POPJ	P,		;NPD WAS BAD, PROPAGATE THE ERROR RETURN
	HLRZ	J,DEVNPD(F)	;GET THE ADDRESS OF THE REMOTE NPD
	SKIPG	T1,NPDNOD(J)	;T1 := THE NODE NUMBER TO SEND CONNECT TO
	JRST	[PUSHJ P,GV2NPD## ;IF IT'S NEGATIVE, RETURN NPD'S
		 JRST TK%NXN]	;  GIVE ILLEGAL NODE ERROR.
	NETDBJ			;GET THE NETSER INTERLOCK
	PUSHJ	P,SRCNDB##	;W := NDB ADDRESS (IF NODE IS UP)
	  JRST	[PUSHJ P,GV2NPD## ;RETURN THE NPD'S
		 PJRST TK%NXN]	;  AND GIVE AN ILLEGAL NODE ERROR
	HRRM	T1,DEVNET(F)	;MAKE THIS TASK'S NODE BE .T1 (FOR NCSCNT)
	PUSHJ	P,T.ACTV	;ENTER ACTIVE STATE. SEND CONNECT INITIATE
	  JRST	[PUSHJ P,GV2NPD## ;NO FREE CORE. FIRST RETURN THE NPD'S
		 PJRST TK%NFC]	;  THEN GIVE "NO FREE CORE" ERROR
	RETSKP			;GIVE GOOD RETURN. STATE = LAT.CC
;SUB-FUNCTION #4 = ENTER IDLE STATE.  SEND DISCONNECT IF NECESSARY.
TSKEI:	PUSHJ	P,GETSTA	;GET AND RANGE CHECK THE CONNECTION STATE
	JRST	@[EXP CPOPJ1##,TSKEI1,TK%ILS,TSKEI2,TK%ILS](T1) ;DISPATCH

TSKEI1:	NETDBJ			;GET THE NETSER INTERLOCK
	PUSHJ	P,GV2NPD##	;RETURN THE TWO NPD'S
	PUSHJ	P,GIVSLA##	;RETURN THE SLA, ENTER STATE LAT.ID
	RETSKP			;GIVE GOOD RETURN

TSKEI2:	NETDBJ			;GET THE NETSER INTERLOCK
	MOVEI	T1,RSN.OK	;GET THE "NORMAL" REASON FOR DISCONNECT
	PUSHJ	P,NTDXDS	;SEND THE DISCONNECT, ENTER LAT.DC STATE
	  PJRST	TK%NFC		;ERROR: NO MONITOR FREE CORE
	RETSKP			;GIVE GOOD RETURN


;SUB-FUNCTION #5 = WAIT FOR CONNECT INITIATE/CONFIRM/REJECT
TSKWT:	PUSHJ	P,T.WAIT	;WAIT FOR TASK TO ENTER "ID" OR "OK" STATE
	RETSKP			;GIVE GOOD RETURN

;SUB-FUNCTION #6 = OUTPUT WITH CONTROL OF INTERRUPT/DAP MESSAGE TYPE
TSKOU:	PUSHJ	P,GETSTA	;GET THE STATE OF THE CONNECTION,
	CAIE	T1,LAT.OK	;  AND IF WE AREN'T CONNECTED, THEN
	PJRST	TK%ILS		;  GIVE "ILLEGAL STATE" ERROR CODE
	HRRI	M,2(P3)		;GET THE ADDRESS OF TSKOP.'S ARG #1
	PUSHJ	P,GETWDU##	;READ THE DAP TYPE
	PUSH	P,T1		;SAVE THE TYPE FOR A BIT
	HLR	M,DEVBUF(F)	;GET THE ADDRESS OF THE BUFFER CONTROL BLOCK
	PUSHJ	P,GETWDU##	;GET THE ADDRESS OF THE BUFFER HEADER
	JUMPL	T1,TSKOU1	;RING NOT SET UP.  CALL "TOUT" TO SET UP RING
	HRRI	M,(T1)		;GET THE USE BIT
	PUSHJ	P,GETWDU##	;  TO SEE IF THIS BUFFER HAS HAD AN "OUT"
	JUMPL	TSKOU1		;  DONE.  IF SO, DON'T CHANGE THE DAP TYPE
	PUSHJ	P,GETWD1##	;GET "XWD 0,WORD-COUNT"
	HRL	T1,(P)		;T1 := "XWD DAP-TYPE,WORD-COUNT"
	PUSHJ	P,PUTWDU##	;STORE TYPE AND COUNT IN THE BUFFER HEADER
TSKOU1:	POP	P,T2		;CLEAN UP THE STACK
	HLLZS	M,M		;CLEAR "BUFFER POINTER" BEFORE DOING AN OUT
	PUSHJ	P,TOUT##	;DO THE OUT. (NTDXMT WILL NOTICE THE DAP TYPE)
	  RETSKP		;IF UUO SUCCEEDS, RETURN NOW.
	JRST	TSKIOE		;IF THE UUO DIDN'T WORK, TELL THE USER

;SUB-FUNCTION #7 = INPUT WITH NOTIFICATION OR INTERRUPT/MESSAGE TYPE
TSKIN:	HRRZ	T1,DEVPCB(F)	;FIRST SEE IF ANY INPUT IS QUEUED
	JUMPN	T1,TSKIN1	;IF SO, READ IT. (EVEN IF DISCONNECTED)
	PUSHJ	P,GETSTA	;GET OUR STATE AND MAKE SURE
	CAIE	T1,LAT.OK	;  THAT WE ARE CONNECTED.
	PJRST	TK%ILS		;IF NOT CONNECTED, "ILLEGAL STATE"
TSKIN1:	HLLZS	M,M		;CLEAR THE "BUFFER POINTER"
	PUSHJ	P,TIN##		;DO THE "IN" UUO
	  SKIPA			;SKIP IF THE UUO WAS SUCCESSFUL
	JRST	TSKIOE		;IF UUO DIDN'T GIVE A BUFFER, GO SEE WHY
	HRR	M,DEVBUF(F)	;TO RETURN E-O-R NOTIFICATION, GET BUFFER
	PUSHJ	P,GETWDU##	;  HEADER, AND FROM THAT TRACK DOWN THE
	HRRI	M,1(T1)		;  ".BTCNT" WORD OF THE BUFFER JUST
	PUSHJ	P,GETWDU##	;  RETURNED.
	HLRZ	T1,T1		;TSKSER PUTS THE DAP TYPE IN LH(.BFCNT)
	HRRI	M,2(P3)		;GET THE ADDRESS OF ARG#1 OF THE TSKOP.
	PUSHJ	P,PUTWDU##	;  BLOCK AND RETURN THE DAP TYPE CODE
	RETSKP			;GIVE A GOOD RETURN TO THE ENTIRE UUO.

TSKIOE:	HRRZ	T1,DEVIOS(F)	;IF UUO FAILS, GET THE DEVICE STATUS
	HRRI	M,2(P3)		;  AND RETURN IT IN ARG #1 OF THE
	PUSHJ	P,PUTWDU##	;  TSK. ARGUMENT BLOCK.
	PJRST	TK%UDW		;TELL THE USER IT FAILED WITH "UUO DIDN'T WORK"
;T.WAIT	ROUTINE TO WAIT FOR A TASK TO ENTER EITHER "LAT.ID" OR "LAT.OK" STATE
;CALL	F := DDB POINTER
;RETURN	CPOPJ			;ALWAYS

T.WAIT:	PUSHJ	P,GETSTA	;GET THE CONNECTION STATE
	CAIE	T1,LAT.ID	;IF IT'S IDLE, OR
	CAIN	T1,LAT.OK	;  IF IT'S "RUNNING"
	POPJ	P,		;  THEN RETURN
	PUSHJ	P,NETHIB##	;OTHERWISE SLEEP TILL SOMEONE WAKES US.
	JRST	T.WAIT		;UPON AWAKING, SEE IF THE STATE CHANGED.


;T.PSIV	ROUTINE TO PUT A TASK IN THE PASSIVE (LAT.CI) STATE.
;CALL	F := DDB POINTER
;RETURN	CPOPJ			;IF NO FREE LINK ADDRESSES (LAT FULL)
;	CPOPJ1			;LINK ADDRESS ASSIGNED. WAITING FOR CI

T.PSIV: 
IFN PARANOID&P$TSK,<		;IF WE'RE BEING CAUTIOUS,

	PUSHJ	P,T.CHKC	;MAKE SURE WE'RE NOT CONNECTED
>
	MOVEI	T1,(F)		;RH(LAT-ENTRY) := DDB ADDRESS
	HRLI	T1,LAT.CI	;LH(LAT-ENTRY) := NEW LINK STATE
	PUSHJ	P,GETSLA##	;ASSIGN A SLA, SET NEW STATE
	  POPJ	P,		;NO FREE LINK ADDRESSES
	DPB	T1,NETSLA##	;REMEMBER THE LINK ADDRESS
	RETSKP			;GIVE GOOD RETURN

;T.ACTV	ROUTINE TO PUT A TASK IN THE ACTIVE (LAT.CC) STATE. SENDS CONNECT
;CALL	F := DDB POINTER (WITH RH(DEVNET) := NODE NUMBER)
;RETURN	CPOPJ			;NO CORE, OR NO FREE LINKS, OR NO NODE
;	CPOPJ1			;CONNECT INITIATE SENT. STATE := LAT.CC

T.ACTV:
IFN PARANOID&P$TSK,<		;IF WE'RE BEING CAUTIOUS,

	PUSHJ	P,T.CHKC	;MAKE SURE WE'RE NOT CONNECTED
>
	MOVEI	T1,(F)		;RH(LAT-ENTRY) := DDB ADDRESS
	HRLI	T1,LAT.CC	;LH(LAT-ENTRY) := LAT.CC
	PUSHJ	P,GETSLA##	;ASSIGN A LINK ADDRESS
	  POPJ	P,		;ERROR: NO FREE LINK ADDRESSES
	DPB	T1,NETSLA##	;REMEMBER OUR LINK ADDRESS
	MOVE	T1,[XWD T.XSPN,T.XDPN] ;GET ADDRESS OF ROUTINE TO SEND "DPN"
	PUSHJ	P,NCSCNT##	;CALL ROUTINE TO ACTUALLY SEND THE CONNECT
	  PJRST	GIVSLA		;ERROR: NO CORE. FREE THE SLA AND RETURN
	RETSKP			;GIVE GOOD RETURN


IFN PARANOID&P$TSK,<		;IF CHECKING, STOP IF DDB IS CONNECTED
T.CHKC:	PUSHJ	P,GETSTA	;GET THE STATE (BETTER BE ZERO)
	MOVE	S,DEVIOS(F)	;GET THE "CONNECTED" BIT (AND OTHERS...)
	CAIN	T1,LAT.ID	;DIE IF STATE /= "IDLE"
	TLNE	S,IOSCON	;DIE IF DEVIOS THINK'S WERE CONNECTED
	PUSHJ	P,NTDSTP##	;DIE, DIE, DIE...
	POPJ	P,		;RETURN IF EVERYTHING'S OK
>


SUBTTL 1.0      UUOCON INTERFACE.

;DISPATCH TABLE (FROM UUOCON)

	POPJ	P,		;(-5) DEVICE OFF LINE
	POPJ	P,		;(-4) SPECIAL ERROR STATUS
	JRST	REGSIZ##	;(-3) LENGTH CAN BE GOTTEN FROM DDB
	JRST	CPOPJ##		;(-2) INITIALIZE
	JRST	CPOPJ##		;(-1) HUNG DEVICE
NDEVTS::JRST	NTDREL##	;(0)  RELEASE
	JRST	T.CLSO		;(1)  CLOSE OUTPUT
	JRST	T.OUT		;(2)  OUTPUT
	JRST	T.IN		;(3)  INPUT
	JRST	T.ENTR		;(4)  ENTER
	JRST	T.LOOK		;(5)  LOOKUP
	JRST	NTDILI##	;(6)  DUMP MODE INPUT
	JRST	NTDILO##	;(7)  DUMP MODE OUTPUT
	POPJ	P,		;(10) USETO
	POPJ	P,		;(11) USETI
	POPJ	P,		;(12) GETF UUO
	POPJ	P,		;(13) RENAME UUO
	JRST	T.CLSI		;(14) CLOSE INPUT
	POPJ	P,		;(15) UTPCLR
	POPJ	P,		;(16) MTAPE UUO
SUBTTL 1.1        DDB SEARCH LOGIC INTERFACE.


;TSTTSK	ROUTINE TO SEE IF A TASK DDB SHOULD BE CREATED.
;CALL	MOVEI	P1,FLAGS	;DD%PHY=1B34, DD%LOG=1B35
;	MOVE	T1,[SIXBIT /DEVICE/]
;	PUSHJ	P,TSTTSK
;RETURN	CPOPJ			;NOT A TSK
;	CPOPJ1			;WAS A TSK, F := DDB POINTER
;

DD%LOG==1B35			;I HOPE IT'S THE SAME AS UUOCON.

TSTTSK::TRNE	P1,DD%LOG	;IS THIS A LOGICAL SEARCH?
	POPJ	P,		;IF SO, THEN DON'T MATCH PHYSICAL TASKS
	TLC	T1,(SIXBIT /TSK/) ;IF T1 := "TSKNNM" THEN THE LH(T1)
	TLNE	T1,-1		; IS NOW ZERO.
	JRST	[TLC T1,(SIXBIT /TSK/) ;IF IT'S NOT, FIXUP T1 AGAIN
		 POPJ P,]	; AND FAIL RETURN
	TLC	T1,(SIXBIT /TSK/) ;FIX UP T1 AGAIN...
	NETDBJ			;INTERLOCK THIS CODE
	PUSHJ	P,SAVE4##	;SAVE THE P'S
	PUSHJ	P,SAVT##	;UUOCON LIKES IT'S TEAS
	MOVE	P2,T1		;COPY DEVICE NAME TO A REASONABLE REGISTER
	PUSHJ	P,DVSCVT##	;CONVERT THE NETWORD DEVICE NAME, GET NODE #
	  POPJ	P,		;ILLEGAL DEVICE NAME
	MOVEI	T1,(T2)		;COPY THE NODE NUMBER FOR SRCNDB
	PUSHJ	P,SRCNDB##	;DOES THE NODE EXIST
	  POPJ	P,		;IF NOT, WE CAN'T CONNECT TO IT'S DEVICES
	MOVEI	P1,(W)		;COPY THE NDB FOR SRCNDT
	SETZ	P3,		;CLEAR THE LOGICAL NAME WORK
	HLRZ	T1,P2		;GET THE GENERIC DEVICE NAME
	PUSHJ	P,SRCNDT##	;DOES THIS NODE SUPPORT THIS DEVICE?
	  POPJ	P,		;IF NOT. THEN SEARCH FAILS
	PUSHJ	P,MAKDDB##	;IF NODE DOES SUPPORT THEM, THEN MAKE A DDB
	  POPJ	P,		;IF NO CORE. JUST MAKE SEARCH FAIL
	PUSHJ	P,LNKDDB##	;LINK IN THIS DDB (EVEN THOUGH NOT CONNECTED)
	RETSKP			;RETURN WITH NEWLY CONSTRUCTED DDB.
SUBTTL 1.2        OUTPUT UUO.


;T.OUT	ROUTINE TO HANDLE THE OUT UUO FOR THE TSK DEVICE.
;
T.OUT:	PUSHJ	P,SAVE4##	;THEY GET CLOBBERED NTDXMT AND FRIENDS
	MOVSI	S,IOSUSO	;CLEAR "UUOCON STOPED OUTPUT" SINCE IT
	ANDCAB	S,DEVIOS(F)	;  APPEARS TO BE TRYING TO START IT AGAIN

TOLOOP:	PUSHJ	P,NTDSET##	;SET UP S, W ETC
	MOVSI	S,IO		;SET DIRECTION TO "OUTPUT"
	IORB	S,DEVIOS(F)	; SO THAT UUOCON WILL BE HAPPY (WAIT1 ETC)
	PUSHJ	P,NTDONL##	;SEE IF THIS DEVICE IS STILL CONNECTED.
	  PJRST	T.SERR		;NOT CONNECTED. SET IOSERR

;
; AS AN ECONOMY OF CODE, SET P1 := XWD CONVERSION-CODE, BYTE-SIZE.  P1
; SHOULD CONTAIN THESE VALUES UNTIL NTDISP IS CALLED.
;
	LDB	T1,PIOMOD##	;GET THE CURRENT MODE
	MOVE	P1,[XWD PCV.NC,^D07] ;ASSMUE ASCII MODE. (NO CONVERSION, 7 BIT)
	CAILE	T1,AL		;IF IT'S NOT ASCII, IT'S IMAGE/BINARY
	MOVE	P1,[XWD PCV.BN,^D12] ; (BINARY CONVERSION, 12 BITS)
	CAIN	T1,BYTMOD	;UNLESS IT'S BYTE MODE.
	MOVE	P1,[XWD PCV.NC,^D08] ; (NO CONVERSION, 8 BIT BYTES)

	MOVEI	T1,(P1)		;GET THE BYTE SIZE
	PUSHJ	P,NTDSOB##	;SET UP THE OUTPUT BUFFER
	  JRST	TODONE		;IF NO BUFFER, OUTPUT UUO IS DONE.

;
; NOTE: THIS CODE ALLOWS ZERO LENGTH DATA BUFFERS
;

	HRRZ	T1,DEVOAD(F)	;GET A POINTER TO THE BUFFER HEADER
	EXCTUX	<HLRZ P2,1(T1)>	; AND USE IT TO GET THE TYPE/INTERRUPT BIT
	PUSHJ	P,NTDPRV##	;DOES THIS GUY HAVE NETWORK PRIVS
	  TRZ	P2,(1B0)	;IF NOT, DON'T LET HIM SEND INTERRUPT MSGS

	TRZN	P2,(1B0)	;IS THIS AN INTERRUPT MESSAGE?
	JRST	[PUSHJ P,NTDCDQ## ;IF NOT, COUNT DOWN THE DATA REQUEST
		  JRST TOWAIT	;IF NONE, THEN GO WAIT FOR SOME
		 JRST .+1]	;WE HAVE DATA-REQUESTS. CONTINUE
	HLRZ	T1,P1		;GET THE CONVERSION CODE
	SKIPN	T2,P2		;GET THE IDC TYPE FIELD
	MOVEI	T2,DC.DAR	;IF THE USER DIDN'T SPECIFY ONE. USE THE DEFAULT
	PUSHJ	P,NTDXMT##	;SEND A PCB'S WORTH OF DATA
	  JRST	T.IMPM		;A NON-DATA MSG DIDN'T FIT. BLOCK TOO LARGE.
	SKIPN	DEVAXO+1(F)	;IS THE BUFFER FINALLY EMPTY
	PUSHJ	P,NTDAOB##	;IF SO, ADVANCE THE OUTPUT BUFFER
	JRST	TOLOOP		;CONTINUE TILL SOMEONE GET'S BORED.

;TOWAIT	ROUTINE TO WAIT FOR TASK OUTPUT DATA REQUESTS
;
TOWAIT:	PUSHJ	P,NTDWTO##	;LET NETSER DO THE WORK.
	  POPJ	P,		;NON-BLOCKING. RETURN TO UUOCON
	JRST	TOLOOP		;WHEN WE WAKE UP. TRY TO DO MORE OUTPUT




;TODONE	HERE WHEN WE HAVE OUTPUT ALL THE USERS BUFFERS
;
TODONE:	POPJ	P,
SUBTTL 1.3        INPUT UUO.


;T.IN	ROUTINE TO HANDLE THE "IN" UUO ENTRY TO THE TSK DEVICE
;
T.IN:	PUSHJ	P,SAVE4##	;WE CLOBBER MOST OF THEM
	MOVSI	S,IOSUSI	;CLEAR "UUOCON STOPED INPUT" SINCE IT'S
	ANDCAB	S,DEVIOS(F)	; OBVIOUSLY TRYING TO START IT AGAIN

TILOOP:	PUSHJ	P,NTDSET##	;USE COMMON SETUP ROUTINE (S, W, ETC)
	MOVE	S,DEVIOS(F)	;GET STATUS BITS BACK AFTER A POSSIBLE SLEEP
	TLNE	S,IOBEG		;IS THIS THE FIRST TIME THROUGH
	JRST	TIFRST		;IF SO, LOOK FOR PSUEDO NON-BLOCKING CONNECT

	MOVSI	S,IO		;CLEAR THE DIRECTION BIT SO THAT
	ANDCAB	S,DEVIOS(F)	; UUOCON WON'T GET CONFUSED.

	PUSHJ	P,NTDIBA##	;IS THEIR AN INPUT BUFFER AVAILABLE?
	  POPJ	P,		;IF NOT, WE ARE DONE.
	HRRZ	T1,DEVPCB(F)	;GET A POINTER TO THE LIST OF INPUT PCB'S
	JUMPE	T1,TIWAIT	;IF NO DATA, WE MUST WAIT
	PUSHJ	P,NTDDID##	;DO THE DELAYED INPUT DISPATCH
	JRST	TILOOP		;KEEP IT UP TILL WE RUN OUT OF DATA.
;TIFRST	HERE WE CHECK TO SEE IF WE ARE CONNECTED.  IF NOT, AND THIS IS NON-
; BLOCKING STYLE I/O. THEN WE DO A DEVERR RETURN TO UUOCON.  OTHERWISE WE JUST
; WAIT.  WHEN WE FINNALY GET CONNECTED. WE MUST REMEMBER TO TURN OFF "IOSERR"
; WHICH GOT SET BY NTDSET.
;
TIFRST:	TLNE	S,IOSCON	;ARE WE CONNECTED YET
	JRST	[MOVSI S,IOBEG!IOSERR!IOSREL ;IF WE ARE CONNECTED, CLEAR
		 ANDCAB S,DEVIOS(F)	;  THESE BITS,
		 JRST TILOOP]	;  AND TRY ONCE AGAIN TO PROCESS DATA.
	PUSHJ	P,NTDWTI##	;IF NON CONNECTED, THEN WAIT FOR CONNECT/DATA
	  POPJ	P,		;IF NONBLOCKING, RETURN TO UUOCON
	JRST	TILOOP		;TRY ONCE MORE TO DO INPUT

;TIWAIT	HERE IF WE HAVE NO INPUT PCB'S TO PROCESS.  FIRST MAKE SURE WE HAVEN'T
; BEEN DISCONNECTED. IF SO, SET EOF.  OTHERWISE SEND DATA REQUESTS, AND
; WAIT IT OUT.
;
TIWAIT:	PUSHJ	P,NTDONL##	;IS THERE ANY PARTICULAR PROBLEM??
	  JRST	T.EOF		; IF SO, GO SEE WHAT IT IS
	PUSHJ	P,NTDXDQ##	;SEE IF WE ARE BEHIND ON OUR DATA-REQUESTS
	PUSHJ	P,NTDWTI##	;WAIT FOR DATA
	  POPJ	P,		;RETURN TO UUOCON IF NON-BLOCKING
	JRST	TILOOP		;AND GO MUNCH IT


;T.EOF	ROUTINE TO RETURN END-OF-FILE ON FIRST "IN" AFTER DISCONNECT.
;
T.EOF:	MOVSI	S,IOEND		;GET THE END-OF-FILE BIT
	TDOE	S,DEVIOS(F)	;SEE IF IT'S ALREADY SET.
	JRST	T.SERR		;IF SO, THEN START COMPLAINING
	MOVEM	S,DEVIOS(F)	;OTHERWISE JUST SET THE BIT
	POPJ	P,		;AND GO BACK TO UUOCON

;T.IMPM, T.SERR ROUTINES TO SET ERROR BITS AND RETURN
;
T.SERR:	MOVE	S,[XWD IOSERR,IODERR]	;THE TWO DEVICE ERROR BITS
	JRST	T.SET		; AND SET THEM IN DEVIOUS
T.IMPM:	MOVEI	S,IOIMPM	;IMPROPER MODE (NOT LOOKED UP/ENTERED)
T.SET:	IORB	S,DEVIOS(F)	;SET THE BITS
	POPJ	P,		;RETURN TO UUOCON.

SUBTTL 1.4        ENTER UUO.
;T.ENTR	ROUTINE TO HANDLE THE ENTER VECTORED ENTRY FROM UUOCON
;CALL	F := XWD FLAGS,DDB
;	M := UUO		;POINTE TO LOOKUP/ENTER BLOCK (LEB)
;RETURN	CPOPJ			;NOT ENTERED. ERROR STORED IN LEB
;	CPOPJ1			;ENTERED.  TASK IS CONNECTED.

T.ENTR:	PUSHJ	P,GETSTA	;GET OUR STATE.
	MOVEI	T2,1		;GET A "1"
	LSH	T2,(T1)		;MAKE IT A 1 BIT MASK
	TRNN	T2,1_LAT.ID!1_LAT.CI!1_LAT.OK ;LEGAL STATES FOR ENTER'ING
	PJRST	RTNISU		;OTHERWISE RETURN "ILLEGAL SEQUENCE OF UUO'S"
	PUSHJ	P,SAVJW##	;WE CLOBBER THEM WITH NPD'S AND NDB'S
	PUSHJ	P,SAVE4##	;SAVE THE P'S
	PUSHJ	P,GETLEA	;GET THE LOOKUP ENTER ARG'S IN THE P'S
	  PJRST	RTNLEE		;  IF LEB ARGS BAD, STORE ERROR IN LEB & RETURN
	PUSHJ	P,GETSTA	;GET THE STATE AGAIN
	CAIN	T1,LAT.ID	;IF WE ARE IDLE, THEN
	JRST	T.ENT1		;  GO STORE ARGS & CONTINUE

;HERE IF TASK HAS BEEN LOOKED-UP (PUT IN PASSIVE STATE, POSSIBLY CONNECTED)

	PUSHJ	P,CHKLEA	;MAKE SURE THAT THE LEB'S ARE IN AGREEMENT
	  PJRST	RTNAEF		;  IF LEB BAD, GIVE AN "AEF" ERROR
	PUSHJ	P,GETSTA	;GET THE CONNECTION STATE
	CAIN	T1,LAT.OK	;IF WE'RE ALREADY CONNECTED, THEN
	RETSKP			;  GIVE A GOOD RETURN TO THE ENTER.

IFN PARANOID&P$TSK,<		;IF WE'RE BEING PARANOID, MAKE SURE
	CAIE	T1,LAT.CI	;  WE'RE IN THE "PASSIVE" STATE
	PUSHJ	P,NTDSTP##	;  IF NOT, THEN WE'VE SCREWED UP.
>
	PUSHJ	P,GV2NPD	;RETURN THE LOOKUP'S NPDS
	PUSHJ	P,GIVSLA##	;RETURN THE LAT (T.ACTV ASSIGNS A NEW ONE)
	JRST	T.ENT2		;GO SEND THE CONNECT INITIATE AND RETURN

;HERE IF WE HAVEN'T BEEN LOOKED UP YET. (STATE IS "IDLE")
T.ENT1:	PUSHJ	P,STOLEA	;STORE THE LOOKUP/ENTER ARGS
;	PJRST	T.ENT2		;GO SEND THE CONNECT INITIATE


;HERE WE SET UP "W", BUILD TWO NPD'S, SEND THE CONNECT & WAIT FOR A REPLY
T.ENT2:	HRRZ	T1,DEVNET(F)	;GET THIS DEVICE'S NODE NUMBER
	PUSHJ	P,SRCNDB##	;SET W := NDB POINTER.
	  PJRST	RTNUNN		;  ERROR. RETURN "UNKNOWN NETWORK NODE"
	PUSHJ	P,LE2NPD	;MAKE 2 NPD'S, REMOTE & LOCAL FOR T.ACTV
	  PJRST	RTNENC		;  IF NO CORE "EXCEEDED NETWORK CAPACITY"
	HLRZ	T1,NDBNNM(W)	;GET THE NODE NUMBER WE'RE TRYING TO CONNECT TO
	HLRZ	J,DEVNPD(F)	;GET THE "REMOTE" NPD
	MOVEM	T1,NPDNOD(J)	;SET THE NPD'S NODE NUMBER
	PUSHJ	P,T.ACTV	;SEND THE CONNECT INITIATE
	  JRST	[PUSHJ P,GV2NPD	;IF NO CORE, OR NO LATS, FREE NPD'S
		 PJRST RTNENC]	;RETURN EXCEEDED NETWORK CAPACITY

;IF NONBLOCKING, WE MIGHT WANT TO RETURN HERE

	PUSHJ	P,T.WAIT	;WAIT FOR CONNECT CONFIRM/REJECT
	PUSHJ	P,GETSTA	;GET OUR STATE (TO SEE IF CONFIRM/REJECT)
	CAIE	T1,LAT.OK	;IF WE'RE NOT CONNECTED, THEN
	JRST	[PUSHJ P,GV2NPD	;  RETURN BOTH THE NPD'S, AND
		 PJRST RTNTNA]	;  GIVE A "TASK NOT AVAILABLE" ERROR
	RETSKP			;  OTHERWISE, GIVE A GOOD RETURN

SUBTTL 1.5        LOOKUP UUO.
;T.LOOK	ROUTINE TO HANDLE THE LOOKUP VECTORED ENTRY FROM UUOCON
;CALL	F := XWD FLAGS,DDB
;	M := UUO		;POINTS TO THE USERS LOOKUP/ENTER BLOCK (LEB)
;RETURN	CPOPJ			;IF ERROR, CODE RETURNED IN LEB
;	CPOPJ1			;TASK LOOKED-UP. NOW IN "PASSIVE" STATE

T.LOOK:	PUSHJ	P,GETSTA	;GET OUR CONNECTION STATE
	MOVEI	T2,1		;GET A "1"
	LSH	T2,(T1)		;MAKE IT A 1 BIT MASK
	TRNN	T2,1_LAT.ID!1_LAT.OK ;LEGAL STATES FOR LOOKING UP
	PJRST	RTNISU		;OTHERWISE RETURN "ILLEGAL SEQUENCE OF UUO'S"
	PUSHJ	P,SAVJW##	;J := NPD'S, W := NDB'S
	PUSHJ	P,SAVE4##	;WE PUT THE LOOKUP/ENTER ARGS HERE
	PUSHJ	P,GETLEA	;GET THE LEB'S DATA
	  PJRST	RTNLEE		;LEB BAD, RETURN ERROR CODE IN "T1"
	PUSHJ	P,GETSTA	;GET THE STATE AGAIN
	CAIN	T1,LAT.ID	;IF NOT IDLE, JUST CHECK THE ARGUMENTS
	JRST	T.LOO1		;IF IDLE, GO TO "PASSIVE" STATE

;HERE IF WE'VE BEEN ENTERED, CHECK THE LEB'S ARGS AND RETURN

	PUSHJ	P,CHKLEA	;MAKE SURE THE LOOKUP AGREES WITH THE ENTER
	  PJRST	RTNAEF		;  IF LEB IS BAD, RETURN "AEF"
	RETSKP			;GIVE GOOD RETURN TO THE LOOKUP

;HERE IF WE'VE NOT BEEN ENTERED, MAKE 2 NPD'S AND ENTER PASSIVE STATE
T.LOO1:	PUSHJ	P,STOLEA	;STORE DEVFIL AND FRIENDS FOR LE2NPD.

IFN PARANOID&P$TSK,<		;IF WERE CAUTIOUS, MAKE SURE NOT CONNECTED
	SKIPE	DEVNPD(F)	;DIE IF WE'VE ALREADY GOT 1 OR MORE NPD'S
	PUSHJ	P,NTDSTP##	;DIE DIE DIE...
>
	HRRZ	T1,DEVNET(F)	;GET THE NUMBER OF THIS TASK'S NODE
	PUSHJ	P,SRCNDB##	;SET W := NDB POINTER.
	  PJRST	RTNUNN		;  ERROR. RETURN "UNKNOWN NETWORK NODE"
	PUSHJ	P,LE2NPD	;MAKE NPD'S BASED ON DEVFIL & FRIENDS
	  PJRST	RTNENC		;  NO CORE. RETURN "EXCEEDED NET CAP"

	CAIE	W,NETNDB##	;IF HE SPECIFIED "ANY" NODE, DON'T SET NPDNOD
	JRST	[HLRZ J,DEVNPD(F) ;GET ADDRESS OF "REMOTE" NPD.
		 HLRZ T1,NDBNNM(W) ;GET OUR NODE NUMBER
		 MOVEM T1,NPDNOD(J) ;SET THE NODE NUMBER
		 JRST .+1]	;CONTINUE WITH MAIN CODE

	PUSHJ	P,T.PSIV	;ENTER "PASSIVE" STATE
	  JRST	[PUSHJ P,GV2NPD	;IF NO CORE, OR NO LATS, FREE NPD'S
		 PJRST RTNENC]	;RETURN EXCEEDED NETWORK CAPACITY
	RETSKP			;GIVE GOOD RETURN TO THE LOOKUP

SUBTTL 1.6        CLOSE UUO.


;T.CLS	ROUTINE TO HANDLE THE CLOSE ENTRY FROM UUOCON
;CALL	MOVEI	F,DDB
;	PUSHJ	P,T.CLS		;FROM CLOSE1 CODE IN UUOCON
;RETURN	CPOPJ
;
;THE CLOSE UUO CODE DOES NOTHING IF THE TSK HAS NOT BEEN CLOSED ON BOTH INPUT
; AND OUTPUT.  IF IT HAS, IT DOES THE FINAL "OUT" TO FLUSH THE BUFFERS, AND
; SENDS A DISCONNECT INITIATE WAITING FOR THE DISCONNECT CONFIRM.
;
T.CLSO:	TLNE	F,ENTRB		;DON'T FORCE OUTPUT IF NOT ENTERED
	PUSHJ	P,NTDCLO##	;FORCE OUT THE LAST BUFFER (AND WAIT)
	TLZA	F,ENTRB		;SIGNIFY THAT WE ARE NO LONGER "ENTERED"
T.CLSI:	TLZ	F,LOOKB		;SIGNIFY THAT WE ARE NO LONGER "LOOKED UP"
T.CLS:	TLNE	F,ICLOSB	;IF WE HAVEN'T CLOSED BOTH INPUT AND
	TLNN	F,OCLOSB	; OUTPUT, THEN
	POPJ	P,		; DON'T ATTEMPT TO DISCONNECT THIS TASK

T.CLS1:	PUSHJ	P,T.WAIT	;WAIT FOR CONNECTS/DISCONNECTS TO FINISH
	MOVE	S,DEVIOS(F)	;NOW SEE IF WE ARE CONNECTED
	TLNN	S,IOSCON
	JRST	T.CLS4		;DON'T SEND DISCONNECT IF NOT CONNECTED

T.CLS2:	MOVEI	T1,RSN.OK	;STANDARD REASON
	PUSHJ	P,NTDXDS##	;SEND THE DISCONNECT
	  JRST	[PUSHJ P,NETSLP## ;IF WE CAN'T SEND THE DISCONNECT, THEN
		 JRST T.CLS2]	; THEN WAIT FOR A BIT AND TRY AGAIN
T.CLS3:	PUSHJ	P,NETHIB##	;WAIT FOR THE CONFIRM
	LDB	T1,NETSLA##	;GET OUR LAT ADDRESS
	JUMPE	T1,T.CLS5	;THE DISCONNECT CONFIRM CODE WILL ZERO IT

IFN PARANOID&P$LAT,<		;MAKE SURE LAT ENTRY IS RIGHT
	LDB	T1,LATSTA##	;GET THE STATE
	CAIE	T1,LAT.DC	;SHOULD STILL BE DISCONNECT CONFIRM
	PUSHJ	P,NTDSTP##	;++ WRONG CONNECTION STATE
>
	JRST	T.CLS3		;MUST HAVE BEEN A SPURIOUS WAKE
T.CLS4:	LDB	T1,NETSLA##	;FIRST CHECK TO SEE IF WE HAVE
	JUMPE	T1,T.CLS5	;LAT ASSIGNED. IF NOT, DON'T FREE IT.

IFN PARANOID&P$LAT,<
	LDB	T2,LATSTA##	;GET THE STATE
	CAIE	T2,LAT.CI	;THE ONLY LEGAL STATE AT THIS POINT IS "CI"
	PUSHJ	P,NTDSTP##	;++ ILLEGAL STATE FOR TASK LAT
>
	PUSHJ	P,GIVSLA##	;FREE THE SLA

T.CLS5:	PUSH	P,J		;NOW FREE THE NPD'S.  FIRST SAVE J
	PUSHJ	P,GV2NPD##	;FREE THE NPD'S
	POP	P,J
	SETZM	DEVFIL(F)	;CLEAR THE FILE NAME
	HRRZS	DEVEXT(F)	; THE EXTENSION
	SETZM	DEVPPN(F)	; THE PPN
	POPJ	P,		;ALL DONE.
SUBTTL 2.0      NETSER INTERFACE.

;TSKSER'S NDP DISPATCH VECTOR (HERE ON MESSAGES FROM NETSER)


	JRST	NTDNWD##	;COMMON CODE FOR CRASHED NODE
	JRST	NTDDSC##	;COMMON CODE FOR DISCONNECT
	JRST	T.CONC		;SPECIAL CODE FOR CONNECT CONFIRM
	JRST	T.CONI		;SPECIAL CODE FOR CONNECT INITIATE
	JRST	NTDRDQ##	;COMMON CODE FOR DATA-REQUESTS
TSKNDP::JRST	NTDQIP##	;QUEUE INCOMING PCB'S TO UUO LEVEL
	JRST	T.DAPI		;DATA WITH OUT EOR
	JRST	T.DAPI		;DATA WITH EOR
	JRST	T.DAPI		;STATUS
	JRST	T.DAPI		;CONTROL
	JRST	T.DAPI		;UNIT ID
	JRST	T.DAPI		;FILE SPEC
SUBTTL 2.1        CONNECT CONFIRM NCL MESSAGE.

;T.CONC	ROUTINE TO PROCESS THE CONNECT CONFIRM FOR A TASK
;CALL	MOVEI	F,DDB
;	P1, P4 := POINT TO THE "SLA" FIELD OF THE CONNECT
;RETURN	CPOPJ1			;ALWAYS
;
T.CONC:	PUSHJ	P,SAVJW##	;WE USE J FOR THE NPD
;SLA
	PUSHJ	P,EBI2BI##	;READ OUR REMOTE LAT ADDRESS
	DPB	T1,NETDLA##	;SAVE IT SO WE CAN TALK TO HIM

	PUSHJ	P,GV2NPD	;RETURN THE TWO STALE NPD'S.
;DPN(OBJ)
	PUSHJ	P,XSKIP##	;WE'RE NOT INTERESTED
;DPN(PID)
	PUSHJ	P,GETSPN	;GET WHAT HE THINKS WE ARE
	  SETZ	J,		;  IF NO CORE, DON'T WORRY...
	HRRM	J,DEVNPD(F)	;STORE NEW LOCAL NPD
;SPN(OBJ)
	PUSHJ	P,XSKIP##	;WE'RE NOT INTERESTED
;SPN(PID)
	PUSHJ	P,GETSPN	;GET HIS ID
	  SETZ	J,		;  IF NO CORE, JUST RETURN ZERO
	HRLM	J,DEVNPD(F)	;STORE THE NEW REMOTE NPD

;MML,FEA(DCM,RLN,DVT)
	PUSHJ	P,GETFEA	;READ THE "FEATURES"
	PUSHJ	P,T.OK		;SET BITS SAYING WE ARE CONNECTED
	RETSKP			;GIVE GOOD RETURN

SUBTTL 2.2        CONNECT INITIATE NCL MESSAGE.

;T.CONI	ROUTINE TO HANDLE THE CONNECT INITIATE ENTRY FOR THE TSK DEVICE.
;CALL	MOVEI	F,DDB
;	MOVE	P3,[XWD SLA,OBJ]
;	P1, P4 := POINT TO THE "DPN(PID)" FIELD OF THE CONNECT MESSAGE
;RETURN	CPOPJ			;DIDN'T LIKE THE CONNECT
;	CPOPJ1			;OK. CONNECT CONFIRM SENT. LINK IN "OK" STATE
;
T.CONI:	HRRZ	T1,P3		;GET THE OBJECT TYPE
	CAIE	T1,OBJ.TK	;  AND MAKE SURE IT'S FOR TYPE "TSK"
	POPJ	P,		;  IF NOT FOR US, EXIT NOW
	PUSHJ	P,SAVJW##	;WE CLOBBER J
	PUSHJ	P,SAVE4##	;  AND MASSACRE THE P'S
	MOVS	J,DEVNPD(F)	;GET THE "PATTERN" NPD POINTER
	TLNE	J,-1		;MAKE SURE THAT BOTH NPD'S
	TRNN	J,-1		;  EXIST
	POPJ	P,		;IF EITHER NPD MISSING, DON'T MATCH

	HLRZ	T1,NDBNNM(W)	;GET THIS NODE'S NUMBER
	SKIPL	T2,NPDNOD(J)	;GET THE PATTERN'S NODE NUMBER
	CAIN	T1,(T2)		;SKIP IF THEY DON'T MATCH
	SKIPA			;EITHER WILD CARD, OR MATCH, SUCCEED.
	POPJ	P,		;NO MATCH. EXIT NOW.

	PUSHJ	P,T.CON1	;CALL ROUTINE TO DO PATTERN MATCH
	  POPJ	P,		;  IF NO MATCH, GIVE "REJECT" RETURN

	HLRZ	T1,P3		;GET THE SLA
	DPB	T1,NETDLA##	;  AND REMEMBER IT.
	HLRZ	T1,NDBNNM(W)	;GET THE NODE NUMBER
	HRRM	T1,DEVNET(F)	;  AND REMEMBER THAT TO.
;READ NCD'S
;DPN(PID)
	PUSHJ	P,GETSPN	;SET J := NPD DESCRIBING WHAT WE MATCHED
	  POPJ	P,		;  NO CORE, GIVE ERROR RETURN FROM T.CONI
	HLRZ	T1,NDBNNM+NETNDB## ;GET OUR NODE NUMBER
	MOVEM	T1,NPDNOD(J)	;AND USE THAT INSTEAD OF HIS.
	PUSH	P,J		;SAVE NPD FOR A BIT
;SPN(OBJ)
	PUSHJ	P,XSKIP##	;WE'RE NOT INTERESTED
;SPN(PID)
	PUSHJ	P,GETSPN	;READ THE SOURCE PID
	  JRST	[POP P,J	;IF NO CORE, GET LAST NPD READ
		 PJRST GIVNPD]	;  RETURN IT, AND ERROR RETURN FROM T.CONI
	HRLM	J,0(P)		;SAVE THE NEW "REMOTE" NPD

;MML,FEA(DCM,RLN,DVT)
	PUSHJ	P,GETFEA	;READ THE "FEATURES"

;SEND CONFIRM
	HLRZ	J,DEVNPD(F)	;GET OLD "REMOTE" NPD AND FREE IT.
	PUSHJ	P,GIVNPD##	;  (THERE MUST BE ONE TO GET THIS FAR...)
	HLRZ	J,0(P)		;GET THE NEW "REMOTE" NPD
	HRLM	J,DEVNPD(F)	;  AND PUT IT WHERE T.XDPN CAN FIND IT.

	MOVE	T1,[XWD T.XSPN,T.XDPN] ;ROUTINES TO SEND SPN AND DPN
	EMRGCY			;USE EMERGENCY MEMORY IF NECESSARY
	PUSHJ	P,NCSCNT##	;SEND THE CONNECT CONFIRM
	  PUSHJ	P,NTDSTP##	;WE'VE SCREWED UP... SHOULDN'T HAPPEN

	HRRZ	J,DEVNPD(F)	;GET OLD "LOCAL" NPD AND FREE IT
	PUSHJ	P,GIVNPD##	;  (THERE MUST BE ONE IF WE GOT THIS FAR)
	POP	P,J		;GET NEW "LOCAL" NPD
	HRRM	J,DEVNPD(F)	;AND PUT IT WHERE A ".TKFRS" CAN FIND IT

	PUSHJ	P,T.OK		;DECLARE THE TSK UP, WAKE ANY WAITING JOBS
	RETSKP			;GIVE GOOD RETURN
;T.CON1	SUB-ROUTINE TO SET THINGS UP FOR THE "MATCH" ROUTINE.
;	THE ONLY REASON THAT THIS IS A SUBROUTINE IS TO MAKE IT EASY
;	TO SKIP/NON-SKIP RETURN.
;CALL	J := POINTER TO THE "PATTERN" NPD
;	P1, P4 := MESSAGE POINTER,COUNT TO PID (AS USUAL)
;RETURN	CPOPJ			;PATTERN DIDN'T MATCH PID
;	CPOPJ1			;PATTERN DID MATCH, P1, P4 UPDATED TO AFTER
;				;  PID

T.CON1:	PUSH	P,P3		;SAVE THE "XWD SLA,OBJ" INFORMATION
	PUSH	P,P1		;SAVE THE BYTE POINTER TO THE MESSAGE
	PUSH	P,P4		;SAVE THE LENGTH OF THE MESSAGE
	MOVE	P3,P4		;COPY THE LENGTH FOR MATCH
	PUSHJ	P,XSKIP##	;ADVANCE PAST PID SO WE CAN CALCULATE LENGTH
	SUB	P3,P4		;SET P3 := LENGTH(PID)
	MOVE	P4,-1(P)	;SET P4 := BYTE-POINTER TO PID

	MOVE	P1,NPDNLN(J)	;SET P1 := LENGTH OF THE "PATTERN"
	MOVEI	P2,NPDNAM(J)	;GET THE ADDRESS OF THE "PATTERN"
	HRLI	P2,(POINT 7)	;SET P2 := BYTE-POINTER TO "PATTERN"

	SETZ	T4,		;GET A ZERO
	EXCH	T4,TKMTCH	;SEE IF THERE IS ALREADY A PSUEDO-STACK
	JUMPE	T4,[MOVEI T2,100	;GET LENGTH OF PSUEDO-STACK
		    PUSHJ P,GETZWD##	;TRY TO ALLOCATE A NEW PSUEDO-STACK
		      JRST T.CON2	;IF NO CORE, CLEAN UP AND ERROR RETURN
		    MOVEI T4,(T1)	;COPY ADDRESS OF NEW STACK
		    HRLI T4,-100	;MAKE IT AN AOBJN POINTER
		    JRST .+1]	;RETURN TO MAIN CODE WITH T4 := STACK POINTER
	PUSHJ	P,MATCH		;SEE IF THE PID MATCHES THE PATTERN
	  JRST	T.CON2		;  IF NO MATCH, CLEAN UP AND ERROR RETURN
	AOS	-3(P)		;IF IT MATCHES. GIVE SKIP RETURN (UGH...)
T.CON2:	EXCH	T4,TKMTCH	;PUT STACK IN THE PSUEDO-STACK CACHE
	JUMPN	T4,[MOVEI T1,(T4)	;IF THERE IS ALREADY A P-STACK,
		    HRLI T2,(T4)	;  THEN WE MUST FREE THE EXTRA
		    MOVN T2,T2		;  ONE.
		    PUSHJ P,GIVZWD##	;CALL NETSER TO FREE THE CORE.
		    JRST .+1]	;RETURN TO MAIN LINE CODE.

	POP	P,P4		;SET P4 := LENGTH(MESSAGE-PID)
	POP	P,P1		;SET P1 := BYTE-POINTER TO PID
	POP	P,P3		;SET P3 := "XWD SLA,OBJ"
	POPJ	P,		;GIVE (POSSIBLY SKIP) RETURN


SUBTTL 2.3        DAP MESSAGES.

;T.DAPI	HERE TO PROCESS ALL OF THE INCOMING DAP MESSAGES
;CALL	MOVEI	T1,IDC MESSAGE TYPE
;	MOVEI	F,DDB OF DEVICE GETTING MESSAGES
;RETURN	CPOPJ			;MESSAGE BAD
;	CPOPJ1			;MESSAGE OK
;
T.DAPI:	HRRZ	T2,DEVPCB(F)	;GET A POINTER TO THE PCB WE'RE READING
	MOVE	T2,PCBIAD(T2)	;GET A BYTE POINTER TO THE NCT FIELD OF THE MSG
	ILDB	T2,T2		;GET THE NCT BYTE
	TLNE	T2,NCT.IT	;IF THIS IS AN INTERRUPT MESSAGE,
	IORI	T1,(1B0)	;  REMEMBER, SET "INTERRUPT" BIT IN BUFFER HEAD
	MOVE	P2,T1		;COPY THE HALFWORD INTO A SAFER REGISTER.

	LDB	T1,PIOMOD##	;GET THE MODE WE ARE READING IN.
	CAIG	T1,AL		;ASCII OR ASCII LINE?
	JRST	T.ASCI		;IF SO, GO TO ASCII CODE
	CAIN	T1,BYTMOD	;BYTE MODE?
	JRST	T.BYTE		;IF SO, SPECIAL CODE
	JRST	T.IMAG		;ALL THE REST IS IMAGE.



T.ASCI:	SKIPA	T4,[7]		;SEVEN BIT BYTES IN ASCII
T.BYTE:	MOVEI	T4,8		;EIGHT BIT BYTES IN BYTE MODE
	PUSHJ	P,T.SIB		;USE COMMON SET-UP ROUTINE
T.BYT1:	SOJL	P4,T.ADVB	;IF DONE. ADVANCE PCB & USER'S BUFFERS
	ILDB	T1,P1		;GET THE NEXT DATA BYTE
	SOSGE	DEVAXI+1(F)	;COUNT OFF NEXT BYTE IN THE BUFFER
	JRST	T.BKTL		;IF NO ROOM, SET IOBKTL
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THE BYTE
	JRST	T.BYT1		;LOOP UNTIL INPUT MESSAGE IS USED UP.


T.IMAG:	MOVEI	T4,^D12		;12 BIT BYTES
	PUSHJ	P,T.SIB		;USE COMMON SETUP ROUTINE
T.IMG1:	SOJL	P4,T.ADVB	;IF NO MORE, ADVANCE PCB'S AND USER'S BUFFERS
	ILDB	T1,P1		;GET THE TOP 8 BITS OF THE FIRST BYTE
	LSH	T1,4		;POSITION THEM IN THE 12 BIT FIELD
	SOJL	P4,T.IMG2	;IF NO MORE, STORE THIS WITH ZERO FILL
	ILDB	T2,P1		;GET LOW 4 BITS THIS BYTE, HIGH 4 OF THE NEXT
	ROT	T2,-4		;POSITION THE LOW 4 BITS
	IORI	T1,(T2)		;COMBINT BOTH HALVS FOR A 12 BIT BYTE
	SOSGE	DEVAXI+1(F)	;COUNT OFF THIS BYTE
	JRST	T.BKTL		;GIVE AN ERROR IF IT WON'T FIT
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THIS FIRST 12 BIT BYTE
	SOJL	P4,T.ADVB	;IF NO MORE, LAST 4 BITS ARE GARBAGE.
	ILDB	T1,P1		;GET THE LAST 8 BITS OF THE SECOND 12 BIT BYTE
	ROT	T2,^D12		;ISOLATE THE LOW 4 BITS AS THE HIGH 4
	IORI	T1,(T2)		;BUILD THE SECOND 12 BIT BYTE
T.IMG2:	SOSGE	DEVAXI+1(F)	;COUNT OFF THIS BYTE
	JRST	T.BKTL		;GIVE AN ERROR IF IT WON'T FIT
	EXCTUU	<IDPB T1,DEVAXI(F)> ;STORE THE SECOND 12 BIT BYTE
	JRST	T.IMG1		;LOOP UNTIL ALL INPUT IS PROCESSED.


;T.SIB	ROUTINE TO SET UP AN INPUT BUFFER FOR TSK INPUT
; CALLS NTDSIB, AND STORES THE MESSAGE TYPE AND INTERRUPT BIT IN THE
; USER'S BUFFER HEADER.
;
T.SIB:	PUSHJ	P,NTDSIB##	;SET UP THE INPUT BUFFER
	  PUSHJ	P,NTDSTP##	;++ NO INPUT BUFFER (BUT WE CHECKED IN T.IN)
	HRRZ	T1,DEVIAD(F)	;GET THE ADDRESS OF THE BUFFER HEADER
	EXCTUU	<HRLM P2,1(T1)>	;STORE THE MESSAGE TYPE AND INTERRUPT BIT
	POPJ	P,		;RETURN TO MAIN-LINE CODE.

;T.ADVB	TASK ADVANCE BUFFER AND PCB ROUTINE.  THIS ROUTINE ADVANCES
;  THE BUFFER IFF THE MESSAGE RECEIVED WAS NOT DATA-WITHOUT-EOR, OR
;  IF THE "DISABLE MESSAGE RE-ASSEMBLY" (IOSDMR) BIT WAS SET.
;CALL	P2 := IDC TYPE		;LEFT OVER FROM EARLIER
;RETURN	CPOPJ1			;ALWAYS.

T.ADVB:	TRZ	P2,(1B0)	;MAKE SURE THE "INTERRUPT" BIT IS OFF
	CAIN	P2,DC.DAT	;IF IT'S NOT DATA-WITHOUT-EOR,
	TLNE	S,IOSDMR	;  OR WE'RE NOT RE-ASSEMBLING BUFFERS
	PJRST	NTDA1B##	;  THEN ADVANCE THE BUFFER
	RETSKP			;IF DATA WITHOUT-EOR, THEN DON'T ADVANCE
				;  THE BUFFER


;T.BKTL	ROUTINE TO SET THE "IOBKTL" ERROR BIT IF A USERS BUFFER IS TOO SMALL
; IT ADVANCES THE USERS BUFFER, AND SKIP RETURNS (ADVANCING THE DAP MESSAGE)
;
T.BKTL:	MOVEI	S,IOBKTL	;GET THE BLOCK TOO LARGE BIT
	IORB	S,DEVIOS(F)	;SET IT
	PJRST	NTDA1B##	;ADVANCE THE USERS BUFFER AND THE DAP MESSAGE

SUBTTL X.X	ONCE/SECOND TASK CODE

;FREE THE TEMPORARY "PSUEDO-STACK" USED BY TSKSER
TSKSEC::SETZ	T2,		;GET A ZERO TO INDICATE NO BLOCK
	EXCH	T2,TKMTCH	;GET "XWD LENG,ADDR" OF BLOCK
	JUMPE	T2,CPOPJ##	;IF NONE, RETURN NOW
	HLRE	T1,T2		;COPY (MINUS) THE LENGTH
	MOVN	T1,T1		;MAKE THE LENGTH POSITIVE
	PJRST	GIVZWD##	;RETURN THE STORAGE
SUBTTL 3.0      SUBROUTINES.

SUBTTL 3.1        LOOKUP/ENTER BLOCK MANIPULATION


;GETLEA	ROUTINE TO GET THE LOOKUP/ENTER ARGUMENTS FOR THE TSK DEVICE.
;CALL	MOVE	M,THE UUO
;	PUSHJ	P,GETLEA
;RETURN	CPOPJ			;ERROR CODE IN T1
;	CPOPJ1			;P1 := DEVNAM
;				;P2 := DEVEXT
;				;P3 := DEVPPN (THE USERS IF NOT PRVJ)
;
GETLEA:				;HERE TO GET LOOKUP/ENTER ARGS
	PUSH	P,U		;USE U AS A TEMP TO
	MOVE	U,M		; THE ADDRESS OF THE ARGUMENT LIST
	PUSHJ	P,GETWDU##	;GET THE FIRST (DEVNAM OR COUNT)
	MOVE	P1,T1		;RETURN FIRST WORD AS DEVNAM
	TLNN	T1,-1		;IS IT AN EXTENDED BLOCK
	JRST	GETLEE		; IF SO. GO TO SPECIAL CODE TO READ IT
	HRRI	M,UUNEXT(U)	;GET THE EXTENSION
	PUSHJ	P,GETWDU##	; FROM THE USERS MEMORY, AND
	MOVE	P2,T1		; RETURN THAT AS DEVEXT
	HRRI	M,UUNPPN(U)	;GET THE PPN FROM THE USERS MEMORY
	JRST	GETLE1		; AND GO TO COMMON CODE.

GETLEE:	MOVEI	T1,FNFERR	;IN CASE TOO SHORT
	CAIGE	P1,UUXEXT	;IS THIS BLOCK LONG ENOUGH
	JRST	UPOPJ##		; IF TOO SHORT, GIVE AN ERROR RETURN
	HRRI	M,UUXNAM(U)	;GET THE FILE NAME
	PUSHJ	P,GETWDU##	; FROM THE USERS MEMORY,
	MOVE	P1,T1		; AND RETURN AS DEVNAM
	HRRI	M,UUXEXT(U)	;GET THE EXTENSION
	PUSHJ	P,GETWDU##	; FROM THE USER
	MOVE	P2,T1		; AND RETURN AS DEVEXT
	HRRI	M,UUXPPN(U)	;GET THE PPN

GETLE1:	PUSHJ	P,GETWDU##	;GET THE PPN
	MOVE	T2,.CPJOB##	;GET THIS GUY'S JOB NUMBER
	SKIPN	P3,T1		;GET USER-SPECIFIED PPN
	MOVE	P3,JBTPPN##(T2)	;HE DIDN'T SPECIFY ONE, USE JOB'S PPN.
	CAME	P3,JBTPPN##(T2)	;SPECIFYING A PPN OTHER THAN HIS?
	CAMN	P3,[-1]		;(OR [777777,777777]?)
	  JRST	GETLE2		;NO, IT IS OK
	MOVEI	T1,PRTERR	;IN CASE NOT PRIVILEGED
	PUSHJ	P,NTDPRV##	; HE MUST BE PRIVILEGED
	  JRST	UPOPJ##		; AND HE IS NOT, PROTECTION ERROR
GETLE2:	MOVE	T1,P3		;GET THE PPN THAT WE WILL USE
	PUSHJ	P,PUTWDU##	;TELL THE USER WHAT PPN WE REALLY ARE USING
	MOVE	M,U		;RESTORE THE UUO
	PJRST	UPOPJ1##	;GIVE A GOOD RETURN

;CHKLEA	ROUTINE TO CHECK TO MAKE SURE THAT THE DDB'S DEVNAM, DEVEXT, AND
;	DEVPPN AGREE WITH THE LOOKUP/ENTER BLOCK'S
;CALL	MOVEI	F,DDB		;WITH DEVNAM ... SET UP
;	P1, P2, P3 := THE LOOKUP/ENTER ARGS
;RETURN	CPOPJ			;THEY DON'T AGREE (AEF ERROR RETURNED)
;	CPOPJ1			;THEY AGREE
;
CHKLEA:	CAMN	P1,DEVFIL(F)	;COMPARE THE FILE NAMES
	CAME	P3,DEVPPN(F)	;COMPARE THE PPN'S
	JRST	RTNAEF		;GIVE THE "AEF" ERROR (ALREADY EXISTING FILE)
	XOR	P2,DEVEXT(F)	;COMPARE THE EXTENSIONS
	TLNE	P2,-1		; AND ONLY THE EXTENSIONS
	JRST	RTNAEF		;DIFFERENT. GIVE ERROR
	RETSKP			;ALL THE SAME. GIVE GOOD RETURN


;STOLEA	ROUTINE TO STORE THE LOOKUP/ENTER ARGS IN P1, P2, P3 INTO A DDB
;CALL	MOVEI	F,DDB
;	P1, P2, P3 := FILE NAME, EXTENSION, PPN
;	PUSHJ	P,STOLEA
;RETURN	CPOPJ			;ALWAYS
;
STOLEA:	MOVEM	P1,DEVFIL(F)	;STORE THE FILE NAME
	HLLM	P2,DEVEXT(F)	;STORE JUST THE EXTENSION
	MOVEM	P3,DEVPPN(F)	;STORE THE PPN
	POPJ	P,		;ALL DONE

;ERRORS	ROUTINES TO RETURN VARIOUS LOOKUP/ENTER ERRORS
;
;    RTNFNF	;(00) FILE NOT FOUND
;    RTNPRT	;(02) PROTECTION ERROR
;    RTNAEF	;(04) ALREADY EXISTING FILE
;    RTNENC	;(37) EXCEEDED NETWORK CAPACITY
;    RTNTNA	;(40) TASK NOT AVAILABLE
;    RTNUNN	;(41) UNKNOWN NETWORK NODE


DEFINE X(CODE),<		;;SIMPLE MACRO TO MAKE DEFINING THESE EASY
RTN'CODE:
	MOVEI	T1,CODE'ERR	;;S.MAC HAS ALL THESE SYMBOLS DEFINED
	PJRST	RTNLEE		;;COMMON CODE TO RETURN THE ERROR
>

	X	FNF		;FILE NOT FOUND
	X	PRT		;PROTECTION FAILURE (USER NOT PRIVILEGED)
	X	AEF		;ALREADY EXISTING FILE
	X	ISU		;ILLEGAL SEQUENCE OF UUO'S
	X	ENC		;EXCEEDED NTEWORK CAPACITY
	X	TNA		;TASK NOT AVAILABLE
	X	UNN		;UNKNOWN NETWORK NODE



;RTNLEE	ROUTINE TO RETURN A LOOKUP/ENTER ERROR CODE.
;CALL	MOVE	U,UUO
;	MOVEI	T1,ERROR NUMBER
;	PUSHJ	P,RTNLEE
;RETURN	CPOPJ			;ALWAYS
;
RTNLEE:	PUSH	P,M		;SAVE THE UUO
	PUSH	P,T1		;STORE THE ERROR CODE FOR LATER
	PUSHJ	P,GETWDU##	;GET THE FIRST WORD (TO SEE IF EXTENDED L/E)
	MOVEI	M,UUNEXT	;ASSUME THAT THIS IS THE OLD NON-EXTENDED FORM
	TLNN	T1,-1		; BUT IF IT IS EXTNEDED,
	MOVEI	M,UUXEXT	; THEN CHANGE OUR MIND
	ADD	M,-1(P)		;ADD IN OFFSET OF THE BASE OF THE BLOCK
	PUSHJ	P,GETWDU##	;GET THE "EXTENSION" FIELD
	HRR	T1,(P)		;PUT THE ERROR CODE IN THE RH
	PUSHJ	P,PUTWDU##	;STORE THE ERROR CODE IN THE USERS MEMORY
	POP	P,T1		;RESTORE THE ERROR CODE
	POP	P,M		;RESTORE THE UUO
	POPJ	P,		;ALL DONE

SUBTTL 3.2        NPD MANIPULATION
SUBTTL 3.2.1	    USER NPD MANIPULATION

;ADCNPD	ROUTINE TO ADDRESS CHECK AN NPD
;CALL	M := USER ADDRESS OF NPD POINTER (XWD LENGTH,ADDR)
;RETURN	NOT AT ALL -- PAGE FAULT, OR ADDRESS ERROR
;	CPOPJ		NPD TOO SHORT
;	CPOPJ1		ALL'S OK

ADCNPD:	PUSHJ	P,GETWDU##	;GET XWD LENGTH,ADDRESS
	HLRZ	T2,T1		;COPY THE LENGTH
	CAIGE	T2,3		;IS IT LONG ENOUGH TO HOLD A VALID NPD
	JRST	TK%ILN		;IF NOT, SAY "ILLEGAL NPD"
	HRRZI	T1,(T1)		;CLEAR LH(T1) FOR BRNGE
	ADDI	T2,-1(T1)	;SET T2 := LAST WORD OF NPD
	PUSHJ	P,LRNGE##	;MAKE SURE THAT THE NPD IS INCORE
	RETSKP			;IF IT IS, GIVE GOOD RETURN

;REDNPD	ROUTINE TO READ AN NPD.  NPD MUST BE ADDRESSABLE (FAULT = "IME")
;CALL	M := USER ADDRESS OF NPD POINTER (XWD LENGTH,ADDR)
;RETURN	CPOPJ		SOME SORT OF ERROR, ERROR CODE STORED
;	CPOPJ1		J := NPD

REDNPD:	PUSHJ	P,SAVE1##	;USE P1 FOR A TEMP
	PUSHJ	P,GETWDU##	;GET "XWD LENGTH,ADDRESS" OF NPD
	MOVE	P1,T1		;SAVE XWD LENGTH,ADDR
	EXCTUX	<SKIPL T1,1(T1)>;GET THE LENGTH OF THE NAME-STRING
	CAILE	T1,^D100	;ALLOW THIS MANY CHARS FOR THE NPD
	PJRST	TK%ILN		;GIVE ILLEGAL NPD ERROR IF BAD LENGTH
	ADDI	T1,<2*5>+4	;ADD 3 WORDS, ROUND UP
	IDIVI	T1,5		;CALCULATE NUMBER OF WORDS TO HOLD NPD
	HLRZ	T2,P1		;GET "DECLARED" LENGTH
	CAILE	T1,(T2)		;MAKE SURE NPD FITS IN RANGE-CHECKED REGION
	PJRST	TK%ILN		;GIVE ILLEGAL NPD ERROR IF IT DOESN'T FIT
	ADDI	T1,1		;ACCOUNT FOR MONITOR'S "NPDBLK" WORD
	PUSHJ	P,GETNPD##	;ALLOCATE AN NPD, J := ADDRESS
	  PJRST	TK%NFC		;ERROR: NO MONITOR FREE CORE
	HRLZ	T1,P1		;MAKE BLT POINTER: FROM = USER ADDRESS
	HRRI	T1,NPDNOD(J)	;  TO = MONITOR NPD ADDRESS
	HLRZ	T2,NPDBLK(J)	;J := LENGTH OF THE NPD
	ADDI	T2,-1(J)	;T2 := ADDRESS OF LAST WORD IN THE NPD
	EXCTUX	<BLT T1,(T2)>	;COPY THE NPD
	RETSKP			;GIVE GOOD RETURN

;RD2NPD	ROUTINE TO READ BOTH NPD'S FOR .TKFEA OR .TKFEP SUB FUNCTIONS
;	FREE'S OLD NPD'S FIRST, THEN READS NEW ONES.
;CALL	P1, P2, P3, P4 := CHANNEL, SUB=FUNCTION, ADDRESS, LENGTH
;RETURN	CPOPJ		SOMETHING'S WRONG, ERROR CODE STORED
;	CPOPJ1		NPD'S READ.  DEVNPD(F) HAS POINTERS TO BOTH

RD2NPD:	SKIPE	DEVNPD(F)	;MAKE SURE THAT THERE AREN'T ANY NPD'S ASSIGNED
	PUSHJ	P,NTDSTP##	;?? NPD'S ALREADY THERE ??

	HRRI	M,2(P3)		;GET THE ADDRESS OF THE FIRST NPD POINTER
	PUSHJ	P,ADCNPD	;ADDRESS CHECK IT
	  POPJ	P,		;ERROR?  PASS IT BACK
	HRRI	M,3(P3)		;GET THE ADDRESS OF THE SECOND NPD POINTER
	PUSHJ	P,ADCNPD	;ADDRESS CHECK THIS ONE TOO
	  POPJ	P,		;ERROR. PASS IT BACK

	HRRI	M,2(P3)		;GET THE ADDRESS OF THE FIRST NPD POINTER AGAIN
	PUSHJ	P,REDNPD	;GET J := ADDRESS OF NPD IN MONITOR FREE CORE
	  POPJ	P,		;SOME RANDOM ERROR. CODE ALREADY STORED
	HRRM	J,DEVNPD(F)	;STORE "LOCAL" NPD
	HRRI	M,3(P3)		;GET ADDRESS OF SECOND NPD POINTER
	PUSHJ	P,REDNPD	;GET J := ADDRESS OF COPY
	  JRST	[SETZ J,	;ERROR. FIRST FREE "LOCAL" NPD
		 EXCH J,DEVNPD(F) ;AND CLEAR DEVNPD
		 PJRST GIVNPD##];THEN RETURN. (ERROR CODE ALREADY STORED)
	HRLM	J,DEVNPD(F)	;STORE THE "REMOTE" NPD
	RETSKP

;WRTNPD	ROUTINE TO COPY A MONITOR NPD BACK INTO USER SPACE.
;CALL	M := ADDRESS OF USER'S NPD POINTER (XWD LENGTH,ADDR)
;	J := ADDRESS OF MONITOR NPD.
;RETURN	CPOPJ			;USER'S NPD DESCRIPTOR IS BAD
;	CPOPJ1			;ALL'S OK. NPD RETURNED.

WRTNPD:	JUMPE	J,[SETZ T1,	;IF NO NPD, (PROBABLY SHORT OF CORE)
		   PJRST PUTWDU##] ;WRITE ZERO'S OVER THE USERS NPD POINTER
	PUSHJ	P,SAVE1##	;WE USE P1 AS A TEMP
	PUSH	P,J		;SAVE NPD POINTER (???WDU## CLOBBERS J)
	PUSHJ	P,GETWDU##	;GET THE NPD POINTER (XWD LENGTH,ADDRESS)
	POP	P,J		;GET NPD POINTER BACK
	HLRZ	T2,NPDBLK(J)	;GET THE LENGTH OF THE MONITOR NPD
	SUBI	T2,1		;  LESS ONE (MONITOR'S LENGTH INCLUDES NPDBLK)
	HLRZ	T3,T1		;GET THE LENGTH OF THE USER'S AREA
	CAIGE	T3,(T2)		;SEE IF THE NPD WILL FIT.
	PJRST	TK%NTS		;ERROR: USER'S NPD IS TOO SHORT
	MOVNI	T2,1(T2)	;GET NEGATIVE COUNT (+1 FOR AOBJP)
	HRLZ	P1,T2		;SET UP THE LH OF THE AOBJN POINTER
	HRRI	P1,(J)		;SET UP THE RH.
	HRRI	M,(T1)		;GET THE ADDRESS OF THE USER'S NPD AREA
	PUSH	P,J		;SAVE NPD POINTER AGAIN. (PUTWRD...)
WRTNP1:	AOBJP	P1,JPOPJ1##	;COUNT OFF THE NEXT ITEM, EXIT IF DONE
	MOVE	T1,(P1)		;FETCH THE NEXT WORD OF THE NPD
	PUSHJ	P,PUTWDU##	;STORE THE WORD
	AOJA	M,WRTNP1	;INCREMENT USER'S ADDRESS AND DO NEXT WORD.

SUBTTL 3.2.2	    MONITOR NPD MANIPULATION

;GETSPN	ROUTINE TO BUILD A REMOTE NPD BASED ON CONNECT MSG DATA
;CALL	P1, P4 := POINTER TO THE "PID"
;	W := POINTER TO NDB OF REMOTE NODE
;	PUSHJ	P,GETPID
;RETURN	CPOPJ			;NO CORE
;	CPOPJ1			;J := POINTER TO A NEWLY CONS-ED NPD
;				;  P1, P4 POINT AFTER THE PID

GETSPN:	MOVE	T2,P1		;COPY THE BYTE POINTER
	HRREI	T1,-1(P4)	;GET THE COUNT -1
GETSP1:	ILDB	T4,T2		;GET THE NEXT CHAR FROM THE MESSAGE
	TRNE	T4,200		;SKIP OUT OF THE LOOP IF NOT EXTENSIBLE
	SOJGE	T1,GETSP1	;LOOP COUNTING ALL CHARS IN THE PID

	SUBM	P4,T1		;CALCULATE THE NUMBER OF CHARS IN THE PID
	PUSH	P,T1		;SAVE THE PID'S LENGTH (IN CHARACTERS)
	ADDI	T1,3*5+4	;ACCOUNT FOR NPDNOD AND NPDNLN, ROUND UP
	IDIVI	T1,5		;DIVIDE TO GET WORDS NEEDED TO HOLD PID
	PUSHJ	P,GETNPD##	;ALLOCATE A NEW NPD
	  JRST	[PUSHJ P,XSKIP##;SKIP OVER THE PID
		 JRST TPOPJ##]	;  FIXUP STACK, RETURN WITH PID NOT COPIED
	HLRZ	T1,NDBNNM(W)	;GET THE NODE NUMBER OF THE REMOTE
	MOVEM	T1,NPDNOD(J)	;  AND SAVE IT IN THE NPD
	POP	P,T4		;GET THE CHARACTER COUNT BACK
	MOVEM	T4,NPDNLN(J)	;  AND SAVE THAT TOO
	MOVE	T3,[POINT 7,NPDNAM(J)] ;GET A POINTER TO THE "NAME" PART


	SUBI	P4,(T4)		;MAKE T4 REFLECT THE CHARS WE ARE ABOUT TO READ
GETSP2:	ILDB	T1,P1		;READ A CHAR FROM THE MESSAGE
	IDPB	T1,T3		;STORE IT IN THE NEW PID STRING
	SOJG	T4,GETSP2	;LOOP OVER ALL CHARACTERS
	RETSKP			;ALL DONE.  GIVE GOOD RETURN
;GETFEA	ROUTINE TO COPY THE "FEA" FIELDS FROM A MESSAGE TO A DDB
;CALL	P1, P4 := MESSAGE POINTERS
;	F := DDB POINTER
;	PUSHJ	P,GETFEA
;RETURN	CPOPJ			;ALWAYS
;
GETFEA:				;HERE TO COPY FEA
;MML
	PUSHJ	P,XSKIP##	;WE DON'T CARE...
;FEA(DCM)
	PUSHJ	P,XSKIP##	;WE DON'T CARE ABOUT THIS
;FEA(RLN)
	PUSHJ	P,EBI2BI##	;GET THE RECORD LENGTH
	DPB	T1,NETRLN##	;SAVE IT IN THE DDB
;FEA(DVT)
	PUSHJ	P,EBI2BI##	;GET THE DEVICE ATTRIBUTES
	DPB	T1,NETDVT##	;SAVE IT IN THT DDB
	POPJ	P,		;ALL DONE

;GETSTA	ROUTINE TO RETURN THE CONNECTION STATE OF A TASK
;CALL	F := DDB ADDRESS
;RETURN	T1 := CONNECTION STATE

GETSTA:	LDB	T1,NETSLA##	;GET THE SOURCE LINK ADDRESS
	SKIPE	T1		;IF NONE, THEN ZERO IS THE STATE
	LDB	T1,LATSTA##	;GET THE STATE
	CAIG	T1,LAT.MX	;MAKE SURE THAT IT'S A LEGAL STATE
	SKIPGE	T1		;  AND NOT NEGATIVE
	PUSHJ	P,NTDSTP##	;STATE IS OUT OF RANGE
	POPJ	P,		;RETURN

;LE2NPD	ROUTINE TO DUMMY UP THE NPD'S FOR TASKS OPENED VIA THE
;	LOOKUP/ENTER MECHANISM.  THIS ROUTINE CREATES 2 NPD'S
;	(ONE REMOTE AND ONE LOCAL) BASED ON THE TASK'S FILE-NAME
;	AND THE JOB'S NAME
;CALL	F := DDB POINTER
;RETURN	CPOPJ			;IF NO CORE
;	CPOPJ1			;DEVNPD(F) := XWD RMT,LOCAL NPD'S

LE2NPD:	SKIPE	DEVNPD(F)	;MAKE SURE THAT THERE AREN'T ANY NPD'S
	PUSHJ	P,NTDSTP##	;DIE IF THERE ARE...

;FIRST BUILD THE "LOCAL" NPD

	MOVEI	T1,3+5		;5 WORDS HOLDS ANY "NAME[P,PN]"
	PUSHJ	P,GETNPD##	;GET STORAGE FOR A "LOCAL" NPD
	  POPJ	P,		;IF NO CORE, JUST GIVE ERROR RETURN
	HLRZ	T1,NDBNNM+NETNDB## ;GET OUR NODE NUMBER
	MOVEM	T1,NPDNOD(J)	;STORE IT IN THE NPD

	MOVE	P2,[POINT 7,NPDNAM(J)] ;P2 := BYTE POINTER TO STRING AREA
	SETZ	P3,		;COUNT STARTS AT ZERO

	MOVE	T1,.CPJOB##	;GET OUR JOB NUMBER
	MOVE	T1,JBTNAM##(T1)	;GET OUR JOB NAME
	PUSHJ	P,SX2EAS##	;WRITE THE NAME

	MOVE	T1,.CPJOB##	;GET OUR JOB NUMBER AGAIN...
	MOVE	T1,JBTPPN##(T1)	;GET OUR P,PN
	PUSHJ	P,PP2EAS##	;WRITE THE "[P,PN]"
	MOVEM	P3,NPDNLN(J)	;STORE THE STRING'S LENGTH
	HRRM	J,DEVNPD(F)	;STORE THE NPD POINTER IN THE DDB

;NOW BUILD THE "REMOTE" NPD

	MOVEI	T1,3+5		;GET THE LENGTH OF THE NPD
	PUSHJ	P,GETNPD##	;TRY TO ALLOCATE ONE
	  PJRST	GV2NPD		;IF NO CORE, RETURN THE "LOCAL" NPD AND ERR

	SETOM	NPDNOD(J)	;DEFAULT TO A WILD-CARD NODE.
	MOVE	P2,[POINT 7,NPDNAM(J)] ;P2 := BYTE POINTER TO STRING AREA
	SETZ	P3,		;COUNT STARTS AT ZERO

	MOVE	T1,DEVFIL(F)	;GET THE FILE NAME
	PUSHJ	P,SX2EAS##	;  AND "OUTPUT" THAT

	MOVE	T1,DEVPPN(F)	;GET THE PPN, AND
	CAMN	T1,[-1]		;  IF IT'S -1, THEN
	JRST	[XMTI "*"	;  OUTPUT A WILDCARD (*)
		 JRST LE2NP1]	;  AND WE'RE DONE WITH THE PPN

	XMTI	"["		;OUTPUT THE OPEN BRACKET
	HLRZ	T1,DEVPPN(F)	;GET THE PROJECT NUMBER
	PUSHJ	P,OC2EAS##	;OUTPUT THE NUMBER
	XMTI	","		;OUTPUT THE COMMA
	HRRZ	T1,DEVPPN(F)	;GET THE PROGRAMMER NUMBER
	PUSHJ	P,OC2EAS##	;OUTPUT THAT TOO
	XMTI	"]"		;CLOSE OFF THE PPN

LE2NP1:	MOVEM	P3,NPDNLN(J)	;REMEMBER THE LENGTH
	HRLM	J,DEVNPD(F)	;SAVE THE "REMOTE" NPD
	RETSKP			;GIVE A GOOD RETURN
;T.X?PN	ROUTINE CALLED BY NCSCNT TO SEND THE "?PN" PART OF A CONNECT MESSAGE
;CALL	P2, P3 := POINTERS TO CONNECT MESSAGE SO FAR
;	F := POINTER TO TASK DDB
;RETURN	CPOPJ			;ALWAYS

T.XSPN:	HRRZ	J,DEVNPD(F)	;GET NPD FOR LOCAL TASK NAME
	PJRST	T.XPN		;GO TO COMMON ROUTINE TO SEND "SPN"

T.XDPN:	HLRZ	J,DEVNPD(F)	;GET NPD FOR REMOTE TASK NAME
;	PJRST	T.XPN		;GO TO COMMON ROUTINE TO SEND "DPN"

T.XPN:				;ROUTINE TO SEND A "DPN/SPN"  J := NPD.
;?PN(OBJ)
	XMTI	OBJ.TK		;SEND THE TASK OBJECT TYPE
;?PC(PID)
	SKIPE	J		;IF NO NPD,
	SKIPN	T3,NPDNLN(J)	;  OR IF NAME IS OF LENGTH "ZERO"
	JRST	J,[XMTI 0	;  SEND A "ZERO" NAME
		   POPJ P,]	;  AND RETURN
	MOVE	T4,[POINT 7,NPDNAM(J)] ;GET A POINTER TO THE NAME
T.XPN1:	ILDB	T1,T4		;GET THE NEXT CHARACTER
	IORI	T1,200		;SET THE EXTENSIBLE BIT.
	XMT1	T1		;SEND THE CHAR
	SOJG	T3,T.XPN1	;LOOP OVER ALL CHARACTERS
	PJRST	CLRBT8##	;CLEAR THE BIT ON LAST CHAR & RETURN


;T.OK	ROUTINE CALLED WHEN A TASK CONNECTION COMPLETED.  SETS THE TASK
; AS ONLINE (CONNECTED, LAT-STATE OK)
;
T.OK:	LDB	T1,NETSLA##	;GET THE LAT ADDRESS
	MOVEI	T2,LAT.OK	;THE "OK" STATE
	DPB	T2,LATSTA##	;SET THE STATE OF THE LAT
	MOVSI	S,IOSCON
	IORB	S,DEVIOS(F)	;SET THE "WE ARE CONNECTED" BIT
	MOVE	S,[XWD IOSERR+IOEND,IODERR]
	ANDCAB	S,DEVIOS(F)	;CLEAR THESE ERROR BITS.
	PUSHJ	P,PSIONL##	;GIVE THE USER AN ON-LINE INTERRUPT
	PUSHJ	P,NTDIAV##	;SAY INPUT IS NOW AVAILABLE
	PJRST	NETWAK##	;  AND WAKE HIM IF SLEEPING OR HIBERING

;MATCH	Routine to perform a pattern match.
;Call	P1, P2 := Length, Byte pointer to the "Pattern"
;	P3, P4 := Length, Byte pointer to the "Source"
;	T4 :=	  Aobjn pointer to block of "free" storage.  This
;		  is used as a Psuedo-stack.  This routine uses no
;		  "real" stack.
;Return	CPOPJ			;Source did not match Pattern
;	CPOPJ1			;Source did match Pattern
;
;Note	Only T1, T2 and T3 are modified.   T4, and P1 - P4 are returned
;	unchanged.
;
;	The algorithm works in the obvious way.  Special "pattern"
;	characters are:
;
;	   ?	Match any next source character.
;	   *	Match zero or more next source characters.
;	   ^V	(Control "V") Treat the next "pattern" char as a normal
;		char even if it is a "?" or a "*".

MATCH:	MOVE	T3,T4		;COPY THE PSUEDO-STACK POINTER
	HLRE	T1,T3		;GET MINUS(LENGTH) OF STACK LEFT
	CAMLE	T1,[EXP -4]	;MAKE SURE WE HAVE AT LEAST 4 WORDS LEFT
	POPJ	P,		;GIVE ERROR RETURN IF NOT ENOUGH STORAGE

;BIG LOOP. ONCE PER STRING
MATCH1:	DMOVEM	P1,0(T3)	;SAVE THE PATTERN DESCRIPTORS
	DMOVEM	P3,2(T3)	;SAVE THE SOURCE DESCRIPTORS

;LOOP. ONCE PER CHARACTER
MATCH2:	SOJL	P1,[SOJL P3,MATCHS ;IF BOTH ARE NULL, RETURN SUCCESS
		    JRST MATCH3];IF SOURCE STRING TOO LONG, BACK-UP
	ILDB	T1,P2		;GET THE NEXT PATTERN CHARACTER
	CAIN	T1,"*"		;SEE IF IT'S A STAR
	JRST	MATCH4		;  IF IT'S A STAR, GO RECURSE ON REST.
	CAIN	T1,"?"		;SEE IF IT'S A WILD CHARACTER
	JRST	[SOJL P3,MATCHF	;  IF SO, COUNT ONE SOURCE CHAR (FAIL IF NONE)
		 IBP P4		;  SKIP OVER NEXT SOURCE CHAR
		 JRST MATCH2]	;  AND CONTINUE THE MATCH WITH NEXT CHAR
	CAIN	T1,"V"-100	;IS IT A ^V?
	JRST	[SOJL P1,MATCHF	;  IF IT'S A ^V, COUNT OFF ON PATTERN CHAR
		 ILDB T1,P2	;  GET THE NEXT "QUOTED" CHAR
		 JRST .+1]	;  AND CONTINUE WITH THE MATCH
	SOJL	P3,MATCHF	;COUNT OFF SOURCE CHAR. COMPLETE FAIL IF NONE.
	ILDB	T2,P4		;GET THE NEXT SOURCE CHARACTER
	XORI	T1,(T2)		;COMPARE THE CHARACTERS
	TRNN	T1,177		;  BUT ONLY LOOK AT LOW 7 BITS
	JRST	MATCH2		;IF THEY MATCH, GO COMPARE NEXT CHARS.

;BACKUP.  HERE IF CHARS DON'T MATCH

MATCH3:	CAMN	T3,T4		;ARE WE AT "LEVEL 0"
	JRST	MATCHF		;IF AT LEVEL 0 THEN THE MATCH FAILED
	DMOVE	P1,0(T3)	;GET BACK ORIGIONAL PATTERH
	DMOVE	P3,2(T3)	;GET BACK SOURCE
	SOJL	P3,MATCHF	;WE ARE PROCESSING A "*".  EAT ONE MORE SOURCE
	IBP	P4		;  CHARACTER.
	DMOVEM	P3,2(T3)	;REMEMBER THE UPDATED SOURCE
	JRST	MATCH2		;NOW TRY THE COMPARE AGAIN ON SHORTER SOURCE

;STAR. RECURSE
MATCH4:	ADD	T3,[XWD 4,4]	;BUMP OUR "PSUEDO-STACK" POINTER
	HLRE	T1,T3		;GET THE NUMBER OF WORDS LEFT
	CAMLE	T1,[EXP -4]	;MAKE SURE THERE ARE AT LEAST 4 LEFT.
	JRST	MATCHF		;IF NO "STACK", RETURN FAILURE
	JRST	MATCH1		;GO "RECURSE"


MATCHS:	AOS	(P)		;IF WE SUCCEED, GIVE SKIP RETURN
MATCHF:	DMOVE	P1,0(T4)	;LOAD ORIGIONAL P1 & P2
	DMOVE	P3,2(T4)	;  OLD P3 & P4
	POPJ	P,		;RETURN
SUBTTL 4.0      TSKSER IMPURE STORAGE.
	$LOW

TKMTCH:	EXP	0		;THIS TEMP CONTAINS THE "PATTERN" MATCH
				;  TEMPORARY PSUEDO-STACK.



	XLIST			;DON'T LIST LITERALS
	$LIT
	LIST
TSKEND::END