Google
 

Trailing-Edge - PDP-10 Archives - BB-4170G-SM - sources/nspsrv.mac
There are 31 other files named nspsrv.mac in the archive. Click here to see a list.
;<3A.MONITOR>NSPSRV.MAC.65, 22-Aug-78 18:08:01, EDIT BY OPERATOR
;FIX NTMVOP TO CHECK FOR NEG COUNT
;<3A.MONITOR>NSPSRV.MAC.64, 22-Aug-78 10:48:51, EDIT BY MILLER
;CHECK FOR BAD OPTDATA FIELD IN CC MESSAGE
;<3A.MONITOR>NSPSRV.MAC.63, 18-Aug-78 09:18:45, EDIT BY MILLER
;FIX TYPEO
;<3A.MONITOR>NSPSRV.MAC.62, 18-Aug-78 09:06:55, EDIT BY MILLER
;FIX SKPFLD TO PASS NUMBER TO GTASCI
;<3A.MONITOR>NSPSRV.MAC.61, 18-Aug-78 08:43:26, EDIT BY MILLER
;MAKE GTASCI AND GTBNRY CHECK LIMITS OF STRINGS
;<3A.MONITOR>NSPSRV.MAC.60, 21-Jul-78 11:15:49, EDIT BY HALL
;CHANGE LLNAM TO LLFNM IN DCNOPN
;<3A.MONITOR>NSPSRV.MAC.59, 26-Jun-78 09:45:19, Edit by KIRSCHEN
;TEST CORRECT AC AT SQISN2 WHEN CHECKING NEED FOR LS MSG
;<3A.MONITOR>NSPSRV.MAC.58, 22-Jun-78 09:12:06, Edit by KIRSCHEN
;DEFER SENDING VERIFICATION MSG UNTIL LINE DEFINITELY UP
;<3A.MONITOR>NSPSRV.MAC.57, 21-Jun-78 17:11:57, EDIT BY MILLER
;GET LARGER BLOCK FOR TASK NAME AT GETTSK
;<3A.MONITOR>NSPSRV.MAC.56,  7-Jun-78 07:59:40, EDIT BY MILLER
;MAKE NSPTSK STAY IN BALSET FOR A LONG TIME
;<3A.MONITOR>NSPSRV.MAC.55, 26-May-78 16:31:55, EDIT BY MILLER
;MORE FIXES TO MTOPR CLOSE FUNCTION
;<3A.MONITOR>NSPSRV.MAC.54, 26-May-78 15:43:20, EDIT BY MILLER
;FIX UP NTMTCZ TO WAIT FOR ACKS
;<3A.MONITOR>NSPSRV.MAC.53, 23-May-78 17:16:04, Edit by MCCLURE
; Add port number to NSPRTH
;<3A.MONITOR>NSPSRV.MAC.52, 22-May-78 08:09:38, EDIT BY MILLER
;ALWAYS REQUEST POSTING OF "NUMBERED SEGMENTS" FROM DEVICE DRIVER.
; DON'T "FLUSH" SEGEMENT STILL AWAITING POSTING
;<3A.MONITOR>NSPSRV.MAC.51, 19-May-78 14:03:01, EDIT BY OPERATOR
;FIX STRMSG NOT TO USE ACVAR
;<3A.MONITOR>NSPSRV.MAC.50, 18-May-78 09:47:30, Edit by MCCLURE
;<3A.MONITOR>NSPSRV.MAC.49, 28-Apr-78 15:31:31, EDIT BY MILLER
;CHECK FOR DATA IN FILE SYSTEM BUFFER AT CHKRAW
;<3A.MONITOR>NSPSRV.MAC.48, 28-Apr-78 12:21:04, Edit by MCCLURE
; ADD ERROR CODES IN NDSLP
;<3A.MONITOR>NSPSRV.MAC.47, 26-Apr-78 09:54:42, EDIT BY MILLER
;CHANGE .DCX40 TO .DCX39 IN DEDMCB
;<3A.MONITOR>NSPSRV.MAC.46, 20-Apr-78 12:00:32, Edit by KIRSCHEN
;<3A.MONITOR>NSPSRV.MAC.45, 16-Apr-78 14:42:57, EDIT BY MILLER
;ADD GJFX50 ERROR RETURNS FOR BAD ATTRIBUTE ARGS
;<3A.MONITOR>NSPSRV.MAC.44, 13-Apr-78 16:28:52, EDIT BY MILLER
;ADD DECR LLDMT IF VERSEG FAILS
;<3A.MONITOR>NSPSRV.MAC.43, 10-Apr-78 14:46:05, EDIT BY MILLER
;CLEAR LINK WORD AT LSINT1
;<3A.MONITOR>NSPSRV.MAC.42,  5-Apr-78 12:28:26, EDIT BY MILLER
;FIX ANOTHER TYPEO IN NTRCOB
;<3A.MONITOR>NSPSRV.MAC.41,  5-Apr-78 12:02:37, EDIT BY KIRSCHEN
;FIX NTRCOB TO USE PROPER FIEDL
;<3A.MONITOR>NSPSRV.MAC.40,  5-Apr-78 08:15:24, Edit by KIRSCHEN
;CHANGE FAL TO BE OBJECT 21
;<3A.MONITOR>NSPSRV.MAC.39,  4-Apr-78 16:06:36, EDIT BY MILLER
;MORE FIXES TO NTMVOP
;<3A.MONITOR>NSPSRV.MAC.38,  4-Apr-78 12:19:47, Edit by KIRSCHEN
;<3A.MONITOR>NSPSRV.MAC.37,  4-Apr-78 10:19:10, Edit by KIRSCHEN
;<3A.MONITOR>NSPSRV.MAC.36,  4-Apr-78 09:42:31, Edit by KIRSCHEN
;<3A.MONITOR>NSPSRV.MAC.35,  3-Apr-78 14:35:32, Edit by KIRSCHEN
;<3A.MONITOR>NSPSRV.MAC.34,  3-Apr-78 12:47:04, EDIT BY MILLER
;CHANGE RETBAD TO "JRST SQOBAD"
;<3A.MONITOR>NSPSRV.MAC.33,  3-Apr-78 12:42:57, EDIT BY MILLER
;CHECK FOR OPTDATA LENGTH IN NTMVOP
;<3A.MONITOR>NSPSRV.MAC.32, 30-Mar-78 11:48:09, EDIT BY MILLER
;ALLOW DEST OBJECT TYPE OF TWO. IF SO, IGNORE GROUP,USER
;<3A.MONITOR>NSPSRV.MAC.31, 15-Mar-78 13:50:16, Edit by MCCLURE
; ADD LOOPBACK SUPPORT FOR KS10
;<3A.MONITOR>NSPSRV.MAC.30, 13-Mar-78 09:24:52, EDIT BY MILLER
;FIX UP VERSION NUMBERS IN NODE INIT MESSAGE
;<3A.MONITOR>NSPSRV.MAC.29,  1-Mar-78 14:31:06, EDIT BY MILLER
;CHANGE RANGE CHECK ON NODE NUMBER IN NODE JSYS
;<3A.MONITOR>NSPSRV.MAC.28, 24-Feb-78 09:40:23, EDIT BY MILLER
;FIX SETTING OF NODE NUMBER IN NSPINI
;<3A.MONITOR>NSPSRV.MAC.27, 24-Feb-78 08:58:48, EDIT BY MILLER
;ADD EXTNS
;<3A.MONITOR>NSPSRV.MAC.26, 24-Feb-78 08:56:48, EDIT BY MILLER
;DEFINE OURNUM. DEFINE NODE FUNCITON TO SET AND READ IT
;<3A.MONITOR>NSPSRV.MAC.25, 13-Feb-78 12:42:37, Edit by MCCLURE
;DON'T SET OURCNT IF DON'T SET OURNAM AT NSPINI
;<3.SM10-RELEASE-3>NSPSRV.MAC.24, 12-Jan-78 15:31:08, EDIT BY KIRSCHEN
;CLEAN UP FILBFI ON OPEN FAILURE
;<3.SM10-RELEASE-3>NSPSRV.MAC.23,  8-Jan-78 13:14:02, EDIT BY MILLER
;SET UP FOR INPUT AT NTMTOP
;<3.SM10-RELEASE-3>NSPSRV.MAC.22,  3-Jan-78 13:15:52, EDIT BY MILLER
;<3.SM10-RELEASE-3>NSPSRV.MAC.21, 30-Dec-77 16:45:21, EDIT BY MILLER
;FIX CREATION OF ACCESS FIELDS
;<3.SM10-RELEASE-3>NSPSRV.MAC.20, 23-Dec-77 01:46:06, EDIT BY MCCLURE
;DON'T SET OURNAM IF SETSPD ALREADY SET IT
;<3-MONITOR>NSPSRV.MAC.207, 10-Nov-77 16:00:27, EDIT BY HURLEY
;BE SURE TO DECREMENT DCCUR WHENEVER NECESSARY
;<3-MONITOR>NSPSRV.MAC.206, 10-Nov-77 15:27:10, EDIT BY HALL
;EDIT BY MILLER- FIX FAILURE CASE IN NTRCN
;<3-MONITOR>NSPSRV.MAC.205,  9-Nov-77 12:03:55, EDIT BY MILLER
;CHANGE "NCU" OBJECT TO BE # 23
;<3-MONITOR>NSPSRV.MAC.204,  9-Nov-77 09:55:31, EDIT BY KIRSCHEN
;MORE COPYRIGHT UPDATING...
;<3.SM10-RELEASE-3>NSPSRV.MAC.18, 14-Dec-77 13:08:07, EDIT BY MILLER
;FIX NCU'S NUMBER
;<3.SM10-RELEASE-3>NSPSRV.MAC.17, 14-Dec-77 11:43:47, EDIT BY MILLER
;REPLACE ALL .DCX11 CODES WITH .DCX9
;<3.SM10-RELEASE-3>NSPSRV.MAC.16, 13-Dec-77 18:34:00, EDIT BY MILLER
;FIX TYPEO IN LAST EDIT
;<3.SM10-RELEASE-3>NSPSRV.MAC.15, 13-Dec-77 18:31:11, EDIT BY MILLER
;FIX DEDMCB TO CLOSE "ALL" LINKS
;<3.SM10-RELEASE-3>NSPSRV.MAC.14,  9-Dec-77 12:03:06, EDIT BY MILLER
;IMPROVE SEARCH CODE IN DCNOPN
;<3.SM10-RELEASE-3>NSPSRV.MAC.13,  8-Dec-77 12:52:31, EDIT BY MILLER
;USE OURCNT IN DCNOPN
;<3.SM10-RELEASE-3>NSPSRV.MAC.12,  8-Dec-77 09:39:56, EDIT BY MILLER
;ADD PROPER EXTN'S
;<3.SM10-RELEASE-3>NSPSRV.MAC.11,  8-Dec-77 09:34:46, EDIT BY MILLER
;SET UP "OURCNT" WHEN "OURNAM" IS DEFINED
;<3.SM10-RELEASE-3>NSPSRV.MAC.10,  8-Dec-77 09:04:40, EDIT BY MILLER
;SAVE COUNTS OF NODE NAMES IN MCBDTE
;<3.SM10-RELEASE-3>NSPSRV.MAC.9,  7-Dec-77 16:47:35, EDIT BY MILLER
;<3.SM10-RELEASE-3>NSPSRV.MAC.8,  7-Dec-77 16:23:34, EDIT BY MILLER
;BUG FIXES
;<3.SM10-RELEASE-3>NSPSRV.MAC.7,  7-Dec-77 14:22:06, EDIT BY MILLER
;MORE FIXES TO STRMSG
;<3.SM10-RELEASE-3>NSPSRV.MAC.6,  7-Dec-77 13:40:04, EDIT BY MILLER
;MAKE NSPMAX AN ARRAY AND FIX UP STRMSG CODE
;<3.SM10-RELEASE-3>NSPSRV.MAC.5,  6-Dec-77 21:53:21, EDIT BY MCCLURE
;<3.SM10-RELEASE-3>NSPSRV.MAC.4,  1-Dec-77 12:48:22, EDIT BY MILLER
;FIX NTRJCT TO SEND OPT DATA IF DESIRED.
;<3.SM10-RELEASE-3>NSPSRV.MAC.3, 30-Nov-77 14:46:39, EDIT BY MILLER
;TELL DRIVER IF SEGEMENT HAS BEEN SENT BEFORE
;<3.SM10-RELEASE-3>NSPSRV.MAC.2,  1-Nov-77 00:52:39, Edit by MCLEAN
;SEARCH PROKL
;<3-MONITOR>NSPSRV.MAC.203, 12-Oct-77 14:02:41, EDIT BY KIRSCHEN
;UPDATE COPYRIGHT FOR RELEASE 3
;<3-MONITOR>NSPSRV.MAC.202,  8-Oct-77 10:37:15, EDIT BY MILLER
;FIX UP CLOSE CODE WHEN SNDDI FAILS
;<3-MONITOR>NSPSRV.MAC.201,  5-Oct-77 10:14:16, EDIT BY MILLER
;CHANGE ALL USES OF .DCX21 TO .DCX41
;<3-MONITOR>NSPSRV.MAC.200, 30-Sep-77 09:06:09, EDIT BY MILLER
;CHANGE OBJECT # OF NCU TO 17
;<3-MONITOR>NSPSRV.MAC.199, 23-Sep-77 08:28:53, EDIT BY MILLER
;WAKE UP PROCESS WHEN LS MESSAGE IS RECEIVED
;<3-MONITOR>NSPSRV.MAC.198, 21-Sep-77 16:04:25, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.197, 21-Sep-77 08:48:51, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.196, 20-Sep-77 14:24:47, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.195, 20-Sep-77 11:21:41, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.194, 20-Sep-77 11:13:23, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.193, 12-Sep-77 14:35:10, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.192,  9-Sep-77 15:10:34, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.191,  8-Sep-77 13:30:41, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.190,  7-Sep-77 16:38:44, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.189,  6-Sep-77 17:33:38, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.188,  6-Sep-77 17:05:24, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.187, 31-Aug-77 17:39:22, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.186, 31-Aug-77 12:39:22, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.185, 29-Aug-77 09:32:59, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.184, 29-Aug-77 09:30:14, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.183, 29-Aug-77 08:32:04, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.182, 27-Aug-77 10:57:12, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.181, 24-Aug-77 16:25:02, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.180, 24-Aug-77 15:26:36, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.179, 24-Aug-77 08:32:04, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.178, 19-Aug-77 12:01:06, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.177, 18-Aug-77 17:13:08, EDIT BY MILLER
;FIX SNDDI FOR OPTDATA
;<3-MONITOR>NSPSRV.MAC.176, 18-Aug-77 16:52:23, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.175, 18-Aug-77 10:33:01, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.174, 17-Aug-77 13:53:26, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.173, 17-Aug-77 11:49:24, EDIT BY MILLER
;<3-MONITOR>NSPSRV.MAC.172, 17-Aug-77 11:17:06, EDIT BY MILLER


;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 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

	SEARCH PROLOG,PROKL
	TTITLE NSPSRV
	EXTN <BLKASG,ITSID,ITSNAM,ITSNUM,LASTSK,LLBIT,LLBITS>
	EXTN <LLHEAD,LLLLCK,MAXBLK,MAXEXP,MAXLNK,MCBDTE,MSGQ>
	EXTN <NAKCNT,NODNUM,NSPLPB,NSPMAX,OBJMAX,OBJTBL,OURCNT>
	EXTN <OURNAM,OURNUM,RMSGQ,SMSGQ>

;THIS MODULE CONTAINS THE CONTROL ROUTINES AND JSYS INTERFACES
;FOR THE HOST-TO-HOST PROTOCOL OF DECNET KNOWN AS NSP.
;NSP ALLOWS COMMUNICATION BETWEEN PROCESSES ON HOSTS BY MEANS
;OF LOGICAL LINKS. A LOGICAL LINK IMPLIES AN "OBJECT" ON ONE
;OF THE HOSTS AND A PROCESS ON ANOTHER HOST WISHING TO AVAIL ITSELF
;OF THE OBJECT'S SERVICES, A PHYSICAL COMMUNICATIONS PATH BETWEEN
;THE HOSTS WHICH IS ERROR-FREE( SEE DDCMP SPECIFICATION FOR THE
;MAGIC BEHIND THIS ASSUMPTION), AND A TON OF LOGIC IN EACH OF
;THE HOSTS AND IN THE INTERVENING MCB NODES (IF ANY) WHICH ROUTE
;AND CONTROL THE FLOW OF THE DATA. THIS MODULE IS RESPONSIBLE
;FOR COMMUNICATING WITH ADJACENT MCB NODES AND FOR MAINTAINING AND
;ESTABLISHING LOGICAL LINKS ON DEMAND OF PROCESSES IN THIS TOPS20
;HOST OR OF PROCESSES IN THE NETWORK.

;A PROCESS OWNS ONE END OF A LOGICAL LINK BY VIRTUE OF ITS HAVING
;A JFN ON THE LINK. THIS JFN IS THE PROCESS' TOOL FOR SENDING
;DATA TO ITS COMPANION PROCESS ON THE OTHER SIDE OF THE LINK OR
;FOR RECEIVING DATA SENT TO IT. THE FOLLOWING JFN FIELDS ARE RELEVANT
;TO NETWORK CONNECTIONS ONLY:

;FILLLB CONTAINS THE ADDRESS OF THE LOGICAL LINK ENTRY
;FILBFO CONTAINS A BYTE POINTER FOR THE CURRENT OUTPUT BUFFER
; LH OF FILBCT CONTAINS COUNT OF BYTES REMAINING IN OUTPUT BUFFER
;FILBFI CONTAINS BYTE POINTER TO CURRENT INPUT BUFFER
; RH OF FILBCT CONTAINS COUNT ON INPUT BYTES REMAINING
; RH OF FILWND CONTAINS WINDOW PAGE ADDRESS FOR INPUT
; LH OF FILWND CONTAINS WINDOW PAGE ADDRESS FOR OUTPUT

; THE FIELDS: FILCNT, FILBYN, FILLEN, AND FILBYT ARE SET UP
; BY NSPSRV FOR THE PROPER DIRECTION OF I/O. THAT IS, WHEN
; THE PROCESS WANTS TO DO OUTPUT, THESE LOCATIONS ARE SET UP
; TO THE VALUES RELEVANT FOR OUTPUT; AND WHEN THE PROCESS
; WANT TO DO INPUT, THESE VALUES ARE SET UP FOR INPUT.


;THIS MODULE CONTROLS, ALLOCATES, AND DEALLOCATES ENTRIES
;IN THE LOGICAL LINK TABLE. AN ENTRY  IN THE LOGICAL LINK TABLE
;CONTAINS INFORMATION NEEDED BY NSPSRV TO PROPERLY MANAGE
;THE LINK. THE INFORMTION IS FALLS INTO ONE OF TWO CLASSES:
;LOGICAL PARAMETERS AND PROCESS PARAMETERS. AMONG THE LOGICAL
;LINK PARAMETERS ARE: CURRENT LINK STATE, BUFFER COUNTS, FLOW
;CONTROL OPTIONS, AND SEGEMENT NUMBERS. AMONG THE PROCESS
;PARAMETERS ARE: PI CHANNELS FOR VARIOUS EVENTS, OWNING FORK,
;WINDOW PAGE BYTE COUNTS

;THE LINK TABLE IS STORED AS A BINARY TREE. ENTRIES ARE LINKED IN
;THE TREE IN ORDER BY LINK NUMBER, AND THE SEARCH ALGORTIHM INSURES
;THAT A LINK CAN BE LOCATED IN LOG(2) OF THE NUMBER OF ENTRIES.

;WITHIN THE LOGICAL LINK TABLE ARE ENTRIES WHICH REPRESENT
;"LISTENING" OBJECTS. THESE ARE PROCESSES WHICH HAVE DECLARED THEIR
;INTEREST IN PARTICIPATING IN A DIALOGUE, BUT NO NETWORK ENTITY HAS
;ATTEMPTED AS YET TO CONNECT TO THE OBJECT. UPON RECEIPT OF A
;CONNECT-INITIATE, THE LOGICAL LINK TABLE IS SEARCHED FOR A LISTENING
;OBJECT WHICH COORESPONDS TO THE REQUIREMENTS OF THE CONNECTOR. THIS
;SEARCH IS,UNFORTUNATELY, EXHAUSTIVE AND MAY REQUIRE A CONSIDERABLE
;AMOUNT OF TIME.

;MESSAGES ARE STORED IN MONITOR RESIDENT FREE SPACE. EACH MESSAGE
;HAS A HEADER ON IT OF THE FORM:

;	POINTER TO NEXT MESSAGE IN THE CHAIN
;	DTE#, FLAGS, SEG #, LOGICAL LINK ADDRESS OF OWNING LINK
;	MESSAGE FLAGS, # OF DATA BYTES, TOTAL # OF BYTES
;	BYTE POINTER TO DATA BYTES (EXCLUDES NSP HEADER)

;THIS MODULE ALSO CONTAINS ROUTINES FOR PARSING AND VERIFYING NETWORK
;FILE SPECS. A FILE SPEC IS OF THE FORM:
;DCN:HOST-OBJECT-DESCRIPTOR.TASKNAME;ATTRIBUTES
; TO MAKE A CONNECTION, OR:
;SRV:OBJECT-DESCRIPTOR.TASKNAME
; TO DECLARE A SERVER
;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)
;DEFINE DATA BASES

;FIELD DEFINITIONS FOR LINK TABLE


LKSIZE==22			;SIZE OF A STANDARD ENTRY
LKOBJS==6			;EXTRA ENTRIES NEEDED FOR OBJECT

DEFSTR (LLUPL,0,35,36)		;UP POINTER
DEFSTR (LLDWN,1,35,36)		;DOWN POINTER
DEFSTR (LLLOK,2,0,1)		;BLOCK LOCK
DEFSTR (LLSTA,2,5,5)		;STATE OF THIS LINK
	LLSTRN==0		;LINK IN TRANSITION. NON-EXISTANT
	LLSLIS==1		;OBJECT IS LISTENING
	LLSCIS==2		;CONNECT-INITIATE SENT
	LLSCIR==3		;CONNECT-INITIATE RECEIVED
	LLSRUN==4		;LINK IS ACTIVE.
	LLSDIS==5		;DI SENT
	LLSDIQ==6		;DI IS QUEUED
	LLSDIR==7		;DI RECIEVED
	LLSABT==10		;CONNECTION ABORTED/REFUSED BY LOCAL NSP
;DEFSTR (LLFLG,2,17,12)		;LINK FLAGS
DEFSTR (LLFOB,2,17,1)		;THIS IS AN OBJECT
DEFSTR (LLFEM,2,16,1)		;EOM
DEFSTR (LLFII,2,15,1)		;INPUT INTERRUPT NEEDED
DEFSTR (LLFDI,2,14,1)		;DI WAS AN ABORT
DEFSTR (LLTRN,2,13,1)		;NEED INTIAL LS MESSAGE
DEFSTR (LLFIM,2,12,1)		;EOM IN INPUT BUFFER
DEFSTR (LLFNA,2,11,1)		;IF SET, BLOCK WAITING FOR ACK TO GO
DEFSTR (LLOPW,2,10,1)		;LINK IS OPEN FOR WRITE
DEFSTR (LLOPI,2,9,1)		;LINK IS OPEN FOR READ
DEFSTR (LLFNN,2,8,1)		;IF ON, DATA MESSAGE WAS THROWN AWAY
DEFSTR (LLSDE,2,7,1)		;IF ON, LL BLOCK DISASSOCIATED FROM PROCESS
DEFSTR (LLLWC,2,6,1)		;LINK WAS CONNECTED (I.E. CC RECEIVED)
DEFSTR (LLLNK,2,35,18)		;LINK I.D. OF THIS LINK
DEFSTR (LLFRK,3,17,18)		;OWNING FORK
DEFSTR (LLDRC,3,23,6)		;PI FOR DATA RECEIVED
DEFSTR (LLPII,3,29,6)		;PI CHANNEL FOR INTERRUPT MESSAGES
DEFSTR (LLPIC,3,35,6)		;PI FOR CONNECT-INITITATE
DEFSTR (LLIIN,4,11,12)		;SEGMENT NUMBER FOR INCOMING LS/INT
DEFSTR (LLFNM,4,19,8)		;REMOTE OBJECT NUMBER
DEFSTR (LLHLK,4,35,16)		;LINK I.D. ON FOREIGN HOST
LLMSG==5			;POINTER TO CHAIN OF RAW MESSAGES
LLMSI==6			;POINTER TO INTERRUPT MESSAGE
DEFSTR (LLBRP,7,0,1)		;BACK-PRESSURE BIT FOR TRANSMIT
DEFSTR (LLBRL,7,1,1)		;BACK-PRESSURE FOR RECEIVE
DEFSTR (LLMFC,7,3,2)		;0=NO FLOW CONTROL
				;1=SEGMENT FLOW CONTROL
				;2=MESSAGE FLOW CONTROL
DEFSTR (LLSWG,7,19,16)		;MAX SEGMENT SIZE FOR MESSAGE
DEFSTR (LLMSM,7,27,8)		;MAX SEGMENTS THIS LINK CAN HAVE
DEFSTR (LLQUN,7,31,4)		;# SEGS IN QUEUER TO RESEND
DEFSTR (LLQOU,7,35,4)		;# OF SEGS IN QUEUER
DEFSTR (LLBOM,10,0,1)		;AT BEGINNING OF MESSAGE
DEFSTR (LLPRT,10,2,2)		;DTE # FOR THIS CONNECTION
DEFSTR (LLFLI,10,3,1)		;INPUT DIRECTION
DEFSTR (LLFLO,10,4,1)		;OUTPUT DIRECTION
DEFSTR (LLIMS,10,5,1)		;INPUT IS MESSAGE-TYPE
DEFSTR (LLOPT,10,35,30)		;OPTIONAL DATA STORAGE
DEFSTR (LLDSN,11,11,12)		;SEG # FOR NEXT DATA TRANSMIT
DEFSTR (LLISN,11,23,12)		;SEG # FOR NEXT LS/INT TRANSMIT
DEFSTR (LLIDN,11,35,12)		;SEG # FOR NEXT DATA RECEIVE
LLOMSG==12			;ORDERED DATA QUEUE
DEFSTR (LLUCT,13,5,6)		;# OF BYTES IN OPTDATA FIELD
DEFSTR (LLTSK,13,35,30)		;POINTER TO TASK NAME
DEFSTR (LLHST,14,35,36)		;POINTER TO REMOTE HOST NAME
DEFSTR (LLMIC,15,5,6)		;COUNT OF INT SEGMENTS ALLOWED TO SEND
DEFSTR (LLFDS,15,35,30)		;REMOTE DESCRIPTOR BLOCK
LLBPTR==16			;WORK CELL CONTAINING BYTE POINTER
LLBPCT==17			;CURRENT BYTE COUNT
DEFSTR (LLBSZ,20,5,6)		;BYTE SIZE OF OPENING
DEFSTR (LLDRW,20,9,4)		;COUNT OF RAW DATA MESSAGES
DEFSTR (LLDMT,20,14,5)		;COUNT OF TOTAL DATA MESSAGES ON QUEUES
DEFSTR (LLLSA,20,15,1)		;SPECIAL FLAG USED TO CONTROL DATA INTS
				; FROM SCHED WHILE DOING LS MESSAGES
DEFSTR (LLLSC,20,19,4)		;COUNT OF LS BUFFERS TO REQUEST
DEFSTR (LLRSN,20,35,16)		;DISCONNECT REASON
LLSEGQ==21			;HEADER FOR SENT QUEUE

;DEFINITIONS FOR OBJECT PART OF TABLE

DEFSTR (LLSOB,LKSIZE,35,18)	;OBJECT USED IN CI BY REMOTE
DEFSTR (LLNAM,LKSIZE,17,18)	;NUMBER OF THIS OBJECT
DEFSTR (LLDSC,LKSIZE+1,35,36)	;POINTER TO DESCRIPTOR BLOCK
DEFSTR (LLUSR,LKSIZE+2,35,36)	;POINTER TO USER NAME BLOCK
DEFSTR (LLACT,LKSIZE+3,35,36)	;POINTER TO ACCOUTN STRING BLOCK
DEFSTR (LLPCT,LKSIZE+4,5,6)	;COUNT OF BYTES IN PASSWORD
DEFSTR (LLPSW,LKSIZE+4,35,30)	;POINTER TO PASSWORD BLOCK
LLUSGP==LKSIZE+5		;SAVE USER,GROUP FROM CI
;MORE DEFINITIONS

;DEFINITIONS FOR OUTGOING MESSAGES

MSHDR==4			;SIZE OF MESSAGE HEADER
DEFSTR (MSRLS,0,0,1)		;IF POSTER SHOULD RELEASE MESSAGE
DEFSTR (MSPST,0,1,1)		;IF MESSAGE NEEDS POSTING
DEFSTR (MSLNK,0,35,18)		;LINK WORD
DEFSTR (MSPRT,1,2,2)		;DTE # OR ALL ONES FOR LOCAL CONNECITON
DEFSTR (MSLCL,1,3,1)		;IF A LOCAL DATA MESSAGE
DEFSTR (MSNAK,1,4,1)		;MESSAGE HAS BEEN NAK'ED
DEFSTR (MSMS1,1,5,1)		;MESSAGE ALREADY SENT IF 1
DEFSTR (MSSEG,1,17,12)		;SEG # OF MESSAGE
DEFSTR (MSLLA,1,33,16)		;LL ADDRESS
DEFSTR (MSTOM,1,35,2)		;TYPE OF THIS MESSAGE
	MSCTL==0		;CONTROL MESSAGE
	MSLSI==1		;LS/INT MESSAGE
	MSDAT==2		;DATA MESSAGE
DEFSTR (MSCNT,2,35,12)		;# OF BYTES IN MESSAGE
DEFSTR (MSDTC,2,23,12)		;# OF BYTES EXCLUDING NSP OVERHEAD BYTES
DEFSTR (MSMFL,2,11,12)		;MESSAGE FLAGS
MSBPTR==3			;BYTE POINTER TO DATA PART OF MESSAGE

	DEFAC (STS,P1)
	DEFAC (JFN,P2)
	DEFAC (DEV,P4)
	DEFAC (F1,P5)

;DEFINITIONS FOR FILE SPECS

MAXDSC==^D16			;MAX CHARACTERS IN DESCRIPTOR
TSKMAX==^D16			;MAX CHARACTERS IN A TASK NAME
MAXHST==6			;MAX SIZE OF A HOST STRING

;GENERAL NSP PARAMETERS

NSPEXT==200			;EXTENSIBLE BIT IN FIELD DEFINITIONS
NSPLCH==53			;STANDARD LINK CHARACTERISTICS
NSPSEG==^D181			;MAXIMUM USER DATA SEGMENT
MAXSEG==5			;MAX SEGS TO RECEIVE ON RONLY LINK
MAXSG1==3			;MAX SEGS TO RECIEVE ON READ/WRITE LINK
MAXSGQ==3			;MAX SEGMENTS IN QUEUER

;MESSAGE AND ROUTING FLAGS

RTFLG==106			;ROUTING FLAGS
VERTYP==2			;VERIFICATION MESSAGE TYPE
CNMRFL==10			;BASIC CONTROL MESSAGE TYPE
 NDIFLG==5B31			;NODE INIT MESSAGE
 CNMCI==20			;CI
 CNMCF==40			;CONNECT-CONFIRM
 CNMDI==60			;DI
 CNMDC==100			;DC
CIMMFL==30			;CI MESSAGE FLAGS
DATMFL==0			;BASIC DATA MESSAGE FLAGS
 DATFLI==20			;INT/LS FLAGS
 DATINT==40			;INTERRUPT MESSAGE FLAG
 DATBOM==40			;BEGINNING OF MESSAGE SEGMENT
 DATEOM==100			;END OF MESSAGE SEGEMENT
	; ..
;MORE NSP DEFINITIONS

CISRVS==1			;CI BASIC SERVICES
 CIMCNT==10			;MESSAGE COUNTS
 CIMSCT==4			;SEGEMENT COUNTS
LNKPRI==2			;DEFAULT LINK PRIORITY
SEGSIZ==400			;MAX SEGMENT SIZE
MAXRSZ==300			;MAX SEG SIZE TO SEND IN A NODE INIT
OBJZRO==0			;OBJECT TYPE 0 (NO DESCRIPTOR)
OBJONE==1			;OBJECT TYPE 1 (WITH DESCRIPTOR)
OBJTWO==2
OBJTSK==0			;OBJECT # FOR TASK
RTHLEN==4			;# OF WORDS NEEDED FOR ROUTING HEADER
DTMLEN==2			;# OF WORDS NEEDED FOR DATA MESSAGE HEADER
CCLEN==13			;# OF WORDS NEEDED FOR CC MESSAGE
LSLEN==3			;# OF WORDS FOR LS MESSAGE
WSEGSZ==<SEGSIZ/11>*11		;SEG SIZE IF OPEN IN WORD MODE
OPTSIZ==5			;# OF WORDS FOR OPTDATA BLOCK
MAXDIF==^D30			;MAX # OF OUTSTANDING SEGEMENTS
ACKBIT==10000			;BIT TO SAY IF ACK OR NACK
ACKIND==100000			;FIELD IS ACK BIT
ACKFLM==4			;MESSAGE FLAG FOR ACK MESSAGE
 ACKLSI==20			;SUB-TYPE FOR LS/INT ACK
DILEN==^D10
CONLEN==^D27			;SIZE OF CI BLOCK
ACKLEN==6			;LENGTH OF AN ACK MESSAGE
INTLEN==6
NSPHDR==7			;# OF BYTES IN HEADER OF DATA MESSAGE

;COMM VERSION DEFINITIONS

COMVER==3			;VERSION OF NSP
COMECO==0			;ECO LEVEL
COMCST==0			;CUSTOMER LEVEL

ROUVER==0			;ROUTING VERSION
ROUECO==0			;ECO LEVEL
ROUCST==0			;CUSTOMER LEVEL
NDISIZ==7			;SIZE OF A NODE INIT MESSAGE
STRTYP==1			;INIT MESSAGE TYPE
OURCAP==0			;OUR CAPABILITIES
OURREQ==6			;REQUIRED CAPS
OURNED==6			;WE NEED THESE FROM MCB
VERIF==1			;VERIFY MESSAGE NEEDED BIT
CNTFLD==77B5			;COUNT FIELD IN ARG TO SNDDI

;TEMPORARY DEFINITIONS

FRKRUN==1B1			;FLAG IN MCBDTE TO SAY NETWORK IS INITED
INIRCV==1B0			;NODE INIT RECEIVED
NTSHUT==1B2			;IF SET, NSP IS IN "SHUTDOWN" STATE
NOTMCB==1B3			;NEIGHBOR IS NOT AN MCB
INISNT==1B4			;NODE INIT SENT
REQVER==1B5			;VERIFICATION MSG NEEDED ON THIS LINE
DEFSTR (NAMCN,,17,3)		;COUNT OF BYTES IN NODE NAME
;ROUTINE TO INIT NETWORK DATA BASES,ETC.

	SWAPCD			;SWAPPABLE
NSPINI::UNLOCK LLLLCK		;UNLOCK LOCK
	DMOVE T1,[ASCIZ /TOPS20/] ;GET OUR NAME
	SKIPE OURNAM		;DID SETSPD SET OUR NODE NAME ?
	JRST NSPIN1		;DON'T SET NAME BECAUSE SETSPD BEAT US
	DMOVEM T1,OURNAM	;NO SO DEFAULT IT
	MOVEI T1,6		;COUNT OF CHARS IN "OURNAM"
	MOVEM T1,OURCNT		;STORE IT
NSPIN1:	MOVEI T1,NODNUM		;GET DEFAULT NODE NUMBER
	SKIPN OURNUM		;NUMBER ALREADY SET?
	MOVEM T1,OURNUM		;NO. SET IT TO THE DEFAULT THEN
	CALL OBJINI		;INIT OBJECT TABLE
	CALL LLINIT		;AND INIT LL ADDRESS BIT TABLE
	MOVX T1,1B1		;MAKE FORK HAVE ALL CAPS
	SETZ T2,
	CFORK			;GET A FORK
	 BUG (HLT,NSPFRK,<NSPINI-CFORK FAILED>)
	MOVEI T2,TSKINI		;THE STARTING ADDRESS
	MSFRK			;START IT
	MOVX T2,FRKRUN		;SAY FORK IS RUNNING
	IORM T2,MCBDTE		;SET FLAG
	RET			;AND DONE
	SWAPCD			;CALLED ONLY IN PROCESS CONTEXT

;ROUTINES USED TO LOCK AND UNLOCK LL TREE

LOKLL:	NOINT			;PREVENT INTS
	LOCK LLLLCK,<CALL LCKTST> ;LOCK UP THE TREE
	RET			;DONE

ULOKLL:	UNLOCK LLLLCK		;UNLOCK THE TREE
	OKINT			;ALLOW INTS
	RET			;AND DONE

;ROUTINES TO LOCK AND UNLOCK INDIVIDUAL LL BLOCKS

;LOCK A BLOCK.
;	T1/ BLOCK ADDRESS
;RETURNS:	+1 FAILED. BLOCK ROUTINE IN T1
;		+2 SUCCESS

BLKLOK:	NOSKED			;PREVENT RACES
	JE LLLOK,(T1),[	SETONE LLLOK,(T1) ;IF NO AVAILABLE, GET IT
			NOINT	;PREVENT INTS
			OKSKED	;ALLOW SCHEDULING AGAIN
			RETSKP]	;AND DONE
	OKSKED			;NOT AVAILABLE
	LOAD T1,LLLNK,(T1)	;GET LL ADDRESS
	HRLS T1			;TO THE LH
	HRRI T1,CHKLOK		;THE TEST ROUTINE
	RET			;AND DONE

;UNLOCK A BLOCK
;	T1/ BLOCK ADDRESS
;RETURNS:	+1 ALWAYS

BLKULK:	SETZRO LLLOK,(T1)	;FREE THE LOCK
	OKINT			;AND ALLOW INTS AGAIN
	RET			;AND DONE

;ROUTINE TO INIT LL ADDRESS BIT TABLE. CALLED AT SYSTEM STARTUP

LLINIT:	ACVAR <W1>		;GET A WORK REGISTER
	MOVSI W1,-MAXLNK	; GET MAX LINK VALUE
	AOS W1			;SKIP ENTRY 0
LLINI1:	HRRZ T1,W1		;GET LINK ADDRESS
	CALL FRELNK		;FREE LINK #
	AOBJN W1,LLINI1		;DO 'EM ALL
	RET			;AND DONE
;ROUTINE TO FIND INDEX INTO LOGICAL LINK TABLES.
;ACCEPTS:	T1/ LOGICAL LINK
;		T2/ FOREIGN LINK I.D. -1 FOR ANY
;		T3/ HOST NAME STRING IF LLLKUH USED
;RETURNS:	+1 FAILED. LINK NOT FOUND
;			T1/ INSERT POINT FOR NEW ENTRY
;		+2 SUCCESS. T1/ ADDRESS OF LINK ENTRY
;			T2/ PREVIOUS NODE ADDRESS
;PRESERVES T4
;LLLKUH MUST NOT BE CALLED FROM SCHED CONTEXT.

	RESCD			;NEEDS TO BE RESIDENT
LLLKUP:	SETOM T3		;NO HOST MATCH IF ENTERED HERE
LLLKUH:	SAVEAC <T4>		;PRESERVE AC
	STKVAR <LASTM,LNKID,LLHO> ;REMEMBER INSERT POINT
	MOVEM T3,LLHO		;SAVE HOST STRING POINTER
	SETZM LASTM		;NO INSERT FOUND YET
	MOVEM T1,LNKID		;SAVE DESIRED ADDRESS
	MOVE T1,LLHEAD		;GET HEAD OF TREE
LLLKU1:	JUMPE T1,LLFAIL		;NO THERE. ERGO, NOT FOUND
	LOAD T3,LLLNK,(T1)	;GET THE LINK I.D.
	CAME T3,LNKID		;IS THIS IT?
	JRST [	MOVEM T1,LASTM	;REMEMBER THIS AS INSERT POINT
		CAMG T3,LNKID	;NEED TO GO UP OR DOWN?
		JRST [	LOAD T1,LLUPL,(T1) ;GET UP POINTER
			JRST LLLKU1] ;AND GO SEE ABOUT IT
		LOAD T1,LLDWN,(T1) ;DOWN. GET DOWN POINTER
		JRST LLLKU1]	;AND GO SEE ABOUT IT
	JUMPL T2,LLLKU2		;IF NO HOST CHECK, FOUND IT
	OPSTR <CAME T2,>,LLHLK,(T1) ;DOES THE HOST MATCH?
	RET			;NO. GIVE ERROR
LLLKU2:	MOVE T2,LASTM		;RETURN PREVIOUS NODE
	SKIPG LLHO		;WANT HOST MATCH?
	RETSKP			;NO. ALL DONE THEN
	LOAD T2,LLHST,(T1)	;GET HOST STRING
	EXCH T1,LLHO		;SAVE LINK. GET SOURCE HOST NAME
	CALL CMPSTR		;DO COMPARE
	 RET			;NO MATCH
	MOVE T1,LLHO		;A MATCH. GET LINK
	MOVE T2,LASTM		;GET PREVIOUS
	RETSKP			;AND DONE

;COULDN'T FIND REQUIRED LINK. RETURN INSERT POINT

LLFAIL:	MOVE T1,LASTM		;FOUND AN INSERT POINT?
	RET			;AND RETURN
;ALL OF THIS CODE IS UNSUITABLE FOR EXTENDED ADDRESSING. SINCE
;OBJECT NAMES CAN RESIDE IN SWAPPABLE FREE SPACE, OBJTBL
;NEEDS TO HAVE 36 BIT ADDRESSES POINTING TO THE STRINGS. ALSO,
;A REPLACEMENT FOR TBLUK IS NEEDED WHICH WILL DO LOOK UP, DELETE
;AND ADD ENTRIES TO SUCH AN "EXTENDED" TABLE. FOR THE TIME BEING,
;HOWEVER, THE CODE AS WRITTEN WILL SUFFICE.

;ROUTINE TO INITIALIZE THE OBJECT TABLE FOR THE MONITOR.

	SWAPCD
OBJINI:	MOVE T1,[OBJPRO,,OBJTBL]
	BLT T1,OBJTBL+OBJENT	;INIT THE TABLE
	RET			;AND DONE

;THIS TABLE SHOULD BE MOVED TO STG SOMEDAY*****************
;PROTOTYPE OBJECT TABLE

OBJPRO:	OBJENT,,OBJMAX
	[ASCIZ /FAL/],,21
	[ASCIZ /NCU/],,23
	[ASCIZ /TASK/],,0
OBJENT==.-OBJPRO-1		;# OF ENTRIES

;ROUTINE TO LOOK UP AN OBJECT NAME IN THE SYSTEM OBJECT TABLES
;ACCEPTS:	T1/ POINTER TO TEST OBJECT NAME
;RETURNS:	+1 NOT FOUND. NO SUCH OBJECT
;		+2 OBJECT FOUND
;			T1/ OBJECT NUMBER

OBJLOK:	ASUBR <OBJPTR>		;SAVE POINTER
	MOVE T2,T1		;COPY POINTER
	MOVE T1,[OBJTBL]	;GET THE OBJECT TABLE
	TBLUK			;LOOK UP THE OBJECT
	TXNN T2,TL%EXM		;FOUND IT?
	JRST OBJLO1		;NO. GO CHECK FOR NUMBER
	HRRZ T1,0(T1)		;YES. GET OBJECT NUMBER
	RETSKP			;AND RETURN WITH IT

;TBLUK DIDNT'T FIND IT. SEE IF IT IS NUMERIC

OBJLO1:	SETZ T1,		;GET AN ACCUMULATOR
OBJLO2:	ILDB T2,OBJPTR		;GET NEXT BYTE
	JUMPE T2,RSKP		;IF AT THE END, GOOD NUMBER
	CAIL T2,"0"		;A VALID NUMBER
	CAILE T2,"9"		;STILL?
	RET			;NO. NOT A VALID NUMBER
	IMULI T1,^D10		;YES. ADJUST ACCUMULATOR
	ADDI T1,-"0"(T2)	;AND ADD IN NEW QUANTITY
	CAILE T1,OBJMAX		;STILL VALID?
	RET			;NO. GIVE AN ERROR
	JRST OBJLO2		;GO DO ALL OF IT

;ROUTINES CALLED FROM GTJFN PROCESSING TO LOOK UP FILE NAMES

;NAME LOOKUP FOR SRC DEVICE

SRNSET:	JUMPE T1,[RETBAD (GJFX18,<OKINT>)] ;CANT'T STEP IT
	CALL [	TRVAR <NTCNT,NTPNT,NTOBJ,NTDDSC,NTDSS>
		CALL SRCNAM	;GO PARSE THE NAME
		 RETBAD()	;HAD AS ERROR
		RETSKP]		;GOOD
	 RETBAD ()		;FAILED
OKRET:	TQNE <UNLKF>		;WANT TO UNLOCK?
	JRST SK2RET		;NO. RETURN
	OKINT			;YES. GO OKINT THEN
	JRST SK2RET		;AND RETURN

;ROUTINE TO DO NAME LOOKUP FOR DCN DEVICE

DCNSET:	JUMPE T1,[RETBAD (GJFX18,<OKINT>)] ;CANT'T STEP IT
	CALL [	TRVAR <NTCNT,NTPNT,NTOBJ,NTDSC,NTDSS,NTHST,NTHSC>
		CALL DCNNAM	;GO PARSE NAME
		  RETBAD()	;SOME SORT OF ERROR
		RETSKP]		;GOOD
	 RETBAD ()		;SOME SORT OF FAILURE
	JRST OKRET		;AND DONE

;EXTENSION CHECKER

EXTSET:	JUMPE T1,[RETBAD (GJFX18,<OKINT>)] ;CANT'T STEP IT
	CALL [	TRVAR <NTCNT,NTPNT>
		CALL NETEXT	;CHECK EXTENSION
		 RETBAD()	;SOME SORT OF ERROR
		RETSKP]		;AND DONE
	 RETBAD ()		;SOME SORT OF FAILURE
	JRST OKRET		;AND DONE

;ROUTINE TO LOOK UP DIRECTORY COMPONENT IN NETWORK FILE SPEC

NETDIR:	TQNE <STEPF>		;WANT TO STEP?
	RETBAD (GJFX17)		;YES. CAN'T DO IT
	NOINT			;PREVENT INTS
	JRST SK2RET		;AND SAY IT IS SET

;VERSION LOOKUP

VERSET:	TQNN <STEPF>		;TRYING TO STEP?
	JRST OKRET		;NO. ALLOW IT THEN
	JUMPGE T1,OKRET		;IF NOT STEPPING, OKAY
	RETBAD (GJFX18,<OKINT>)	;ALL ELSE IS WRONG
;ROUTINE TO FIND A "LISTENING" OR ACTIVE OBJECT IN THE LOGICAL
;LINK TABLE. WILL ALSO DO SCAN OF ENTIRE TREE
;ACCEPTS:
;	T1/ COUROUTINE ADDRESS TO CALL WHEN OBJECT IS FOUND
;	T2/ 0 IF OBJECT MAY BE LISTENING IR ACTIVE
;		1 IF OBJECT MUST BE LISTENING ONLY
;		-1 IF ANY LINK IS ACCEPTBLE
;RETURNS:
;	+1 OBJECT NOT FOUND
;	+2 OBJECT FOUND. 
;		T1/ POINTER INTO LINK TABLE FOR THIS OBJECT
;		T2/ LINK I.D. OF THE OBJECT

;THE COROUTINE IS CALLED TO CHECK IF THE OBJECT IS THE ONE
;WANTED. THE COROUTINES ARE CALLED WITH THE FOLLOWING ARGS:
;	T1/ ADDRESS OF LOGICAL LINK ENTRY
;	ALL OF THE P AND Q REGISTERS INTACT
;THE COROUTINES RETURN AS FOLLOWS:
;	+1 DON'T WANT THIS OBJECT
;	+2 THIS IS THE ONE
;THE COROUTINE MUST PRESERVE ALL TEMPORARY AC'S

OBJSRC:	DMOVE T3,T1		;SAVE ARGS
	SKIPN T1,LLHEAD		;ANY LINKS?
	RET			;NO. CAN'T FIND IT THEN
	PUSH P,[0]		;PUT A "FENCE" ON THE STACK
OBJSND:	PUSH P,T1		;SAVE THIS ONE
	JUMPL T4,OBJSN2		;IF ANY MATCH, GO HANDLE THIS ONE
	JE LLFOB,(T1),OBJSNO	;IF NOT OBJECT, CAN'T BE A MATCH
	JUMPN T4,[LOAD T2,LLSTA,(T1) ;IF MUST BE LISTENING, GET STATE
		CAIE T2,LLSLIS	;IS IT LISTENING?
		JRST OBJSNO	;NO. NOT INTERESTED THEN
		JRST .+1]	;YES
OBJSN2:	JUMPE T3,OBJSFD		;IF NO COROUTINE, DONE
	CALL 0(T3)		;CALL THE COROUTINE
	SKIPA			;NOT THE ONE
	JRST OBJSFD		;FOUND IT
OBJSNO:	LOAD T1,LLUPL,(T1)	;NOT THE ONE. GET THE UP POINTER
	JUMPN T1,OBJSND		;HAVE ONE. GO LOOK AT IT
OBJSN1:	POP P,T1		;NOT FOUND. GET PREVIOUS ONE
	JUMPE T1,R		;IF BACK TO FENCE, NO SUCH OBJECT
	LOAD T1,LLDWN,(T1)	;GET DOWN SIDE
	JUMPN T1,OBJSND		;IF HAVE ONE, GO LOOK AT IT
	JRST OBJSN1		;IF NOT, KEEP POPING

;FOUND THE OBJECT

OBJSFD:	POP P,T2		;MUST CLEAN UP THE STACK
	JUMPN T2,.-1		;KEEP CLEANING
	LOAD T2,LLLNK,(T1)	;GET LOGICAL LINK I.D.
	RETSKP			;DONE. RETURN GOOD
;ROUTINE TO GET A UNIQUE TASK NAME.
;ACCEPTS:	T1/ LL POINTER
;		LL TREE MUST BE LOCKED
;RETURNS:	+1 ALWAYS
;		LLTSK FILLED IN WITH NAME
;PRESERVES T1

GETTSK:	TRVAR <LLADDR,TSKBLK>
	MOVEM T1,LLADDR		;SAVE LL BLOCK ADDRESS
	MOVEI T1,3		;NEED A BLOCK OF THIS SIZE
	CALL GETBLK		;GO GET A BLOCK
	 RET			;NO MORE SPACE
	MOVEM T1,TSKBLK		;SAVE ADDRESS
GETTS1:	HRLI T1,(<POINT 7,>)	;MAKE A BYTE POINTER
	AOS T2,LASTSK		;GET A NUMBER FOR THE TASK NAME
	MOVEI T3,10		;CONVERT OCTAL
	NOUT			;MOVE NUMBER
	 JFCL			;WILL WORK
	XMOVEI T1,TSKLOK	;MAKE SURE IS UNIQUE
	SETOM T2		;ANY LINK
	CALL OBJSRC		;GO LOOK FOR A MATCH
	 JRST [	MOVE T1,LLADDR
		MOVE T2,TSKBLK	;GET BLOCK ADDRESS
		STOR T2,LLTSK,(T1)
		RETSKP]		;AND DONE
	MOVE T1,TSKBLK		;FOUND IT
	JRST GETTS1		;TRY AGAIN

;COROUTINE TO CHECK FOR TASK MATCH

TSKLOK:	SAVET			;SAVE ALL TEMPS
TSKLO1:	LOAD T2,LLTSK,(T1)	;GET THIS ONE'S ADDRESS
	JUMPE T2,R		;IF NONE, CAN'T BE IT
	MOVE T1,TSKBLK		;GET BLOCK ADDRESS
	CALLRET CMPSTR		;GO DO THE COMPARE
;COLLECTION OF UTILITIES

;COMPARE TWO STRING STORED IN EXTENDED BLOCKS
;ACCEPTS:	T1/ BLOCK 1
;		T2/ BLOCK 2
;		T3/ COUNT
;RETURNS:	+1 NO MATCH
;		+2 MATCH

CMPSTR:	MOVSI T3,1		;GET HUGE COUNT
CMPST1:	ACVAR <W1,W2,W3>	;GET SOME REGS
	MOVE W3,T3		;SAV COUNT
	SKIPN T1		;HAVE A POINTER HERE?
	MOVEI T1,[0]		;NO. INVENT A NULL STRING THEN
	SKIPN T2		;HAVE A POINTER HERE?
	MOVEI T2,[0]		;NO. INVENT ONE HERE TOO
	MOVE W1,[POINT 7,0(T1)]
	MOVE W2,[POINT 7,0(T2)]
CMPLOP:	ILDB T3,W1		;GET NEXT BYTE
	ILDB T4,W2		;GET THIS ONE'S NEXT
	CAME T3,T4		;MATCH?
	RET			;NO. NO MATCH THEN
	SOSLE W3		;ANY MORE BYTES?
	JUMPN T3,CMPLOP		;DO ENTIRE STRING
	RETSKP			;A MATCH!!!!

;MOVE ONE STRING TO ANOTHER.
;ACCEPTS:	T1/ DEST STRING BLOCK
;		T2/ SOURCE STRIGN BLOCK
;		T3/ COUNT OR -1
;RETURNS:	+1 ALWAYS.
;ALL REGISTERS PRESERVED

MOVSTR:	SAVET			;SAVE ALL TEMPS
	ACVAR <W1,W2>		;GET SOME WORK REGS
	MOVE W1,[POINT 7,0(T1)]
	MOVE W2,[POINT 7,0(T2)]	;SET UP ARGS
MOVST0:	ILDB T4,W2		;GET NEXT BYTE
	IDPB T4,W1		;STASH IT
	JUMPE T4,R		;IF NULL, ALL DONE
	JUMPL T3,MOVST0		;IF NO COUNT, KEEP GOING
	SOJG T3,MOVST0		;MORE IN THE COUNT?
	RET			;NO. ALL DONE

;ROUTINE TO "FREE" A LL ADDRESS.
;ACCEPTS:	T1/ LL ADDRESS TO FREE
;RETURNS:	+1 ALWAYS

FRELNK:	ANDI T1,MAXLNK		;ISOLATE LOCAL INDEX
	IDIVI T1,44		;COMPUTE WORD AND OFFSET
	ADD T1,[LLBITS]		;GET BIT TABLE OFFSET
	MOVE T2,BITS(T2)	;GET A BIT
	IORM T2,0(T1)		;TURN OF THE BIT
	RET			;AND DONE
;ROUTINES TO GET AND RETURN SWAPPABLE FREE SPACE

;ROUTINE TO GET A BLOCK FROM THE LL STRING SPACE POOL
;ACCEPTS:	T1/ SIZE TO GET
;RETURNS:	+1 FAILED. T1/ERROR CODE
;		+2 SUCCESS T1/ BLOCK ADDRESS

GETBLK:	MOVEI T2,1(T1)		;ACCOUNT FOR HEADER
	ADD T2,BLKASG		;COMPUTE AMOUNT THIS WOULD MAKE
	CAILE T2,MAXBLK		;WITHIN BOUNDS?
	RETBAD (MONX01)		;NO. INSUFFICIENT RESOURCES
	AOS T1			;GET SPACE +1
	CALL ASGSWP		;GET SOME SPACE
	 RETBAD			;FAILED. GIVE IT UP
	HRRZ T2,0(T1)		;GET COUNT ASSIGNED
	ADDM T2,BLKASG		;ACCOUNT FOR IT
	AOS T1			;POINT TO FIRST USEFUL BLOCK
	RETSKP			;AND GOOD

;ROUTINE TO RETURN A STRING BLOCK
;ACCEPTS:	T1/ ADDRESS OF FIRST DATA LOCATION (HEADER+1)
;RETURNS:	+1 ALWAYS

RELBLK:	SOS T1			;POINT TO HEADER
	HRRZ T2,0(T1)		;GET WORDS IN THIS BLOCK
	EXCH T2,BLKASG
	SUBM T2,BLKASG		;COMPUTE NEW COUNT
	HRRZ T2,0(T1)		;GET SIZE OF THE BLOCK AGAIN
	CALLRET RELSWP		;RELEASE THE BLOCK

;ROUTINE TO GET A RESIDENT FREE SPACE BLOCK
;ACCEPTS:	T1/ SIZE REQUIRED

GETRES:	HRLI T1,.RESP3		;IN PROCESS CONTEXT
	MOVE T2,[RS%SE0!.RESNP]	;FROM THE NETWORK
	CALL ASGRES		;GET SOME SPACE
	 RETBAD()		;COULDN'T
	RETSKP			;GOT IT

;ROUTINE TO MOVE A STRING FROM JSB FREE SPACE TO SWAPPABLE FREE SPACE.
;ACCEPTS:	T1/ DESTINATION BLOCK ADDRESS
;		T2/ SP TO JSB FREE SPACE
;		T3/ COUNT
;CLOBBERS ALL TEMPS

MOVST1:	ACVAR <W1>		;GET A WORK REG
	MOVE W1,[POINT 7,0(T1)]	;FORM STRING POINTER
MOVST2:	ILDB T4,T2		;GET A BYTE
	IDPB T4,W1		;STORE IT
	SOJG T3,MOVST2		;DO ALL BYTES
	RET			;DONE
;COMMON ROUTINE FOR OPENF JSYS. THIS CODE IS CALLED BY BOTH SRCOPN
;AND DCNOPN TO ASSIGN A LL BLOCK, ASSIGN A LL ADDRESS, AND FILL
;IN COMMON VALUES.
;	RETURNS +1	FAILED. T1/ ERROR CODE
;		+2 SUCCESS	T1/ LL BLOCK ADDRESS
;			 AND LL TREE LOCKED

OPNDNC:	TDZA T1,T1		;NO ADDITIONAL WORDS
OPNSRC:	MOVEI T1,LKOBJS		;ADDITIONAL WORDS FOR OBJECT
	MOVX T2,FRKRUN		;SEE IF NETWORK IS INTIALIZED
	TDNN T2,MCBDTE		;IS IT?
	RETBAD (DCNX11)		;NO. ILLEGAL TO USE IT THEN
	ADDI T1,LKSIZE		;BASIC SIZE OF A LL BLOCK
	TRVAR <SAVBLK,SAVERR>	;TO REMEMBER LL BLOCK ADDRESS
	TQZE <RNDF>		;WANT APPEND?
	TQO <WRTF>		;YES. FORCE ON WRITE THEN
	TQNN <READF,WRTF>	;WANT SOME FORM OF ACCESS?
	RETBAD (OPNX14)		;NO. ILLEGAL OPEN
	LDB T2,PBYTSZ		;LOOK AT REQUESTED BYTE SIZE
	CAIE T2,10		;BYTES?
	CAIN T2,7		;OR ASCII?
	JRST BYTGUD		;YES. ACCEPTS IT
	CAIE T2,44		;-10 WORD MODE?
	RETBAD (SFBSX2)		;NO. ILLEGAL BYTE SIZE
BYTGUD:	HRLI T1,.RESP3		;IN PROCESS CONTEXT
	MOVEI T2,.RESNP		;FROM THE NETWORK POOL
	CALL ASGRES		;GET A LL BLOCK
	 RET			;COULDN'T. MUST FAIL
	MOVEM T1,SAVBLK
	MOVEI T1,OPTSIZ		;SIZE OF OPTDATA BLOCK
	CALL GETBLK		;GET A BLOCK OF PROPER SIZE
	 JRST RLBLK		;COULDN'T. FREE BLOCK
	MOVE T2,SAVBLK		;GET BACK BLOCK ADDRESS
	STOR T1,LLOPT,(T2)	;SAVE BLOCK ADDRESS
	MOVE T1,T2		;GET LL BLOCK ADDRESS
	LLLOCK			;LOCK UP THE TREE
	CALL MAKLNK		;GET LL ADDRESS AND INSERT ENTRY
	 JRST [	MOVEM T1,SAVERR	;SAVE ERROR CODE
		LLLULK
		MOVE T1,SAVBLK	;GET BLOCK
		LOAD T1,LLOPT,(T1)
		CALL RELBLK	;FREE UP OPT BLOCK
		JRST RLBLK1]	;AND GET RID OF LL BLOCK
	LLLULK			;RELEASE LOCK
	; ..
;OPEN CONTINUED. CHECK QUOTA TO SEE IF CAN MAKE THIS LINK

	NOSKED			;MUST MAKE THIS CHECK RACE FREE
	OPSTRM <AOS T2,>,DCCUR	;GET AND INCREMENT COUNT
	MOVE T3,CAPENB		;GET CURRENT CAPABILITIES
	LOAD T4,DCMAX		;GET MAX COUNT ALLOWED
	TXNN T3,SC%WHL!SC%OPR	;IS THIS A PRIVILEGED FORK?
	CAIG T2,0(T4)		;NO. ALLOWED TO MAKE ANOTHER LINK?
	SKIPA			;YES
	JRST [	MOVEI T1,DCNX5	;NO. GIVE ERROR
		OKSKED		;ALLOW SCHEDULING AGAIN
		JRST OPNFAI]	;AND GO FAIL
	OKSKED			;AND ALLOW SCHEDULING AGAIN
	MOVEI T1,2		;SIZE OF HOST NAME BLOCK
	CALL GETBLK		;GET ONE
	 JRST OPNFAI		;COULDN'T
	MOVE T2,SAVBLK		;GET LL BLOCK ADDRESS
	STOR T1,LLHST,(T2)	;SAVE IT
	MOVEI T1,<MAXDSC+4>/4	;A BLOCK FOR REMOTE DESCRIPTOR
	CALL GETBLK		;GET ONE
	 JRST OPNFAI		;COULDN'T
	MOVE T2,SAVBLK		;GET LL BLOCK
	STOR T1,LLFDS,(T2)	;SAVE BLOCK
	HRRZ T1,FILNEN(JFN)	;GET POINTER TO EXTENSION BLOCK
	JUMPE T1,OPNDFT		;NONE. GO DEFAULT TASK NAME
	LDB T2,[POINT 7,1(T1),6] ;GET FIRST BYTE
	JUMPE T2,OPNDFT		;IF NULL EXTENSION. GO DEFAULT TASK NAME
	; ..
;USER SPECIFIED EXTENSION. CHECK FOR DUPLICATE

	HRRZ T1,0(T1)		;GET SIZE OF EXTENSION
	SOS T1			;DISCOUNT THE HEADER
	CALL GETBLK		;GET A BLOCK TO HOLD IT
OPNFAI:	 JRST [	LLLOCK		;LOCK UP TREE
		EXCH T1,SAVBLK	;GET BLOCK ADDRESS
		CALL DELNOD	;RELEASE LL BLOCK
		LLLULK		;RELEASE LOCK
		MOVE T1,SAVBLK	;GET ERROR CODE
		DECR DCCUR	;DISCOUNT THIS LINK
		RET]		;DONE
	MOVEM T1,SAVERR		;SAVE BLOCK ADDRESS
	HRRZ T2,FILNEN(JFN)	;GET STRING BLOCK
	AOS T2			;POINT TO TEXT
	SETOM T3		;NO COUNT
	CALL MOVSTR		;MOVE THE STRING
	MOVEI T1,TSKCHK		;COROUTINE ADDRESS
	SETOM T2		;SEARCH ALL LOGICAL LINKS
	LLLOCK			;LOCK UP THE TREE
	CALL OBJSRC		;DO IT
	 SKIPA			;NOT FOUND. CAN USE IT
	JRST [	MOVE T1,SAVERR	;GET TASK NAME BLOCK
		CALL RELBLK	;RELEASE IT
		MOVE T1,SAVBLK	;GET LL BLOCK ADDRESS
		CALL DELNOD	;RELEASE THE BLOCK
		LLLULK		;FREE THE TREE LOCK
		MOVEI T1,DCNX4	;ILLEGAL TASK NAME
		DECR DCCUR	;DISCOUNT THIS LINK
		RET]		;AND DONE
	MOVE T2,SAVERR		;GET TASK BLOCK
	MOVE T1,SAVBLK		;GET LL BLOCK ADDRESS
	STOR T2,LLTSK,(T1)	;STORE BLOCK ADDRESS
OPNEXT:	SETONE LLBOM,(T1)	;NEXT OUTPUT WILL BE BOM
	LDB T3,PBYTSZ		;GET BYTE SIZE OF OPENING
	STOR T3,LLBSZ,(T1)	;SAVE BYTE SIZE
	CAIE T3,44		;WORD MODE?
	JRST OPENX1		;NO. GO ON
	SETONE LLFDI,(T1)	;YES. REMEMBER THIS
OPENX1:	MOVEM T1,FILLLB(JFN)	;SAVE BLOCK ADDRESS
	TQNE <READF>		;WANT BI-DIRECTIONAL LINK?
	CALL [	SETONE LLOPI,(T1) ;YES.
		RET]
	TQNE <WRTF>		;WANT WRITE?
	CALL [	SETONE LLOPW,(T1) ;YES.
		RET]
	RETSKP			;AND DONE
;ROUTINE TO GET RID OF LL BLOCK AFTER ERROR

RLBLK:	MOVEM T1,SAVERR		;SAVE ERROR
RLBLK1:	MOVE T1,SAVBLK		;GET BLOCK ADDRESS
	CALL RELRES		;FREE IT
	MOVE T1,SAVERR		;GET ERROR
	RET			;AND DONE

;ROUTINE TO GET DEFAULT TASK NAME FOR A LINK

OPNDFT:	LLLOCK			;LOCK UP THE TREE
	MOVE T1,SAVBLK		;GET BLOCK ADDRESS
	CALL GETTSK		;GO GET A NAME
	 JRST [	MOVE T1,SAVBLK	;FAILED
		CALL DELNOD	;SO RELEASE LL BLOCK
		LLLULK		;FREE TREE LOCK
		MOVEI T1,DCNX4	;?
		RET]		;DONE
	MOVE T1,SAVBLK		;GET BACK LL BLOCK ADDRESS
	JRST OPNEXT		;AND DONE

;COROUTINE OF OPEN CODE TO CHECK VALIDITY OF A USER-SUPPLIED
;TASK NAME

TSKCHK:	SAVET			;SAVE TEMPS
	LOAD T2,LLFRK,(T1)	;SEE IF THE SAME FORK
	CAMN T2,FORKX		;IS IT?
	RET			;YES. NO NEED TO CHECK ANYMORE
	JRST TSKLO1		;NO. DO NORMAL TASK CHECKING
;DELETE NODE FROM LL TREE
;	T1/ BLOCK ADDRESS

DELNOD:	ASUBR <SAVBLK>		;SAVE BLOCK ADDRESS
	LOAD T1,LLLNK,(T1)	;GET ITS ADDRESS
	SETOM T2		;ANY MATCH
	CALL LLLKUP		;GO LOOK IT UP
	 BUG (HLT,DELNDF,<DELNOD-LLLKUP FAILED>)
	JUMPE T2,[SETZM LLHEAD	;IF THE HEAD. CLEAR HEADER
		JRST DELNO1]	;AND PROCEED
	LOAD T3,LLUPL,(T2)	;SEE IF THIS IS UP OR DOWN
	NOSKED
	CHNOFF DLSCHN		;TURN OFF INTERRUPTS
	CAMN T3,T1
	JRST [	SETZRO LLUPL,(T2) ;UP
		JRST DELINS]	;GO DO INSERTS
	SETZRO LLDWN,(T2)	;DOWN
DELINS:	CHNON DLSCHN
	OKSKED
DELNO1:	LOAD T1,LLLNK,(T1)	;GET ADDRESS
	CALL FRELNK		;RELEASE THE LINK #
	MOVE T1,SAVBLK		;GET BACK LL BLOCK ADDRESS
	LOAD T2,LLUPL,(T1)	;DOES THIS HAVE AN UP POINTER?
	JUMPE T2,DELDWN		;NO
	MOVE T1,T2		;YES.
	CALL ADDLNK		;GO PUT IT IN
	MOVE T1,SAVBLK		;GET BACK ADDRESS
DELDWN:	LOAD T2,LLDWN,(T1)	;SEE IF IT HAS A DOWN
	JUMPE T2,DELDNE		;AND GO RELEASE BLOCKS
	MOVE T1,T2		;GET ADDRESS
	CALL ADDLNK
	MOVE T1,SAVBLK		;GET BACK BLOCK ADDRESS
DELDNE:	OPSTR <SKIPE T2,>,LLOPT,(T1) ;HAVE AN OPTDATA STRING?
	CALL DELREL		;YES. GET RID OF IT
	OPSTR <SKIPE T2,>,LLTSK,(T1) ;HAVE A TASK NAME?
	CALL DELREL		;YES. GET RID OF IT
	OPSTR <SKIPE T2,>,LLHST,(T1) ;HAVE A HOST NAME STRING?
	CALL DELREL		;YES. GET RID OF IT
	OPSTR <SKIPE T2,>,LLFDS,(T1) ;HAVE A DESCRIPTOR STRING?
	CALL DELREL		;YES. GET RID OF IT
	JE LLFOB,(T1),DELBLK	;AN OBJECT?
	OPSTR <SKIPE T2,>,LLDSC,(T1) ;YES. HAVE A DESCRIPTOR STRING?
	CALL DELREL		;YES. GET RID OF IT
	OPSTR <SKIPE T2,>,LLUSR,(T1) ;HAVE A USER STRING?
	CALL DELREL		;YES. GET RID OF IT
	OPSTR <SKIPE T2,>,LLACT,(T1) ;HAVE AN ACCOUNT STRING?
	CALL DELREL		;YES. GET RID OF IT
	OPSTR <SKIPE T2,>,LLPSW,(T1) ;HAVE A PASSWORD STRING?
	CALL DELREL		;YES. GET RID OF IT
DELBLK:	CALLRET RELRES		;FREE BLOCK AND RETURN

DELREL:	SAVET
	MOVE T1,T2		;GET BLOCK ADDRESS
	CALLRET RELBLK		;FREE BLOCK
;ROUTINE TO RESET AN LL BLOCK SO THAT IT CAN REVERT TO
;THE LISTENING STATE. USED WHEN A SERVER REJECTS A CONNECTION.

CLRBLK:	CALL FLUSH		;FIRST GET RID OF MESSAGES
	SETZRO LLFNM,(T1)	;CLEAR CONNECTOR
	SETZRO LLHLK,(T1)
	SETZRO LLUCT,(T1)	;NO OPTDATA
	LOAD T2,LLHST,(T1)
	SETZM 0(T2)		;NO REMOTE HOST NAME
	LOAD T2,LLFDS,(T1)
	SETZM 0(T2)		;NO REMOTE DESCRIPTOR
	SETZRO LLRSN,(T1)	;NO DISCONNECT REASON
	JE LLFOB,(T1),R		;IN CASE CALLED FOR NON-OBJECT
	SETZM LLUSGP(T1)	;NO GROUP,USER
	SETZRO LLSOB,(T1)	;NO OBJECT #
	LOAD T2,LLUSR,(T1)	;GET USER BLOCK
	SETZM 0(T2)		;NO USER
	LOAD T2,LLACT,(T1)	;GET ACCOUNT BLOCK
	SETZM 0(T2)		;NONE
	SETZRO LLPCT,(T1)	;NO PASSWORD DATA
	RET			;AND DONE
;ROUTINE TO GET A LL ADDRSS AND INSERT A NODE IN THE TREE
;MUST BE CALLED WITH LL LOCK LOCKED.
;ACCEPTS:	T1/ BLOCK ADDRESS
;RETURNS:	+1 SOME SORT OF FAILURE (SHOULDN'T HAPPEN)
;		+2 INSERTED.

MAKLNK:	ASUBR <SAVADR>		;SAVE BLOCK ADDRESS
	MOVSI T1,-LLBIT		;# OF WORDS IN BIT TABLE
	MOVE T2,[LLBITS]	;THE TABLE ITSELF
MAKLN1:	SKIPN T3,0(T2)		;HAVE SOME BITS?
	JRST [	AOS T2		;NO. NEXT WORD THEN
		AOBJN T1,MAKLN1	;SEE IF ANY MORE
		MOVEI T1,DCNX5	;NO MORE LINKS
		RET]		;AND DONE
	JFFO T3,.+1		;COMNPUTE LEADING ZEROES
	MOVE T3,BITS(T4)	;GET THE BIT
	ANDCAM T3,0(T2)		;TURN IT OFF
	HRRZS T1		;GET # OF FULL WORDS SKIPPED
	IMULI T1,44		;COMPUTE SKIPPED BITS
	ADDI T1,0(T4)		;THE INDEX
	HRRZ T2,TODCLK		;GET THE CURRENT CLOCK
	LSH T2,MAXEXP		;ZERO RIGHT-HAND BITS
	ANDI T2,177777		;GET A 16 BIT QUANTITY
	ADDI T2,0(T1)		;FORM LL ADDRESS
	MOVE T1,SAVADR		;GET BACK BLOCK ADDRESS
	STOR T2,LLLNK,(T1)	;PUT IN THE ADDRESS
	MOVE T2,FORKX		;PUT IN FORK OWNER
	STOR T2,LLFRK,(T1)	;TO THE BLOCK
	CALL ADDLNK		;AND GO ADD IN THE LINK
	RETSKP			;DONE

;ROUTINE TO ADD A BLOCK TO THE LL TREE
;ACCEPTS:	T1/BLOCK TO ADD
;RETURNS:	+1 ALWAYS.
;MUST BE CALLED WITH TREE LOCKED

ADDLNK:	ASUBR <SAVBLK>		;SAVE BLOCK ADDRESS
	LOAD T1,LLLNK,(T1)	;GET LINK I.D.
	SETO T2,		;NO HOST CHECK
	CALL LLLKUP		;GO GET INSERT POINT
	 SKIPA			;GOOD
	BUG (HLT,ADDONF,<ADDOBJ-LLLKUP FAILED>)
	MOVE T2,SAVBLK		;GET BACK LL BLOCK
	JUMPE T1,[MOVEM T2,LLHEAD ;FIRST ONE
		RET]		;AND DONE
	LOAD T3,LLLNK,(T2)	;GET THIS LINK I.D.
	LOAD T4,LLLNK,(T1)	;GET INSERT I.D.
	CAML T3,T4
	JRST [	STOR T2,LLUPL,(T1)
		RET]		;DONE
	STOR T2,LLDWN,(T1)	;NEW LINK
	RET			;AND DONE
;ROUTINE CALLED FROM GTJFN TO VERIFY AN ATTRIBUTE
;ACCEPTS:	T1/ BLOCK ADDRESS
;		T2/ ATTRIBUTE VALUE
;RETURNS:	+1 INVALID. ERROR CODE IN T1
;		+2 GOOD ATTRIBUTE

NETATR:	ACVAR <W1>		;GET A WORK REG
	MOVSI T3,-MAXNTA	;# OF ATTRIBUTES IN TABLE
NETAT2:	OPSTR <CAME T2,>,NTATR,ATTRTB(T3) ;IS THIS IT?
	JRST [	AOBJN T3,NETAT2	;DO ALL OF THEM
		RETBAD (GJFX49)] ;COULDN'T FIND IT
	LOAD W1,NTATB,ATTRTB(T3) ;FOUND IT. GET BINARY BIT
	LOAD T2,NTATC,ATTRTB(T3) ;GET MAX COUNT
	SKIPE W1		;BINARY?
	IMULI T2,3		;YES. ADJUST COUNT
	HRLI T1,(<POINT 7,0,34>) ;FORM A BYTE POINTER
CNTLOP:	ILDB T4,T1		;GET NEXT BYTE
	JUMPE T4,NETAT1		;IF NULL, DONE
	SOJL T2,[ RETBAD (GJFX50)] ;ATTRIBUTE TOO LONG
	JUMPE W1,CNTLOP		;IF NOT BINARY, GO GET MORE
	CAIL T4,"0"		;IS BINARY. CHECK RANGE
	CAILE T4,"7"		;""
	SKIPA
	JRST CNTLOP		;GOOD RANGE
	RETBAD (GJFX50)		;INVALID
NETAT1:	LOAD T2,NTATE,ATTRTB(T3) ;GET EXCLUSION PARTNER
	SKIPE T2		;HAVE ONE?
	CALL FNDATR		;YES. GO LOOK FOR IT
	 RETSKP			;NOT THERE. ERGO, GOOD ARG
	RETBAD (GJFX45)		;CONFLICT

;THE ATTRIBUTE TABLE

ATTRTB:	ATTENT (.PFUDT,0,^D16,0)
	ATTENT (.PFPWD,0,^D8,.PFBPW)
	ATTENT (.PFBPW,1,^D8,.PFPWD)
	ATTENT (.PFACN,0,^D16,0)
	ATTENT (.PFOPT,0,^D16,.PFBOP)
	ATTENT (.PFBOP,1,^D16,.PFOPT)
MAXNTA==.-ATTRTB
;DEFINE DTB'S

;FOR DEVICE SRV

SRVDTB::IFIW!NETDIR		;DIRECTORY SET
	IFIW!SRNSET		;NAME LOOKUP
	IFIW!EXTSET		;EXTENSION LOOKUP
	IFIW!VERSET		;VERSION LOOKUP
	DTBBAD (DESX9)		;NO PROTECTION
	DTBBAD (DESX9)		;NO ACCOUNT
	DTBBAD (DESX9)		;NO STATUS
	IFIW!SRCOPN		;OPEN
	IFIW!NETSQI		;INPUT
	IFIW!NETSQO		;OUTPUT
	IFIW!NETCLZ		;CLOSE
   REPEAT 7,<
	DTBBAD (DESX9)>	;ILLEGAL FUNCTIONS
	IFIW!NTMTOP		;MTOPR
   REPEAT 2,<DTBBAD (DESX9)>	;ILLEGAL FUNCTIONS
	IFIW!NETSQR		;SOUTR
	IFIW!RFTADN		;NO TIME AND DATE
	IFIW!RFTADN		;NO TIME AND DATE
	IFIW!NETINP		;SET FOR INPUT
	IFIW!NETOUP		;SET FOR OUTPUT
	DTBBAD (GJFX49)		;NO ATTRIBUTES

;FOR THE DCN DEVICE

DCNDTB::IFIW!NETDIR		;DIR SET
	IFIW!DCNSET		;NAME LOOKUP
	IFIW!EXTSET		;EXTENSION LOOKUP
	IFIW!VERSET		;VERSION LOOKUP
   REPEAT 3,<
	DTBBAD (DESX9)>	;ILLEGAL FUNCTIONS
	IFIW!DCNOPN		;OPEN
	IFIW!NETSQI		;INPUT
	IFIW!NETSQO		;OUTPUT
	IFIW!NETCLZ		;CLOSE
   REPEAT 7,<
	DTBBAD (DESX9)>	;ILLEGAL FUNCTIONS
	IFIW!NTMTOP		;MTOPR
   REPEAT 2,<DTBBAD (DESX9)>	;ILLEGAL FUNCITONS
	IFIW!NETSQR		;SOUTR
	IFIW!RFTADN		;NO TIME AND DATE
	IFIW!SFTADN		;NO TIME AND DATE
	IFIW!NETINP		;SET FOR INPUT
	IFIW!NETOUP		;SET FOR OUTPUT
	IFIW!NETATR		;PARSE ATTRIBUTES
;ROUTINES TO OPEN NETWORK CONNECTION. CALLED FROM OPENF JSYS

;OPEN SRC JFN

SRCOPN:	ACVAR <W1>		;GET A WORK REG
	TRVAR <NTCNT,NTPNT,NTOBJ,NTDSC,NTDSS>
	HLRZ T1,FILNEN(JFN)	;GET NAME FOR THE CONNECTION
	CALL SRCNAM		;PARSE NETWORK NAME
	 RETBAD()		;ERROR
	CALL OPNSRC		;GO DO COMMON OPEN SETUP
	 RETBAD()		;FAILED
	MOVE W1,T1		;SAVE LL BLOCK
	SKIPG T2,NTOBJ		;GET OBJECT TYPE
	JRST NOOOBJ		;NONE GIVEN
	STOR T2,LLNAM,(W1)	;SAVE OBJECT
NOOOBJ:	SKIPN T1,NTDSC		;HAVE A DESCRIPTOR?
	JRST NODESC		;NO. GO ON
	ADDI T1,4
	IDIVI T1,5		;COMPUTE WORDS NEEDED
	CALL GETBLK		;GET ONE
	 JRST SRCFAL		;FAILED
	STOR T1,LLDSC,(W1)	;SAVE POINTER
	MOVE T2,NTDSS		;GET STRING POINTER
	MOVE T3,NTDSC		;GET COUNT
	CALL MOVST1		;MOVE THW STRING
	MOVEI T1,OPNUNQ		;MUST VERIFY UNIQUENESS OF NAME
	SETZM T2		;NEED TO CHECK OBJECTS ONLY
	CALL OBJSRC		;DO IT
	 JRST NODESC		;NOT FOUND. CAN HAVE IT
	LOAD T2,LLFRK,(T1)	;FOUND ONE. WHICH JOB?
	HLRZ T2,FKJOB(T2)	;""
	MOVEI T1,DCNX9		;DUPICATE NAME ERROR
	CAME T2,JOBNO		;THIS JOB?
	JRST SRCFAL		;NO. CAN'T HAVE IT
NODESC:	CALL GTSBLK		;GET A BLOCK FOR USER NAME
	 JRST SRCFAL		;NONE
	STOR T1,LLUSR,(W1)	;SAVE IT
	CALL GTSBLK		;GET A BLOCK FOR THE ACCOUNT
	 JRST SRCFAL		;NONE
	STOR T1,LLACT,(W1)	;SAVE IT
	CALL GTSBLK		;GET A BLOCK FOR THE PASSWORD
	 JRST SRCFAL		;NONE
	STOR T1,LLPSW,(W1)	;SAVE IT
	CALL ASGWDW		;GO GET WINDOW PAGES
	 JRST SRCFAL		;FAILED
	MOVEI T1,LLSLIS		;GET INITIAL STATE
	STOR T1,LLSTA,(W1)	;SET UP THIS LISTENER
	SETONE LLFOB,(W1)	;SAY THIS IS AN OBJECT
	LLLULK			;FREE LOCK
	RETSKP			;AND DONE
;COROUTINE OF SRCOPN TO CHECK FOR UNIQUE NAME

OPNUNQ:	SAVET			;SAVE TEMPS
	LOAD T2,LLNAM,(T1)	;GET OBJECT NUMBER
	OPSTR <CAME T2,>,LLNAM,(W1) ;SAME AS OURS?
	RET			;NO. NO CONFLICT THEN
	LOAD T1,LLDSC,(T1)	;GET ITS DESCRIPTOR
	LOAD T2,LLDSC,(W1)	;GET OURS
	CALL CMPSTR		;SEE IF A MATCH
	 RET			;NO.
	RETSKP			;YES. COULD BE A PROBLEM

;OPEN FAILURE ROUTINE. CLEAN UP FROM ATTEMPT

SRCFAL:	SETZM FILBFI(JFN) 	;CLEAN UP JFN BLOCK
	DECR DCCUR		;ONE LESS LINK ON FAILURE
	EXCH T1,W1		;GET BLOCK ADDRESS
	CALL DELNOD		;FREE THE NODE
	LLLULK			;UNLOCK THE TREE
	MOVE T1,W1		;GET ERROR CODE
	RET			;AND FAIL

;LOCAL ROUTINE TO GET A STRING BLOCK FOR SRCOPN.

GTSBLK:	MOVEI T1,OPTSIZ		;THE PROPER SIZE
	CALL GETBLK		;GET ONE
	 RET			;FAILED
	RETSKP			;GOT IT
;ROUTINE CALLED FROM THE OPENF JSYS TO OPEN A DCN NETWORK CONNECTION

DCNOPN:	ACVAR <W1,W2,W3>	;GET A WORK REGISTER
	TRVAR <NTCNT,NTPNT,NTOBJ,NTDSC,NTDSS,NTHST,NTHSC,NTCIB>
	HLRZ T1,FILNEN(JFN)	;GET NAME FOR THE CONNECTION
	CALL DCNNAM		;GO PARSE THE NAME FIELD
	 RETBAD ()		;FAILED
	CALL OPNDNC		;GO DO COMMON SETUP
	 RETBAD ()		;FAILED
	MOVE W1,T1		;SAVE LL BLOCK ADDRESS
	MOVE T1,NTOBJ		;GET OBJECT
	STOR T1,LLFNM,(W1)	;SAVE IT
	SKIPG T3,NTHSC		;HAVE A HOST NAME?
	JRST [	SKIPL W2,NSPLPB	;DOING LOOPBACK ?
		JRST HSTLCL	;NO SO USUAL LOCAL PROCEDURE
		MOVE T2,[POINT 7,OURNAM] ;POINT TO OUR NAME
		MOVE T3,OURCNT	;AND SIZE OF OUR NAME
		JRST DCNOP8 ]
	CAME T3,OURCNT		;SAME COUNT AS OUR NAME?
	JRST DCNOP0		;NO. CAN'T BE US THEN
	HRRZ T1,NTHST		;GET BLOCK POINTER
	AOS T1			;PUT TO START OF NAME
	MOVEI T2,OURNAM		;GET OUR NAME
	CALL CMPST1		;SEE IF THE SAME
	 JRST DCNOP0		;NO. SAVE IT THEN
	SKIPL W2,NSPLPB		;IS THERE A LOOPBACK PORT ?
	JRST HSTLCL		;NO. DO SAME AS LOCAL THEN
	JRST DCNOP7		;USE LOOPBACK PORT FOR MESSAGES
DCNOP0:	MOVSI W2,-DCN		;MAKE PORT NUMBER COUNTER
	SETOM W3		;WHERE TO REMEMBER INT. NODE
DCNOP2:	SKIPGE T2,MCBDTE(W2)	;IS PORT ACTIVE ?
	TXNE T2,NTSHUT		;IS PORT SHUTTING DOWN ?
	JRST DCNOP3		;CAN'T USE THIS ONE
	TXNN T2,NOTMCB		;IS THIS AN MCB?
	HRRZ W3,W2		;YES. REMEMBER PORT THEN
	MOVE T3,NTHSC		;GET COUNT OF CHARS IN NAME
	OPSTR <CAME T3,>,NAMCN,MCBDTE(W2) ;SAME COUNT AS NODE NAME?
	JRST DCNOP3		;NO. THIS CAN'T BE IT THEN
	MOVEI T2,ITSNAM(W2)	;ALMOST ADR OF NEIGHBOR'S NAME
	ADDI T2,(W2)		;MAKE NEIGHBORS NAME
	HRRZ T1,NTHST		;GET BLOCK POINTER AGAIN
	AOS T1			;PUT TO START OF NAME
	CALL CMPST1		;SEE IF THIS MATCHES
DCNOP3:	 AOBJN W2,DCNOP2	;LOOP BACK FOR REST OF PORTS
	JUMPL W2,DCNOP7		;IF FOUND MATCH
	SKIPGE W2,W3		;FOUND AN MCB?
	JRST [	MOVEI T1,DCNX13	;NODE NOT ACCESSIBLE
		JRST SRCFAL]	;AND BOMB
DCNOP7:	MOVE T2,NTHST		;GET POINTER TO STRING TO BE MOVED
	MOVE T3,NTHSC		;GET COUNT
DCNOP8:	STOR W2,LLPRT,(W1)	;SAVE PORT #
	LOAD T1,LLHST,(W1)	;GET ADDRESS OF HOST STRING
	CALL MOVST1		;AND MOVE IT
HSTLCL:	SKIPG T3,NTDSC		;HAVE A DESCRIPTOR?
	JRST DSCNUL		;NO.
	LOAD T1,LLFDS,(W1)	;GET DESCRIPTOR BLOCK
	MOVE T2,NTDSS		;GET JSB STRING POINTER
	CALL MOVST1		;AND MOVE IT
	; ..
;ALL STRINGS ARE MOVED. MUST GENERATE CONNECT-INITIATE MESSAGE

DSCNUL:	MOVEI T1,CONLEN+MSHDR+RTHLEN ;GET A BLOCK FOR THE CI
	CALL GETRES		;GET A RESIDENT BLOCK
	 JRST SRCFAL		;FAILED. GIVE UP
	MOVEM T1,NTCIB		;SAVE BLOCK ADDRESS
	HRLI T1,(<POINT 8,>)	;MAKE A BYTE POINTER
	ADDI T1,MSHDR		;RESERVE HEADER
	MOVEM T1,LLBPTR(W1)	;SAVE IN LL BLOCK
	SETZM LLBPCT(W1)	;ZERO COUNT
	CALL ASGWDW		;NOW SET UP WINDOWS
	 JRST [	EXCH T1,NTCIB	;SAVE ERROR. GET BLOCK
		CALL RELRES	;RELEASE IT
		MOVE T1,NTCIB	;GET BACK ERROR CODE
		JRST SRCFAL]	;AND GIVE UP
	MOVE T1,W1		;LL BLOCK ADDRESS
	MOVEI T2,CNMRFL+CNMCI	;MESSAGE FLAGS
	CALL RTHDCI		;GO PUT ON CI ROUTING HEADER
	CALL DOSRVS		;DO COMMON SERVICES
	; ..
;DCNOPN CONTINUED...

;NOW BUILD OBJECT ADDRESSING FIELDS

	SKIPG NTDSC		;HAVE A COUNT FOR DESCRIPTOR
	JRST [	MOVEI T2,OBJZRO	;GET OBJECT TYPE ZERO INDICATOR
		CALL ONEBYT
		MOVE T2,NTOBJ	;GET OBJECT TYPE
		CALL ONEBYT
		LOAD T1,LLFDS,(W1) ;GET DESCRIPTOR STRING
		SETZRO LLFDS,(W1) ;CLEAR LOCATION
		CALL RELBLK	;RELEASE UNUSED BLOCK
		MOVE T1,W1	;RESTORE LL BLOCK ADDRESS
		JRST DSCDON]	;DONE WITH THIS
	MOVEI T2,OBJONE		;GET OBJECT TYPE 1
	CALL ONEBYT		;STORE HEADER
	MOVE T2,NTOBJ		;GET OBJECT NUMBER
	CALL ONEBYT		;PUT IT IN
	LOAD T3,LLFDS,(T1)	;GET DESCRIPTOR STRING
	CALL ASCIIZ		;PUT IT IN

;MESSAGE BUILT. INSERT SENDER'S NAME AND USER DATA

DSCDON:	MOVEI T2,OBJONE		;SENDER IS A TASK
	CALL ONEBYT
	MOVEI T2,OBJTSK		;THE I.D. FOR TASK
	CALL ONEBYT
	LOAD T3,LLTSK,(T1)	;GET POINTER TO TASK NAME
	CALL ASCIIZ		;AND INSERT IT
	; ..
;NOW CHECK FOR AND INSERT ANY OPTIONAL DATA

	SETZ T2,		;DEFAULT MENU BYTE
	CALL ONEBYT		;PUT IT IN
	MOVE T3,LLBPTR(T1)	;GET POINTER TO MENU
	MOVEM T3,NTPNT		;SAVE IT
	MOVEI T2,1		;ASSUME WILL BE PRESENT
	MOVEM T2,NTCNT		;ASSUME WILL BE PRESENT
	MOVEI T2,.PFUDT		;SEE IF USER I.D. GIVEN
	CALL FNDATR		;IS IT?
	 JRST [	SETZM T2	;NOT THERE.
		CALL ONEBYT	;STORE A NULL COUNT
		JRST DOPSW1]	;AND GO TO THE PASSWORD
	CALL ASCIIZ		;PUT IN THE DATA
DOPSW1:	MOVEI T2,.PFPWD		;SEE IF A PASSWORD IS GIVEN
	CALL FNDATR		;IS IT?
	 JRST [	MOVEI T2,.PFBPW	;NO. SEE ABOUT ALTERNATE FORM
		CALL FNDATR
		 JRST [	SETZ T2, ;NO.
			CALL ONEBYT ;INSERT A PLACEHOLDER
			JRST DOACT] ;AND GO ON
		MOVEI T4,BININ	;YES. INSERT BINARY VALUE
		JRST DOPSWD]
	MOVEI T4,ASCIIZ		;YES. INSERT ASCII FORM
DOPSWD:	CALL 0(T4)		;PUT IT IN
DOACT:	MOVEI T2,.PFACN		;SEE IF AN ACCOUNT
	CALL FNDATR		;HAVE ONE?
	 MOVEI T3,[0]		;NO. PUT IN NULL STRING
	CALL ASCIIZ		;YES. PUT IT IN
NOUSED:	MOVEI T2,.PFOPT		;HAVE OPTIONAL USER DATA?
	CALL FNDATR		;?
	 JRST [	MOVEI T2,.PFBOP	;NO. TRY OTHER FORM
		CALL FNDATR
		 JRST INMENU	;NO USER DATA
		MOVEI T4,BININ	;FOUND IT
		JRST DOOPT]	;PUT IT IN
	MOVEI T4,ASCIIZ		;FOUND ASCII FORM
DOOPT:	MOVEI T2,2		;SAY FOUND OPTDATA
	IORM T2,NTCNT		;TO THE MENU
	CALL 0(T4)		;INSERT IT
INMENU:	MOVE T2,NTCNT		;GET FINAL MENU
	DPB T2,NTPNT		;PUT IT IN THE MESSAGE
	MOVEI T2,LLSCIS		;GET NEW STATE
	STOR T2,LLSTA,(T1)	;STORE NEW STATE
	LLLULK			;RELEASE TREE NOW
	MOVE T2,NTCIB		;GET BLOCK ADDRESS
	CALL SNDCTL		;SEND MESSAGE TO THE NETWORK
	RETSKP			;AND DONE FOR NOW
;ROUTINE TO INSERT THE LL ADDRESSES IN A MESSAGE.
;ACCEPTS:	T1/ LL BLOCK ADDRESS

PUTLLR:	TDZA T2,T2		;SAY SEND 0 SOURCE IF IN CIR
PUTLLA:	SETOM T2		;SAY ALWAYS SEND CURRENT SOURCE
	ACVAR <W1>		;GET A WORK REG
	MOVE W1,T2		;SAVE ENTRY FLAG
	LOAD T2,LLHLK,(T1)	;GET DEST ADDRESS
	CALL TWOBYT		;PUT IT IN
	LOAD T2,LLLNK,(T1)	;GET SOURCE ADDRESS
	JUMPN W1,PUTLL1		;IF NO REJECT CHECK, GO ON
	LOAD W1,LLSTA,(T1)	;GET LINK STATE
	CAIN W1,LLSCIR		;IS THIS A LINK REJECT THEN?
	SETZM T2		;YES. SEND 0 SOURCE ADDRESS
PUTLL1:	CALLRET TWOBYT		;AND PUT IT IN

;ROUTINE TO INSERT CI/CC COMMON FIELDS

;	T1/ LL BLOCK

DOSRVS:	CALL PUTLLA		;PUT IN LL ADDRESSES
	MOVEI T2,CISRVS+CIMSCT	;ASSUME SEG COUNTS
	OPSTR <SKIPE>,LLIMS,(T1) ;WANT MESSAGE COUNTS?
	TXC T2,CIMSCT+CIMCNT	;YES
	CALL ONEBYT		;PUT IN SERVICES BYTE
	MOVEI T2,LNKPRI		;GET DEFAULT PRIORITY
	CALL ONEBYT
	MOVEI T2,SEGSIZ		;GET SEGMENT SIZE
	OPSTR <SKIPE>,LLFDI,(T1) ;OPEN IN WORD MODE?
	MOVEI T2,WSEGSZ		;YES. GET PROPER SEG SIZE
	SETZRO LLFDI,(T1)	;INIT THIS FLAG
	CALLRET TWOBYT
;ROUTINE TO BUILD A ROUTING HEADER. CALLED FOR CONTROL MESSAGES
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ PROPER MESSAGE FLAGS

RTHDCI:	STKVAR <MSGFLG>		;TO SAVE MESSAGE FLAGS
	MOVEM T2,MSGFLG		;SAVE FLAGS
	MOVEI T2,RTFLG		;ROUTING FLAGS ARE FIRST
	CALL ONEBYT		;PUT IN FLAGS
	LOAD T3,LLHST,(T1)	;GET HOST STRING POINTER
	CALL ASCIIZ		;GO PUT IN IMAGE ASCII FIELD
	MOVEI T3,OURNAM		;GET OUR NAME
	CALL TSTLCL		;SEE IF A LOCAL CONNECTION
	 MOVEI T3,[0]		;IT IS
	CALL ASCIIZ		;PUT IT IN
	MOVE T2,MSGFLG		;GET MESSAGE FLAGS
	CALLRET ONEBYT		;AND PUT IT IN THE MESSAGE

;ROUTINE TO INSERT IMAGE-ASCII FIELD INTO MESSAGE
;		T2/ COUNT OF BYTES
;ACCEPTS:	T3/ BLOCK ADDRESS

ASCIIZ:	MOVX T2,1B1		;ENTRY FOR ZERO TERMINATED STRING
ASCIIC:	ACVAR <W1,W2,W3>	;GET A REGISTER
	MOVE W1,[POINT 7,0(T3)]	;GET A BYTE POINTER
	STKVAR <ASCCNT>		;THE COUNT
	MOVEM T2,ASCCNT		;SAVE COUNT
	SETZB T2,W3		;SET COUNT REGS
	CALL ONEBYT		;PUT IN ZERO COUNT
	MOVE W2,LLBPTR(T1)	;SAVE BYTE POINTER
ASCIIL:	SOSGE ASCCNT		;HAVE ANY MORE BYTES?
	JRST ASCIID		;NO. GO WRAP UP
	ILDB T2,W1		;GET NEXT BYTE
	JUMPG T2,ASCII1		;NO. IS THIS A NULL?
ASCIID:	DPB W3,W2		;YES.
	RET			;ALL DONE
ASCII1:	CALL ONEBYT		;STASH IT
	AOJA W3,ASCIIL		;AND DO ENTIRE STRING

;MOVE A BINARY FIELD

MVBNRY:	ACVAR <W1,W2>		;GET WORK REGS
	MOVE W1,[POINT 8,0(T3)]	;GET A POINTER
	MOVE W2,T2		;SAVE COUNT
MVBNR1:	CALL ONEBYT		;PUT IN THE BYTE
	SOJL W2,R		;ANY MORE?
	ILDB T2,W1		;GET NEXT BYTE
	JRST MVBNR1		;GO STASH IT
;MORE ROUTINES

;INSERT BINARY QUANTITY IN A MESSAGE
;ACCEPTS:	3/ BLOCK ADDRESS

BININ:	ACVAR <W1,W2,W3>	;GET A WORK REG
	SETZB T2,W2
	HRLI T3,(<POINT 7,>)	;FORM A BYTE POINTER
	CALL ONEBYT		;PUT IN COUNT BYTE
	MOVE W3,LLBPTR(T1)	;SAVE POINTER
BININ1:	MOVSI W1,-3		;DO 3 BYTES
	SETZ T2,		;AN ACCUMULATOR
BININ2:	CALL BINXT		;GET NEXT BYTE
	 JRST BININ3		;DONE
	LSH T2,3		;ADJUST ACCUMULATOR
	ADDI T2,-"0"(T4)	;PUT IN NEXT BYTE
	AOBJN W1,BININ2		;DO AN OCTET
BININ3:	TRNN W1,-1		;FOUND ANY?
	JRST BININ4		;NO. ALL DONE
	CALL ONEBYT		;YES. PUT IT IN
	AOS W2			;ONE MORE IN
	JUMPGE W1,BININ1	;IF MORE TO DO, DO THEM
BININ4:	DPB W2,W3		;PUT IN FINAL COUNT
	RET			;AND DONE

BINXT:	ILDB T4,T3		;GET NEXT BYTE
	JUMPE T4,R		;IF THE NULL, ALL DONE
	RETSKP			;A VALID BYTE

;ROUTINES TO INSERT BYTES IN MESSAGE AND ACCOUNT FOR THEM

;INSERT ONE BYTE. ACCEPTS:	T2/ THE BYTE
;				T1/ LL BLOCK ADDRESS
;PRESERVES ALL REGISTERS

ONEBYT:	IDPB T2,LLBPTR(T1)	;STASH BYTE
	AOS LLBPCT(T1)		;ACCOUNT FOR IT
	RET			;DONE

;ROUTINE TO INSERT TWO BYTES, EXTENDED OR NOT
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ THE BYTE
;MAY CLOBBER T2.

TWOBYT:	CALL ONEBYT		;STORE LOW ORDER BYTE
	ROT T2,-^D8		;GET HIGH ORDER BYTE
	CALLRET ONEBYT		;STORE IT
;ROUTINES TO FIND AND PARSE ARBITRARY ATTRIBUTES

;FIND ATTRIBUTE:
;ACCEPTS:	T2/ PREFIX VALUE
;RETURNS:	+1/ NO SUCH PREFIX
;		+2/ FOUND. T3=POINTER TO VALUE STRING

FNDATR:	LOAD T3,FILATL,(JFN)	;GET LIST OF ATTRIBUTES
FNDAT1:	JUMPE T3,R		;IF NO MORE, ALL DONE
	OPSTR <CAME T2,>,PRFXV,(T3) ;IS THIS THE ONE WE WANT
	JRST [	LOAD T3,PRFXL,(T3) ;NO. GET NEXT
		JRST FNDAT1]	;AND LOOK AT IT
	MOVEI T3,1(T3)		;GET POINTER TO BLCOK
	RETSKP			;AND SAY WE FOUND IT
;ROUTINE TO ASSIGN WINDOW PAGES TO A JFN.
;ACCEPTS:	NORMAL FILE SYSTEM REGISTER (JFN,ETC...)
;RETURNS:	+1	FAILED
;		+2	SUCCESS.

ASGWDW:	SETZM FILWND(JFN)
	SETZM FILBCT(JFN)	;AND CLEAR COUNTS
	TQNN <READF>		;WANT READ ON THIS FILE?
	JRST ASGWRT		;NO. TRY WRITE
	CALL ASGPAG		;GET A JSB PAGE
	 RETBAD (MONX02)	;COULDN'T
	HRRM T1,FILWND(JFN)	;SAVE WINDOW PAGE
	LDB T3,PBYTSZ		;GET BYTE SIZE
	CALL MAKINP		;GET A POINTER FOR INPUT
	MOVEM T1,FILBFI(JFN)	;INIT INPUT POINTER
ASGWRT:	TQNN <WRTF>		;WANT WRITE
	RETSKP			;NO ALL DONE
	CALL ASGPAG		;GET A PAGE FOR OUTPUT
	 JRST [	SKIPE T1,FILWND(JFN) ;FAILED. HAVE READ WINDOW?
		CALL RELPAG	;RELEASE THE INPUT PAGE
		SETZM FILBFI(JFN) ;CLEAN UP JFN BLOCK
		RETBAD (MONX02)] ;AND FAIL
	HRLM T1,FILWND(JFN)	;STORE WINDOW
	RETSKP			;AND DONE

;ROUTINE TO MAKE PROPER BYTE POINTER AND RETURN MAX COUNT FOR A
;BUFFER.
;ACCEPTS:	T1/ WINDOW ADDRESS
;		T3/ BYTE SIZE
;RETURNS:	+1
;		T1/ BYTE POINTER
;		T2/ COUNT

MAKPTR:	MOVE T4,T3		;SAVE IT
	IORI T3,4400		;MAKE A BYTE POINTER
	DPB T3,[POINT 12,T1,11]
	MOVEI T2,44		;BITS IN A WORD
	IDIVI T2,0(T4)		;COMPUTE BYTES IN A WORD
	LSH T2,PGSFT		;COMPUTE BYTES IN A PAGE
	RET			;AND DONE

;SPECIAL ROUTINE TO MAKE AN INPUT POINTER FOR FLOW FROM NETWORK

MAKINP:	PUSH P,T3		;SAVE BYTE SIZE
	CALL MAKPTR		;GET A POINTER
	POP P,T3		;GET BACK BYTE SIZE
	CAIN T3,44		;WORD MODE?
	HRRZS T1		;YES. GET ADDRESS ONLY
	RET			;DONE
;MTOPR ROUTINES

NTMTOP:	CALL NETINP		;SET UP FOR INPUT...
	MOVE T1,FILLLB(JFN)	;MUST LOCK UP BLOCK
	CALL BLKLOK		;DO IT
	 JRST WATBLK		;MUST WAIT FOR THE LOCK
	XCTU [HRRZ T2,2]	;GET FUNCTION CODE
	MOVSI T3,-NTMTCT	;SCAN TABLE FOR THE FUNCTION
NTMTO1:	HLRZ T4,NTMTTB(T3)	;GET NEXT ENTRY
	CAIN T2,0(T4)		;IS THIS IT?
	JRST [	HRRZ T2,NTMTTB(T3) ;GET DISPATCH ADDRESS
		JRST 0(T2)]	;AND GO DO IT
	AOBJN T3,NTMTO1		;DO ENTIRE TABLE
	MOVEI T1,MTOX1		;NOT FOUND
	JRST SQOBAD		;GIVE ERROR

NTMTTB:	.MOACN,,MTASGN		;SET CONNECT INTERRUPT
	.MORLS,,NTSTS		;READ LINK STATUS
	.MORHN,,NTRHN		;READ FOREIGN HOST NAME
	.MORTN,,NTRTN		;READ LINK TASK NAME
	.MORUS,,NTRUS		;READ USER STRING
	.MORPW,,NTRPW		;READ PASSWORD
	.MORAC,,NTRAC		;READ ACCOUNT STRING
	.MORDA,,NTRDA		;READ OPTIONAL DATA
	.MORIM,,MTRDIN		;READ INT MESSAGE
	.MOSIM,,MTSNIN		;SEND INT MESSAGE
	.MOROD,,NTRCOB		;READ OBJ-DESC OF CONNECT OBJECT
	.MOCLZ,,NTMTCZ		;CLOSE/REJECT A CONNECTION
	.MOCC,,NTACPT		;ACCEPT A CONNECTION
	.MORCN,,NTRCN		;READ CONNECT OBJECT NUMBER
	.MORSS,,MTGSS		;GET LINK SEGMENT SIZE
NTMTCT==.-NTMTTB		;LENGTH OF TABLE

;SET INTERRUPT CHANNEL NUMBERS

MTASGN:	ACVAR <W1>		;GET A WORK REG
	UMOVE W1,3		;GET ARGUMENT
	LOAD T2,MO%CDN,W1	;GET CONNECT INTERRUPT
	CALL MTSETC		;GO SET IT
	 JRST SQOBAD		;BAD
	LOAD T2,MO%INA,W1	;GET INT CHANNEL
	CALL MTSETI		;GO DO INT CHANNEL
	 JRST SQOBAD		;BAD
	LOAD T2,MO%DAV,W1	;GET DATA CHANNEL
	CALL MTSETD		;SET IT
	 JRST SQOBAD		;BAD
	CALL BLKULK		;FREE BLOCK
	RETSKP			;AND DONE
;MTOPR FUNCTIONS CONTINUED...

;READ LINK TASK NAME

NTRTN:	LOAD T2,LLTSK,(T1)	;GET THE NAME
NTCPY:	CALL NTACPY		;DO THE WORK
	CALL BLKULK		;RELEASE LL BLOCK
	RETSKP			;AND DONE

;READ FOREIGN HOST NAME

NTRHN:	CALL MTRDCK		;VERIFY LINK STATE
	JRST [	MOVEI T1,DCNX11	;SAY NOT CONNECTED ANYMORE
		JRST SQOBAD]	;AND DONE
	LOAD T2,LLHST,(T1)	;YES. GET HOST STRING
	CALL TSTLCL		;IS THIS A LOCAL  CONNECTION?
	 MOVEI T2,OURNAM	;YES. USE  LOCAL NAME THEN
	CALLRET NTCPY		;AND GO COPY TO USER

;WORKER ROUTINE TO COPY AN ASCII STRING TO THE USER.
;		T2/ ADDRESS OF STRING BLOCK

NTACPY:	UMOVE T3,3		;GET USER'S STRING POINTER
	TLC T3,-1
	TLCN T3,-1		;WANT DEFAULT?
	HRLI T3,(<POINT 7,>)	;USE. DO IT
	ACVAR <W1>		;GET A WORK REG
	MOVE W1,[POINT 7,0(T2)]	;POINT TO SOURCE
NTCPY1:	ILDB T4,W1		;GET A BYTE
	JUMPE T4,NTCPY2		;IF NULL, ALL DONE
	XCTBU [IDPB T4,T3]	;STORE BYTE
	JRST NTCPY1		;DO THEM ALL
NTCPY2:	UMOVEM T3,3		;RETURN BYTE POINTER
	XCTBU [IDPB T4,T3]	;APPEND A NULL
	RET			;AND DONE
;MTOPR FUNCTIONS CONTINUED...

;READ LINK STATUS

NTSTS:	LOAD T3,LLRSN,(T1)	;GET REASON IN CASE NOW DISCONNECTED
	OPSTR <SKIPE>,LLFOB,(T1) ;IS THIS AN OBJECT?
	TXO T3,MO%SRV		;YES
	LOAD T2,LLSTA,(T1)	;GET CURRENT STATE
	CAIN T2,LLSRUN		;RUNNING?
	TXO T3,MO%CON		;YES. ALL CONNECTED
	CAIE T2,LLSLIS		;LISTENING?
	CAIN T2,LLSCIS		;OR CI SENT?
	TXO T3,MO%WFC		;YES. WAITING FOR CONNECT THEN
	CAIN T2,LLSCIR		;CI RECEIVED?
	TXO T3,MO%WCC		;YES. WAITING FOR US TO CONFIRM
	CAIE T2,LLSDIR		;DI RECEIVED?
	CAIN T2,LLSABT		;OR ABORTED?
	JRST [	TXO T3,MO%ABT	;YES. ASSUME ABORTED
		JE LLFDI,(T1),.+1
		TXC T3,MO%ABT!MO%SYN ;NO. SWITCH TO SYNCH DI
		JRST .+1]	;AND PROCEED
	OPSTR <SKIPE>,LLFIM,(T1) ;HAVE WHOLE MESSAGE IN BUFFER?
	TXO T3,MO%EOM		;YES
	SKIPE LLMSI(T1)		;HAVE ANY INTERRUPT MESSAGES?
	TXO T3,MO%INT		;YES. SAY SO
	JN LLLWC,(T1),[TXO T3,MO%LWC ;NOTE LINK WAS CONNECTED IF CC RECEIVED
		      JRST .+1]	;CONTINUE
	UMOVEM T3,3		;RETURN RESULT
	CALL BLKULK		;FREE BLOCK
	RETSKP			;AND DONE

;MTOPR FUNCTION TO RETURN OBJECT USED TO CONNECT TO THE SERVER

NTRCN:	JE LLFOB,(T1),[CALL BLKULK ;FREE BLOCK
			RETBAD (DESX9)] ;AND RETURN ERROR
	LOAD T2,LLSTA,(T1)	;GET CURRENT STATE
	CAIN T2,LLSLIS		;LISTENING?
	JRST [	MOVEI T1,DCNX11	;YES. NOT CONNECTED
		JRST SQOBAD]	;GO CLEAN UP AND GIVE ERROR
	LOAD T2,LLSOB,(T1)	;GET OBJECT USED TO CONNECT
	UMOVEM T2,3		;RETURN TO USER
MTDON:	CALL BLKULK		;FREE BLOCK
	RETSKP			;AND DONE
;MORE MTOPR ROUTINES...

;READ USER NAME

NTRUS:	CALL MTOBJ		;MAKE SURE IS RUNNING OBJECT
	 JRST SQOBAD		;NOT
	LOAD T2,LLUSR,(T1)	;GET BLOCK ADDRESS
	CALLRET NTCPY		;GO DO IT

;READ ACCOUNT STRING

NTRAC:	CALL MTOBJ		;MAKE SURE IS RUNNING OBJECT
	 JRST SQOBAD		;NOT
	LOAD T2,LLACT,(T1)	;GET BLOCK
	CALLRET NTCPY		;AND GO DO IT

;COMMON ROUTINE TO VERIFY OBJECT


MTOBJ:	JE LLFOB,(T1),MTOBJ1	;MAKE SURE IS OBJECT
MTRDCK:	LOAD T2,LLSTA,(T1)	;IT IS. GET CURRENT STATE
	CAIN T2,LLSCIR		;IN CIR STATE?
	RETSKP			;YES. IS GOOD THEN
MTRNCK:	LOAD T2,LLSTA,(T1)	;GET STATE
	CAIN T2,LLSRUN		;RUNNING?
	RETSKP			;YES.
MTOBJ1:	RETBAD (DCNX11)		;NOT A RUNNING OBJECT

;READ PASSWORD

NTRPW:	CALL MTOBJ		;MAKE SURE IS RUNNING OBJECT
	 JRST SQOBAD		;NOT
	LOAD T2,LLPSW,(T1)	;GET BLOCK ADDRESS
	LOAD T3,LLPCT,(T1)	;AND THE COUNT
NTCPYB:	UMOVEM T3,4		;RETURN COUNT
	ACVAR <W1,W2>		;GET WORK REGS
	MOVE W2,T3		;SAVE COUNT
	MOVE W1,[POINT 8,0(T2)]	;GET POINTER TO DATA
	UMOVE T3,3		;GET USER SP
	TLC T3,-1
	TLCN T3,-1
	HRLI T3,(<POINT 7,>)	;FORM DEFAULT
	JRST NTCP11		;GO MAKE SURE IS AT LEAST ONE
NTCP1:	ILDB T4,W1		;GET NEXT BYTE
	XCTBU [IDPB T4,T3]	;STORE IT
NTCP11:	SOJGE W2,NTCP1		;AND DO THEM ALL
	UMOVEM T3,3		;RETURN BYTE POINTER
NTMTGD:	CALL BLKULK		;FREE THE BLOCK
	RETSKP			;AND DONE
;READ OPT DATA

NTRDA:	LOAD T2,LLOPT,(T1)	;GET OPTIONAL DATA BLOCK
	LOAD T3,LLUCT,(T1)	;GET COUNT
	CALLRET NTCPYB		;AND GO DO IT

;SET CONNECT DONE INTERRUPT CHANNEL

MTSETC:	CALL CHKCHL		;VERIFY CHANNEL
	 RET			;BAD
	JUMPL T2,RSKP		;IF NO CHANGE, DONE
	STOR T2,LLPIC,(T1)	;SAVE CHANNEL
	LOAD T3,LLSTA,(T1)	;GET STATE OF LINK
	CAIL T3,LLSCIR		;NEED INTERRUPT NOW?
	CALL CONINT		;YES. GIVE IT
	RETSKP			;AND DONE

;SET INTERRUPT MESSAGE CHANNEL

MTSETI:	CALL CHKCHL		;CHECK CHANNEL
	 RET			;BAD
	JUMPL T2,RSKP		;IF NO CHANGE, ALL DONE
	STOR T2,LLPII,(T1)	;SAVE CHANNEL
	SKIPE LLMSI(T1)		;HAVE ANY INT MESSAGES
	CALL INTINT		;YES. DO INTERRUPT NOW THEN
	RETSKP			;AND DONE

;SET DATA ARRIVED INT CHANNEL

MTSETD:	CALL CHKCHL		;VERIFY CHANNEL
	 RET
	JUMPL T2,RSKP		;IF NO CHANGE, RETURN
	STOR T2,LLDRC,(T1)	;SAVE CHANNEL
	OPSTR <SKIPN>,LLDRW,(T1) ;HAVE ANY MESSAGES ON RAW Q?
	SKIPE LLOMSG(T1)	;NO. ANY ORDERED MESSAGES?
	CALL DATINR		;YES. GIVE INT THEN
	RETSKP			;DONE
;ROUTINE TO VERIFY CHANNEL #
;		T2/ CHANNEL
;RETURNS:	+1 BAD CHANNEL
;		+2 VALID CHANNEL

CHKCHL:	CAIN T2,.MOCIA		;CLEAR?
	JRST [	SETZM T2	;IF SO. UNSETTING
		RETSKP]		;SO, RETURN A ZERO
	CAIN T2,.MONCI		;NO CHANGE?
	JRST [	SETOM T2	;YES
		RETSKP]		;SO SAY SO
	CAIL T2,44		;WITHIN RANGE?
	JRST CHKILL		;NO
	CAILE T2,5		;WITHIN RANGE 0-5?
	CAIL T2,^D23		;OR WITHIN RANGE 23-35
	AOSA T2			;YES. A GOOD CHANNEL
	JRST CHKILL		;NO. ILLEGAL
	RETSKP			;RETURN GOOD VALUE
CHKILL:	RETBAD (ARGX13)		;INVALID CHANNEL

;COMMON ROUTINE TO GENERATE INTERRUPT RECEIVED INTERRUPT

INTINT:	SAVET			;SAVE REGS
	LOAD T2,LLFRK,(T1)	;GET FORK TO INT
	OPSTR <SKIPN T1,>,LLPII,(T1) ;HAVE AN INT CHANNEL?
	RET			;NO
	SOS T1			;YES
	CALLRET PSIRQ		;GO DO THE INTERRUPT
;MORE MTORP FUNCTIONS...

;RECEIVE INTERRUPT MESSAGE

MTRDIN:	CALL MTRNCK		;CHECK STATE
	 JRST SQOBAD		;ERROR
	ACVAR <W1>		;GET A REG
	SKIPN T2,LLMSI(T1)	;HAVE AN INT MESSAGE?
	JRST [	MOVEI T1,DCNX11	;NO.
		CALLRET SQOBAD]	;GIVE ERROR
	LOAD T3,MSSEG,(T2)	;GET SEG NUMBER
	STOR T3,LLIIN,(T1)	;IT IS NOW LAST ACKED SEG
	CALL ACKLI		;GO ACK IT
	 JRST SQOBAD		;GO BLOCK
	MOVEI T2,1		;ASK FOR ONE MORE
	MOVEI T3,MSLSI		; INTERRUPT MESSAGE
	CALL SNDLS		;SEND MESSAGE
	 JRST SQOBAD		;NEED TO BLOCK
	MOVE T2,LLMSI(T1)	;GET BACK MESSAGE
	SETZM LLMSI(T1)		;NONE NOW
	LOAD T4,MSDTC,(T2)	;GET COUNT
	UMOVEM T4,4		;RETURN COUNT TO USER
	UMOVE T3,3		;GET USER;S BYTE POINTER
	TLC T3,-1
	TLCN T3,-1
	HRLI T3,(<POINT 7,>)	;GET DEFAULT
	UMOVEM T3,3		;RETURN BYTE POINTER
	MOVE T3,MSBPTR(T2)	;GET POINTER TO MESSAGE DATA
	JRST MTRDI2		;GO MOVE DATA
MTRDI1:	ILDB W1,T3		;GET NEXT BYTE
	XCTBUU [IDPB W1,3]	;STORE IT
MTRDI2:	SOJGE T4,MTRDI1		;DO THEM ALL
	CALL BLKULK		;DONE WITH BLOCK
	MOVE T1,T2		;GET FREE SPACE ADDRESS
	CALL RELRES		;RELEASE MESSAGE
	RETSKP			;AND DONE
;MORE MTOPR'S....  SEND INTERRUPT MESSAGE

MTSNIN:	CALL MTRNCK		;MAKE SURE IS RUNNING
	 JRST SQOBAD		;NOT. ERROR
	UMOVE T4,4		;GET COUNT
	CAILE T4,MAXDSC		;WITHIN RANGE?
	JRST [	MOVEI T1,DCNX12	;ARG TOO LARGE
		JRST SQOBAD]	;GIVE ERROR
	JE LLMIC,(T1),[	MOVEI T1,DCNX14 ;ANY QUOTA?
			JRST SQOBAD] ;NO
	ACVAR <W1>		;CAN SEND IT
	MOVEI T1,INTLEN+MSHDR	;LENGTH
	CALL GETRES		;GET SOME SPACE
	 JRST SQOBAD		;NONE AVAIABLE. TRY LATER
	MOVE W1,T1		;SAVE BLOCK ADDRESS
	MOVEI T2,MSHDR(T1)	;GET TO DATA PART
	HRLI T2,(<POINT 8,>)
	MOVE T1,FILLLB(JFN)	;GET LL BLOCK
	MOVEM T2,LLBPTR(T1)	;THE POINTER
	SETZM LLBPCT(T1)	;INIT COUNT
	MOVEI T2,DATMFL+DATFLI+DATINT ;FLAGS
	STOR T2,MSMFL,(W1)	;SAVE IN MESSAGE
	CALL ONEBYT		;INTO THE MESSAGE
	CALL PUTLLA		;PUT IN LL ADDRESSES
	LOAD T2,LLISN,(T1)	;GET SEG #
	AOS T2			;NEXT ONE
	ANDI T2,7777		;MOD 4096
	STOR T2,MSSEG,(W1)	;SAVE IN MESSAGE
	STOR T2,LLISN,(T1)	;LAST SEG SENT
	CALL TWOBYT		;PUT IN DATA PART
	DECR LLMIC,(T1)		;ONE LESS PIECE OF QUOTA
	UMOVE T4,4		;GET COUNT
	UMOVE T3,3		;GET BP
	TLC T3,-1
	TLCN T3,-1
	HRLI T3,(<POINT 7,>)	;FORM DEFAULT
	UMOVEM T3,3		;STORE IT BACK
	JRST MSTSN2		;GO SEND THEM
MSTSN1:	XCTBUU [ILDB T2,3]	;GET NEXT BYTE
	CALL ONEBYT		;STORE IN MESSAGE
MSTSN2:	SOJGE T4,MSTSN1		;DO THEM ALL
	LOAD T2,LLLNK,(T1)	;GET LINK ADDRESS
	STOR T2,MSLLA,(W1)	;SAVE IN MESSAGE
	MOVEI T2,MSLSI		;GET TYPE OF THIS MESSAGE
	STOR T2,MSTOM,(W1)	;SAVE IN MESSAGE
	MOVE T2,W1		;GET MESSAGE
	CALL SNDSEG		;SEND IT
	MOVE T1,FILLLB(JFN)	;GET BACK BLOCK ADDRESS
	JRST MTDON		;AND DONE
;MTOPR ROUTINE TO RETURN OBJECT-DESCRIPTOR.
;RETURNS OBJECT-DESCRIPTOR IN STRING POINTED TO BY USER AC3
;RETURNS USER,GROUP CODE IN AC4 (OR A ZERO IN AC4 IF NONE).

NTRCOB:	JE LLFOB,(T1),NTRCB1	;MAKE SURE IT IS AN OBJECT
	LOAD T2,LLSTA,(T1)	;GET STATE
	CAIE T2,LLSCIR		;RECIEVED A CI?
	CAIN T2,LLSRUN		;OR RUNNING?
	SKIPA			;YES
NTRCB1:	JRST [	CALL BLKULK	;NO. UNLOCK BLOCK
		JRST MTOBJ1]	;AND DONE
	MOVE T2,LLUSGP(T1)	;GET USER,GROUP
	UMOVEM T2,4		;RETURN IT
	LOAD T2,LLFNM,(T1)	;GET OBJ NUMBER USED IN CI
	MOVE T3,[-OBJENT,,OBJPRO+1] ;SET UP FOR SEARCH
NTRCB2:	HRRZ T4,0(T3)		;GET OBJECT NUMBER
	CAIN T4,0(T2)		;THIS THE ONE?
	JRST [	HLRZ T2,0(T3)	;YES. GET POINTER TO NAME
		JRST NTRCB3]	;AND PROCEED
	AOBJN T3,NTRCB2		;NO. LOOK AT NEXT
	STKVAR <NTRCBN>		;NOT FOUND
	MOVEI T3,12		;CONVERT OBJECT NUMBER TO TEXT
	HRROI T1,NTRCBN
	NOUT
	 JFCL
	MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK
	MOVEI T2,NTRCBN		;GET POINTER TO NUMBER
NTRCB3:	CALL NTACPY		;PUT OBJECT STRING IN USER SPACE
	LOAD T3,LLFDS,(T1)	;GET DESCRIPTOR
	SKIPN 0(T3)		;HAVE ONE?
	JRST MTDON		;NO. ALL DONE THEN
	MOVEI T2,[ASCIZ /-/]	;YES. PUT IN PUNCTUATION
	CALL NTACPY
	LOAD T2,LLFDS,(T1)	;GET BACK DESCRIPTOR STRING
	CALLRET NTCPY		;AND DONE
;MTOPR FUNCTION TO REFUSE A CONNECTION
;*************** NOTE *******************
;THIS CODE HAS A RACE IN THAT THE LINK IS IMMEDIATELY CONVERTED
;INTO A "LISTENER". THEREFORE, WHEN THE DC ARRIVES, THERE
;IS POTENTIAL CONFUSION OVER THE OWNER. THE
;PROBABILITY OF FAILURE IS <1/(HOSTS*2**16)> WHERE,
;"HOSTS" = # OF HOSTS ON THE NET.

NTRJCT:	CALL NTRFCI		;SEND DI
	 JRST SQOBAD		;NEED TO BLOCK
	CALL FLUSH		;KILL OF BUFFERS (IF ANY)
	CALL CLRBLK		;RESET LL BLOCK
	MOVEI T2,LLSLIS		;GET NEW STATE
	STOR T2,LLSTA,(T1)	;SET IT BACK TO LISTENING
	CALLRET NTMTGD		;AND DONE

;MTOPR FUNCTION TO CLOSE A CONNECTION

NTMTCZ:	LOAD T2,LLSTA,(T1)	;GET CURRENT STATE
	CAIN T2,LLSCIR		;REALLY REJECTING A CONNECTION?
	CALLRET NTRJCT		;YES. GO DO IT
	CAIN T2,LLSDIQ		;DI QUEUED?
	JRST NTMCZ0		;YES. GO ON THEN
	CAIE T2,LLSRUN		;NOW CONNECTED?
	JRST NTRCB1		;NO. CAN;T DISCONNECT THEN
	UMOVE T2,2		;GET DISCONNECT REASON
	SKIPE T2		;NORMAL CLOSE?
	CAIN T2,.DCX11		;OR THIS WAY?
	SKIPA			;YES. GO ON
	JRST [	CALL FLUSH	;ABORT CLOSE. CLEAN OUT MESSAGES
		JRST NTMCZ0]	;AND SEND THE MESSAGE
	JE LLQOU,(T1),NTMCZ0	;IF QUEUER EMPTY, GO ON.
	CALL MOVSEG		;PICK UP ACKS
	 JRST OUTWAT		;NEED TO BLOCK
	MOVEI T2,CHKEMP		;WAIT FOR ALL ACKS
	JRST OUTWAT		; AND GO DO IT

;READY TO SEND THE MESSAGE

NTMCZ0:	MOVEI T2,LLSDIQ		;SET STATE
	STOR T2,LLSTA,(T1)	;""
	CALL NTRFCI		;SEND DI
	 JRST SQOBAD		;MUST WAIT
	MOVEI T2,LLSDIS		;NEW STATE
	STOR T2,LLSTA,(T1)	;STORE IT
	CALLRET NTMTGD		;AND DONE

;ROUTINE TO ACCEPT A CONNECTION

NTACPT:	STKVAR <<OPTDAT,4>>
	LOAD T2,LLSTA,(T1)	;GET STATE
	CAIE T2,LLSCIR		;PROPER STATE
	JRST NTRCB1		;NO. ERROR
	MOVEI T3,OPTDAT		;MOVE OPTDATA IF ANY
	CALL NTMVOP		;GET OPTDATA ARG
	 JRST SQOBAD		;TOO LONG
	CALL CNFCOM		;GO CONFIRM IT
	 JRST SQOBAD		;NEED TO WAIT
	CALLRET NTMTGD		;DONE

;MTOPR TO RETURN MAX SEGMENT SIZE FOR THE LINK

MTGSS:	CALL MTRNCK		;MUST BE RUNNING
	 JRST SQOBAD		;NOT
	LOAD T2,LLSWG,(T1)	;GET MAX SEG SIZE
	UMOVEM T2,3		;RETURN TO USER
	CALLRET NTMTGD		;AND DOEN
;COMMON ROUTINE USED TO SET UP FOR CALL TO SNDDI TO DISCONNECT
;OR REFUSE A CONNECTION.

NTRFCI:	STKVAR <<OPTDAT,4>>	;GET SOME SPACE TO HOLD USER DATA
	MOVEI T3,OPTDAT		;WHERE TO MOVE OPTDATA TO
	CALL NTMVOP		;DO IT
	 RETBAD ()		;TOO LONG?
	XCTU [HLRZ T2,2]	;GET REASON
	MOVEI T4,CNMRFL+CNMDI	;GET PROPER FLAGS
	CALL SNDDI		;SEND THE DI
	 RETBAD			;MUST WAIT AWHILE
	CALL SNDCTL		;SEND THE MESSAGE
	RETSKP			;AND DONE

;ROUTINE TO COPY OPTDATA TO A BUFFER AND RETURN PROPER OPTDATA
;ARG
;	T3/ BUFFER ADDRESS
;RETURNS:	+1 TOO LONG
;		+2 DONE

NTMVOP:	ACVAR <W1,W2,W3>
	MOVE W3,T3		;SAVE BUFFER ADDRESS
	SETZM T3		;ASSUME NO DATA
	UMOVE T4,4		;GET COUNT
	JUMPE T4,RSKP		;IF NONE, NO ARG
	SKIPL T4		;COUNT MUST BE POSITIVE
	CAILE T4,MAXDSC		;WITHIN LIMITS?
	 RETBAD (DCNX12)	;NO. TOO LONG
	STOR T4,CNTFLD,W3	;BUILD RETURN ARG
	MOVE W2,[POINT 8,0(W3)]	;GET POINTER TO SOURCE
	UMOVE T3,3		;GET USER'S POINTER
NTMVO1:	XCTBU [ILDB W1,T3]	;GET BYTE
	IDPB W1,W2		;STASH IT
	SOJG T4,NTMVO1		;COPY THEM ALL
	MOVE T3,W3		;GET ARG
	RETSKP			;AND DONE
;CODE TO DO CLOSF

NETCLZ:	ACVAR <W1,W2>		;GET SOME WORK REGISTERS
	MOVE W2,T1		;SAVE ENTRY FLAGS
	CALL NETUOU		;UNDO OUTPUT
NETCL1:	MOVE T1,FILLLB(JFN)	;GET LL BLOCK ADDRESS
	CALL BLKLOK		;LOCK THE BLOCK
	 JRST [	TXNN W2,CZ%ABT	;ABORT?
		JRST WATBLK	;NO. CONVENTIONAL WAIT THEN
		MDISMS		;YES. WAIT HERE
		JRST NETCL1]	;AND TRY AGAIN
	CALL MOVSEG		;PICK UP LATENT ACKS
	 MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK ADDRESS
	LOAD T2,LLSTA,(T1)	;GET CURRENT STATE
	JRST @CLZSTA-1(T2)	;GO DO PROPER THING
;STATE ROUTINES OF NETCLZ
;LINK IN RUN STATE

CLZRUN:	TXNE W2,CZ%ABT		;WANT ABORT?
CLZDI:	JRST [	MOVEI T2,.DCX9	;YES. SAY USER ABORT
		JRST CLZEMP]	;AND GO SEND DI,ETC...
	LOAD T3,LLBSZ,(T1)	;GET BYTE SIZE
	CALL MAKPTR		;COMPUTE MAX BYTES IN BUFFER
	MOVE T1,FILLLB(JFN)	;GET BACK POINTER
	HLRZ T3,FILBCT(JFN)	;SEE IF ANY BYTES
	SUBI T2,0(T3)		;COMPUTE BYTES TO BE SENT
	OPSTR <SKIPE>,LLFLO,(T1); FLOW NOW TO F/S?
	SKIPE T2		;YES. ANY BYTES?
	SKIPA			;HAVE DATA TO SEND
	JRST CLZCMS		;ALL DATA SENT. WAIT FOR ACKS
	SETONE LLFEM,(T1)	;SAY EOM IN THIS BUFFER
	CALL OUTRR		;GO FORCE OUT DATA
	 RETBAD()		;COULDN'T. WAIT A WHILE
	MOVE T1,FILLLB(JFN)	;RESTORE LL BLOCK ADDRESS

;ALL DATA OUT. WAIT FOR ACKS

CLZCMS:	SETZ T2,		;SYNCHRONOUS DI
	JE LLQOU,(T1),CLZEMP	;IF ALL ACK'ED, READY TO GO
	MOVEI T2,CHKEMP		;WAIT FOR EMPTY
	JRST OUTWAT		;AND ARRANGE FOR THE WAIT
CLZEMP:	STOR T2,LLRSN,(T1)	;SAVE REASON CODE
	MOVEI T2,LLSDIQ		;DI IS NOW QUEUED
	STOR T2,LLSTA,(T1)	;MARK STATE CHANGE
CLZDIQ:	SETZM T3		;NO USER DATA
	LOAD T2,LLRSN,(T1)	;GET OUR REASON
	MOVEI T4,CNMRFL+CNMDI	;IS A DI
	CALL SNDDI		;GO SEND DI
	 JRST [	TXNN W2,CZ%ABT	;ABORT?
		JRST SQOBAD	;NO. CONVENTIONAL WAIT
		BUG (INF,CLZDIN,<NETCLZ-COULD NOT SEND DI>)
		CALL MOVUNL	;TURN OFF BLOCK. RESTORE LL POINTER
		JRST CLZDQ1]	;AND PROCEED
	CALL SNDCTL		;SEND THE MESSAGE
CLZDQ1:	MOVEI T2,LLSDIS		;SAY DI IS SENT
	STOR T2,LLSTA,(T1)
CLZWDC:	TXNE W2,CZ%ABT		;ABORT CLOSE?
	JRST [	SETONE LLSDE,(T1) ;YES. DISSOCIATE PROCESS AND LINK
		CALL FLUSH	;KILL OF QUEUES
		CALL BLKULK	;FREE THE BLOCK
		JRST CLZDN1]	;AND GO FINISH UP
	MOVEI T2,CHKDCR		;WAIT FOR DC TO COME BACK
	JRST OUTWAT
;MORE CLOSE ROUTINES
;DC HAS ARRIVED. FIND OUT IF IT WHAT WE WANTED

CLZDIR:				;CLOSE IN DI RECEIVED STATE
CLZABT:	LOAD T2,LLRSN,(T1)	;GET REASON
	SKIPE T2		;NON-SPECIAL ERROR?
	CAIN T2,.DCX42		;OR REPLY TO DI?
	JRST CLZDON		;YES. GOOD CODE
	TXNN W2,CZ%ABT		;NOT. ARE WE ABORTING?
	JRST [	CALL BLKULK	;NO. SYNCH DI DIDN'T WORK
		RETBAD (DCNX11)] ;SAY SO
CLZDON:	CALL FLUSH		;CLEAN UP Q'S
	LLLOCK			;LOCK THE TREE
	CALL DELNOD		;GET RID OF NODE
	LLLULK
	OKINT			;MATCH BLKLOK THAT IS NEVER MATCHED
CLZDN1:	DECR DCCUR		;GIVING BACK A LINK
	HLRZ T1,FILWND(JFN)	;GET OUTPUT WINDOW
	SKIPE T1
	CALL RELPAG		;RELEASE IT
	HRRZ T1,FILWND(JFN)	;GET INPUT WINDOW
	SKIPE T1
	CALL RELPAG		;RELEASE IT
	SETZM FILBFO(JFN)
	SETZM FILBFI(JFN)
	RETSKP			;AND DONE
;ROUTINE TO SEND A DI OR A DC

;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ REASON
;		T3/ <COUNT>B5+PTR TO USER DATA
;		T4/ FLAGS
;RETURNS:	+1/ COULDN'T. TEST ROUTINE IN T1
;		+2/ ALL SENT

SNDDI:	ASUBR <LLBLK,DISRSN,DIUDAT,DIFLGS>
	STKVAR <LLMSGB>
	MOVEI T1,DILEN+MSHDR	;GET A BLOCK FOR THE DI
	CALL GETRES		;GET IT
	 JRST GENWAT		;FAILED
	MOVEM T1,LLMSGB		;SAVE BLOCK ADDRESS
	MOVEI T2,MSHDR(T1)	;GET TO START OF DATA PORTION
	HRLI T2,(<POINT 8,>)
	MOVE T1,LLBLK		;GET BACK LL BLOCK ADDRESS
	MOVEM T2,LLBPTR(T1)	;SAVE POINTER
	SETZM LLBPCT(T1)	;INIT COUNT
	MOVE T2,DIFLGS		;GET FLAGS
	CALL RTHDCI		;PUT ON ROUTING HEADER
	CALL PUTLLR		;PUT IN LL ADDRESSES
	MOVE T2,DISRSN		;GET REASON
	CALL TWOBYT		;PUT IT IN
	MOVE T3,DIFLGS		;SEE IF DI OR DC
	CAIN T3,CNMRFL+CNMDC	;DC?
	JRST SNDDI1		;YES. NO OPTDATA THEN
	MOVE T3,DIUDAT		;GET USER DATA
	LOAD T2,CNTFLD,T3 	;YES. GET COUNT
	SETZRO CNTFLD,T3 	;CLEAR THOSE BITS
	CALL MVBNRY		;PUT IN THE DATA
SNDDI1:	MOVE T2,LLMSGB		;GET BACK BLOCK ADDRESS
	RETSKP			;AND DONE
;ROUTINES CALLED FROM FILE SYSTEM TO SWITCH THE SENSE OF THE
;JFN. FIRST, ROUTINE TO SWITCH JFN TO INPUT SENSE

NETINP:	CALL NETUOU		;GO UNDO OUTPUT IF NECESSARY
	CALL NETUIN		;UNDO INPUT
	MOVE T1,FILLLB(JFN)	;GET LL BLOCK
	CALL BLKLOK		;LOCK IT UP
	 JRST [	MDISMS		;WAIT FOR LOCK
		JRST NETINP]	;AND TRY AGAIN
	TQO <FILINP>		;NOW WILL SWITCH TO INPUT
	LOAD T3,LLSTA,(T1)	;GET STATE
	CAIN T3,LLSDIS		;DID USER TERMINATE LINK ?
	JRST [	CALL BLKULK	;YES, UNLOCK LOGICAL LINK BLOCK
		SETZM T1	;NOTE NO MORE INPUT AVAILABLE
		RET ]		;AND DONE
	CAIE T3,LLSRUN		;RUNNING?
	CAIN T3,LLSDIR		;OR STILL AVAILBALE FOR INPUT?
	SKIPA			;YES
	JRST NETIN2		;NO. GO ON
	HRRZ T3,FILBCT(JFN)	;GET COUNT OF BYTES
	OPSTR <SKIPE>,LLFLI,(T1) ;IS FLOW FROM NETWORK?
	SKIPN T3		;NO. NEED BYTES?
	CALL NETSET		;YES. GO GET SOME BYTES
	 MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK ADDRESS
	TQZ <BLKF>		;IGNORE BLOCKING IF SET
NETIN2:	CALL BLKULK		;FREE LOCK
	MOVE T2,FILBFI(JFN)	;GET INPUT BYTE POINTER
	HRRZ T1,FILBCT(JFN)	;GET COUNT
	MOVE T3,FILLLB(JFN)	;GET LL BLOCK
	OPSTR <SKIPE>,LLFLI,(T3) ;IS INPUT FLOW TO THE F/S?
	SKIPE LLMSI(T3)		;YES. FREE OF INT MESSAGES
	SETZM T1		;NO. USE ZERO COUNT THEN
NETSCM:	MOVEM T1,FILCNT(JFN)	;TO THE JFN
	MOVEM T2,FILBYT(JFN)	;STORE NEW POINTER
	SETZM FILBYN(JFN)	;ZERO BYTE NUMBER
	JUMPE T1,R		;IF NO COUNT, RETURN NOW
	OPSTR <SKIPN>,LLFIM,(T3) ;EOM IN THE INPUT BUFFER?
	AOS T1			;NO. MAKE SINR COME BACK THEN
	MOVEM T1,FILLEN(JFN)	;AND MAKE COUNT THE LENGTH
	RET			;DONE

;ROUTINE TO SET UP FOR OUTPUT

NETOUP:	CALL NETUIN		;UNDO INPUT IF NECESSARY
	TQOE <FILOUP>		;NOW DOING OUTPUT?
	RET			;YES. ALL DONE
	MOVE T2,FILBFO(JFN)	;GET POINTER
	HLRZ T1,FILBCT(JFN)	;GET COUNT
	MOVE T3,FILLLB(JFN)	;GET LL BLOCK
	OPSTR <SKIPN>,LLFLO,(T3) ;IS OUTPUT FLOW FROM THE F/S?
	SETZM T1		;NO.
	JRST NETSCM		;AND DONE
;SET UP ROUTINES CONTINUED...

;UNDO OUTPUT

NETUOU:	TQZN <FILOUP>		;NOW DOING OUTPUT?
	RET			;NO. ALL DONE
	MOVE T1,FILLLB(JFN)	;GET LL BLOCK
	OPSTR <SKIPN>,LLFLO,(T1) ;FLOW FROM THE F/S?
	RET			;NO. DONE
	MOVE T1,FILCNT(JFN)	;GET COUNT
	SKIPGE T1
	SETZM T1		;ONLY ALLOW DOWN TO ZERO
	HRLM T1,FILBCT(JFN)	;STORE NEW COUNT
	MOVE T1,FILBYT(JFN)	;GET BYTE POINTER
	MOVEM T1,FILBFO(JFN)	;SAVE IT
	RET			;DONE

;UNDO INPUT

NETUIN:	TQZN <FILINP>		;NOW DOING INPUT?
	RET			;NO. ALL DONE
	MOVE T1,FILLLB(JFN)	;GET LL BLOCK
	OPSTR <SKIPN>,LLFLI,(T1) ;FLOW TO THE F/S?
	RET			;NO. ALL DONE
	MOVE T1,FILCNT(JFN)	;GET COUNT
	SKIPGE T1		;VALID COUNT?
	SETZM T1		;ONLLY ALLOW DOWN TO ZERO
	HRRM T1,FILBCT(JFN)	;SAVE IT
	MOVE T1,FILBYT(JFN)	;GET BYTE POINTER
	MOVEM T1,FILBFI(JFN)	;SAVE IT
	RET			;AND DONE
;ROUTINE TO COMPUTE NUMBER OF USEFUL BYTES IN A JSB STRING.
;CALLED FROM ROUTINES THAT PROCESS NETWORK FILE NAMES.
;ACCEPTS:	T1/FREE BLOCK ADDRESS
;	TRVAR <NTCNT,NTPNT,.....>
;RETURNS:	+1 ALWAYS WITH COUNT IN NTCNT AND POINTER IN NTPNT

	SWAPCD			;IS SWAPPABLE
COMPUT:	HRRZ T3,0(T1)		;GET COUNT OF WORDS IN BLOCK
	SOS T3			;DISCOUNT THE HEADER
	IMULI T3,5		;GET BYTE COUNT
	AOS T3			;ADD IN FINAL TERMINATOR
	MOVEM T3,NTCNT		;STARTING COUNT
	HRLI T1,(<POINT 7,0,35>) ;GET STRING POINTER TO THE BLOCK
	MOVEM T1,NTPNT		;AND SAVE THE STARTING POINTER
	MOVE T2,[POINT 0,0,2]	;GET DUMMY POINTER
	SETZ T4,
	SIN			;FIND NUMBER OF USEFUL BYTES IN THE STRING
	JUMPE T3,R		;IF NO NULLS, ALL SET
	SUB T3,NTCNT		;FOUND A NULL THEN. GET CHARACTERS SKIPPED
	MOVNS T3		;GET COUNT
	MOVEM T3,NTCNT		;AND SAVE CORRECT COUNT
	RET			;AND DONE

;ROUTINE TO SCAN NAME STRING FOR NETWORK PUNCTUATION CHARACTER AND
;UPDATE COUNTS.
;ACCEPTS:	IN TRVAR'S
;	NTPNT	CURRENT TEXT POINTER
;	NTCNT	CURRENT BYTE COUNT

;RETURNS:
;	NTPNT	UPDATED POINTER
;	NTCNT	UPDATED COUNT
;	T1/ ORIGINAL POINTER
;	T3/ NUMBER OF CHARCTERS FOUND BEFORE PUNCTUATION

NETDSH:	MOVE T1,NTPNT		;GET BYTE POINTER
	MOVE T2,[POINT 0,0,2]	;DUMMY
	MOVE T3,NTCNT		;THE COUNT
	MOVEI T4,"-"		;STOP ON THE END OF THE HOST FIELD
	SIN			;GET IT
	EXCH T1,NTPNT		;STORE NEW POINTER. GET OLD
	EXCH T3,NTCNT		;STORE NEW COUNT. GET OLD COUNT
	SUB T3,NTCNT		;GET BYTES TRANSPIRED
	RET			;AND DONE
;ROUTINE TO PARSE THE NAME FIELD OF A SOURCE SPECIFICATION.
;A NAME FIELD LOOKS LIKE:
;	OBJECT-DESCRIPTOR
;OR
;	-
;WHERE THE FORMER IS THE SYNTAX FOR A GENERIC OBJECT
;AND THE LATTER IS THE SYNTAX FOR A TASK ONLY
;ACCEPTS:
;	T1/ POINTER TO NAME BLOCK
;	TRVAR <NTCNT,NTPNT,NTOBJ,NTDSC,NTDSS>
;RETURNS:
;	+1 SYNTAX OR SEMANTICS ERROR. CODE IN T1
;	+2 ACCEPTABLE NAME.

;	WITH TRVAR'S FILLED IN

SRCNAM:	CALL COMPUT		;COMPUTE STRING COUNT
	SETOM NTOBJ		;ASSUME NO OBJECT
	CALL NETDSH		;GO FIND OBJECT NAME
	CAIG T3,1		;WAS IT NULL?
	JRST SRCNOB		;YES. NO GENERIC OBJECT GIVEN
	LDB T4,NTPNT		;GET TERMINATOR
	MOVEM T4,NTOBJ		;SAVE IT
	SETZ T4,		;GET A NULL
	DPB T4,NTPNT		;TIE OFF OBJECT NAME
	CALL OBJLOK		;GO LOOK UP THE OBJECT
	 RETBAD (DCNX3)		;NO SUCH OBJECT. COMPLAIN
	SKIPG T1		;A LEGAL OBJECT TYPE?
	RETBAD (DCNX3)		;NO. COMPLAIN
	CAIG T1,DECOBJ		;IS IT A DEC RESERVED OBJECT?
	JRST [	MOVX T3,SC%WHL!SC%OPR ;YES. MUST BE PRIVILEGED THEN
		TDNE T3,CAPENB	;IS IT ENABLED?
		JRST .+1	;YES. PROCEED
		RETBAD (DCNX3)]	;NO. ERROR
	EXCH T1,NTOBJ		;SAVE GENERIC OBJECT TYPE
	DPB T1,NTPNT		;AND PUT BACK TERMINATOR
SRCNOB:	SETZM NTDSC		;ASSUME NO DESCRIPTOR
	SKIPE T3,NTCNT		;ANY BYTES LEFT IN STRING?
	CAIG T3,1		;YES. ENOUGH TO MAKE A DESCRIPTOR?
	RETSKP			;NO ALL DONE THEN
	MOVEM T3,NTDSC		;STORE COUNT OF DESCRIPTOR
	SKIPGE NTOBJ		;HAVE AN OBJECT?
	RETBAD (DCNX3)		;NO. ILLEGAL SPECIFICATION
	CAILE T3,MAXDSC		;WITHIN RANGE?
	RETBAD (DCNX12)		;NO.ILLEGAL DESCRIPTOR
	MOVE T1,NTPNT		;GET POINTER
	MOVEM T1,NTDSS		;SAVE BEGINNING OF DESCRIPTOR
	RETSKP			;AND DONE
;ROUTINE TO PARSE NAME FOR A CONNECT ATTEMPT.
;AACEPTS:	T1/ BLOCK ADDRESS OF NAME
;	TRVAR <NTCNT,NTPNT,NTOBJ,NTDSC,NTDSS,NTHST,NTHSC>
;RETURNS:
;		+1 SYNTAX ERROR
;		+2 NAME IS GOOD. TRVAR'S FILLED IN

DCNNAM:	CALL COMPUT		;FIND COUNT
	CALL NETDSH		;GO PICK OFF HOST NAME
	SKIPN NTCNT		;MORE IN THE STRING?
	RETBAD (DCNX1)		;NO. SYNTAX ERROR THEN
	SETOM NTHSC		;ASSUME LOCAL CONNECTION
	SOSG T3			;HAVE A REAL STRING?
	JRST DCNOBJ		;NO. GO LOOK FOR OBJECT THEN
	CAILE T3,MAXHST		;WITHIN BOUNDS?
	RETBAD (DCNX12)		;NO. STRING TOO LONG
	MOVEM T1,NTHST		;SAVE POINTER TO HOST
	MOVEM T3,NTHSC		;AND SAVE COUNT
DCNOBJ:	CALL NETDSH		;GO FIND OBJECT
	CAIG T3,1		;HAVE A REAL STRING?
	RETBAD (DCNX3)		;NO. INVALID OBJECT THEN
	LDB T4,NTPNT		;GET BACK TERMINATOR
	MOVEM T4,NTOBJ		;SAVE IT
	SETZ T4,		;GET A NULL
	DPB T4,NTPNT		;TIE OFF STRING
	CALL OBJLOK		;GO LOOK UP THE OBJECT
	 RETBAD (DCNX3)		;NO SUCH
	EXCH T1,NTOBJ		;SAVE OBJECT
	DPB T1,NTPNT		;AND PUT BACK TERMINATOR
	JRST SRCNOB		;FINISH UP ON DESCRIPTOR

;ROUTINE TO PARSE EXTENSION. THIS FIELD WILL BE THE TASKNAME

NETEXT:	CALL COMPUT		;GET COUNT
	MOVE T1,NTCNT		;GET THE COMPUTED COUNT
	CAILE T1,TSKMAX		;WITHING RANGE
	RETBAD (DCNX12)		;NO. TOO LONG
	RETSKP			;AND DONE
;SEQUENTIAL I/O JSYSS.

;SEQUENTIAL OUTPUT.

NETSQO:	ASUBR <NETCHR>		;SAVE THE CHARACTER
	MOVE T1,FILLLB(JFN)	;GET LL BLOCK ADDRESS
	CALL BLKLOK		;LOCK IT UP
	 JRST WATBLK		;GO WAIT FOR THE LOCK
	LOAD T2,LLSTA,(T1)	;GET CURRENT STATE
	JRST @SQOSTA-1(T2)	;AND DO PROPER THING
NETSQ1:	SOSGE FILCNT(JFN)	;HAVE ANY CHARACTERS?
	JRST [	CALL OUTRR	;AND SEND SOME MESSAGES
		 RETBAD()	;FAILED
		CALL NETOUP	;SET UP FOR OUTPUT
		MOVE T1,FILLLB(JFN) ;GET BACK LL BLOCK
		JRST NETSQ1]	;AND TRY AGAIN
	MOVE T2,NETCHR		;GET BYTE
	IDPB T2,FILBYT(JFN)	;STASH BYTE
	CALLRET BLKULK		;RELEASE BLOCK AND RETURN

;FORCE OUT ALL BUFFERED CHARACTERS. CALLED FROM SOUTR

NETSQR:	MOVE T1,FILLLB(JFN)	;GET LL BLOCK ADDRESS
	CALL BLKLOK		;LOCK IT
	 JRST WATBLK		;GO WAIT FOR THE LOCK
	LOAD T2,LLSTA,(T1)	;GET STATE
	JRST @SQOOTR-1(T2)	;DO WORK
NETSR1:	SETONE LLFEM,(T1)	;SAY SHOULD GET EOM ON OUTPUT
	CALL OUTRR		;DO THE WORK
	 RETBAD()		;FAILED
	MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK
	CALL BLKULK		;UNLOCK BLOCK
	RETSKP			;AND RETURN GOOD
;WORKER ROUTINE TO FORCE OUT ALL DATA.

OUTRR:	STKVAR <MSIZE,MBLOCK,MLODR>
	CALL MOVSEG		;PICK UP ACKS,ETC...
	 JRST OUTWAT		;ERROR OCCURRED
	CALL NETUOU		;UNDO OUTPUT
	MOVE T1,FILLLB(JFN)	;GET LL BLOCK
	OPSTR <SKIPN>,LLFLO,(T1) ;IS FLOW FROM THE F/S?
	JRST OUTRR1		;NO. ALL SET TO GO THEN

;FLOW IS FROM THE FILE SYSTEM. COMPUTE BYTES NOW IN OUTPUT BUFFER
;AND SWITCH FLOW TO THE NETWORK

	SETZRO LLFLO,(T1) 	;SWITCH FLOW
	LOAD T3,LLBSZ,(T1)	;GET BYTE SIZE
	HLRZ T1,FILWND(JFN)	;GET WINDOW ADDRESS
	CALL MAKPTR		;GET MAX BYTES IN BUFFER
	HLRZ T3,FILBCT(JFN)	;GET REMAINING COUNT
	SUBI T2,0(T3)		;COMPUTE BYTES IN THE BUFFER
	MOVE T4,FILLLB(JFN)
	LOAD T3,LLBSZ,(T4)	;GET BYTE SIZE
	CAIN T3,44		;WORD MODE?
	JRST [	IMULI T2,44	;YES. COMPUTE TOTAL BITS
		ADDI T2,7	;ROUND UP
		LSH T2,-3	;AND NOW COMPUTE FULL BYTES
		JRST .+1]	;AND CONTINUE
	JUMPE T2,RSKP		;IS NONE LEFT, ALL DONE
	MOVEM T1,FILBFO(JFN)	;PUT IN STARTING BYTE POINTER
	HRLM T2,FILBCT(JFN)	;STORE COUNT TO SEND
	; ..
;OUTRR CONTINUED.... TRY TO MAKE A MESSAGE

OUTR00:	MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK ADDRESS
OUTRR1:	HLRZ T2,FILBCT(JFN)	;SEE IF ANY MORE BYTES
	JUMPE T2,[SETONE LLFLO,(T1) ;NO. SWITCH FLOW TO F/S
		LOAD T3,LLBSZ,(T1) ;GET BYTE SIZE
		HLRZ T1,FILWND(JFN) ;GET BUFFER PAGE
		CALL MAKPTR	;MAKE OUTPUT POINTER
		MOVEM T1,FILBFO(JFN) ;SET UP NEW POINTER
		HRLM T2,FILBCT(JFN) ;AND COUNT
		RETSKP]		;AND DONE
	JN LLBRP,(T1),[	MOVEI T2,CHKBRP ;IF FLOW CONTROL OFF, WAIT
			JRST OUTWAT]
	JN LLQUN,(T1),[MOVEI T2,CHKSWD ;IF ANY NAK'ED SEGS
		JRST OUTWAT]	;WAIT
	LOAD T2,LLQOU,(T1)	;GET SEGS NOW IN THE QUEUER
	CAILE T2,MAXSGQ		;CAN WE PUT ANOTHER ONE IN?
OUTRR8:	JRST [	MOVEI T2,CHKQTA ;WAIT FOR QUEUER COUNT TO COME DOWN
		JRST OUTWAT]	;AND GO SET UP WAIT
	LOAD T3,LLMFC,(T1)	;GET TYPE OF FLOW CONTROL
	JUMPE T3,OUTRR2		;IF NO FLOW CONTROL, ALL SET
	LOAD T4,LLMSM,(T1)	;GET CURRENT FLOW COUNT
	JUMPE T4,[MOVEI T2,CHKSCT ;WAIT FOR SOME COUNT TO APPEAR
		JRST OUTWAT]	;AND GO SET UP BLOCK
	CAIE T3,2		;MESSAGE FLOW CONTROL?
	TRNN T4,200		;NO. SEGMENT. IS COUNT POSITIVE?
	JRST OUTRR2		;YES. CAN SEND A SEGMENT
	MOVEI T2,CHKSCP		;WAIT FOR COUNT TO GO POSITIVE
OUTWAT:	TQNE <ERRF>		;ERROR?
	JRST SQOBAD		;YES. GO AWAY
	CALL MAKTST		;MAKE A STANDARD TEST WORD
OUTWA1:	TQO <BLKF>		;REQUEST BLOCK
	CALLRET SQOBAD		;AND FINISH UP

;CAN SEND SOME DATA

OUTRR2:	HLRZ T3,FILBCT(JFN)	;GET # OF BYTES REMAINING
	LOAD T4,LLSWG,(T1)	;GET MAX SEG SIZE
	CAILE T3,0(T4)		;CAN WE SEND IT ALL?
	MOVEI T3,0(T4)		;NO. SO SEND MAX AMOUNT
	MOVEM T3,MSIZE		;SAVE # OF BYTES TO SEND
	MOVEI T1,<<MSHDR+DTMLEN>*4+3>(T3) ;COMPUTE BYTES REQUIRED
	LSH T1,-2		;CONVERT TO WORDS
	CALL GETRES		;GET ONE
	 JRST [	CALL GENWAT	;GET A WAIT
		CALLRET SQOBAD]	;AND DONE
	; ..
;OUTRR CONTINUED... ADJUST COUNTS IN JFN BLOCK

	MOVEM T1,MBLOCK		;SAVE BLOCK ADDRESS
	MOVEI T2,MSHDR(T1)	;GET BEGINNING OF DATA STORAGE
	HRLI T2,(<POINT 8,>)	;FORM BYTE POINTER
	MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK
	MOVEM T2,LLBPTR(T1)	;SAVE WORK POINTER
	SETZM LLBPCT(T1)	;INIT COUNT
	MOVE T3,MSIZE		;GET # OF BYTES TO GO
	HLRZ T2,FILBCT(JFN)	;GET # NOW IN BUFFER
	SUBI T2,0(T3)		;COMPUTE # LEFT
	HRLM T2,FILBCT(JFN)	;SAVE FOR NEXT ROUND
	MOVEI T4,DATMFL		;GET BASIC MESSAGE FLAGS
	LOAD T3,LLMFC,(T1)	;GET TYPE OF FLOW CONTROL ON THIS LINK
	JN LLBOM,(T1),[	SETZRO LLBOM,(T1) ;YES. IS THIS START OF MESSAGE?
			TXO T4,DATBOM ;YES. SET BOM THEN
			JRST OUTRR4] ;YES. KEEP BOM
OUTRR4:	OPSTR <SKIPE>,LLFEM,(T1) ;WANT EOM?
	SKIPE T2		;IS THIS LAST SEGMENT OF MESSAGE?
	JRST [	CAIN T3,2	;MESSAGE FLOW CONTROL?
		JRST OUTRR6	;YES. SKIP FLOW ADJUSTMENT
		JRST OUTRR3]	;NO. ADJUST FLOW COUNTER
	SETZRO LLFEM,(T1)	;YES. TURN OFF EOM
	SETONE LLBOM,(T1)	;AND NEXT ONE IS BOM
	TXO T4,DATEOM		;AND SET EOM
	; ..
;OUTRR CONTINUED...

OUTRR3:	JUMPE T3,OUTRR6		;IF NO FLOW CONTROL, SKIP ADJUSTMENT
	NOSKED			;PREVENT RACES
	CALL DECMSM		;ADJUST FLOW CONTROL
	OKSKED			;AND ALLOW SCHEDULING AGAIN
OUTRR6:	MOVE T2,T4		;GET COMPUTED FLAGS
	MOVE T4,MBLOCK		;GET MESSAGE BLOCK ADDRESS
	STOR T2,MSMFL,(T4)	;SAVE MESSAGE FLAGS
	CALL ONEBYT		;STASH IT
	CALL PUTLLA		;PUT IN LL ADDRESSES
	MOVE T2,LLBPTR(T1)	;GET CURRENT POINTER
	MOVEM T2,MSBPTR(T4)	;SAVE IN MESSAGE BLOCK
	LOAD T2,LLDSN,(T1)	;GET SEG NUMBER
	AOS T2			;NEXT ONE
	STOR T2,LLDSN,(T1)	;PUT IT BACK
	ANDI T2,7777		;ONLY 12 BITS
	STOR T2,MSSEG,(T4)	;SAVE SEG # IN DATA BLOCK
	CALL TWOBYT		;PUT IN SEGNUM
	MOVE T4,MSIZE		;GET COUNT
	ADDM T4,LLBPCT(T1)	;AND COUNT UP MESSAGE SIZE
	LOAD T2,LLBSZ,(T1)	;GET BYTE SIZE
	CAIN T2,44		;WORD MODE?
	JRST OUTWRD		;YES. GO DO IT
OUTRR5:	MOVE T2,LLBPTR(T1)	;GET DESTINATION
	MOVE T1,FILBFO(JFN)	;GET SOURCE
	MOVE T3,T4		;COUNT
	CALL NETMOV		;MOVE THE BYTES
	MOVEM T1,FILBFO(JFN)	;UPDATE SOURCE POINTER
	MOVE T1,FILLLB(JFN)	;RESTORE LL BLOCK POINTER
OUTRR7:	MOVE T2,MBLOCK		;GET BACK BLOCK
	MOVEI T3,MSDAT		;GET TYPE OF THIS MESSAGE
	STOR T3,MSTOM,(T2)	;TO THE MESSAGE
	MOVE T3,LLBPCT(T1)	;GET COUNT OF BYTES IN MESSAGE
	SUBI T3,5		;DISCOUNT NSP OVERHEAD
	STOR T3,MSDTC,(T2)	;AND SAVE IN MESSAGE
	CALL SNDSEG		;GO SEND A SEGMENT. ROUTINE
				;PLUGS IN LL ADDRESS AND MESSAGE SIZE
	JRST OUTR00		;AND TRY FOR ANOTHER SEGMENT

;ROUTINE TO ARRANGE FOR A TIMED WAIT OF 1/2 SEC. THIS IS USED
;WHEN FREE SPACE IS EXHAUSTED.

GENWAT:	TQO <BLKF>		;NEED TO BLOCK
	MOVE T2,TODCLK		;GET NOW
	ANDI T2,377777
	ADDI T2,^D500		;WAIT 1/2 SEC FOR FREE SPACE
	MOVSI T1,0(T2)		;TIME TO THE LH
	HRRI T1,BLOCKM		;WAIT THIS LONG
	RET			;AND GO BLOCK
;CODE TO MOVE 36 BIT BYTES INTO A NETWORK MESSAGE.

OUTWRD:	MOVEM P3,MLODR		;SAVE A WORK REG
OUTWR0:	CAIGE T4,11		;HAVE AT LEAST 2 MORE WORDS?
	JRST [	MOVE T2,@FILBFO(JFN) ;NO. GET LAST WORD
		AOS FILBFO(JFN)
		SETZ T3,	;TO GEN NULLS
		MOVEI P3,5	;5 MORE BYTES TO MOVE
		JRST OUTWR1]	;GO DO IT
	DMOVE T2,@FILBFO(JFN)	;GET TWO MORE WORDS
	MOVEI P3,2		;THE INCREMENTER
	ADDM P3,FILBFO(JFN)
	MOVEI P3,11		;MOVE 9 BYTES
OUTWR1:	SUBI T4,11		;TAKE SOME BYTES
OUTWR2:	ROTC T2,10		;GET NEXT BYTE RIGHT JUSTIFIED
	IDPB T3,LLBPTR(T1)	;STORE IT
	SOJG P3,OUTWR2		;DO ALL BYTES
	JUMPG T4,OUTWR0		;GO DO MORE DATA
	MOVE P3,MLODR		;RESTORE REG
	JRST OUTRR7		;AND CONTINUE

;ROUTINE TO MAKE A STANDARD TEST WORD

MAKTST:	LOAD T1,LLLNK,(T1)	;GET LL BLOCK ADDRESS
	HRLS T1			;TO THE LH
	HRRI T1,0(T2)		;TEST ROUTINE
	RET			;DONE
;ROUTINES OF NETSQO GOTTEN TO BY STATE TRANSITION TABLE

;SET UP BLOCK UNTIL LINK IS CONNECTED

SQOLIS:	MOVEI T2,CHKCON		;WAIT UNTIL CONNECTED
	JRST OUTWAT		;AND GO ARRANGE FOR THE BLOCK

;IMPLICIT CONFIRM

SQOCNF:	SETZM T3		;NO OPTDATA
	CALL CNFCOM		;GO CONFORM CONNECTION
	 JRST SQOBAD		;FAILED
	JRST NETSQ1		;AND COMPLETE OUTPUT REQUEST

;LINK HAS BEEN CLOSED BY PROCESS OR NSP. GIVE ERROR

SQOABT:	SKIPA T1,[DCNX11]	;NSP ABORT
SQODIS:	MOVEI T1,DCNX8		;ILLEGAL USER OPERATION
	TQO <ERRF>		;SAY HAVE AN ERROR
	JRST SQOBAD		;DONE

;FOREIGN HOST HAS DISCONNECTED

SQODIR:	TQO <ERRF>		;USER ERROR
	MOVEI T1,DCNX11		;GIVE ERROR
	JRST SQOBAD		;AND DONE
SQOEOF:	TQO <EOFF>		;NO. SAY EOF
	JRST SQOBAD		;DONE
;ROUTINE TO BUILD BASIC CC MESSAGE
;	T1/ LL BLOCK ADDRESS
;	T3/ <COUNT>B5+OPTDATA STRING
;RETURNS	+1 NO FREE SPACE. NEED TO BLOCK
;		+2 READY. T2/ BLOCK ADDRESS

SNDCC:	ASUBR <SAVLL,SAVBLK,SAVOPT>
	MOVEI T1,MSHDR+CCLEN	;GET ENOUGH SPACE
	CALL GETRES		;GET IT
	 RET			;FAILED. WAIT FOR A WHILE
	MOVEM T1,SAVBLK
	MOVEI T2,MSHDR(T1)	;GET START OF DATA
	HRLI T2,(<POINT 8,>)
	MOVE T1,SAVLL		;GET BACK LL BLOCK
	MOVEM T2,LLBPTR(T1)
	SETZM LLBPCT(T1)
	MOVEI T2,CNMRFL+CNMCF	;GET CC FLAGS
	CALL RTHDCI		;PUT IN ROUTE HEADER
	CALL DOSRVS		;PUT IN STANDARD CI/CC SERVICES
	MOVE T3,SAVOPT		;GET OPTDATA ARG
	LOAD T2,CNTFLD,T3	;GET COUNT
	SETZRO CNTFLD,T3	;CLEAR OUT COUNT BITS
	CALL MVBNRY		;PUT IN THE DATA
	MOVE T2,SAVBLK		;GET BLOCK
	RETSKP			;AND DONE

;COMMON ERROR RETURN

SQOBAD:	EXCH T1,FILLLB(JFN)	;SAVE ERROR. GET BLOCK ADDRESS
	CALL BLKULK		;FREE BLOCK
	EXCH T1,FILLLB(JFN)	;GET BACK ERROR
	RETBAD			;AND DONE

;IMPLICIT CONFIRM FROM SOUTR

SQOCN2:	SETZM T3		;NO OPTDATA
	CALL CNFCOM		;GO CONFIRM IT
	 JRST SQOBAD		;FAILED
	JRST NETSR1		;AND GO ON

;ROUTINE TO DO IMPLICIT CONFIRM

CNFCOM:	JN LLTRN,(T1),SQOCN1	;IF ONLY NEED LS, GO DO IT
	CALL SNDCC		;GO BUILD CONNECT CONFIRM
	 JRST GENWAT		;BLOCK UNTIL FREE SPACE
	CALL SNDCTL		;SEND CONTROL MESSAGE
SQOCN1:	CALL TURNON		;TRY TO SEND IT
	 JRST [	SETONE LLTRN,(T1) ;SAY STILL NEED LS
		JRST GENWAT]	;AND GO WAIT AWHILE
	SETZRO LLTRN,(T1)	;DON'T NEED LS ANYMORE
	MOVEI T2,LLSRUN		;NOW IN RUN STATE
	STOR T2,LLSTA,(T1)	;SAY SO
	MOVEI T2,1		;INITIAL LS/INT REQ COUNT
	STOR T2,LLMIC,(T1)	;STORE IT
	RETSKP			;DONE
;COLLECTION OF SCHEDULER TEST ROUTINES USED BY NETSQO AND OTHERS

	RESCD			;MUST ALL BE RESIDENT
;BLOCK UNTIL CONNECTED

CHKCON:	SETOM T2		;ANY MATCH
	CALL LLLKUP		;GO FIND LL BLOCK
	 JRST 1(4)		;THIS SHOULDN'T HAPPEN
	LOAD T2,LLSTA,(T1)	;GET CURRENT STATE
	CAIE T2,LLSLIS		;LISTENING?
	CAIN T2,LLSCIS		;OR CI SENT?
	JRST 0(4)		;YES. NOT CONNECTED THEN
	JRST 1(4)		;NO. CONNECTED

;WAIT UNTIL BLOCK LOCK IS FREE

CHKLOK:	SETOM T2		;ANY MATCH
	CALL LLLKUP		;FIND LL BLOCK
	 JRST 1(4)		;CAN'T HAPPEN
	JN LLLOK,(T1),0(4)	;IF STILL SET, MUST WAIT
	JRST 1(4)		;IS FREE

;WAIT UNITL QUEUER WILL TAKE SOME MORE MESSAGES

CHKQTA:	CALL CHKSET		;GET LL BLOCK, MAKE SURE STILL RUNNING
	 JRST 1(4)		;SOMETHING WRONG WITH LINK
	LOAD T2,LLQOU,(T1)	;GET QUEUER COUNT
	CAILE T2,MAXSGQ		;CAN TAKE SOME MORE?
	JRST 0(4)		;NO. WAIT SOME MORE
	JRST 1(4)		;YES.

;WAIT UNTIL SOME ACKS COME IN

CHKSCT:	CALL CHKSET		;VERIFY LINK STATE
	 JRST 1(4)		;LINK CHANGED STATED
	JN LLMSM,(T1),1(4)	;IF SOME ACKS, WAKE UP
	JRST 0(4)		;STILL NO ACKS. WAIT SOME MORE

;WAIT UNTIL SEG ACK COUNT IS POSITIVE

CHKSCP:	CALL CHKSET		;VERIFY LINK STATE
	 JRST 1(4)		;LINK CHANGED STATE
	LOAD T2,LLMSM,(T1)	;GET SEG COUNT
	TRNE T2,177		;IS IT ZERO?
	TRNE T2,200		;NO. IS IT NEGATIVE?
	JRST 0(4)		;YES. MUST WAIT SOME MORE
	JRST 1(4)		;NO. CAN SEND SOME MORE DATA

;ROUTINE TO WAIT FOR MESSAGES TO ARRIVE

CHKRAW:	CALL CHKSET		;FORCE WAKE?
	 JRST 1(4)		;YES.
	OPSTR <SKIPN>,LLFLI,(T1) ;ANYTHING IN FILE BUFFER PAGE?
	SKIPE LLOMSG(T1)	;ANYTHING ON ORDERED Q?
	JRST 1(4)		;YES. WAKE UP THEN
	JRST 0(4)		;NOTHING TO DO YET

;COMMON ROUTINE TO FIND LL BLOCK AND VERIFY THAT IT IS RUNNING

CHKSET:	SETOM T2		;ANY LINK
	CALL LLLKUP		;GO FIND BLOCK
	 RET			;NOT THERE. SOMETHING TERRIBLE HAPPENED
	LOAD T2,LLSTA,(T1)	;GET STATE
	SKIPN LLMSG(T1)		;MESSAGES ON QUEUE?
	CAIE T2,LLSRUN		;IS IT RUNNING?
	RET			;WAKE UP
	RETSKP			;YES. ALL FINE

;CHECK IF RESENDS ARE ALL DONE

CHKSWD:	CALL CHKSET		;GO VERIFY LINK STATE
	 JRST 1(4)		;CHANGED. WAKE UP
	JE LLQUN,(T1),1(4)	;ALL NAK'ED SEGS NOW SENT?
	JRST 0(4)		;STILL RESENDS. WAIT

;TESTS FOR CLOSF

CHKDCR:	SETOM T2		;ANY MATCH
	CALL LLLKUP		;FIND LL BLOCK
	 JRST 1(4)
	LOAD T2,LLSTA,(T1)	;GET STATE
	CAIE T2,LLSABT		;DC RECEIVED?
	JRST 0(4)		;NO. KEEP WAITING
	JRST 1(4)		;YES. AWAKE

CHKEMP:	CALL CHKSET		;MAKE SURE ALL IS SET
	 JRST 1(4)		;NOT. A STATE CHANGE OCCURRED
	JE LLQOU,(T1),1(4)	;HAVE ALL ACKS ARRIVED?
	JRST 0(4)		;NO

;WAIT FOR BACK-PRESSURE

CHKBRP:	CALL CHKSET		;MAKE SURE ALL IS SET
	 JRST 1(4)		;NO. AWAKE
	JE LLBRP,(T1),1(4)	;IF NOW ON, AWAKE
	JRST 0(4)		;NO YET ON

;TEST ROUTINE FOR NSPTSK

NSPTST:
	SKIPE KDPFLG		;DOES KMC11 WANT SERVICE
	JRST 1(4)		;YES
;	SKIPN RMSGQ		;ANY BLOCKS TO RELEASE?
	SKIPE MSGQ		;NO. ANY MESSAGES TO DO?
	JRST 1(4)		;YES.
	JRST 0(4)		;NO.
;ROUTINES FOR SEQUENTIAL INPUT

;ROUTINE TO TAKE SEGMENTS OFF OF THE RAW DATA QUEUE AND
;PUT THEM ON THE ORDERED DATA QUEUE

	SWAPCD
MOVSEG:	ACVAR <W1,W2>
	OPSTR <SKIPE>,LLFNN,(T1) ;NEED A NACK?
	CALL MOVNAK		;YES. SEND NACK
MOVSE1:	SKIPN T2,LLMSG(T1)	;HAVE ANY?
	RETSKP			;NO. MUST BE DONE THEN
	NOSKED			;PREVENT SCHEDULING
	LOAD T3,MSLNK,(T2)	;GET LINK
	MOVEM T3,LLMSG(T1)	;NEW LINK
	OKSKED			;AND ALLOW SCHEDULING
	LOAD T3,MSMFL,(T2)	;GET FLAGS
	TXNE T3,ACKFLM		;IS IT AN ACK?
	JRST [	CALL MOVACK	;YES. GO DO THE ACK THEN
		 RETBAD()	;ERROR OCCURRED
		JRST MOVSE1]	;AND DONE
	DECR LLDRW,(T1)		;ONE LESS DATA SEG ON Q
	MOVEI T3,MSDAT		;IS A DATA SEGMENT
	CALL VERSEG		;GO VERIFY CORRECTNESS OF MESSAGE
	 JRST [	MOVE W1,T3	;SAVE FLAG FROM VERSEG
		DECR LLDMT,(T1)	;ONE LESS DATA MESSAGE
		MOVE T1,T2	;GET SEGMENT ADDRESS
		CALL RELRES	;FREE IT UP
		MOVE T1,FILLLB(JFN) ;GET BACK LL BLOCK
		JUMPE W1,BADSEG	;IF PROTOCOL ERROR, GO SHUT LINK
		LOAD T2,LLIDN,(T1) ;GET LAST ACKED SEG
		MOVEI T3,MSDAT	;ON THE DATA CHANNEL
		CALL SNDACK	;ACK IT AGAIN
		 CALL MOVUNL	;FAILED. FORGE AHEAD ANYWAY
		JRST MOVSE1]	;AND DONE

;MESSAGE IS GOOD. PUT IT ON THE ORDERED QUEUE

	CAILE T3,MAXSEG		;SEE IF REASONABLE TO KEEP IT?
	JRST [	DECR LLDMT,(T1)	;NO. REMOVE SEG
		JE LLIMS,(T1),BADSEG ;IF NOT MESSAGE CONTROL, ERROR
		MOVE T1,T2	;NO. IS BEYOND QUOTA
		CALL RELRES	;FREE THE BLOCK
		MOVE T1,FILLLB(JFN) ;GET BACK LL BLOCK
		CALL MOVNAK	;AND SEND THE NACK
		JRST MOVSE1]	;DONE
	SKIPN T3,LLOMSG(T1)	;ANYTHING ON THE QUEUE?
	JRST [	MOVEM T2,LLOMSG(T1) ;NO. MAKE THIS THE QUEUE
		SETZRO MSLNK,(T2) ;TIE IT OFF
		JRST MOVSE1]	;AND DONE
	SETZ W1,		;AT THE TOP
	LOAD W2,MSSEG,(T2)	;GET SEG NUMBER
	; ..
;MOVSEG CONTINUED...

MOVSEL:	LOAD T4,MSSEG,(T3)	;GET THIS ONE'S NUMBER
	CAIN W2,0(T4)		;SAME?
	JRST [	MOVE T1,T2	;YES
		CALL RELRES	;THROW IT AWAY
		MOVE T1,FILLLB(JFN) ;GET LL BLOCK ADDRESS
		JRST MOVSE1]	;AND GO AGAIN
	SUBI T4,0(W2)		;COMPUTE THE DIFFERENCE
	MOVM W3,T4		;GET MAGNITUDE OF DIFFERENCE
	CAILE W3,MAXDIF		;IS GREATER THAN MAX DIFFERENCE?
	TLC T4,(1B0)		;YES. FLIP SIGN THEN
	JUMPL T4,[MOVE W1,T3	;IF LESS, INSERT AFTER
		LOAD T3,MSLNK,(T3) ;GET LINK
		JUMPN T3,MOVSEL	;AND GO LOOK SOME MORE
		JRST MOVSE2]	;AND GO INSERT IT
	JUMPE W1,[MOVE T4,LLOMSG(T1) ;GET OLD HEAD
		MOVEM T2,LLOMSG(T1) ;NEW HEAD
		STOR T4,MSLNK,(T2) ;AND FINISH LINK
		JRST MOVSE1]	;DONE
MOVSE2:	LOAD T4,MSLNK,(W1)	;GET OLD LINK
	STOR T2,MSLNK,(W1)	;INSERT IT
	STOR T4,MSLNK,(T2)	;FINISH UP
	JRST MOVSE1		;AND DONE

;SNDACK WANTED TO BLOCK. IGNORE IT AND CONTINUE THE SCAN

MOVUNL:	MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK ADDRESS
	TQZ <BLKF>		;CON'T WANT TO BLOCK ANYMORE
	RET			;AND DONE

;ROUTINE TO SEND A NACK FOR THE LINK

MOVNAK:	LOAD T2,LLIDN,(T1)	;GET SEG NUMBER
	TXO T2,ACKBIT		;MAKE IT A NACK
	MOVEI T3,MSDAT		;ON THE DATA CHANNEL
	CALL SNDACK		;SEND THE NACK
	 JRST [	CALL MOVUNL	;IGNORE FAILURE
		CALLRET DATINR]	;BUT MAKE IT RETRY SOON
	SETZRO <LLFNN,LLFNA>,(T1) ;CLEAR FLAGS
	RET			;AND DONE
;LOCAL ROUTINE TO HANDLE AN ACK FOUND ON LLMSG QUEUE
;	T1/ LL BLOCK ADDRESS
;	T2/ MESSAGE BLOCK ADDRESS

MOVACK:	TRVAR <MSGCNT,MSGBYP,MSGBLK,MSGLL>
	MOVEM T1,MSGLL		;SAVE LL BLOCK
	MOVEM T2,MSGBLK		;SAVE DATA BLOCK
	LOAD T3,MSDTC,(T2)	;GET DATA COUNT
	MOVEM T3,MSGCNT
	MOVE T3,MSBPTR(T2)	;GET POINTER TO DATA
	MOVEM T3,MSGBYP		;SET UP POINTER
	LOAD T2,MSMFL,(T2)	;GET FLAGS
	CALL ACKDO		;GO DO THA ACTUAL ACK
	 JRST BADSEG		;BADLY FORMED SEGMENT ENCOUNTERED
	MOVE T1,MSGBLK		;GET BLOCK ADDRESS
	CALL RELRES		;FREE IT UP
	MOVE T1,MSGLL		;GET LL ADDRESS
	RETSKP			;AND DONE

;WORKER ROUTINE TO DO ACK. CALLED FROM BOTH PROCESS CONTEXT AND FROM
;NSPTSK.
;	T1/ LL BLOCK ADDRESS
;	T2/ MESSAGE FLAGS

ACKDO:	MOVE T4,T2		;SAVE FLAGS
	CALL GETTWO		;GET ACKNUM
	 RET			;BAD
	MOVEI T3,MSDAT		;IS A DATA ACK
	TRNE T4,ACKLSI		;ACKING DATA?
	MOVEI T3,MSLSI		;NO.
	CALL ACKCHN		;GO DO IT
	RETSKP			;AND DONE

;A BADLY FORMED SEGMENT WAS ENCOUNTERED

BADSEG:	MOVEI T2,LLSDIQ		;CHANGE LINK STATE
	STOR T2,LLSTA,(T1)
	CALL FLUSH		;RELEASE ALL PENDING MESSAGES
	MOVEI T2,.DCX40		;DATA LOSE ERROR
	STOR T2,LLRSN,(T1)	;THE ABORT REASON
	CALL DATINR		;GIVE INT
	SETZM T3		;NO USER DATA
	MOVEI T4,CNMRFL+CNMDI	;A DI
	CALL SNDDI		;GO SEND IT
	 CALLRET GENWAT		;NO FREE SPACE
	CALL SNDCTL		;SEND CONTROL MESSAGE
	MOVEI T2,LLSDIS		;NEW STATE
	STOR T2,LLSTA,(T1)
	CALLRET SEGERR		;AND GIVE ERROR
;ROUTINE TO VERIFY A SEGMENT
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ SEGMENT ADDRESS
;		T3/ SEGMENT TYPE
;RETURNS:	+1 BAD SEGMENT.
;			T3=0 MEANS BADLY FORMED (PROTOCOL ERROR)
;			T3=/0 MEANS OLD SEGMENT. NEEDS TO BE IGNORED
;		+2 GOOD. T3/ "AGE"

VERSEG:	TRVAR <MSGCNT,MSGBYP,MSGBLK,MSGSGT>
	MOVEM T3,MSGSGT		;SAVE SEGMENT TYPE
	MOVE T3,MSBPTR(T2)	;GET POINTER TO DATA
	MOVEM T3,MSGBYP		;TO THE POINTER
	LOAD T3,MSDTC,(T2)	;GET COUNT
	MOVEM T3,MSGCNT		;SAVE COUNT
	MOVEM T2,MSGBLK		;SAVE MESSAGE BLOCK
	CALL GETTWO		;GET ACKNUM
	 JRST VERBDY		;BAD
	TRZN T2,ACKIND		;IS THIS AN ACKNUM?
	JRST GOTSEG
	MOVE T3,MSGSGT		;GET TYPE
	CALL ACKCHN		;AND GO HANDLE THE ACK
	CALL GETTWO		;GET SEGNUM
	 JRST VERBDY		;BAD
GOTSEG:	SKIPG MSGCNT		;HAVE ANY BYTES LEFT?
	JRST VERBDY		;NO. BADLY FORMED MESSAGE THEN
	MOVE T3,T2		;SAVE SEGMENT #
	MOVE T2,MSGSGT		;GET TYPE
	XCT [	LOAD T4,LLIIN,(T1)
		LOAD T4,LLIDN,(T1)]-1(T2)
	MOVE T2,MSGBLK		;GET BLOCK
	STOR T3,MSSEG,(T2)	;SAVE SEGMENT #
	SUBI T3,0(T4)		;COMPUTE "AGE"
	ANDI T3,7777		;MOD 4096
	SKIPE T3		;IS IT CURRENT ONE?
	CAILE T3,MAXDIF		;NO. IS IT NEW?
	AOJA T3,R		;NO. IS OLD
	RETSKP			;YES. RETURN AGE IN T3
VERBDY:	MOVE T2,MSGBLK		;GET BACK BLOCK ADDRESS
	SETZM T3		;SAY PROTOCOL ERROR
	RET			;AND DONE
;ROUTINE TO DO SEQUENTIAL INPUT.

NETSQI:	MOVE T1,FILLLB(JFN)	;GET LL BLOCK ADDRESS
	CALL BLKLOK		;LOCK IT UP
	 JRST WATBLK		;GO WAIT FOR THE LOCK
	LOAD T2,LLSTA,(T1)	;GET STATE
	JRST @SQISTA-1(T2)	;GO DO PROPER THING
SQI1:	SKIPE LLMSI(T1)		;have pending interrupt message?
	JRST [	MOVEI T1,DCNX2	;yes. illegal to do this input then
		TQO <ERRF>	;make it a file sys error
		JRST SQOBAD]	;and tell the process
	SOSL FILCNT(JFN)	;ANY MORE BYTES?
	JRST [	ILDB T2,FILBYT(JFN) ;YES. GET ONE
		CALL BLKULK	;FREE THE BLOCK
		MOVE T1,T2
		RET]		;AND DONE
	JE LLFLI,(T1),SQI11	;IF FLOW FROM NETWORK...
	SETZRO LLFIM,(T1)	;CLEAR FLAG
SQI11:	CALL NETUIN		;UNDO INPUT
	MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK POINTER
	CALL NETSET		;GO TRY TO GET SOME BYTES
	 JRST OUTWA1		;GO BLOCK
	CALL BLKULK		;FOUND SOME. FREE THE LOCK
	CALL NETINP		;SET UP FOR INPUT
	JRST NETSQI		;AND TRY AGAIN

;ROUTINE TO SET BLKF AND RETURN

WATBLK:	TQO <BLKF>
	RETBAD()

;STATE TRANSITION ROUTINES FOR SEQUENTIAL INPUT

;DI RECEIVED.

SQIDIR:	JN LLFDI,(T1),[	SKIPE FILCNT(JFN) ;SYNCHRONOUS?
			JRST SQI1 ;GO GET REMAINING BYTES
			CALL NETSET ;SEE IF ANY MORE
			 JRST SQOEOF ;NO. GIVE EOF THEN
			JRST SQI1] ;YES. GO GET THEM
	CALL FLUSH		;NO . GO FLUSH ALL QUEUES
	TQO <ERRF>		;AN ERROR
	MOVEI T1,DCNX11		;ABORT ERROR
	JRST SQOBAD		;AND GIVE ERROR TO USER

;NEED IMPLICIT CONFIRM

SQICNF:	SETZM T3		;NO OPTDATA
	CALL CNFCOM		;GO DO CONFIRM
	 JRST SQOBAD		;NEED TO BLOCK
	JRST SQI1		;AND PROCEED
;ROUTINE TO SCAN INPUT QUEUES AND GET BYTES TO DELIVER TO PROGRAM

NETSET:	TRVAR <MSGCNT,MSGBYP,SQICNT,<MDPTR,2>>
	SETZM SQICNT		;NONE YET
	OPSTR <SKIPN>,LLFLI,(T1) ;IS FLOW FROM THE NETWORK?
	JRST SQI22		;YES. ALL SET TO GO THEN
	SETZRO LLFIM,(T1)	;NO LONGER EOM
	SETZRO LLFLI,(T1)	;NO. SET FLOW FROM THE NETWORK
	LOAD T3,LLBSZ,(T1)	;GET BYTE SIZE
	HRRZ T1,FILWND(JFN)	;GET WINDOW PAGE
	CALL MAKINP		;GO GET INPUT POINTER
	MOVEM T1,FILBFI(JFN)	;SAVE BYTE POINTER
	SETZM SQICNT		;SAVE CURRENT COUNT
SQI23:	MOVE T1,FILLLB(JFN)	;RESTORE LL BLOCK
SQI22:	CALL MOVSEG		;FIRST, PICK UP ACKS
	 RETBAD()		;OOPS. AN ERROR
	JN LLFNA,(T1),SQISNA	;IF NEED ACK ONLY, GO DO IT
	JN LLLSC,(T1),SQISN2	;NEED AN LS MESSAGE?
SQI2:	CALL MOVSEG		;NO INPUT. GET ANY SEGS
	 RETBAD()		;ERROR
	SKIPN T2,LLOMSG(T1)	;GET TOPMOST SEGMENT
	JRST SQIEMP		;NO. ALL DONE THEN
	LOAD T3,MSSEG,(T2)	;GET SEGMENT NUMBER
	LOAD T4,LLIDN,(T1)	;GET LAST ACKED DATA SEGMENT
	AOS T4			;THE ONE WE EXPECT
	ANDI T4,7777		;MOD 12
	CAIE T3,0(T4)		;IS THIS IT?
	JRST SQIEMP		;NO. CAN'T DO INPUT THEN
	LOAD T3,MSDTC,(T2)	;GET COUNT OF BYTES
	MOVEM T3,MSGCNT		;STASH IT
	MOVE T3,MSBPTR(T2)	;GET POINTER TO DATA
	MOVEM T3,MSGBYP		;SET UP POINTER
	CALL GETTWO		;GET NEXT FIELD
	 JFCL
	TRNE T2,100000		;IS THIS ACKNUM?
	 CALL GETTWO		;YES. SO SKIP SEGNUM NOW
	 JFCL
	; ..
;NOW POSITIONED TO DATA PORTION OF SEGMENT. MOVE DATA INTO
;JFN WINDOW PAGE

	MOVE T4,MSGCNT		;GET REMAINING COUNT
	ADD T4,SQICNT		;COMPUTE BYTES TO BE IN BUFFER
	CAILE T4,4000		;WILL THEY FIT?
	JRST SQIEMP		;NO. DON'T MOVE IT THEN
	MOVEM T4,SQICNT		;YES. UPDATE COUNT
	MOVE T2,LLOMSG(T1)	;GET MESSAGE ADDRESS	
	LOAD T2,MSMFL,(T2)	;GET FLAGS
	TXNN T2,DATEOM		;IS THIS THE END-OF-MESSAGE?
	JRST SQI3		;NO
	SETONE LLFIM,(T1)	;YES
SQI3:	OPSTR <SKIPE>,LLIMS,(T1) ;MESSAGE INTERFACE?
	JRST [	JE LLFIM,(T1),SQI4 ;YES. HAVE EOM IN BUFFER?
		JRST .+1]	;YES
	INCR LLLSC,(T1)		;NEED ANOTHER BUFFER SENT
SQI4:	MOVE T4,MSGCNT		;GET BACK THE COUNT
	LOAD T2,LLBSZ,(T1)	;GET BYTE SIZE
	CAIN T2,44		;WORD MODE?
	JRST SQIWRD		;YES. MOVE WORDS THEN
SQIMOV:	MOVE T3,T4		;GET COUNT
	MOVE T1,MSGBYP		;GET SOURCE POINTER
	MOVE T2,FILBFI(JFN)	;GET DESTINATION
	CALL NETMOV		;MOVE THE BYTES
	MOVEM T2,FILBFI(JFN)	;UPDATE DESTINATION POINTER
	MOVE T1,FILLLB(JFN)	;RESTORE LL BLOCK POINTER
SQIMV1:	MOVE T2,LLOMSG(T1)	;GET EXPENDED MESSAGE
	LOAD T3,MSSEG,(T2)	;GET SEG #
	STOR T3,LLIDN,(T1)	;AND UPDATE LL BLOCK
	LOAD T3,MSLNK,(T2)	;GET NEXT
	MOVEM T3,LLOMSG(T1)	;NEW HEAD
	MOVE T1,T2		;MESSAGE BLOCK
	CALL RELRES		;FREE IT
	MOVE T1,FILLLB(JFN)	;GET BACK LL ADDRESS
	DECR LLDMT,(T1)		;ONE LESS DATA MESSAGE
	OPSTR <SKIPN>,LLFIM,(T1) ;HAVE EOM?
	JRST SQI2		;AND TRY AGAIN
	; ..
;NETSQI CONTINUED....
;GOT ALL MESSAGES MOVED.

SQIEMP:	SKIPG SQICNT		;GET ANY BYTES?
	JRST SQINOB		;NO. NOTHING TO DO
	LOAD T3,LLBSZ,(T1)	;GET BYTE SIZE
	HRRZ T1,FILWND(JFN)	;GET WINDOW ADDRESS
	CALL MAKPTR		;MAKE A POINTER
	MOVEM T1,FILBFI(JFN)	;TO THE BLOCK
	MOVE T4,FILLLB(JFN)
	LOAD T3,LLBSZ,(T4)	;GET BYTE SIZE
	MOVE T2,SQICNT		;GET COUNT WE FOUND
	CAIN T3,44		;WORD MODE?
	JRST [	IDIVI T2,11	;YES. COMPUTE BYTES
		LSH T2,1	;""
		JUMPE T3,.+1	;AN ODD WORD ON THE END?
		AOJA T2,.+1]	;YES. COUNT IT
	HRRM T2,FILBCT(JFN)	;SAVE IT
SQISNA:	MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK
	LOAD T2,LLIDN,(T1)	;GET SEG # TO ACK
	MOVEI T3,MSDAT		;ON THE DATA CHANNEL
	OPSTR <SKIPE>,LLFNN,(T1) ;NEED A NACK?
	TXO T2,ACKBIT		;YES.
	CALL SNDACK		;SEND IT
	 JRST [	MOVE T2,FILLLB(JFN)
		SETONE LLFNA,(T2) ;SAY NEED TO DO IT AGAIN
		JRST CHKFRE]	;GO CHECK ON TYPE OF FAILURE
	SETZRO <LLFNA,LLFNN>,(T1) ;CLEAR ACK FLAGS
SQISN2:	LOAD T2,LLLSC,(T1)	;GET SEGS TO REQUEST
	JUMPE T2,SQISN3		;IF NONE, JUMP OFF
	MOVEI T3,MSDAT		;ON THE DATA CHANNEL
	SETONE LLLSA,(T1)	;TELL SCHED TRYING FOR LS SEND
	CALL SNDLS		;SEND MESSAGE
	 JRST [	MOVE T2,FILLLB(JFN) ;GET BACK LL BLOCK
		SKIPN LLMSG(T2)	;HAVE A MESSAGE NOW?
		JRST CHKFRE	;NO. MUST BLOCK THEN
		TQZ <BLKF>	;YES. NO LONGER WANT TO BLOCK
		JRST SQI23]	;AND GO TRY AGAIN
	SETZRO <LLLSC,LLLSA>,(T1) ;CLEAR ALL LS INDICATORS
SQISN3:	SETONE LLFLI,(T1)	;FLOW IS NOW TO F/S
	RETSKP			;ALL DONE. WITH GOOD DATA

;COULDN'T FIND ANY BYTES

SQINOB:	SKIPE LLMSG(T1)		;HAVE ANY NOW?
	JRST SQI2		;AND TRY AGAIN
	MOVEI T2,CHKRAW		;THE BLOCK ROUTINE
	CALLRET MAKTST		;GO ARRANGE FOR THE BLOCK
;ROUTINE TO MOVE WORDS FROM THE NETWORK TO AN INPUT BUFFER

SQIWRD:	DMOVEM Q1,MDPTR		;SAVE WORK REGS
SQIWR1:	SETZB Q1,Q2		;INIT WORDS
	MOVEI T3,11		;GET MAX BYTE COUNT
	CAIGE T4,11		;ENOUGH FOR FULL 2 WORDS?
	MOVE T3,T4		;NO. GET WHAT IS LEFT THEN
	SUBI T4,11		;TAKE SOME BYTES
SQIWR2:	LSHC Q1,10		;SHIFT BYTES
	ILDB T2,MSGBYP		;GET NEXT BYTE FROM NET BUFFER
	DPB T2,[POINT 8,Q2,35]	;STASH IT
	SOJG T3,SQIWR2		;DO THEM ALL
	JUMPL T4,[LSHC Q1,-4	;ALIGN ODD WORD
		MOVEM Q2,@FILBFI(JFN) ;STORE ODD WORD
		AOS FILBFI(JFN)	;MOVE TO NEXT WORD
		JRST SQIWR3]	;AND DONE
	DMOVEM Q1,@FILBFI(JFN)	;STORE BOTH WORDS
	MOVEI Q1,2		;INCREMENTER
	ADDM Q1,FILBFI(JFN)
	JUMPG T4,SQIWR1		;DO MORE
SQIWR3:	DMOVE Q1,MDPTR		;RESTORE REGS
	JRST SQIMV1		;ALL DONE

;ERROR ROUTINE FOR BADLY FORMED SEGMENT ENCOUNTERED

SEGERR:	TQO <ERRF>		;SET FILE SYSTEM ERROR
	RETBAD (DCNX11)		;AND RETURN WITH ERROR INDICATOR

;ROUTINE TO ANALYZE FAILURE TO SEND ACK OR LS MESSAGE. IF IT IS
;A FREE SPACE FAILURE, THEN A DATA INT IS ISSUED TO INSURE THE PROCESS
;TRIES AGAIN SOON

CHKFRE:	HRRZ T3,T1		;GET TEST ROUTINE
	CAIE T3,BLOCKM		;A FREE SPACE FAILURE?
	RET			;NO. DONE THEN
	EXCH T1,FILLLB(JFN)	;YES. GET LL BLOCK
	CALL DATINR		;REQEUST DATA INT
	EXCH T1,FILLLB(JFN)	;RESTORE TEST ROUTINE
	RET			;AND DONE
;ROUTINES TO ADJUST FLOW CONTROL COUNTS FOR A LL

;INCREMENT COUNT

INCMSM:	ACVAR <W1>		;USE A PRESERVED REG
	LOAD W1,LLMSM,(T1)	;GET CURRENT COUNT
	AOS W1			;INCREMENT IT
INCMS1:	STOR W1,LLMSM,(T1)	;NEW COUNT
	RET			;DONE

;DECREMENT COUNT

DECMSM:	ACVAR <W1>		;USE A PRESERVED REG
	LOAD W1,LLMSM,(T1)	;GET COUNT
	SOS W1			;DECREMENT IT
	JRST INCMS1		;AND FINISH UP IN COMMON CODE
;NOW DEFINE STATE TRANSITION TABLES

;FOR SEQUENTIAL OUTPUT

	SWAPCD			;ALL OF THESE ARE SWAPPABLE
SQOSTA:	IFIW!SQOLIS		;BLOCK UNTIL CONNECTED
	IFIW!SQOLIS		;SAME HERE
	IFIW!SQOCNF		;GO CONFIRM CIR
	IFIW!NETSQ1		;ALL SET TO GO
	IFIW!SQODIS		;LINK IS CLOSED. GIVE ERROR
	IFIW!SQODIS		;SAME HERE
	IFIW!SQODIR		;DI RECEIVED. SEE IF ABORT OR CLOSE
	IFIW!SQOABT

;FOR SOUTR CALL

SQOOTR:	IFIW!SQOLIS		;BLOCK UNTIL CONNECTED
	IFIW!SQOLIS		;BLOCK UNTIL CONNECTED
	IFIW!SQOCN2		;GO CONFIRM
	IFIW!NETSR1		;NORMAL STUFF
	IFIW!SQODIS		;LINK IS CLOSED
	IFIW!SQODIS		;""
	IFIW!SQODIR		;DI RECIEVED
	IFIW!SQOABT		;LINK ABORTED

;FOR SEQUENTIAL INPUT

SQISTA:	IFIW!SQOLIS		;WAIT FOR CONNECT
	IFIW!SQOLIS		;WAIT FOR CONNECT
	IFIW!SQICNF		;CONFIRM CONNECTION
	IFIW!SQI1		;ALL SET
	IFIW!SQODIS		;GIVE ERROR
	IFIW!SQODIS		;GIVE ERROR
	IFIW!SQIDIR		;DI RECEIVED
	IFIW!SQOABT		;ERROR

;TABLE FOR CC RECEIVED

CCREC:	IFIW!CCJECT		;CAN'T CONFIRM A LISTENER
	IFIW!CCGUD		;GOOD CC
	IFIW!CCDON		;IGNORE IT
	IFIW!CCDON		;IGNORE IT
	IFIW!CCDON		;IGNORE IT
	IFIW!CCDON		;IGNORE IT
	IFIW!CCDON		;IGNORE IT
	IFIW!CCJECT		;ERROR

;TABLE FOR DI RECEIVED

DIREC:	IFIW!CCJECT		;ILLEGAL ADDRESS
	IFIW!CONREJ		;CONNECT BEING REJECTED
	IFIW!CCDON		;IGNORE
	IFIW!DIMSG2		;CLOSING DOWN THE LINK
	IFIW!DIABT		;ABORT IT
	IFIW!DIABT		;ABORT IT
	IFIW!DIABT		;ABORT IT
	IFIW!DCDCS		;SEND DC AND IGNORE IT

;TABLE FOR DC RECEIVED

DCREC:	IFIW!CCDON		;IGNORE FOR LISTENER
	IFIW!CHKIDL		;CHECK FOR VALID DC
	IFIW!CCDON		;IGNORE
	IFIW!DCRUN		;SHUTTING DOWN
	IFIW!DCABT		;VALID REPLY TO DI SENT
	IFIW!DCABT		;ABORT THE LINK
	IFIW!DCABT		;ABORT THE LINK
	IFIW!CCDON		;IGNORE IT

;CLOSF

CLZSTA:	IFIW!CLZDON		;JUST GET RID OF A LISTENER
	IFIW!CLZDON		;SAME FOR CIS
	IFIW!CLZDI		;NEED TO REFUSE CONNECTION
	IFIW!CLZRUN		;NORMAL STATE
	IFIW!CLZWDC		;WAIT FOR DC
	IFIW!CLZDIQ		;Q STATE
	IFIW!CLZDIR
	IFIW!CLZABT

;ACK RECEIVED

ACKSTA:	IFIW!CCJECT
	IFIW!ACKCIS
	IFIW!CCDON
	IFIW!ACKRUN
	IFIW!CCDON
	IFIW!CCDON
	IFIW!CCDON
	IFIW!CCDON

;DATA,INT OR LS MESSAGE

DATSTA:	IFIW!CCJECT		;ERROR
	IFIW!CCDON		;IGNORE
	IFIW!CCDON		;IGNORE
	IFIW!DATRUN		;GOOD MESSAGE
    REPEAT 4,<
	IFIW!CCDON>		;IGNORE
;THIS CODE IS THE REQUEST QUEUER AND THE BACKGROUND NSP
;TASK. THE QUEUER IS RESPONSIBLE FOR "ROUTING" ALL MESSAGES
;TO EITHER THE NETWORK (VIA THE DTE OR WHATEVER ELSE CONNECTS
;US TO THE NETWORK) OR TO ANOTHER LOGICAL LINK ON THE SAME HOST.
;ALSO, IT IS RESPONSIBLE FOR RETRANSMITTING ANY NACK'ED MESSAGES.

;THE BACKGORUND PROCESS RUNS AS A FORK OF JOB 0 AND IS RESPONSIBLE
;FOR PARSING ALL CONTROL MESSAGE, COMPLETING ALL CONNECTS, PROCESSING
;ACK AND LINK SERVICE MESSAGES, ACTING AS A SERVICE OF NETSQI FOR
;ACTING ON ACKS THAT ARE PIGGY-BACKED ONTO DATA SEGMENTS, AND FOR
;GENERATING PROCESS INTERRUPTS. ALSO, THIS PROCESS WILL EVOLVE OVER
;TIME TO HANDLE ALL ROUTING STRATEGIES.

	SWAPCD			;ALL OF THIS CODE IS SWAPPABLE

TSKINI:	MCENTR			;GET INTO MONITOR CONTEXT
	SE1ENT			;MAKE IT RUN IN PROPER SECTION
	TRVAR <MSGCNT,MSGBYP,MSGSRC,MSGDST,MSGBLK,MSGLLB,MSGOBJ,<MSGDDC,5>,<MSGHSN,2>,MSGW1,MSGW2,MSGSOB,<MSGSDC,5>,<MSGDML,LKSIZE>,MSGLCL>
	MOVEI T1,MAXQ		;DON'T ALLOW THIS FORK TO BE "COMPUTE-BOUND"
	MOVEM T1,JOBBIT		;BY PREVENTING MAXQ SCHEDULING BEHAVIOR
NSPTSK:
   REPEAT 0,<			;RMSGQ NOT USED PRESENTLY
	SKIPN T1,RMSGQ		;ANYTHING ON EXPENDED QUEUE?
	JRST NSPTS1		;NO. GO ON
	HRRZS T1		;GET HEAD OF QUEUE
	NOSKED			;NO SCHEDULING
	CHNOFF DLSCHN		;TURN OFF CHANNEL
	LOAD T2,MSLNK,(T1)	;GET NEXT
	MOVEM T2,RMSGQ		;NEW HEAD
	CHNON DLSCHN		;TURN ON CHANNEL
	OKSKED			;AND THE SCHEDULER
	CALL RELRES		;FREE THE BLOCK
	JRST NSPTSK		;AND DO THEM ALL
   >				;END OF REPEAT 0
NSPTS1:	SKIPN MSGQ		;ANYTHING ON THE QUEUE?
	JRST [	SKIPE KDPFLG	;DOES KMC11 WANT SERVICE
		CALL KDPTSK	;YES SO CHECK IT
		MOVEI T1,NSPTST	;REST UNTIL WORK TO DO
		HDISMS (^D1500)	;WAIT, BUT STAY IN BALSET
		JRST NSPTSK]	;AND TRY AGAIN
	NOSKED			;GET SET TO PULL A MESSAGE OFF
	CHNOFF DLSCHN		;TURN OFF DTE
	HRRZ T1,MSGQ		;GET TOP MOST ENTRY
	LOAD T2,MSLNK,(T1)	;GET LINK
	HRRM T2,MSGQ		;STASH IT
	SKIPN T2		;WAS A MESSAGE THERE?
	SETZM MSGQ		;NO. CLEAR ENTIRE HEADER
	CHNON DLSCHN		;TURN ON DTE
	OKSKED			;AND ALLOW SCHEDULING
	SETZM MSGLCL		;ASSUME NOT LOCAL
	OPSTR <SKIPE>,MSLCL,(T1) ;IS IT LOCAL?
	SETOM MSGLCL		;YES. REMEMBER THIS
	MOVEM T1,MSGBLK		;SAVE BLOCK ADDRESS
	LOAD T2,MSCNT,(T1)	;GET BYTE COUNT OF THE MESSAGE
	MOVEM T2,MSGCNT		;SAVE IT
	ADDI T1,MSHDR		;GET TO START OF DATA
	HRLI T1,(<POINT 8,>)	;FORM BYTE POINTER
	MOVEM T1,MSGBYP		;AND SET UP BYTE POINTER
	; ..
;MESSAGE ALL SET UP. GET MESSAGE FLAGS

;HAVE A MESSAGE. SEE WHAT IT IS

	SETZM MSGHSN		;ASSUME NO HOST NAME
	CALL GETBYT		;GET A BYTE
	 JRST BADMSG		;BADLY FORMED. REJECT IT
	TRNE T2,201		;IS THIS A COUNT?
	JRST INVHDR		;HAS A COUNT. INVALID THEN
	TRNN T2,2		;IS THIS A ROUTING HEADER?
	JRST DOMSG		;NO. GO HANDLE MESSAGE THEN
	TRNE T2,100		;MUST BE ASCII NAME
	TRNE T2,60		;VALID ROUTING HEADER?
	JRST INVHDR		;NO.
	CALL SKPFLD		;SKIP OUR NAME
	 JRST BADMSG		;BADLY FORMED
	MOVEI T3,MSGHSN
	MOVEI T4,MAXHST
	CALL GTASCI		;AND GET ASCII FIELD
	 JRST BADMSG		;BADLY FORMED MESSAGE
	CALL GETBYT		;GET MESSAGE FLAGS
	 JRST BADMSG		;BADLY FORMED
DOMSG:	MOVE T3,MSGBLK		;GET MESSAGE BLOCK
	STOR T2,MSMFL,(T3)	;SAVE FLAGS
	LDB T4,[POINT 3,T2,31]	;EXTRACT SUBTYPE
	LDB T3,[POINT 2,T2,33]	;EXTRACT TYPE OF MESSAGE
	JRST @MSGTYP(T3)	;GO DO MESSAGE

MSGTYP:	IFIW!DATMSG		;DATA MESSAGE
	IFIW!ACKMSG		;AN ACK MESSAGE
	IFIW!CTLMSG		;A CONTROL MESSAGE
	IFIW!BADMSG		;BADLY FORMED MESSAGE

CTLMSG:	JRST @.+1(T4)		;GET TO PROPER TYPE OF MESSAGE
	IFIW!CIDON		;A NOOP. IGNORE IT
	IFIW!CIMSG		;CONNECT-INITIATE
	IFIW!CCMSG		;CONNECT-CONFIRM
	IFIW!DIMSG		;DI MESSAGE
	IFIW!DCMSG		;DC MESSAGE
	IFIW!STRMSG		;A STARTUP MESSAGE
	IFIW!BADMSG		;BADLY FORMED MESSAGE
	IFIW!BADMSG		;BADLY FORMED MESSAGE

;RECEIVED A MESSAGE WITH AN INVALID ROUTING HEADER.

INVHDR:	MOVE T1,MSGBLK		;GET MESSAGE
	LOAD T1,MSPRT,(T1)	;GET PORT I.D.
	BUG (CHK,NSPRTH,<NSPTSK- INVALID ROUTING HEADER>,<T1,T2>)
				;OPTIONAL DATA IS PORT NUMBER, OFFENDING CHARACTER
	CALL PROOFF		;TURN OFF THE INT THAT DID IT
	JRST CIDON		;AND GIVE UP
;GOT A STARTUP MESSAGE

STRMSG:	SETZM Q2		;INITIALIZE "VERIFICATION REQUESTED" FLAG
	MOVE T2,MSGBLK		;POINT TO MSG BLOCK AGAIN
	LOAD Q1,MSPRT,(T2)	;GET PORT MESSAGE CAME FROM
	JN INIRCV,MCBDTE(Q1),BADSTR	;IF ALREADY RUNNING, ERROR
	CALL GETBYT		;GET STARUP TYPE
	 JRST BADSTR		;BADLY FORMED
	CAIE T2,STRTYP		;THE EXPECTED ONE?
	JRST BADSTR		;NO
	CALL GETEXT		;GET NODE NUMBER
	 JRST BADSTR
	MOVEM T2,ITSNUM(Q1)	;SAVE NODE NUMBER
	MOVEI T3,ITSNAM(Q1)	;ITSNAM IS 2 WORDS/PORT
	ADDI T3,(Q1)		;POINT WHERE TO PUT NAME
	MOVEI T4,MAXHST
	CALL GTASCI		;GET IT
	 JRST BADSTR		;BAD
	STOR T2,NAMCN,MCBDTE(Q1) ;STORE COUNT OF BYTES IN NAME
	CALL GETBYT		;GET SUPPORTED FUNCTIONS
	 JRST BADSTR		;BAD
	TRC T2,OURNED
	MOVX T1,NOTMCB		;NEIGHBOR IS NOT AN MCB
	ANDCAM T1,MCBDTE(Q1)	;ASSUME NEIGHBOR IS AN MCB
	TRNE T2,OURNED		;DOES IT SUPPORT ALL REQUIRED FUNCTIONS?
	IORM T1,MCBDTE(Q1)	;REMEMBER NOT AN MCB
	CALL GETBYT		;GET ITS REQUIRED FUNCS
	 JRST BADSTR		;BAD
	TXNE T2,VERIF		;WANT SECURITY MESSAGE?
	SETOM Q2		;NOTE VERIFICATION WANTED
	CALL GETTWO		;GET MAX BLOCK SIZE
	 JRST BADSTR		;BAD
	MOVEM T2,MSGW1		;SAVE IT
	CALL GETTWO		;GET NSP MAX
	 JRST BADSTR
	CAMLE T2,MSGW1		;VALID?
	JRST BADSTR		;NO
	MOVEM T2,NSPMAX(Q1)	;YES. SET UP NSPMAX THEN
	MOVEI T4,10		;BYTES TO IGNORE
STRMS1:	CALL GETBYT		;GET A BYTE
	 JRST BADSTR
	SOJG T4,STRMS1		;SKIP BYTES
	MOVE T3,Q1		;GET PORT
	IMULI T3,^D9		;ITSID IS 9 WORDS/PORT
	ADDI T3,ITSID		;WHERE TO PUT IS ID
	MOVEI T4,^D36		;MAX SIZE OF ITSID
	CALL GTASCI		;GET IT
	 JRST BADSTR
	HRRM Q1,MCBDTE(Q1)	;SAVE PORT WE INITED ON
	MOVEI T1,ITSNAM(Q1)	;ITSNAM IS 2 WORDS/PORT
	ADDI T1,(Q1)		;POINT WHERE TO PUT NAME
	MOVEI T2,OURNAM		;POINT TO OUR NAME
	CALL CMPSTR		;SEE IF SAME NAME
	JRST STRMS6		;NAMES ARE NOT THE SAME
	SKIPE T1,NSPLPB		;GET PORT SCHEDULED FOR LOOPBACK
	CAIE Q1,(T1)		;IS THIS PORT SCHEDULED FOR LOOPBACK ?
	JRST BADSTR		;NO SO FLUSH INIT
	SETONE ND%LPR,NSPLPB	;LOOPBACK NOW RUNNING
	JRST STRMS7		;WE ARE NOW IN LOOPBACK MODE
STRMS6:	SKIPN T1,NSPLPB		;GET PORT FOR LOOPBACK
	JRST STRMS7		;NO PORT SCHEDULED FOR LOOPBACK
	CAIN Q1,(T1)		;IS THIS PORT SCHEDULED FOR LOOPBACK ?
	JRST BADSTR		;FLUSH THE PORT
STRMS7:	SETONE INIRCV,MCBDTE(Q1) ;NOTE INIT MSG RECEIVED
	JUMPN Q2,[JE INISNT,MCBDTE(Q1),[SETONE REQVER,MCBDTE(Q1)
					JRST .+1]
		  MOVE T1,Q1	;VERIFICATION WANTED, GET PORT NUMBER
		  CALL NODVER	;SEND VERIFICATION MESSAGE
		  JRST .+1 ]	;DONE, CONTINUE
	JRST CIDON		;AND GO TO IT

BADSTR:	CALL PROOFF		;TURN OFF FE
	BUG (INF,ILLSTR,<NSPTSK-ILLEGAL INIT MESSAGE>,<Q1>)
	JRST BADMSG		;DON'T INIT

;ROUTINE USED BY STRMSG TO TURN OFF AN MCB IF NODE INIT
;FAILS

PROOFF:	MOVE T1,MSGBLK		;GET MESSAGE
	LOAD T3,MSPRT,(T1)	;GET PORT I.D.
	MOVEI T2,T3		;POINT TO ARG BLOCK
	MOVEI T1,.BTTPR		;TURN OFF PROTOCOL
	BOOT			;DO IT
	 ERJMP .+1		;?
	RET			;DONE
;NODVER - ROUTINE TO ASSEMBLE AND SEND A NODE VERIFICATION MESSAGE
;
;ACCEPTS IN T1/	PORT ID
;		CALL NODVER
;RETURNS: +1 ALWAYS

NODVER:	TRVAR <<LLDUM,LKSIZE>,NODMSG,NODPRT>
	MOVEM T1,NODPRT		;SAVE PORT I.D.

; INITIALIZE MESSAGE BLOCK

	MOVEI T1,NDISIZ+MSHDR	;REQUIRES BLOCK SIZE
	CALL GETRES		;GET A BLOCK
	 RETBAD			;COULDN'T
	MOVEM T1,NODMSG		;SAVE BLOCK
	MOVEI T2,MSHDR(T1)	;POINT TO DATA PART
	HRLI T2,(<POINT 8,>)
	MOVEI T1,LLDUM		;DUMMY LL BLOCK
	SETZM LLBPCT(T1)	;INIT COUNT
	MOVEM T2,LLBPTR(T1)	;SET UP BYTE POINTER

; ASSEMBLE MESSAGE FLAGS AND STARTTYPE FIELDS

	MOVEI T2,CNMRFL+NDIFLG	;MESSAGE FLAGS
	CALL ONEBYT
	MOVEI T2,VERTYP		;NOD VERIFICATION MESSAGE
	CALL ONEBYT

; ADD PASSWORD TO MESSAGE

	MOVSI T4,-10		;8 BYTES
	MOVE T3,[POINT 7,[ASCII/DECNET20/]]
NDVER1:	ILDB T2,T3		;GET NEXT BYTE
	CALL ONEBYT		;ADD TO MESSAGE
	AOBJN T4,NDVER1		;DO ALL 8 BYTES

; SEND THE MESSAGE

	MOVE T2,NODMSG		;MESSAGE BLOCK
	MOVE T3,NODPRT		;GET PORT I.D.
	STOR T3,LLPRT,(T1)	;SAVE IN LL BLOCK
	MOVE T3,LLBPCT(T1)	;COUNT 
	CALLRET SNDSG0		;SEND IT
;ROUTINE USED TO SHUT ALL LINKS TO AN MCB THAT HAS DIED.
;ACCEPTS:	T1/ PORT NUMBER

DEDMCB::TRVAR <WAITER,DEDPRT,<DEDDUM,14>,MSGW1>
	SKIPL MCBDTE(T1)	;WAS THAT OURS
	RET			;NO
	SETZRO <INISNT,INIRCV,REQVER>,MCBDTE(T1)	;YES. NO LONGER INITED
	MOVEI T2,.DCX39		;GET ERROR
	MOVEM T2,MSGW1		;SAVE REASON
	MOVEM T1,DEDPRT		;SAVE PORT
	HRRZ T2,NSPLPB		;GET LOOPBACK PORT
	CAMN T1,T2		;WAS THAT ONE WHICH DIED ?
	SETZM NSPLPB		;NO LONGER LOOPED BACK
DEDMC1:	LLLOCK			;LOCK TREE
	MOVE T1,[DEDCOR]	;COROUTINE
	SETOM T2		;ALL LINKS
	CALL OBJSRC
	 JRST [	LLLULK		;FREE TREE
		RET]		;AND DONE
	LLLULK
	MOVE T1,WAITER		;GET WAIT TEST
	MDISMS			;WAIT FOR LINK
	JRST DEDMC1		;AND PROCEED
	RET			;DONE

;COROUTINE TO DO THE WORK

DEDCOR:	SAVET
	LOAD T2,LLPRT,(T1)	;GET PORT
	CAME T2,DEDPRT		;THIS ON THIS MCB?
	RET			;NO
	CALL BLKLOK		;YES. LOCK IT
	 JRST [	MOVEM T1,WAITER	;CAN'T. STORE WAIT
		RETSKP]		;AND STOP NOW
	CALL TSTLCL		;IS IT LOCAL?
	 JRST DEDMC2		;YES. NOT INTERESTED
	LOAD T2,LLSTA,(T1)	;GET STATE
	CAIG T2,LLSDIR		;NEED TO CHANGE STATE?
	XCT [	CALL RJECT	;YES. FOR CIS
		CALL RJECT1	;FOR CIR
		CALL SHUTLK	;FOR RUNNING
		CALL RJECT1	;FOR DI SENT
		CALL RJECT1	;FOR QUEUED
		CALL RJECT1]-2(T2) ;AND, FINALLY, FOR DI REC
	JN LLSDE,(T1),[	OKINT	;IF DISASSOCIATED
			CALLRET DELNOD] ;RELEASE NDOE
DEDMC2:	CALLRET BLKULK		;RELEASE BLOCK AND RETURN
;ROUTINES TO HANDLE CONTROL MESSAGES

;PROCESS A CONNECT-INITIATE

CIMSG:	CALL GETLLA		;GET LL ADDRESSES
	 JRST BADMSG		;BADLY FORMED
	SKIPE MSGDST		;IS DEST ADDR 0?
	JRST [	MOVEI T2,.DCX21	;ILLEGAL DEST ADDR
		JRST CIDC]	;AND GO BOMB IT OUT
	CALL CIPSRV		;GO DO OTHER FIELDS
	 JRST [	MOVEI T2,.DCX35
		JRST CIDC]	;AND BOMB IT OUT
	CALL GETBYT		;GET FORMAT OF DEST OBJECT
INVPRC:	 JRST [	MOVEI T2,.DCX5
		JRST CIDC]	;AND ERROR
	CAILE T2,OBJTWO		;IS IT A FORMAT WE UNDERSTAND?
	 JRST INVPRC
	MOVE T4,T2		;SAVE OBJECT TYPE
	CALL GETBYT		;GET OBJECT NUMBER
	 JRST INVPRC
	MOVEM T2,MSGOBJ		;SAVE OBJECT #
	SETZM MSGDDC		;ASSUME NO DESCRIPTOR
	CAIN T4,OBJZRO		;ANY MORE?
	JRST DSCNO		;NO
	CAIE T4,OBJONE		;A GROUP CODE INCLUDED?
	JRST [	CALL GETTWO	;YES. GET GOUP
		 JRST INVPRC	;INVALID
		CALL GETTWO	;GET USER CODE
		 JRST INVPRC	;INVALID
		JRST .+1]	;ALL READY TO GO
	MOVEI T3,MSGDDC		;DESCRIPTOR BLOCK
	MOVEI T4,MAXDSC		;MAX SIZE
	CALL GTASCI		;MOVE DESCRIPTOR STRING
	 JRST INVPRC
DSCNO:	CALL GETBYT		;GET SOURCE OBJECT TYPE
	 JRST INVPRC
	CAILE T2,OBJTWO		;VALID?
	 JRST INVPRC
	MOVE T4,T2		;SAVE IT
	CALL GETBYT		;GET OBJECT #
	 JRST INVPRC
	MOVEM T2,MSGSOB		;SAVE SOURCE OBJECT #
	SETZM MSGSDC		;ASSUME NO DESCRIPTOR
	SETZM MSGDML		;ASSUME NO GROUP,USER
	CAIN T4,OBJTWO		;DOES IT INCLUDE A GROUP?
	JRST [	CALL GETTWO	;YES. GET GROUP
		 JRST INVPRC	;BAD
		HRLM T2,MSGDML	;SAVE IT
		CALL GETTWO	;GET USER
		 JRST INVPRC
		HRRM T2,MSGDML	;SAVE IT
		JRST .+1]	;AND PROCEED
	CAIGE T4,OBJONE		;HAVE A DESCRIPTOR?
	JRST DSCNO1		;NO. GO FIND MATCH
	MOVEI T3,MSGSDC		;MOVE DESCRIPTOR
	MOVEI T4,MAXDSC		;MAX SIZE
	CALL GTASCI		;GET IT
	 JRST INVPRC
	; ..
;CIMSG CONTINUED .....

DSCNO1:	MOVE T2,MSGBLK		;POINT TO MSG BLOCK AGAIN
	LOAD T2,MSPRT,(T2)	;GET PORT MESSAGE CAME FROM
	OPSTR <SKIPE>,NTSHUT,MCBDTE(T2) ;SHUTTING DOWN?
	SKIPE MSGLCL		;YES. IS THIS A FOREIGN HOST?
	JRST DSCNO2		;NO. ALLOW IT.
	MOVEI T2,.DCX3		;"NODE SHUTTING DOWN"
	JRST CIDC		;AND REJECT THE CONNECT
DSCNO2:	MOVEI T1,CICOR		;COROUTINE ADDRESS
	MOVEI T2,1		;LOOK FOR LISTENING OBJECT ONLY
	LLLOCK			;LOCK THE TREE
	CALL OBJSRC		;GO LOOK FOR IT
	 JRST [	LLLULK		;RELEASE TREE
		MOVEI T2,.DCX4	;NO SUCH OBJECT
		JRST CIDC]
	CALL BLKLOK		;LOCK THE BLOCK
	 JRST [	LLLULK		;COULDN'T.
		MDISMS		;WAIT HERE
		JRST DSCNO2]	;AND TRY AGAIN
	LLLULK			;AND FREE THE TREE
	MOVEI T2,LLSCIR		;HAVE A CONNECT-INITIATE
	STOR T2,LLSTA,(T1)	;NOTE STATE CHANGE
	MOVEM T1,MSGLLB		;SAVE BLOCK
	MOVE T2,MSGOBJ		;GET OBJECT USED IN CONNECT
	STOR T2,LLSOB,(T1)	;SAVE IT
	MOVE T2,MSGDML		;GET GROUP,USER
	MOVEM T2,LLUSGP(T1)	;SAVE IN LL BLOCK
	SKIPE MSGLCL		;LOCAL CONNECTION?
	JRST HOSTNL		;YES. LEAVE NULL HOST NAME
	MOVEI T2,MSGHSN		;GET POINTER TO HOST NAME
	LOAD T1,LLHST,(T1)	;GET OUT HOST STRING
	SETOM T3		;NO COUNT
	CALL MOVSTR		;MOVE THE STRING
	MOVE T1,MSGLLB		;GET BACK BLOCK ADDRESS
	MOVE T2,MSGBLK		;GET MESSAGE
	LOAD T2,MSPRT,(T2)	;GET PORT #
	STOR T2,LLPRT,(T1)	;SAVE IN LL BLOCK
HOSTNL:	CALL FILLIN		;GO FILL IN COMMON QUANTITIES
	MOVE T2,MSGSOB		;GET SOURCE OBJECT
	STOR T2,LLFNM,(T1)	;SAVE IT
	LOAD T1,LLFDS,(T1)	;GET DESCRIPTOR STRING
	SKIPN T2,MSGSDC		;HAVE A DESCRIPTOR?
	JRST [	CALL RELBLK	;FREE THE BLOCK
		MOVE T1,MSGLLB	;GET BACK LL BLOCK
		SETZRO LLFDS,(T1) ;CLEAR IT
		JRST DSCMOV]
	SETOM T3		;UNTIL A NULL
	MOVEI T2,MSGSDC		;GET POINTER TO STRING
	CALL MOVSTR		;MOVE IT
	MOVE T1,MSGLLB		;GET BACK BLOCK ADDRESS
	; ..
;CIMSG CONTINUED. FOUND BLOCK. GET OPTIONAL ACCESS CONTROL STUFF

DSCMOV:	CALL GETBYT		;GET MENU BYTE
	 JRST NODATA		;NONE. NO OPTIONAL DATA THEN
	MOVEM T2,MSGW1		;SAVE MENU
	TRNN T2,1		;HAVE ACCESS CONTROL?
	JRST NOUSER		;NO. CHECK FOR OPDATA
	LOAD T3,LLUSR,(T1)	;WHERE TO PUT USER DATA
	MOVEI T4,MAXDSC		;MAX SIZE
	CALL GTASCI		;GET IT
	 JRST BADUDT		;BADLY FORMED
	LOAD T3,LLPSW,(T1)	;WHERE TO PUT PASSWORD
	MOVEI T4,^D8		;MAX PASSWORD SIZE
	CALL GTBNRY		;GET OCTETS
	 JRST BADUDT		;BADLY FORMED
	STOR T2,LLPCT,(T1)	;SAVE COUNT
	LOAD T3,LLACT,(T1)	;GET ACCOUNT DATA
	MOVEI T4,MAXDSC		;MAX SIZE
	CALL GTASCI		;GET IT
	 JRST BADUDT		;BADLY FORMED
NOUSER:	MOVE T2,MSGW1		;GET BACK MENU
	TRNN T2,2		;HAVE OPTDATA?
	JRST NODATA		;NO. ALL DONE
	LOAD T3,LLOPT,(T1)	;WHERE TO PUT IT
	MOVEI T4,MAXDSC		;MAX SIZE OF OPTDATA
	CALL GTBNRY		;GET OCTETS
	 JRST BADUDT		;BADLY FORMED
	STOR T2,LLUCT,(T1)	;SAVE COUNT
NODATA:	CALL BLKULK		;RELEASE THE BLOCK
DSCMV1:	CALL CONINT		;GIVE INTERRUPT
BADMSG:				;IGNORE THE MESSAGE
CIDON:	MOVE T1,MSGBLK		;GET BACK MESSAGE BLOCK
	CALL RELRES		;FREE THE BLOCK
	JRST NSPTSK		;AND TRY AGAIN
;COROUTINE OF CIMSG TO FIND THE PROPER LISTENING OBJECT

CICOR:	SAVET			;SAVE ALL TEMPS
	SKIPN T2,MSGOBJ		;WANT TASK NAME MATCH?
	JRST [	LOAD T2,LLTSK,(T1) ;YES. PICK UP STRING
		JRST CICOR1]	;AND GO TRY
	OPSTR <CAME T2,>,LLNAM,(T1) ;IS THIS THE CORRECT OBJECT?
	RET			;NO.
	LOAD T2,LLDSC,(T1)	;YES. CHECK DESCRIPTOR STRINGS
CICOR1:	MOVEI T1,MSGDDC		;GET REQUESTED DESCRIPTOR
	CALL CMPSTR		;GO COMPARE STRINGS
	 RET			;NOT THE ONE
	RETSKP			;FOUND IT!!!!

;COMMON ROUTINE TO FETCH LL ADDRESSES FROM MESSAGES AND STORE IN
;PROPER TRVAR'S

	RESCD			;USED BY INT LEVEL
GETLLA:	CALL GETTWO		;GET DEST LL
	 RET			;BADLY FORMED
	MOVEM T2,MSGDST		;SAVE IT
	CALL GETTWO		;GET SOURCE
	 RET			;BADLY FORMED
	MOVEM T2,MSGSRC
	RETSKP			;GO THEM

;COMMON ROUTINE TO FILL IN LL BLOCK AFTER SUCCESSFUL CONNECTION

	SWAPCD			;IS SWAPPABLE
FILLIN:	MOVE T2,MSGW1		;GET FC OPTION
	STOR T2,LLMFC,(T1)	;STORE IT
	MOVE T2,MSGW2		;GET SEGSIZE
	LOAD T3,LLBSZ,(T1)	;GET BYTE SIZE
	CAIE T3,44		;WORD MODE?
	JRST FILLI1		;NO.
	IDIVI T2,11		;YES. MAKE IT EVEN # OF WORDS THEN
	IMULI T2,11		;""
FILLI1:	STOR T2,LLSWG,(T1)	;SAVE IT
	MOVE T2,MSGSRC		;GET FOREIGN LINK I.D.
	STOR T2,LLHLK,(T1)	;SAVE IT
	RET			;AND DONE

;COMMON ROUTINE TO GEN CONNECT INTERRUPT

CONINT:	SAVET			;SAVE TEMPS
	LOAD T2,LLFRK,(T1)	;GET OWNING FORK
	OPSTR <SKIPN T1,>,LLPIC,(T1) ;HAVE A CONNECT PI?
	RET			;NONE TO DO
	SOS T1			;GET PROPER CHANNEL
	CALLRET PSIRQ		;GEN INTERRUPT
;PROCESS A CONNECT-CONFIRM

CCMSG:	CALL GETLLA		;GET LINK ADDRESSES
	 JRST BADMSG		;BADLY FORMED
	SETZM MSGSOB		;ASSUME WE LIKE SERVICES
	CALL CIPSRV		;GET SERVICES INFO
	 SETOM MSGSOB		;DIDN'T LIKE IT. REMEMBER THIS
CCMSG1:	MOVE T1,MSGDST		;GET OUR ALLEGED NAME
	SETOM T2		;ANY MATCH
	MOVEI T3,MSGHSN		;COMPARE HOST NAMES
	LLLOCK			;LOCK THE TREE
	CALL LLLKUH		;AND LOOK UP THE BLOCK
	 JRST [	LLLULK		;FREE THE TREE
		MOVEI T2,.DCX41	;NO MATCH
		JRST CIDC]	;GO DC THE LINK
	CALL BLKLOK		;LOCK BLOCK LOCK
	 JRST [	LLLULK		;FREE TREE LOCK
		MDISMS		;WAIT HERE A WHILE
		JRST CCMSG1]	;AND TRY AGAIN
	LLLULK			;FREE THE TREE
	JN LLFOB,(T1),CCJECT	;CAN'T BE AN OBJECT
	LOAD T2,LLSTA,(T1)	;GET STATE
	JRST @CCREC-1(T2)	;GO DO RIGHT THING

;EXPECTING A CC.

CCGUD:	SKIPN MSGSOB		;DID WE LIKE SERVICES?
	JRST CCGUD1		;YES
	MOVEI T2,LLSABT		;NEED TO CLOSE LINK
	STOR T2,LLSTA,(T1)	;SAY LINK IS DEAD
	CALL CONINT		;GET AN INTERRUPT
	MOVEI T2,.DCX35		;SERVICES MISMATCH
	JRST CCJEC1		;AND SEND A DC
CCGUD1:	SKIPG MSGSRC		;A VALID SOURCE I.D.?
	JRST [	SETZM MSGW1	;NO.
		CALL RJECT	;SHUT DOWN LINK
		JRST CCDON]	;AND GIVE UP
	CALL FILLIN		;FILL IN NECESSARY INFORMATION
	CALL TURNON		;GO SEND INTIAL LS MESSAGE
	 JRST [	CALL BLKULK	;FREE THIS BLOCK
		CALL GENWAT	;WAIT HERE FOR A WHILE
		MDISMS		;UNTIL FREE SPACE IS AVAILABLE
		JRST CCMSG1]	;AND DO IT AGAIN
	MOVEI T2,LLSRUN		;NOW WE ARE RUNNING
	STOR T2,LLSTA,(T1)	;SAY SO
	SETONE LLLWC,(T1)	;NOTE THAT LINK WAS CONNECTED
	LOAD T3,LLOPT,(T1)	;SEE IF ANY OPTDATA
	MOVEI T4,MAXDSC		;MAX SIZE OF OPTDATA
	CALL GTBNRY
	 JRST [	JUMPE T2,CCGUD2	;IF NO OPTDATA, OKAY
		JRST BADUDT]	;OTHERWISE, BAD MESSAGE
	STOR T2,LLUCT,(T1)	;YES. SAVE COUNT
CCGUD2:	MOVEI T2,1		;INITIAL COUNT FOR LS/INT
	STOR T2,LLMIC,(T1)	;STASH IT
	CALL BLKULK		;DONE WITH THE BLOCK
	JRST DSCMV1		;AND GO INTERRUPT, ETC.
;CCMSG CONTINUED...
;DON'T LIKE IT

CCJECT:	MOVEI T2,.DCX41		;ILLEGAL DEST ADDRESS
CCJEC1:	CALL BLKULK		;FREE THE BLOCK
	JRST CIDC		;AND SEND DC

CCDON:	CALL BLKULK		;FREE THE BLOCK
	JRST CIDON		;IGNORE THE MESSAGE

;ROUTINES TO SEND DC'S FOR CONNECT ERRORS

CIDC:	SKIPE MSGLCL		;IS IT LOCAL?
	JRST CIDCLC		;YES. GO DO IT
	SKIPN MSGHSN		;HAVE A HOST NAME FOR THE RETURN?
	JRST [	BUG (CHK,NOMHDR,<ILLEGAL MESSAGE WITH NO HEADER>)
		JRST CIDON]	;AND GIVE UP
	MOVEM T2,MSGW1		;SAVE CODE
CIDCT:	MOVEI T1,MSGDML		;USE DUMMY LINK BLOCK
	MOVEI T3,CNMRFL+CNMDC	;FLAGS
	MOVE T2,MSGW1		;GET REASON
	CALL SNDDC		;BUILD THE DC MESSAGE
	 JRST [	MDISMS		;WAIT A WHILE
		JRST CIDCT]	;AND TRY AGAIN
	CALL SNDCTL		;SEND IT
	JRST CIDON		;AND DONE

CIDCLC:	MOVE T1,MSGDST
	EXCH T1,MSGSRC		;EXCHANGE SOURCE AND DEST
	MOVEM T1,MSGDST		;""
	JRST DCMSG4		;AND GO DO DC

;ROUTINE TO HANDLE ACCESS INFORMATION ERRORS

BADUDT:	CALL CONINT		;INT PROCESS
	MOVEI T2,.DCX43		;SAY BAD OPTDATA
	STOR T2,LLRSN,(T1)	;AND STASH IT
	MOVEI T3,LLSABT		;NEW STATE
	STOR T3,LLSTA,(T1)
	CALL BLKULK		;FREE BLOCK
	JRST CIDC		;AND SEND DC
;ROUTINE TO BUILD A DI OR DC MESSAGE FOR NSPTSK
;ACCEPTS:	T1/ ADDRESS OF DUMMY LL BLOCK
;		T2/ REASON
;		T3/ FLAGS
;RETURNS:	+1 FAILED. NEED TO BLOCK
;		+2 ALL SENT

SNDDC:	MOVEI T4,MSGHSN		;GET ADDRESS OF HOST NAME
	STOR T4,LLHST,(T1)	;STORE IT
	MOVE T4,MSGSRC		;GET SOURCE NAME
	STOR T4,LLHLK,(T1)	;SAVE AS REMOTE NAME
	MOVE T4,MSGDST		;GET OUR NAME
	STOR T4,LLLNK,(T1)	;SAVE IT
	MOVE T4,T3		;MOVE FLAGS
	MOVE T3,MSGBLK		;GET MESSAGE
	LOAD T3,MSPRT,(T3)	;GET PORT
	STOR T3,LLPRT,(T1)	;SAVE IN LL BLOCK
	SETZM T3		;NO USER DATA
	CALLRET SNDDI		;BUILD THE MESSAGE
;RECEIVED AN ACK

ACKMSG:	CALL GETLLA		;GET LINK ADDRESSES
	 JRST BADMSG		;BADLY FORMED
	MOVE T1,MSGBLK		;GET BLOCK ADDRESS
	MOVE T3,MSGBYP		;GET CURRENT POINTER
	MOVEM T3,MSBPTR(T1)	;SAVE POINTER
	MOVE T3,MSGCNT		;GET CURRENT COUNT
	STOR T3,MSDTC,(T1)	;SAVE IT
ACKMS1:	LLLOCK			;LOCK THE TREE
	MOVE T1,MSGDST		;GET OUR NAME
	MOVE T2,MSGSRC
	CALL LLLKUP		;LOOK UP THE NAME
	 JRST [	LLLULK		;NOT FOUND
		MOVEI T2,.DCX41	;INVALID ADDRESS
		JRST CIDC]	;SEND A DC TO SHUT OFF THIS NOISE
	CALL BLKLOK		;FOUND IT. LOCK IT
	 JRST [	LLLULK		;CAN'T
		MDISMS		;WAIT A WHILE
		JRST ACKMS1]	;AND TRY AGAIN
	LLLULK
	LOAD T2,LLSTA,(T1)	;GET CURRENT STATE
	JRST @ACKSTA-1(T2)	;GO HANDLE IT

;IN CIS STATE

ACKCIS:	CALL GETTWO		;GET ACK VALUE
	 JRST ACKINV		;NOT VALID
	TXNE T2,ACKBIT		;ACK OR NACK?
	JRST CCDON		;A NACK. IGNORE IT
	JUMPN T2,ACKINV		;AN ACK. MUST BE FOR SEG # 0
	MOVE T2,MSGBLK		;GET FLAGS
	LOAD T2,MSMFL,(T2)	;""
	SKIPN MSGSRC		;MUST NOT HAVE A SOURCE NAME YET
	TXNE T2,ACKLSI		;AND MUST BE FOR DATA SUBCHANNEL
	JRST ACKINV		;NOT
	JRST CCDON		;A VALID ACK. IGNORE IT HOWEVER
ACKINV:	MOVEI T2,.DCX41		;INVALID.
	MOVEM T2,MSGW1		;SET UP ERROR CODE
	JRST CONREJ		;AND FAKE A CI REJECT

;IN RUN STATE

ACKRUN:	MOVE T2,MSGBLK		;GET MESSAGE
	LOAD T2,MSMFL,(T2)	;GET FLAGS
	CALL ACKDO		;GO DO THE ACTUAL ACK
	 JRST ABTMSG		;BADLY FORMED MESSAGE
	OPSTR <SKIPE>,LLLSA,(T1) ;WANT TO RETRY A LS SEND?
	CALL DATINR		;YES. MAKE PROCESS WAKE NOW THEN
	JRST CCDON		;AND DONE
;RECEIVED A DI MESSAGE

DIMSG:	CALL GETLLA		;GET LINK ADDRESSES
	 JRST BADMSG		;BAD MESSAGE
	CALL GETTWO		;GET REASON CODE
	 SETOM T2		;BADLY FORMED MESSAGE
	MOVEM T2,MSGW1		;SAVE REASON CODE
DIMSG1:	MOVE T1,MSGDST		;GET OUR NAME
	SETOM T2		;MATCH ANY LINK
	MOVEI T3,MSGHSN		;GET HOST NAME
	LLLOCK			;LOCK THE TREE
	CALL LLLKUH		;FIND THE LINK
	 JRST [	LLLULK		;FREE THE TREE
		MOVEI T2,.DCX41	;INVALID LINK I.D.
		JRST CIDC]	;AND SEND A DC
	MOVEM T1,MSGLLB		;SAVE BLOCK ADDRESS
	CALL BLKLOK		;LOCK THE BLOCK
	 JRST [	LLLULK		;FREE THE TREE
		MDISMS		;WAIT HERE FOR A WHILE
		JRST DIMSG1]	;AND TRY AGAIN
	LLLULK			;FREE THE TREE
	LOAD T3,LLOPT,(T1)	;GET OPTDATA, IF ANY
	MOVEI T4,MAXDSC
	CALL GTBNRY		;GO GET IT
	 SETZM T2		;NONE THERE.
	STOR T2,LLUCT,(T1)	;SAVE COUNT OF DATA
	LOAD T2,LLSTA,(T1)	;GET CURRENT STATE
	JRST @DIREC-1(T2)	;GO DO STATE ACTION

;DI RECIEVED WHEN IN CI SENT STATE

CONREJ:	CALL RJECT		;SET STATE OF LINK
	JRST DIMSG3		;SEND DC

;HERE FOR DI RECEIVED WHEN IN NON-RUN STATE

DIABT:	CALL CHKFRN		;SOURCE ADDR MUST MATCH
	 JRST CCJECT		;DOESN'T
	JN LLSDE,(T1),[	CALL RELLNK ;IF DISASSOCIATED
			MOVEI T2,.DCX9 ;SAY A USER ABORT
			JRST CIDC] ;AND SEND DC
	CALL RJECT1		;GO CHANGE LINK STATE
	JRST DIMSG3		;SEND DC

;DI OR DC RECIEVED IN RUN STATE

DIMSG2:	CALL CHKFRN		;SOURCE ADDR MUST MATCH
	 JRST CCJECT		;DOESN'T
	CALL SHUTLK		;SHUT DOWN LINK
DIMSG3:	SKIPN T2,MSGW1		;HAVE A BAD REASON?

;COMMON POINT FOR DI OR DC IN RUN STATE OR DC IN ABT STATE

DCDCS:	MOVEI T2,.DCX42		;NO. SAY REPLY TO DI THEN
	JRST CCJEC1		;AND GO SEND DC
;ROUTINES TO CHANGE LINK STATE WHEN DI OR DC IS RECIEVED

;FOR DI OR DC RECEIVED IN CIS STATE

RJECT:	MOVEI T2,LLSABT		;CONNECTION IS ABORTED
	STOR T2,LLSTA,(T1)	;SAY SO
	MOVE T2,MSGW1		;GET REASON CODE
	STOR T2,LLRSN,(T1)	;SAVE IN THE LL BLOCK
	CALLRET CONINT		;GIVE CONNECTION INTERRUPT

;FOR DI OR DC RECIEVED IN NON-RUN STATE

RJECT1:	MOVEI T2,LLSABT		;SAY LINK NOW ABORTED
	STOR T2,LLSTA,(T1)
	MOVE T2,MSGW1		;GET REASON
	STOR T2,LLRSN,(T1)	;STORE IN BLOCK
	CALLRET FLUSH		;CLEAR OUT LINK'S QUEUES

;FOR DI OR DC RECEIVED IN RUN STATE

SHTLK1:	SKIPA T3,[LLSDIS]	;NEW STATE
SHUTLK:	MOVEI T3,LLSDIR		;NEW STATE
	MOVE T2,MSGW1		;GET REASON
	STOR T2,LLRSN,(T1)	;SAVE IT
	STOR T3,LLSTA,(T1)	;SAVE NEW STATE
	CALL DATINR		;GIVE INT IF NECESSARY
	SKIPE MSGW1		;SYNCHRONOUS DI?
	JRST [	SETZRO LLFDI,(T1) ;NO. CLEAR THIS JUST IN CASE
		CALLRET FLUSH]	;AND CLEAN UP LINK
	SETONE LLFDI,(T1)	;YES. SAY SO
	RET			;AND DONE

;ROUTINE USED BY DIMSG TO VERIFY SOURCE ADDR
;	T1/ LINK ADDRESS
;RETURNS:	+1 NOT A MATCH
;		+2 A MATCH

CHKFRN:	LOAD T2,LLHLK,(T1)	;GET FOREIGN HOST I.D.
	CAME T2,MSGSRC		;IS THIS WHO SENT IT?
	RET			;NO
	RETSKP			;YES
;RECEIVED A DC MESSAGE

DCMSG:	CALL GETLLA		;GET LINK ADDRESSES
	 JRST BADMSG		;BADLY FORMED
	CALL GETTWO		;GET REASON
	 SETOM T2		;NONE THERE
DCMSG4:	MOVEM T2,MSGW1		;SAVE IT
DCMSG1:	MOVE T1,MSGDST		;GET OUR NAME
	MOVE T2,MSGSRC		;GET SOURCE ADDRESS
	MOVEI T3,MSGHSN		;HOST NAME STRING
	LLLOCK			;LOCK THE TREE
	CALL LLLKUH		;FIND THE LINK
	 JRST [	LLLULK		;FREE THE TREE
		JRST CIDON]	;IGNORE THE MESSAGE
	CALL BLKLOK		;LOCK THE BLOCK
	 JRST [	LLLULK		;CAN'T. FREE TREE
		MDISMS		;WAIT HERE
		JRST DCMSG1]	;AND TRY AGAIN
	LLLULK			;FREE TREE
	LOAD T2,LLSTA,(T1)	;GET STATE
	JRST @DCREC-1(T2)	;AND GO DO RIGHT THING

CHKIDL:	SKIPN MSGSRC		;REJECTING A CONNECTION?
	CALL RJECT		; YES, GO SET PROPER LINK STATE
	JRST CCDON		;AND DONE

;RECEIVED DC IN NON-RUN STATE

DCABT:	JN LLSDE,(T1),[	CALL RELLNK ;IF DISASSOCIATED
			JRST CIDON] ;JUST GIVE UP QUIETLY
	CALL RJECT1		;SET PROPER LINK STATE
	JRST CCDON		;AND DONE

;DC RECEIVED IN RUN STATE

DCRUN:	SKIPN T2,MSGW1		;AN ABORT?
	MOVEI T2,.DCX9		;NO. MAKE IT ONE THEN
	MOVEM T2,MSGW1
	CALL SHUTLK		;BEGIN LINK SHUT DOWN
	JRST CCDON		;AND DONE
;UTILITY ROUTINE TO RELEASE A DISASSOCIATED NODE

RELLNK:	OKINT			;DO THE OKINT TO MATCH THE LOCK
	CALLRET DELNOD		;FREE NODE AND RETURN
;DATA MESSAGE RECEIVED

DATMSG:	MOVEM T4,MSGW1		;SAVE SUBTYPE
	CALL GETLLA		;GET LINK ADDRESSES
	 JRST BADMSG		;BADLY FORMED
DATMS1:	LLLOCK			;LOCK TREE
	MOVE T1,MSGDST		;GET OUR NAME
	MOVE T2,MSGSRC		;GET REMOTE'S NAME
	CALL LLLKUP		;LOOK IT UP
	 JRST [	LLLULK		;FREE TREE
		MOVEI T2,.DCX41	;INVALID ADDRESS
		JRST CIDC]	;SEND A DC
	CALL BLKLOK		;LOCK UP THE BLOCK
	 JRST [	LLLULK		;FREE TREE
		MDISMS		;WAIT FOR BLOCK
		JRST DATMS1]	;AND TRY AGAIN
	LLLULK			;HAVE THE BLOCK
	MOVEM T1,MSGLLB		;SAVE LL BLOCK
	LOAD T2,LLSTA,(T1)	;GET STATE
	JRST @DATSTA-1(T2)	;GO DO IT

DATRUN:	MOVE T4,MSGW1		;GET BACK SUBTYPE
	TXNE T4,1		;DATA MESSAGE?
	JRST INTLS		;NO.
	CALL SETCNT		;SET COUNTS IN MESSAGE HEADER
	MOVE T2,MSGBLK		;GET MESSAGE BLOCK
	CALL ONRAWQ		;PUT IT ON THE Q
DATDON:	CALL BLKULK		;FREE BLOCK
	JRST NSPTSK		;AND DONE

INTLS:	CALL GETTWO		;GET ACK NUMBER
	 JRST ABTMSG		;GO KILL LINK
	TXZE T2,ACKIND		;AN ACK?
	JRST [	MOVEI T3,MSLSI	;GET PROPER CHANNEL
		CALL ACKCHN	;DO ACK
		CALL GETTWO	;GET SEGNUM
		 JRST ABTMSG	;BADLY FORMED
		JRST .+1]
	MOVE T3,MSGBLK		;GET BLOCK ADDRESS
	STOR T2,MSSEG,(T3)	;SAVE SEG #
	LOAD T3,LLIIN,(T1)	;GET EXPECTED NUMBER
	AOS T3
	ANDI T3,7777		;COMPUTE IT
	SUBI T3,0(T2)		;COMPUTE DIFFERENCE
	ANDI T3,7777
	JUMPE T3,LSINT1		;HAVE IT
	CAILE T3,MAXDIF		;OLD OR NEW?
	JRST LSIDON		;TOO NEW. IGNORE IT FOR NOW
INTLS1:	CALL ACKLI		;OLD SEG. GO REACK SUBCHANNEL
	 JRST [	MDISMS		;NO FREE SPACE. WAIT AWHILE
		MOVE T1,MSGLLB	;RESTORE BLOCK ADDRESS
		JRST INTLS1]	;AND TRY AGAIN
	JRST LSIDON		;AND DONE
;HAVE A GOOD INT OR LS MESSAGE

LSINT1:	STOR T2,LLIIN,(T1)	;STORE SEG #
	MOVE T4,MSGW1		;GET BACK SUBTYPE
	TRNN T4,2		;INT OR LS MESSAGE?
	JRST LSMSG		;LS
	SKIPE LLMSI(T1)		;NOW HAVE AN INTERRUPT MESSAGE?
	 JRST ABTMSG		;KILL LINK
	CALL SETCNT		;GO SET COUNTS IN BLOCK
	MOVE T2,MSGBLK		;GET BLOCK
	SETZRO MSLNK,(T2)	;CLEAR LINK WORD
	MOVEM T2,LLMSI(T1)	;STORE IT
	CALL INTINT		;GO INTERRUPT PROCESS
	CALL ACKLI		;GO ACK IT
	 SKIPA T1,MSGLLB	;GET BACK LL BLOCK
	JRST DATDON		;AND DONE
	TQZ <BLKF>		;IGNORE BLOCK REQUEST
	JRST DATDON		;AND DONE
;HAVE A LS MESSAGE

LSMSG:	CALL ACKLI		;ACK THE LS MESSAGE NOW
	 JRST [	MDISMS		;WAIT HERE UNTIL CAN DO IT
		MOVE T1,MSGLLB	;GET BACK LL BLOCK
		JRST LSMSG]	;AND TRY AGAIN
	CALL GETBYT		;GET LSFLAGS BYTE
	 JRST ABTMSG		;BADLY FORMED
	TXNN T2,3		;CHANGING BACK-PRESSURE?
	JRST LSMSG1		;NO
	TRNE T2,1		;STOPPING?
	JRST [	SETONE LLBRP,(T1) ;YES. SAY SO
		JRST LSMSG1]	;AND PROCEED
	SETZRO LLBRP,(T1)	;NO. START IT UP
LSMSG1:	MOVE T3,T2		;SAVE FIELD
	CALL GETBYT		;GET NEXT
	 JRST ABTMSG		;BADLY FORMED
	TXNE T3,4		;DATA COUNTS?
	JRST [	OPSTR <ADD T2,>,LLMIC,(T1) ;NO. COMPUTE NEW VALUE
		TXNE T2,200	;WITHIN RANGE?
		JRST ABTMSG	;NO
		STOR T2,LLMIC,(T1) ;YES. STORE IT
		JRST LSIDON]	;AND DONE
	LOAD T3,LLMFC,(T1)	;GET FLOW CONTROL TYPE
	JUMPE T3,LSIDN1		;IF NONE, GO ON
	TRNE T2,200		;IS THE COUNT NEGATIVE?
	CAIE T3,2		;YES. IS FLOW CONTROL MESSAGE TYPE?
	SKIPA			;NO. IS GOOD THEN
	JRST ABTMSG		;YES. LINK ERROR
	OPSTR <ADD T2,>,LLMSM,(T1) ;ADD IN THE NUMBER
	STOR T2,LLMSM,(T1)	;SAVE NEW VALUE
	TXNN T2,200		;IS THE COUNT NEGATIVE?
	JUMPN T2,[MOVEI T2,CHKSCT ;NO. HAVE SOME COUNT MORE
		PUSH P,T1	;SAVE LL BLOCK
		LOAD T1,LLFRK,(T1) ;GET FORK NUMBER
		CALL NETWKF	;WAKE UP THE PROCESS
		POP P,T1	;GET BACK LL BLOCK
		JRST .+1]	;AND PROCEED
LSIDN1:	CALL RESEND		;SEE IF CAN RESEND ANYTHING
LSIDON:	CALL BLKULK		;FREE THE BLOCK
	JRST CIDON		;AND DONE
;ROUTINES USED BY DATMSG.....

;KILL OFF LINK AFTER PROTOCOL ERROR.

ABTMSG:	MOVEI T2,.DCX40		;DATA LOSS
	MOVEM T2,MSGW1		;SAVE CODE
	CALL SHTLK1		;SHUT IT OFF
	MOVEM T1,MSGLLB		;SAVE LL BLOCK
	MOVEI T4,CNMRFL+CNMDI	;SEND A DI
	SETZM T3		;NO OPTDATA
	CALL SNDDI		;GO DO IT
	 JRST [	MOVE T1,MSGLLB	;RESTORE BLOCK ADDRESS
		MOVEI T2,LLSDIQ	;NEW STATE
		STOR T2,LLSTA,(T1)
		JRST LSIDON]	;AND DONE
	CALL SNDCTL		;SEND THE MESSAGE
	JRST LSIDON		;DONE

;ROUTINE TO FILL IN MESSAGE COUNTS IN MESSAGE BLOCK

SETCNT:	MOVE T3,MSGBLK		;GET BLOCK ADDRESS
	MOVE T4,MSGBYP		;GET CURRENT BYTE POINTER
	MOVEM T4,MSBPTR(T3)	;SAVE IT
	MOVE T4,MSGCNT		;GET CURRENT COUNT
	STOR T4,MSDTC,(T3)	;SAVE IT
	RET			;AND DONE
;ROUTINE TO SEND INTIAL LS MESSAGE TO OTHER END OF THE LINK.
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;RETURNS:	+1 FAILED. MESSAGES NOT SENT
;		+2 SUCCESS. MESSAGES SENT

TURNON:	JE LLOPI,(T1),RSKP	;IF NOT OPEN FOR READ, DON'T SEND LS
	MOVEI T3,MSDAT		;ON THE DATA SUBCHANNEL
	MOVEI T2,MAXSEG		;ASSUME SEG FLOW CONTROL
	OPSTR <SKIPE>,LLOPW,(T1) ;OPEN FOR WRITE AS WELL?
	MOVEI T2,MAXSG1		;YES. USE A SMALLER NUMBER
	OPSTR <SKIPE>,LLIMS,(T1) ;MESSAGE?
	MOVEI T2,1		;YES. ONE MESSAGE THEN
	CALLRET SNDLS		;SEND IT OFF
;ROUTINE TO CHECK IF A CONNECTION IS TO ANOTHER TASK
;ON THE SAME NODE.
;	T1/ LL BLOCK ADDRESS
;RETURNS:	+1 IS TO A LOCAL
;		+2 TO ANOTHER NODE

TSTLCL:	SAVEAC <T2>
	LOAD T2,LLHST,(T1)	;GET REMOTE HOST NAME
	SKIPE T2		;IF NO BLOCK
	SKIPN 0(T2)		;OR IF NO STRING
	RET			;IS LOCAL
	RETSKP			;OTHERWISE, IS TO A REMOTE
;COLLECTION OF ROUTINES TO GET FIELDS FROM A MESSAGE
;MOST ARE RESIDENT BECAUSE THEY ARE USED BY THE CHANNEL 7 CODE

;GET A BYTE

	RESCD			;CALLED FROM SCHEDULER
GETBYT:	SOSGE MSGCNT		;HAVE ANOTHER BYTE?
	RET			;NO. PROBABLY ERROR
	ILDB T2,MSGBYP		;GET A BYTE
	RETSKP			;AND DONE

;GET TWO BYTE FIELD
;PRESERVES T4

GETTWO:	CALL GETBYT		;GET A BYTE
	 RET			;FAILED
	LSHC T2,-10		;SAVE LOW ORDER BYTE
	CALL GETBYT		;GET NEXT ONE
	 RET			;FAILED
	LSHC T2,10		;COMBINE BYTES
	RETSKP			;AND DONE

;COPY ASCII STRING
;	T3/ POINTER TO COPY TO
;	T4/ MAX SIZE OF STRING
;RETURNS:
;	+1 FAILURE. BAD MESSAGE
;	+2 SUCCESS. T2/ COUNT OF BYTES COPIED

GTBNRY:	SKIPA T2,[POINT 8,0(T3)] ;ENTRY FOR OCTET COPY
GTASCI:	MOVE T2,[POINT 7,0(T3)]	;ENTRY FOR ASCII COPY
GTASC0:	ACVAR <W1,W2>		;ENTRY FOR SKPFLD
	MOVE W1,T2		;SAVE POINTER
	CALL GETBYT		;GET COUNT FIELD
	 JRST [	SETZM T2	;NO STRING
		RET]		;DONE
	CAMLE T2,T4		;COUNT WITHIN RANGE?
	RET			;NO. BAD MESSAGE THEN
	MOVE W2,T2		;SAVE COUNT
	SKIPN T4,T2		;SAVE COUNT
	JRST GTASCD		;NO COUNT
GTASC1:	CALL GETBYT		;GET A BYTE
	 RET			;FAILED
	IDPB T2,W1		;SAVE IT
	SOJG T4,GTASC1		;DO ALLOF THEM
GTASCD:	SETZ T2,		;GET A NULL
	IDPB T2,W1		;TIE OFF STRING
	MOVE T2,W2		;RETURN COUNT
	RETSKP			;AND DONE
;MORE BYTE MANIPULATION ROUTINES

;SKIP AN IMAGE FIELD

SKPFLD:	MOVE T2,[POINT 0,0,2]	;GET DUMMY FIELD
	MOVEI T4,-1		;BIG NUMBER
	CALLRET GTASC0		;MOVE ASCII FIELD TO NULL AREA

;GET AN EXTENSIBLE FIELD

	SWAPCD			;ONLY FROM PROCESS CONTEXT
GETEXT:	SETZB T3,T4		;INIT ACCUMULATOR AND COUNTER
GETEX1:	CALL GETBYT		;GET NEXT BYTE
	 RET			;BAD
	AOS T4			;GOT ANOTHER ONE
	LSHC T2,-7		;PUT DATA PART IN ACCUMULATOR
	TXZE T2,1		;WAS IT EXTENDED?
	JRST GETEX1		;YES. GET NEXT THEN
	IMULI T4,7		;COMPUTE GOOD BITS IN ACCUMULATOR
	LSHC T2,0(T4)		;PUT FIELD IN T2
	RETSKP			;AND DONE
;ROUTINE USED BY CI AND CC TO PROCESS COMMON FIELDS

	SWAPCD			;SWAPPABLE
CIPSRV:	CALL GETBYT		;GET SERVICES
	 RET			;BAD
	TXC T2,1
	TRNE T2,363		;MUST BE NORMAL LINK AND NO MSG ACK
	RET			;NO. CAN'T HAVE IT
	LSH T2,-2		;GET FCOPT FIELD
	CAIN T2,3		;A VALID FLOW CONTROL?
	RET			;NO.
	MOVEM T2,MSGW1		;YES. SAVE IT
	CALL GETBYT		;GET LINK PRI
	 RET			;ASSUME IT IS GOOD
	CALL GETTWO		;GET SEGSIZE
	 RET			;BAD
	SKIPN MSGLCL		;LOCAL LINK?
	CALL [	SAVEAC <T3>
		MOVE T3,MSGBLK	;GET MESSAGE ADDRESS
		LOAD T3,MSPRT,(T3) ;GET PORT OF MESSAGE
		CAMLE T2,NSPMAX(T3) ;NO. SEE IF CAN SEND ONE THIS BIG
		MOVE T2,NSPMAX(T3) ;NO. USE INTERCEPT'S NUMBER
		SUBI T2,NSPHDR	;ADJUST FOR THE HEADER
		RET]		;AND DONE
	MOVEM T2,MSGW2		;SAVE IT
	RETSKP			;ALL GOOD
;REQUEST QUEUER ROUTINES
;SEND CONTROL MESSAGE
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ MESSAGE BLOCK
;RETURNS:	+1 ALWAYS

SNDCTL:	SAVET			;SAVE ALL REGISTERS
	ASUBR <SAVLL,SAVMSG>	;SAVE ARGS
	MOVE T3,LLBPCT(T1)	;GET MESSAGE COUNT
	STOR T3,MSCNT,(T2)	;STORE IN THE BLOCK
	CALL TSTLCL		;SEE IF TO A LOCAL
	 JRST CTLLCL		;YES. GO HANDLE IT
	MOVE T2,SAVMSG		;GET BLOCK ADDRESS
SNDSG0:	LOAD T1,LLPRT,(T1)	;GET PORT I.D.
;	HRLI T1,MSGPST		;POSTING ADDRESS
	HRLI T1,RELRES		;MAKE DTESRV RELEASE THE BLOCK
SNDMSG:	STKVAR <SAVPST,SAVFF>	;TEMP SAVE LOCATIONS
	MOVEM F,SAVFF		;SAVE F
	MOVE F,T2		;UNIQUE CODE FOR POST
	OPSTR <SKIPE>,MSMS1,(T2) ;SENT THIS MESSAGE ONCE YET?
	TXO T3,1B0		;YES. TELL DRIVER OF THIS THEN
	SETONE MSMS1,(T2)	;SAY SENT IT ONCE
	MOVEI T2,MSHDR(T2)	;GET DATA PORTION OF MESSAGE
	HRLI T2,(<POINT 8,>)	;MAKE A BYTE POINTER
	HLRZM T1,SAVPST		;SAVE POSTING ADDRESS
	CALL DCNMSO		;SEND THE MESSAGE
	 JRST [	MOVE T1,F	;FAILED. PORT MUST BE TURNED OFF.
				;SET UP FOR POST IF ANY
		SKIPE T2,SAVPST	;WANT A POST ON DONE?
		CALL 0(T2)	;YES. DO IT THEN
		JRST .+1]	;AND GO FINISH UP
	MOVE F,SAVFF		;RESTORE F
	RET			;AND DONE

;CONNECTION IS TO A TASK ON THIS NODE

CTLLCL:	SETONE MSLCL,(T2)	;REMEMBER IS LOCAL
	CALLRET ONMSQ		;AND GO DO IT
;VARIOUS QUEUENING ROUTINES USED BY INT, SCHED, AND PROCESS LEVELS

;ROUTINE TO PUT A MESSGE ON NSPTSK'S QUEUE

	RESCD
ONMSGQ:	MOVEI T3,MSGQ		;GET QUEUE HEAD
	CALLRET PUTONQ		;PUT DATA ON

;ROUTINE TO QUEUE UP EXPENDED MESSAGE BLOCKS FROM DTESRV

   REPEAT 0,<			;NOT USED PRESETNLY
MSGPST:	MOVE T2,RMSGQ		;GET OLD HEAD
	MOVEM T1,RMSGQ		;MAKE NEW HEAD
	STOR T2,MSLNK,(T1)	;LINK IN
	RET			;AND DONE
   >				;END OF REPEAT 0

;ROUTINE CALLED FROM INTERRUPT LEVEL TO PUT A MESSAGE ON THE SCHEDULER'S
;QUEUE
;		T2/ DATA ADDRESS

NSPQ::	MOVEI T2,-MSHDR(T2)	;GET POINTER TO HEADER
	MOVEI T3,SMSGQ		;GET QUEUE HEAD
	CALLRET PUTONQ		;AND DO IT
;ROUTINE TO SEND A DATA,LS, OR INT MESSAGE
;ACCEPTS:	T1/ LL BLOCK
;		T2/ MESSAGE BLOCK

	SWAPCD			;IS SWAPPABLE

SNDSEG:	ASUBR <SNLBLK,SNMSG>
	MOVE T3,LLBPCT(T1)	;GET BYTE COUNT
	STOR T3,MSCNT,(T2)	;TO THE MESSAGE
	LOAD T3,LLLNK,(T1)	;GET LINK I.D.
	STOR T3,MSLLA,(T2)	;TO THE MESSAGE
	CALL TSTLCL		;LOCAL CONNECTION?
	 JRST SNDLCL		;YES.
	CALL ONSEGQ		;PUT IT ON THE SEG QUEUE
SNDSE2:	LOAD T3,MSCNT,(T2)	;GET COUNT
	LOAD T1,LLPRT,(T1)	;PORT I.D.
	HRLI T1,SEGPST		;POSTING ADDRESS
	SETONE MSPST,(T2)	;SAY WAITING FOR POST
	CALL SNDMSG		;SEND IT
SNDSE1:	MOVE T1,SNLBLK		;GET BLOCK ADDRESS
	RET			;AND DONE

;ROUTINE TO PUT A DATA,LS, OR INT SEGEMENT ON THE SEND Q
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ MESSAGE BLOCK

ONSEGQ:	INCR LLQOU,(T1)		;ONE MORE ON Q
ONSGQ0:	MOVEI T3,LLSEGQ(T1)	;GET HEADER
	CALLRET PUTONQ		;PUT SEG ON THE Q

;LOCAL ROUTINE TO PUT MESSAGE ON INPUT QUEUE

ONMSQ:	NOSKED			;NO SCHEDULING
	CALL ONMSGQ		;PUT MESSAGE ON THE QUEUE
	OKSKED			;AND SCHEDULING
	RET			;AND DONE

;ENTRY USED TO RESEND A NACKED MESSAGE

SNDSE0:	ASUBR <SNLBLK,SNMSG>
	CALLRET SNDSE2		;SEND IT
;SNDSEG CONTINUED...
;ROUTINE TO SEND SEGMENT TO A LOCAL CONNECTION

SNDLCL:	SETONE MSLCL,(T2)	;SAY IS LOCAL
	LOAD T3,MSMFL,(T2)	;GET FLAGS
	TXNE T3,DATFLI		;IS THIS AN INTERRUPT MESSAGE?
	JRST SNDBAD		;YES. GO HANDLE VIA NSPTSK
	LOAD T2,LLLNK,(T1)	;GET OUR I.D.
	LOAD T1,LLHLK,(T1)	;GET I.D. OF OTHER PROCESS
	LLLOCK			;LOCK UP THE TREE
	CALL LLLKUP		;GO FIND ENTRY
	 JRST SNDBAD		;NOT THERE
	LLLULK			;RELEASE THE TREE
	MOVE T2,SNMSG		;GET MESSAGE BLOCK
	NOSKED			;PROTECT LINK STATE
	LOAD T3,LLSTA,(T1)	;GET STATE OF THE LINK
	CAIE T3,LLSRUN		;RUNNING?
	JRST SNDBA1		;NO.
	CALL ONRAWQ		;GO PUT ON THE QUEUE
	OKSKED			;ALL DONE
	JRST SNDSE1		;GO Q IT UP ON SEG Q

;ERROR ROUTINES

SNDBA1:	OKSKED
SNDBAD:	MOVE T2,SNMSG		;GET MESSAGE ADDRESS
	CALL ONMSQ		;PUT DATA MESSAGE ON NSPTSK'S Q
	JRST SNDSE1		;AND DONE FOR NOW
;ROUTINES USED BY INTERRUPT LEVEL TO QUEUE UP PACKETS

;PUT A DATA MESSAGE ON THE LINK'S QUEUE
;	T1/ LL BLOCK ADDRESS
;	T2/ MESSAGE BLOCK

	RESCD			;MUST BE RESIDENT
ONRAWQ:	NOSKD1			;HOLD OFF SCHEDULER
	LOAD T3,MSMFL,(T2)	;GET MESSAGE FLAGS
	TXNE T3,ACKFLM		;IS IT AN ACK?
	 JRST [	JN LLLSA,(T1),ONRAW2 ;IN LS SEND WAIT?
		JRST ONRAW1]	;NO. GO ON
	OPSTR <AOS T3,>,LLDMT,(T1) ;ACCOUNT FOR ONE MORE DATA MESSAGE
	CAILE T3,MAXSEG		;TOO MANY ON Q?
	JRST [	SETONE LLFNN,(T1) ;YES.
		PUSH P,T1	;SAVE LL BLOCK
		MOVE T1,T2	;GET DATA BLOCK ADDRESS
		CALL RELRES	;GET RID OF IT
		POP P,T1
		CALL DATINR	;REQUEST INT
		JRST ONRAW3]	;AND GO WRAP UP
	STOR T3,LLDMT,(T1)	;NO. SAVE NEW COUNT
	OPSTRM <AOS T3,>,LLDRW,(T1) ;INCREMENT DATA MESSAGE COUNT
	CAIN T3,1		;NO. IS THIS NOT THE FIRST ONE?
ONRAW2:	CALL DATINR		;GIVE INT
ONRAW1:	MOVE T3,LLMSG(T1)	;GET HEAD OF QUEUE
	MOVEM T2,LLMSG(T1)	;STORE NEW HEAD
	STOR T3,MSLNK,(T2)	;COMPLETE LINK
ONRAW3:	OKSKD1
	RET			;AND DONE

;GIVE DATA INTERUPT

DATINR:	SAVEAC <T1,T2>		;SAVE VOLATILE REGS
	LOAD T2,LLFRK,(T1)	;GET FORK I.D.
	OPSTR <SOSL T1,>,LLDRC,(T1) ;WANT DATA INT?
	CALL PSIRQ		;YES. GIVE IT
	RET			;AND DONE
;POSTING ADDRESS FOR SEGMENTS. T1= MESSAGE ADDRESS

SEGPST:	JN MSRLS,(T1),RELRES	;IF "RELEASED", GO DO IT
	SETZRO MSPST,(T1)	;NOT. SAY POSTED
	RET			;AND DONE
;ROUTINE TO HANDLE ACK OR NACK FOR A SUBCHANNEL.
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ ACK OR NACK #
;		T3/ SUBCHANNEL OF THE ACK/NACK
;RETURNS:	+1 ALWAYS. ALL REGS PRESERVED

	SWAPCD
ACKCHN:	CALL TSTLCL		;LOCAL?
	 RET			;YES. NOTHING TO DO
	SAVET			;SAVE ALL REGS
	ACVAR <W1,W2,W3>	;GET WORK REGS
	STKVAR <LLBLK,ACKNO,ACKCHL,LNKADR>
	MOVEM T1,LLBLK		;SAVE LL BLOCK
	MOVEM T3,ACKCHL		;SAVE CHANNEL
	MOVEM T2,ACKNO
	TRZE T2,ACKBIT		;IS IT A NACK?
	JRST [	CALL ACKCHN	;DO IT
		JRST DONACK]	;AND GO DO THE NACK
	ANDI T2,7777		;GET SEG NUMBER ONLY
	MOVEM T2,ACKNO		;SAVE ACK NUMBER
ACKLP1:	SKIPN W1,LLSEGQ(T1)	;HAVE ANY SEGS?
	JRST ACKDON		;NO. ALL DONE THEN
	SETZ W2,		;NO PREVIOUS
	HRRZS W1		;GET TOP SEG
	; ..
;ACKCHN CONTINUED...
;LOOP TO PROCESS QUEUE

ACKLOP:	LOAD T3,MSTOM,(W1)	;GET TYPE
	CAME T3,ACKCHL		;IS THIS THE PROPER SUBCHANNEL?
	JRST ACKNXT		;NO. GO ON
	LOAD T3,MSSEG,(W1)	;GET SEGMENT #
	SUB T3,ACKNO		;COMPUTE "AGE"
	ANDI T3,7777		;MOD 4096
	SKIPE T3		;IS IT THE VERY ONE WE ARE DOING?
	CAILE T3,MAXDIF		;NO. IS IT ACKABLE ANYWAY?
	SKIPA			;YES. ACK IT THEN
	JRST ACKNXT		;NO.
	MOVEI T4,LLSEGQ(T1)	;THE Q ADDRESS
	CALL UNQSEG		;REMOVE SEGEMENT
	DECR LLQOU,(T1)		;ONE LESS SEG IN QUEUER
	EXCH T1,W1		;GET BLOCK
	CALL RELRES		;FREE IT
	MOVE T1,W1
	JUMPE W2,ACKLP1		;IF AT THE HEAD, START OVER
	LOAD W1,MSLNK,(W2)	;GET THE ONE TO DO NEXT
	JUMPN W1,ACKLOP		;DO IT IF ONE THERE
	JRST ACKDON		;ALL DONE
ACKNXT:	MOVE W2,W1		;SAVE PREVIOUS
	LOAD W1,MSLNK,(W1)	;GET NEXT
	JUMPN W1,ACKLOP		;DO ALL
ACKDON:	RET			;AND DONE

;LOCAL ROUTINE TO TAKE A SEGMENT OFF OF A SEGMENT Q

UNQSEG:	JUMPE W2,[LOAD T3,MSLNK,(W1) ;IS HEAD
		HRRM T3,0(T4)	;MAKE NEW HEAD
		SKIPN T3	;NOW EMPTY?
		SETZM 0(T4)	;YES
		RET]		;AND DONE
	LOAD T3,MSLNK,(W1)	;GET LINK
	STOR T3,MSLNK,(W2)	;REMOVE FROM Q
	SKIPN T3		;REMOVING THE TAIL?
	HRLM W2,0(T4)		;YES. MAKE NEW TAIL THEN
	RET			;AND DONE
;ROUTINE TO PROCESS A NACK
;	T1/ BLOCK ADDRESS
;	NACK NUMBER IN THE STKVAR "ACKNO"

DONACK:	AOS T2,ACKNO		;GET THE ACK #
	ANDI T2,7777		;AND GET MODULO 4096
	MOVEM T2,ACKNO		;SAVE IT
	SETZ W2,		;NO HEAD
DONAC2:	SKIPN W1,LLSEGQ(T1)	;HAVE ANY SEGS?
	JRST ACKDON		;NO. ALL DONE
	HRRZS W1		;GET FIRST MESSAGE
DONAC1:	LOAD T3,MSTOM,(W1)	;GET MESSAGE TYPE
	CAME T3,ACKCHL		;THE CORRECT CHANNEL?
	JRST DONNXT		;NO
	LOAD T3,MSSEG,(W1)	;GET SEG #
	SUB T3,ACKNO		;COMPUTE "AGE"
	ANDI T3,7777		;""
	CAILE T3,MAXDIF		;IS IT ONE BEING NACKED?
	JRST DONNXT		;NO
	AOS NAKCNT		;COUNT THIS SEGMENT
	MOVE T3,ACKCHL		;YES. GET CHANNEL
	CAIE T3,MSDAT		;DATA?
	JRST DONRES		;NO. RESEND NOW
	LOAD T3,LLMFC,(T1)	;GET FLOW CONTROL TYPE
	CAIN T3,1		;SEGMENT?
	JRST [	CALL INCMSM	;YES. ACCOUNT FOR THE NACK
		JRST .+1]
	JN LLBRP,(T1),[
		CAIE T3,2	;MESSAGE FLOW CONTROL?
		JRST DONRQ	;NO. GO ARRANGE FOR REQUEUE
		LOAD T3,MSMFL,(W1) ;YES. GET MESSAGE FLAGS
		TXNE T3,DATEOM	;IS THIS THE EOM?
		CALL INCMSM	;YES. INCREMENT REQUEST COUNT
		JRST DONRQ]	;AND REQUEUE IT
	CAIE T3,1		;YES. SEGMENT?
	JRST DONRES		;NO. RESEND NOW
	LOAD T3,LLMSM,(T1)	;GET SEG COUNT TO SEND
	SKIPE T3		;ANY THERE?
	TXNE T3,200		;AND IS IT POSITIVE?
	JRST DONRQ		;NO.
	CALL DECMSM		;YES. COUNT DOWN
DONRES:	MOVE T2,W1		;GET SEG
	CALL SNDSE0		;RESEND IT NOW
DONNXT:	MOVE W2,W1		;NEW HEAD
	LOAD W1,MSLNK,(W2)	;GET NEXT
	JUMPN W1,DONAC1		;IF MORE, DO IT
	JRST ACKDON		;DONE
DONRQ:	SETONE MSNAK,(W1)	;REMEMBER IS NAKED
	INCR LLQUN,(T1)		;AND ACCOUNT FOR IT
	JRST DONNXT		;AND CONTINUE DOWN Q
;ROUTINE TO PUT A DATA MESSAGE ON A SEGMENT Q
;	T2/ THE MESSAGE
;	T3/ THE QUEUE ADDRESS
;CLOBBERS T4

	RESCD
PUTONQ:	SKIPN T4,0(T3)		;HAVE A QUEUE?
	JRST [	HRRM T2,0(T3)	;NO MAKE ONE
		HRLM T2,0(T3)
		JRST PUTOND]	;DONE
	HLRZS T4		;GET TAIL
	STOR T2,MSLNK,(T4)	;LINK THIS IN
	HRLM T2,0(T3)		;AND MAKE IT THE TAIL
PUTOND:	SETZRO MSLNK,(T2)	;TIE IT OFF
	RET			;AND DONE
;ROUTINE TO RESEND NACK'ED SEGMENTS
;ACCEPTS:	T1/ BLOCK ADDRESS
; BLOCK MUST BE LOCKED

RESEND:	JE LLQUN,(T1),R		;ANY NAKED SEGS?
	JN LLBRP,(T1),R		;YES. IS FLOW ON?
	JE LLMFC,(T1),RSEND0	;IF NO FLOW CONTROL, GO RESEND NOW
	LOAD T3,LLMSM,(T1)	;GET COUNT
	SKIPE T3		;IF ZERO
	TXNE T3,200		;OR IF NEG
	RET			;CAN'T RESEND
RSEND0:	HRRZ T2,LLSEGQ(T1)	;GET HEAD OF Q
RSEND1:	OPSTR <SKIPN>,MSNAK,(T2) ;IS THIS A NAKED SEG?
	JRST [	LOAD T2,MSLNK,(T2) ;NO. GET NEXT
		JRST RSEND1]	;AND PROCEED
	DECR LLQUN,(T1)		;ONE LESS NAKED SEG
	LOAD T3,LLMFC,(T1)	;GET TYPE OF FLOW CONTROL
	JUMPE T3,RSEND3		;IF NO FLOW CONTROL, SEND IT NOW
	CAIE T3,2		;MESSAGE FLOW CONTROL?
	JRST RSEND2		;NO. SEND IT NOW THEN
	LOAD T3,MSMFL,(T2)	;GET MESSAGE FLAGS
	TXNE T3,DATEOM		;IS THIS EOM?
RSEND2:	CALL DECMSM		;YES. DOWNCOUNT REQUEST COUNT
RSEND3:	SETZRO MSNAK,(T2)	;NO LONGER A NACKED SEG
	CALL SNDSE0		;AND RESEND IT
	JRST RESEND		;AND DO IT AGAIN
;ROUTINE TO FLUSH ALL QUEUES FOR A LL
;FLUSHES: SEGQ,RSEGQ,LLMSG,LLOMSG
;	T1/ LL BLOCK LL TREE MUST BE LOCKED
;RETURNS +1 ALWAYS

	SWAPCD

FLUSH:	SETZRO <LLQUN,LLQOU>,(T1) ;CLEAR COUNTS
	MOVEI T2,LLOMSG(T1)	;GET ORDERED QUEUE
	CALL PRUNE		;KILL IT
	MOVEI T2,LLMSG(T1)	;GET ORDERED Q
	CALL PRUNE		;KILL IT
	MOVEI T2,LLMSI(T1)	;INT MESSAGES
	CALL PRUNE		;KILL THIS AS WELL
	MOVEI T2,LLSEGQ(T1)	;GET SENT Q
	CALLRET PRUNE		;GET RID OF THEM

;WORKER ROUTINE TO FLUSH A LINK Q

PRUNE:	SAVET			;SAVE ALL REGS
	HRRZ T1,0(T2)		;GET HEAD
	SETZM 0(T2)		;CLEAR Q
PRUNE1:	JUMPE T1,R		;IF AT THE END, DONE
	LOAD T2,MSLNK,(T1)	;GET NEXT
	PUSH P,T2		;SAVE IT
	JN MSPST,(T2),CHKPST	;IF POSTING ON, GO CHECK OUT MESSAGE
PRUNE2:	CALL RELRES		;RELEASE NODE
PRUNE3:	POP P,T1		;GET BACK NEXT
	JRST PRUNE1		;AND DO IT

;MESSAGE NEEDS TO BE PRUNED BUT POSTING IS STILL OUTSTANDING.

	RESCD

CHKPST:	PIOFF			;OWN MACHINE WHILE CHECKING MESSAGE
	JE MSPST,(T1),CHKPS1	;IF NO LONGER NEEDED, GO ON
	SETONE MSRLS,(T1)	;IS STILL NEEDED. REQUEST RELEASE WHENEVER
	PION			;ALLOW INTS AGAIN
	JRST PRUNE3		;DON'T RELEASE IT
CHKPS1:	PION			;ALLOW INTS
	JRST PRUNE2		;AND RELEASE IT
	SWAPCD			;BACK TO SWAPPABLE MONITOR
;ROUTINE TO SEND AN ACK MESSAGE.
;	T1/ LL BLOCK
;	T2/ SEGMENT # TO ACK
;	T3/ SUBCHANNEL TO ACK
;RETURNS +1	ALL REGS PRESERVED

SNDACK:	ASUBR <LLBLK,ACKNO,ACKTYP>
	CALL TSTLCL		;SEE IF A LOCAL CONNECTION
	 RETSKP			;YES IT IS. NOTHING TO DO THEN
	JRST ACKRMT		;NO. NEED TO SEND A MESSAGE

;HANDLE LOCAL ACK
;THIS CODE HAS BEEN REMOVED AS IT IS NO LONGER NECESSARY.
;NOTE, THERE IS A BUG IN IT ANYWAY,AS A FAILURE TO LOCK THE
;OTHER BLOCK WILL CAUSE CONFUSION IN NETSET. IF THIS CODE
;IS EVER TURNED ON AGAIN, THEN CHKFRE MUST INCLUDE A CHECK
;FOR LOCK FAILURE AS WELL AS FREE SPACE FAILURE.   ASM

   REPEAT 0,<
	LOAD T2,LLLNK,(T1)
	LOAD T1,LLHLK,(T1)	;GET OTHER ONE'S ADDRESS
	LLLOCK			;LOCK THE TREE
	CALL LLLKUP		;GO LOOK UP MATCHER
	 JRST ACKLO2		;NOT THERE. THIS WILL GET FIXED
	LOAD T2,LLSTA,(T1)	;GET CURRENT STATE?
	CAIE T2,LLSRUN		;RUNNING
	CAIN T2,LLSDIQ		;OR DI QUEUED?
	JRST ACKLO1		;IS GOOD
ACKLO2:	LLLULK			;FREE TREE
ACKLO3:	MOVE T1,LLBLK		;RETURN LL BLOCK ADDRESS
	RETSKP			;AND RETURN
ACKLO1:	CALL BLKLOK		;LOCK THE BLOCK
	 JRST [	LLLULK		;FAILED
		RET]		;TRY AGAIN LATER
	LLLULK			;FREE TREE
	MOVE T2,ACKNO		;GET NUMBER
	MOVE T3,ACKTYP		;AND THE TYPE
	CALL ACKCHN		;GO DO THE ACK
	CALL BLKULK		;UNLOCK THE BLOCK
	JRST ACKLO3		;AND GO WRAP UP
   >				;END OF REPEAT 0

;ROUTINE TO ACK THE LS/INT CHANNEL

ACKLI:	LOAD T2,LLIIN,(T1)	;GET SEG TO ACK
	MOVEI T3,MSLSI		;THE CHANNEL I.D.
	CALLRET SNDACK		;SEND ACK
;SNDACK CONTINUED.....
;SEND ACK TO REMOTE NODE.

ACKRMT:	STKVAR <MSGBL>		;PLACE TO SAVE MESSAGE BLOCK
	MOVEI T1,ACKLEN+MSHDR	;LENGTH REQUIRED
	CALL GETRES		;GET IT
	 CALLRET GENWAT		;FAILED
	MOVEM T1,MSGBL		;SAVE BLOCK ADDRESS
	MOVE T2,T1
	MOVE T1,LLBLK		;GET BACK LL BLOCK ADDRESS
	SETZM LLBPCT(T1)	;INIT MESSAGE COUNT
	ADDI T2,MSHDR		;GET TO DATA PART
	HRLI T2,(<POINT 8,>)
	MOVEM T2,LLBPTR(T1)	;INIT POINTER
	MOVEI T2,ACKFLM		;BASIC ACK MESSAGE
	MOVE T3,ACKTYP		;GET SUBCHANNEL
	CAIN T3,MSLSI		;LS/INT SUBCHANNEL?
	ADDI T2,ACKLSI		;YES.
	CALL RTHDCI		;PUT ON ROUTING HEADER
	CALL PUTLLA		;PUT IN LL ADDRESSES
	MOVE T2,ACKNO		;GET SEG TO ACK
	TXO T2,ACKIND		;SET ACK INDICATOR
	CALL TWOBYT		;PUT IT IN
	MOVE T2,MSGBL		;GET MESSAGE
	CALL SNDCTL		;SEND IT
	RETSKP			;AND DONE
;ROUTINE TO BUILD AND SEND A NODE INIT
;	T1/ PORT I.D.

NODINI::TRVAR <<LLDUM,LKSIZE>,NODMSG,NODPRT>
	MOVEM T1,NODPRT		;SAVE PORT I.D.
	MOVEI T1,NDISIZ+MSHDR	;REQUIRES BLOCK SIZE
	CALL GETRES		;GET A BLOCK
	 RETBAD			;COULDN'T
	MOVEM T1,NODMSG		;SAVE BLOCK
	MOVEI T2,MSHDR(T1)	;POINT TO DATA PART
	HRLI T2,(<POINT 8,>)
	MOVEI T1,LLDUM		;DUMMY LL BLOCK
	SETZM LLBPCT(T1)	;INIT COUNT
	MOVEM T2,LLBPTR(T1)	;SET UP BYTE POINTER
	MOVEI T2,CNMRFL+NDIFLG	;MESSAGE FLAGS
	CALL ONEBYT
	MOVEI T2,STRTYP		;NOD INIT MESSAGE
	CALL ONEBYT
	MOVE T2,OURNUM		;GET OUR NUMBER
	CALL ONEBYT		;STASH IT
	MOVEI T3,OURNAM		;OUR NAME
	CALL ASCIIZ		;PUT IT IN
	MOVEI T2,OURCAP		;SUPPORTED CAPS
	CALL ONEBYT
	MOVEI T2,OURREQ		;REQUIRED CAPS
	CALL ONEBYT
	MOVEI T2,MAXRSZ		;OUR SEG SIZE
	CALL TWOBYT
	MOVEI T2,MAXRSZ		;OUR NSP SIZE
	CALL TWOBYT
	MOVEI T2,MAXLNK		;MAX LINKS
	CALL TWOBYT
	MOVEI T2,ROUVER		;ROUTING VERSION
	CALL ONEBYT
	MOVEI T2,ROUECO		;ROUTING ECO LEVEL
	CALL ONEBYT
	MOVEI T2,ROUCST		;CUSTOMER MODS
	CALL ONEBYT
	MOVEI T2,COMVER		;NSP VERSION
	CALL ONEBYT
	MOVEI T2,COMECO		;NSP ECO LEVEL
	CALL ONEBYT
	MOVEI T2,COMCST		;CUST MODS TO NSP
	CALL ONEBYT
	SETZ T2,		;NO TEXT YET
	CALL ONEBYT
	MOVE T2,NODMSG		;MESSAGE BLOCK
	MOVE T3,NODPRT		;GET PORT I.D.
	STOR T3,LLPRT,(T1)	;SAVE IN LL BLOCK
	MOVE T3,LLBPCT(T1)	;COUNT 
	CALL SNDSG0		;SEND IT
	MOVE T1,NODPRT		;GET PORT NUMBER
	SETONE INISNT,MCBDTE(T1) ;NOTE INIT MSG SENT
	JE REQVER,MCBDTE(T1),RSKP ;DONE IF NO VERIFICATION MSG NEEDED
	CALL NODVER		;SEND VERIFICATION MSG
	MOVE T1,NODPRT		;RESTORE PORT ID
	SETZRO REQVER,MCBDTE(T1) ;NOTE VERIFICATION NO LONGER NEEDED
	RETSKP			;DONE, RETURN
;ROUTINE TO SEND AN LS MESSAGE
;	T1/ LL BLOCK ADDRESS
;	T2/ COUNT OF SEGS TO REQUEST
;	T3/ SUBCHANNEL

SNDLS:	ASUBR <SNDLBL,SNDLCT,SNDLTP,SNDLMS>
	CALL TSTLCL		;LOCAL?
	 JRST SNDLSL		;YES
	LOAD T2,LLQOU,(T1)	;GET SEGS IN QUEUER
	CAILE T2,MAXSGQ+1	;ROOM FOR THIS ONE?
	JRST [	MOVEI T2,CHKQTA	;NO. MUST WAIT UNTIL THERE IS
		CALLRET MAKTST]	;""
	MOVEI T1,MSHDR+LSLEN	;GET FREE SPACE
	CALL GETRES		;GET SOME
	 JRST GENWAT		;NONE.
	MOVEM T1,SNDLMS		;SAVE BLOCK ADDRESS
	MOVEI T2,MSHDR(T1)	;POINT TO DATA PORTION
	HRLI T2,(<POINT 8,>)
	MOVE T1,SNDLBL		;GET BACK LL BLOCK
	MOVEM T2,LLBPTR(T1)
	SETZM LLBPCT(T1)
	MOVEI T2,DATFLI		;GET FLAGS
	CALL ONEBYT		;PUT IT IN THE MESSAGE
	CALL PUTLLA		;PUT IN ADDRESSES
	LOAD T2,LLISN,(T1)	;GET SEG #
	AOS T2			;NEXT ONE
	ANDI T2,7777
	STOR T2,LLISN,(T1)
	MOVE T4,SNDLMS		;GET MESSAGE ADDRESS
	STOR T2,MSSEG,(T4)	;SAVE SEG #
	STOR T1,MSLLA,(T4)	;SAVE LINK ADDRESS
	MOVEI T3,MSLSI		;SAY THIS IS A LS MSG
	STOR T3,MSTOM,(T4)	;""
	CALL TWOBYT		;PUT IN SEG #
	SETZM T2		;ASSUME DATA CHANNEL
	MOVE T3,SNDLTP		;GET SUBCHANNEL
	CAIE T3,MSDAT		;DATA?
	MOVEI T2,4		;NO. LS/INT
	CALL ONEBYT
	MOVE T2,SNDLCT		;GET COUNT
	CALL ONEBYT
	MOVE T2,SNDLMS		;GET MESSAGE
	CALL SNDSEG		;SEND THE DATA
	RETSKP			;AND DONE
;SNDLS CONTINUED...
;SEND ON A LOCAL CONNECTION

SNDLSL:	SAVEAC <T1>		;SAVE LL BLOCK
	SETOM T2		;ANY MATCH IS OKAY
	LOAD T1,LLHLK,(T1)	;GET OTHER ADDRESS
	LLLOCK
	CALL LLLKUP		;GET BLOCK ADDRESS
	 JRST [	LLLULK		;?
		RETSKP]		;OTHER ONE WENT AWAY
	MOVE T2,SNDLCT		;GET COUNT
	MOVE T3,SNDLTP		;GET SUBCHANNEL
	NOSKED
	CAIE T3,MSDAT		;DATA
	JRST [	OPSTRM <ADDM T2,>,LLMIC,(T1) ;NO
		JRST SNDLS1]	;GO WRAP UP
	OPSTRM <ADDM T2,>,LLMSM,(T1) ;YES
SNDLS1:	OKSKED
	LLLULK			;FREE TREE
	RETSKP			;DONE
;ROUTINES CALLED FROM INT LEVEL TO GET AND QUEUE UP BUFFERS

;GET A BUFFER
;	T1/ PORT # (E.G. DTE#)
;	T2/ # OF BYTES REQUIRED
;RETURNS:
;	+1 COULDN'T GET BLOCK
;	+2 T1=BLOCK ADDRESS.

	RESCD
NSPSPC::ASUBR <PRTNO,PRTCNT>
	MOVEI T1,MSHDR*4+3(T2)	;GET # OF BYTES
	LSH T1,-2		;CONVERT TO WORDS
	HRLI T1,.RESP1		;PRIORITY 1
	MOVE T2,[RS%SE0+.RESNP]	;FROM THE NET POOL
	CALL ASGRES		;GET THE SPACE
	 RETBAD			;COULDN'T
	MOVE T2,PRTNO		;GET PORT I.D.
	STOR T2,MSPRT,(T1)	;SAVE IT
	MOVE T2,PRTCNT		;GET COUNT OF BYTES IN MESSAGE
	STOR T2,MSCNT,(T1)	;SAVE IT
	ADDI T1,MSHDR		;POINT TO DATA PORTION
	RETSKP			;AND RETURN WITH BLOCK
;SCHEDULER AND INT INTERFACES

;ROUTINE TO QUEUE UP A RECEIVED MESSAGE.
;	T1/ BLOCK ADDRESS

NSPMSG::TRVAR <MSGCNT,MSGBYP,MSGSRC,MSGDST,MSGBLK,NAKFLG>
	MOVEI T2,MSHDR(T1)	;GET TO DATA PORTION
	MOVEM T1,MSGBLK		;SAVE BLOCK ADDRESS
	HRLI T2,(<POINT 8,>)
	MOVEM T2,MSGBYP		;SAVE BYTE POINTER
	LOAD T1,MSCNT,(T1)	;GET BYTE COUNT
	MOVEM T1,MSGCNT		;SET UP COUNT
	CALL GETBYT		;GET FIRST BYTE
	 JRST NSPMSE		;ERROR
	TRNE T2,201		;A ROUTINE HEADER?
	JRST NSPMSE		;YES, BUT IN ERROR
	TRNN T2,2		;IS THIS FLAGS OR ROUTE HEADER?
	JRST NSPMS1		;FLAGS, GO DO MESSAGE
	TRNE T2,100
	TRNE T2,60		;VALID HEADER?
	JRST NSPMSE		;NO
	CALL SKPFLD		;SKIP HOST NAME
	 JRST NSPMSE		;SOMETHING WRONG
	CALL SKPFLD		;SKIP OTHER HOST NAME
	 JRST NSPMSE		;SOMETHING WRONG
	CALL GETBYT		;GET FLAGS
	 JRST NSPMSE		;BAD MESSAGE
NSPMS1:	MOVE T1,MSGBLK		;GET BLOCK
	STOR T2,MSMFL,(T1)	;SAVE FLAGS
	SETZM NAKFLG		;ASSUME NOT AN ACK OR NACK
	TRNN T2,ACKFLM!CNMRFL!ACKLSI ;IS IT A DATA SEGMENT?
	JRST NSPMS2		;YES. KEEP IT THEN
	TRNN T2,ACKFLM		;NO. IS IT AN ACK OR NACK?
	JRST NSPMSE		;NO. IS CONTROL, LS, OR INT MESSAGE
	AOS NAKFLG		;YES. NOTE THAT
NSPMS2:	CALL GETLLA		;YES. GET LINK NUMBERS
	 JRST NSPMSE		;BAD MESSAGE
	MOVE T1,MSGDST		;GET OUR NAME
	MOVE T2,MSGSRC		;GET ITS NAME
	CALL LLLKUP		;FIND THE LINK
	 JRST NSPMSE		;COULDN'T.
	LOAD T2,LLSTA,(T1)	;GOT IT. GET STATE
	CAIE T2,LLSRUN		;RUNNING?
	JRST NSPMSE		;NO
	MOVE T2,MSGBLK		;YES.
	MOVE T3,MSGCNT		;GET REMAINING COUNT
	STOR T3,MSDTC,(T2)	;SAVE RESIDUAL COUNT
	MOVE T3,MSGBYP
	MOVEM T3,MSBPTR(T2)	;SAVE RESIDUAL BYTE POINTER
	SKIPE NAKFLG		;IS THIS AN ACK OR NACK?
	JRST [	CALL GETTWO	;YES. GET ACKNUM FIELD
		 JRST NSPMSE	;BAD MESSAGE
		TRNE T2,ACKBIT	;A NACK?
		JRST NSPMSE	;YES. GIVE IT TO NSPTSK
		MOVE T2,MSGBLK	;NO, MUST RESTORE MESSAGE BLOCK ADDRESS
		JRST .+1]	;GO ON
	CALLRET ONRAWQ		;AND PUT IT ON LINK'S Q

NSPMSE:	MOVE T2,MSGBLK		;GET BLOCK ADDRESS
	CALLRET ONMSGQ		;PUT IN ON THE TASK'S Q
;ROUTINE CALLED BY THE SCHEDULER EVERY 20 MS TO PROCESS MESSAGES
;ARRIVED FROM THE NETWORK

NSPCH7::ACVAR <W1>		;GET A WORK REG
	MOVEI W1,12		;DO A LIMITED # PER PASS
NSPCH0:	SKIPN T1,SMSGQ		;ANY MESSAGE TO DO?
	RET			;NO. ALL DONE
	CHNOFF DLSCHN		;TURN OFF NETWORK
	HRRZS T1		;GET HEAD POINTER
	LOAD T2,MSLNK,(T1)	;GET POINTER
	HRRM T2,SMSGQ		;NEW HEAD
	SKIPN T2		;ANY MORE IN THE Q?
	SETZM SMSGQ		;NO
	CHNON DLSCHN		;TURN ON NET
	CALL NSPMSG		;GO PROCESS THE MESSAGE
	SOJGE W1,NSPCH0		;GO DO MORE
	RET			;ALL DONE
SUBTTL	NODE JSYS

	SWAPCD			;IS SWAPPABLE
.NODE::	MCENT			;MONITOR CONTEXT ENTRY

; VALIDATE FUNCTION CODE AND DISPATCH TO PROCESSING ROUTINE

	UMOVE T1,1		;GET FUNCTION CODE FROM USER
	CAIL T1,0		;FUNCTION CODE WITHIN
	CAIL T1,NODMAX		; VALID RANGE ?
	ITERR (ARGX02)		;NO, RETURN "INVALID FUNCTION" ERROR
	MOVE T4,NODTAB(T1)	;GET ADDRESS OF PROCESSING ROUTINE
	CALL (T4)		;DISPATCH TO PROPER ROUTINE
	 ITERR ()		;FAILED, RETURN ERROR CODE
	MRETNG			;SUCCESS, DONE.

; TABLE OF NODE JSYS FUNCTIONS

NODTAB:	EXP SETNAM		;(0) SET LOCAL NODE NAME
	EXP GETNAM		;(1) GET LOCAL NODE NAME
	EXP SETNUM		;(2) SET LOCAL NODE NUMBER
	EXP GETNUM		;(3) GET LOCAL NODE NUMBER
	EXP NDSLP		;(4) SET LOOPBACK PORT
	EXP NDCLP		;(5) CLEAR LOOPBACK PORT
	EXP NDFLP		;(6) FIND LOOPBACK PORT


NODMAX==.-NODTAB
;SETNAM - ROUTINE TO SET THE LOCAL NODE NAME

SETNAM:	STKVAR <<NODNAM,2>,BLKADR,ERRFLG>
	SETZM ERRFLG		;INITIALIZE ERROR FLAG
	MOVE T1,CAPENB		;GET CURRENTLY ENABLED CAPABILITIES
	TXNN T1,SC%WHL!SC%OPR	;WHEEL OR OPERATOR CAPABILITY REQUIRED
	RETBAD (CAPX1)		;NOT ENOUGH CAPABILITY, RETURN ERROR

; COPY THE NODE NAME STRING FROM THE USER ADDRESS SPACE

	UMOVE T2,2		;GET ADDRESS OF USER'S ARGUMENT BLOCK
	UMOVE T1,.NDNOD(T2)	;GET POINTER TO STRING IN USER SPACE
	CALL CPYFUS		;COPY STRING FROM USER
	 RETBAD ()		;FAILED
	MOVEM T1,BLKADR		;SAVE ADDRESS OF FREE BLOCK

; CHECK NUMBER OF CHARACTERS IN THE STRING

	HRRI T4,1(T1)		;GET ADDRESS OF STRING
	HRLI T4,(POINT 7,)	;FORM POINTER TO STRING
	MOVEI T3,0		;INITIALIZE CHARACTER COUNT
	MOVE T1,[POINT 7,NODNAM] ;GET POINTER TO WHERE NAME IS BEING ASSEMBLED
STNAM1:	ILDB T2,T4		;GET NEXT CHARACTER FROM USER STRING
	IDPB T2,T1		;ADD CHARACTER TO DESTINATION STRING
	JUMPE T2,STNAM2		;IF END OF STRING, PUT IT INTO NSP DATABASE
	CAIL T3,6		;TOO MANY CHARACTERS IN NAME ?
	JRST [	MOVEI T4,NODX01	;YES, GET ERROR CODE
		MOVEM T4,ERRFLG	;NOTE ERROR
		JRST STNAM3 ]	;GO RELEASE FREE BLOCK AND RETURN
	AOJA T3,STNAM1		;LOOP OVER EACH CHARACTER

; HERE TO ADD STRING TO NSP DATABASE

STNAM2:	DMOVE T1,NODNAM		;GET NODE NAME
	DMOVEM T1,OURNAM	;STORE FOR NSP
	MOVEM T3,OURCNT		;STORE CHARACTER COUNT AS WELL

; HERE TO RELEASE FREE BLOCK AND RETURN

STNAM3:	MOVEI T1,JSBFRE		;GET ADDRESS OF FREE HEADER
	MOVE T2,BLKADR		;GET ADDRESS OF FREE BLOCK
	CALL RELFRE		;RELEASE SPACE
	SKIPE T1,ERRFLG		;ANY ERRORS ?
	RETBAD ()		;YES, RETURN ERROR CODE
	RETSKP			;NO, SUCCESS RETURN
;GETNAM - RETURN LOCAL NODE NAME

GETNAM:	UMOVE T2,2		;GET ADDRESS OF USER'S ARGUMENT BLOCK
	UMOVE T1,.NDNOD(T2)	;GET POINTER TO WHERE NODE NAME IS TO GO
	MOVEI T3,.NDNOD(T2)	;GET ADDRESS TO RETURN UPDATED POINTER
	HRROI T2,OURNAM-1	;GET POINTER TO SOURCE STRING
	CALL CPYTU1		;COPY STRING TO USER SPACE, RETURN POINTER
	RETSKP			;DONE, RETURN SUCCESS

;SET LOCAL NODE NUMBER

SETNUM:	UMOVE T2,2		;GET WORD WHERE NODE NUMBER IS
	UMOVE T2,0(T2)		;GET USER'S NODE NUMBER
	CAIL T2,2
	CAILE T2,177		;WITHIN RANGE?
	RETBAD()		;NO. CAN'T
	MOVEM T2,OURNUM		;YES. SET IT
	RETSKP			;AND DONE

;GET LOCAL NODE NUMBER

GETNUM:	UMOVE T2,2
	MOVE T3,OURNUM
	UMOVEM T3,0(T2)		;RETURN IT
	RETSKP			;AND DONE
;SET LOOPBACK PORT
NDSLP:	MOVE T1,CAPENB		;GET CURRENTLY ENABLED CAPABILITIES
	TXNN T1,SC%WHL!SC%OPR!SC%MNT ;WHEEL OPERATOR OR MAINTENANCE CAPABILITY REQUIRED
	RETBAD (CAPX2)		;WHEEL, OPERATOR, or MAINTENANCE capability required
	UMOVE T2,2		;GET ADDRESS OF USERS ARGUMENT BLOCK
	UMOVE T3,.NDPRT(T2)	;GET PORT WANTS TO SET IN LOOPBACK
	SKIPE T2,NSPLPB		;IS ANOTHER PORT ALREADY ASSIGNED ?
	JRST [	CAIE T3,(T2)	;IS IT SAME PORT ?
		RETBAD (NODX03)	;Another line already looped
		RETSKP	]	;ALL DONE
	MOVEI T1,.BTSTS		;WANT TO GET PORT STATUS
	MOVEI T2,T3		;ADDRESS OF ARGUMENT BLOCK
	BOOT			;GET ARGUMENT STATUS
	ERJMP [RETBAD (ARGX19)]	;Invalid unit number
	CAME T4,[EXP -1]	;IS PORT TURNED OFF
	RETBAD (NODX02)		;Line not turned off
	HRLI T3,(ND%LPA)	;HAVE A PORT FOR LOOPBACK NOW
	MOVEM T3,NSPLPB		;REMEMBER WHICH PORT WILL BE LOOPED
	RETSKP

;CLEAR LOOPBACK PORT
NDCLP:	MOVE T1,CAPENB		;GET CURRENTLY ENABLED CAPABILITIES
	TXNN T1,SC%WHL!SC%OPR!SC%MNT ;WHEEL OPERATOR OR MAINTENANCE CAPABILITY REQUIRED
	RETBAD (CAPX2)		;WHEEL, OPERATOR, or MAINTENANCE capability required
	SKIPN T1,NSPLPB		;GET LOOPBACK PORT NUMBER
	RETSKP			;NONE SO DONE
	UMOVE T2,2		;GET ADDRESS OF USERS ARGUMENT BLOCK
	UMOVE T3,.NDPRT(T2)	;GET PORT TO CLEAR LOOPBACK
	CAIE T3,(T1)		;SAME PORT AS IS LOOPED BACK ?
	RETBAD (ARGX19)		;Invalid unit number
	MOVEI T1,.BTTPR		;TERMINATE PROTOCOL
	MOVEI T2,T3		;ADDRESS OF ARGUMENT BLOCK
	BOOT			;DISABLE LINE
	ERJMP .+1		;CAN'T TURN OFF ?
	SETZM NSPLPB		;NOTHING IS LOOPED BACK NOW
	RETSKP

;FIND LOOPBACK PORT
NDFLP:	UMOVE T2,2		;GET ADR OF USERS ARGUMENT BLOCK
	MOVE T1,NSPLPB		;GET LOOPED BACK LINE
	UMOVEM T1,.NDPRT(T2)	;GIVE ANSWER TO USER
	RETSKP


	TNXEND
	END