Google
 

Trailing-Edge - PDP-10 Archives - BB-K911B-SM - sources/nspsrv.mac
There are 31 other files named nspsrv.mac in the archive. Click here to see a list.
; UPD ID= 220, SNARK:<4.MONITOR>NSPSRV.MAC.416,  24-Jan-80 15:58:24 by GRANT
;TCO 4.2599 - DEDMCB should not clear the loopback word
;<4.MONITOR>NSPSRV.MAC.415,  3-Jan-80 08:09:53, EDIT BY R.ACE
;UPDATE COPYRIGHT DATE
; UPD ID= 123, SNARK:<4.MONITOR>NSPSRV.MAC.414,  10-Dec-79 15:31:00 by GRANT
;Fix typeo in UPD ID=100 in MOVSEG
; UPD ID= 114, SNARK:<4.1.MONITOR>NSPSRV.MAC.415,   8-Dec-79 13:09:40 by MILLER
;FIX BUGS IN NETINP AND NETSQI.
; UPD ID= 100, SNARK:<4.1.MONITOR>NSPSRV.MAC.413,   5-Dec-79 17:20:06 by MILLER
;REPLACE MISSING CODE IN MOVSEG. FIX ANCIENT RACE BETWEEN MOVSEG AND
; THE SCHEDULER
; UPD ID= 84, SNARK:<4.MONITOR>NSPSRV.MAC.412,   3-Dec-79 15:02:17 by GRANT
;TCO 4.2588 - Change CCMSG: and DCMSG: to be compatible with Phase III
;<4.MONITOR>NSPSRV.MAC.411, 20-Nov-79 11:40:56, EDIT BY GRANT
;TCO 4.2575 - Make loopback test work for the 2020
;<4.MONITOR>NSPSRV.MAC.410, 20-Oct-79 14:45:43, EDIT BY MILLER
;FIX TYPEO IN DOSRVS.
;<4.MONITOR>NSPSRV.MAC.409, 18-Oct-79 13:06:43, EDIT BY GRANT
;FIX THE TEST FOR OPTIONAL DATA IN CLZSDI
;<4.MONITOR>NSPSRV.MAC.408, 17-Oct-79 10:06:17, EDIT BY GRANT
;TCO 4.2528 - FIX CC HANDLING TO DO PROPER ADJUSTMENT FOR SEGMENT SIZE
;<4.MONITOR>NSPSRV.MAC.407,  3-Oct-79 12:07:13, EDIT BY GRANT
;ADD ARGUMENT NAMES FOR BUGxxx
;<4.MONITOR>NSPSRV.MAC.406,  1-Oct-79 11:02:43, EDIT BY GRANT
;TCO 4.2503 - ELIMINATE DOUBLE RELEASING OF FREE SPACE BLOCK
;<4.MONITOR>NSPSRV.MAC.405, 26-Sep-79 15:55:39, EDIT BY HALL
;NDSNT IN NODE JSYS - CALL BLTUM1 INSTEAD OF BLTUM FOR EXTENDED
;ADDRESSING
;<4.MONITOR>NSPSRV.MAC.404, 25-Sep-79 10:29:52, EDIT BY GRANT
;TCO 4.2485 - SET UP T1 CORRECTLY AT ADIN10 BEFORE CALLING RELMES
;<4.MONITOR>NSPSRV.MAC.403, 13-Sep-79 15:05:28, EDIT BY GRANT
;TCO 4.2468 - ADD ROUTE HEADERS TO DATA, LS, AND INT MESSAGES
;<4.MONITOR>NSPSRV.MAC.402, 12-Sep-79 15:39:07, EDIT BY GRANT
;TCO 4.2461 - GET PORT NO. IN CORRECT AC FOR NSPRTH BUGCHK
;<OSMAN.MON>NSPSRV.MAC.1, 10-Sep-79 15:50:04, EDIT BY OSMAN
;TCO 4.2412 - Move definition of BUGHLTs, BUGCHKs, and BUGINFs to BUGS.MAC
;<4.MONITOR>NSPSRV.MAC.400,  4-Sep-79 16:38:40, EDIT BY GRANT
;TCO 4.2438 - DON'T TOUCH THE NODE NUMBER AFTER SETSPD RUNS
;<4.MONITOR>NSPSRV.MAC.399, 31-Aug-79 14:24:08, EDIT BY GRANT
;TCO 4.2434 - DON'T SUBTRACT LENGTH OF HEADER IN CIPSRV
;<4.MONITOR>NSPSRV.MAC.398,  3-Aug-79 10:12:50, EDIT BY GRANT
;TCO 4.2371 - MAKE MTOPR DO A SYNCHRONOUS DISCONNECT CORRECTLY
;<4.MONITOR>NSPSRV.MAC.397, 11-Jul-79 09:58:11, EDIT BY ENGEL
;FIX ERROR CODES AT SNINT. CHANGE DCNX14 TO DCNX12 AND DCNX11 TO DCNX14
;<4.MONITOR>NSPSRV.MAC.396, 14-Jun-79 16:03:21, EDIT BY KIRSCHEN
;RETURN ERROR CODE WHEN CANNOT SEND LS MSG ON READING INT MSG
;<4.MONITOR>NSPSRV.MAC.395,  3-May-79 14:27:53, EDIT BY KIRSCHEN
;FIX J0NRUN'S AND OTHER RANDOMNESS ON LINE DOWN IN DEDCOR
;<4.MONITOR>NSPSRV.MAC.394, 25-Apr-79 15:24:57, EDIT BY OSMAN
;ADD NAMINI TO SET NAME TO "TOPS20"
;<4.MONITOR>NSPSRV.MAC.393, 18-Apr-79 16:01:43, EDIT BY KIRSCHEN
;USE INPUT QUEUE INSTEAD OF OUTPUT QUEUE AT ONRAWQ AND MOVSEG
;<4.MONITOR>NSPSRV.MAC.392, 11-Apr-79 11:59:37, EDIT BY KIRSCHEN
;ANTICIPATE DECNET PHASE III AND REMOVE UNNEEDED CHECK FOR COUNT BIT
;<4.MONITOR>NSPSRV.MAC.391, 11-Apr-79 11:55:35, EDIT BY KIRSCHEN
;USE DIFFERENT SEGMENT SIZE IF INTERNAL LINK
;<4.MONITOR>NSPSRV.MAC.390, 27-Mar-79 13:17:08, EDIT BY ENGEL
;ADD NSBP10 FOR SAMPLING QUEUE LENGTH
;<4.MONITOR>NSPSRV.MAC.389, 21-Mar-79 14:07:39, EDIT BY KIRSCHEN
;PREVENT RELINT BUGCHKS FROM DELREL
;<4.MONITOR>NSPSRV.MAC.388, 19-Mar-79 16:22:31, EDIT BY KIRSCHEN
;INSURE CODE IS ALWAYS NOINT WHEN ASSIGNING FREE SPACE
;<4.MONITOR>NSPSRV.MAC.387,  8-Mar-79 13:14:26, EDIT BY ENGEL
;FIX FREE SPACE PROBLEM AT INSER1
;<4.MONITOR>NSPSRV.MAC.386,  4-Mar-79 18:43:23, EDIT BY KONEN
;UPDATE COPYRIGHT FOR RELEASE 4
;<4.MONITOR>NSPSRV.MAC.385, 25-Feb-79 13:31:33, EDIT BY KIRSCHEN
;SAVE STATUS FROM CORRECT AC AT CONIN1; FIX STKVAR IN TELDIS
;<4.MONITOR>NSPSRV.MAC.384, 21-Feb-79 21:43:04, EDIT BY KIRSCHEN
;FIX REGISTER CLOBBERAGE IN OUTSND
;<4.MONITOR>NSPSRV.MAC.383, 20-Feb-79 13:34:32, EDIT BY KIRSCHEN
;GIVE DRIVER TOPS20 ERROR CODES ON CONNECT/DISCONNECT NOTIFICATION
;<4.MONITOR>NSPSRV.MAC.382, 19-Feb-79 14:44:25, EDIT BY KIRSCHEN
;MORE OF PREVIOUS EDIT
;<4.MONITOR>NSPSRV.MAC.381, 18-Feb-79 09:09:56, EDIT BY KIRSCHEN
;NSPSRV.MAC.80 WAS EDIT TO FIX BACKGROUND TASK WAKEUP BUG
;<4.MONITOR>NSPSRV.MAC.379, 15-Feb-79 16:42:23, EDIT BY ENGEL
;ADD CODE TO ALLOW ATS TO SET FLOW CONTROL
;<4.MONITOR>NSPSRV.MAC.378, 12-Feb-79 16:33:42, EDIT BY ENGEL
;FIX NODDEL
;<4.MONITOR>NSPSRV.MAC.377,  9-Feb-79 14:45:14, EDIT BY KIRSCHEN
;RESTORE LINK BLOCK ADDRESS IF SQILS CALL FAILS IN ACKRUN
;<4.MONITOR>NSPSRV.MAC.376,  9-Feb-79 09:57:31, EDIT BY ENGEL
;FIX NODDEL TO ACCOUNT FOR TABLE CHANGES WHILE DELETING
;<4.MONITOR>NSPSRV.MAC.375,  8-Feb-79 17:48:54, EDIT BY MILLER
;FIX NETCLZ IF CLZSDI FAILS.
;<4.MONITOR>NSPSRV.MAC.374,  8-Feb-79 11:40:22, EDIT BY ENGEL
;ADD SOS T1 TO ADDINT AND REMNDX
;<4.MONITOR>NSPSRV.MAC.371,  7-Feb-79 10:10:22, EDIT BY OSMAN
;MOVE OURNAM INI CODE FROM HERE INTO MEXEC (SOLVES PROBLEMS OF NON-DECNET SYSTEMS)
;<4.MONITOR>NSPSRV.MAC.370,  6-Feb-79 08:20:45, EDIT BY ENGEL
;RE-ADJUST NSBP02 AND NSBP05
;<4.MONITOR>NSPSRV.MAC.369,  5-Feb-79 11:07:24, EDIT BY ENGEL
;MORE BREAKPOINTS
;<4.MONITOR>NSPSRV.MAC.368,  2-Feb-79 14:57:38, EDIT BY ENGEL
;MORE BREAKPOINTS
;<4.MONITOR>NSPSRV.MAC.367, 31-Jan-79 13:50:55, EDIT BY KIRSCHEN
;CHECK FOR ZERO POINTER TO NODE NAME IN INSNOD
;<4.MONITOR>NSPSRV.MAC.366, 30-Jan-79 13:18:49, EDIT BY ENGEL
;ADD MORE BREAKPOINTS
;<4.MONITOR>NSPSRV.MAC.365, 30-Jan-79 09:32:55, EDIT BY KIRSCHEN
;MAKE NSPERR INTERNAL
;<4.MONITOR>NSPSRV.MAC.364, 30-Jan-79 08:56:43, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.363, 29-Jan-79 22:45:18, EDIT BY KIRSCHEN
;RETURN RIGHT NODE STATE (FIX TYPO)
;<4.MONITOR>NSPSRV.MAC.362, 29-Jan-79 18:53:35, EDIT BY ENGEL
;ADD BREAKPOINT LABELS FOR PERFORMANCE MEASUREMENT
;<4.MONITOR>NSPSRV.MAC.361, 29-Jan-79 13:04:33, EDIT BY KIRSCHEN
;DO NOT UNLOCK LINK BLOCK BEFORE GIVING CONNECT NOTIFICATION AT DSCMV1
;<4.MONITOR>NSPSRV.MAC.360, 29-Jan-79 12:59:43, EDIT BY KIRSCHEN
;CORRECTLY RETURN NODE STATE IN NDGNT
;<4.MONITOR>NSPSRV.MAC.359, 26-Jan-79 15:45:31, EDIT BY ENGEL
;FIX MONPDL PROBLEM IN NODDEL
;<4.MONITOR>NSPSRV.MAC.358, 24-Jan-79 16:57:42, EDIT BY KIRSCHEN
;RESTORE LINK BLOCK ADR AFTER TURNON FAILS
;<4.MONITOR>NSPSRV.MAC.357, 24-Jan-79 16:11:30, EDIT BY HALL
;COMMENT CALLING CONVENTIONS FOR TURNON AND SNDLS
;<4.MONITOR>NSPSRV.MAC.356, 16-Jan-79 12:31:09, EDIT BY KIRSCHEN
;DO NOT RELEASE LINK BLOCK TWICE IF CRTLNK FAILS
;<4.MONITOR>NSPSRV.MAC.355, 14-Jan-79 20:48:19, EDIT BY KIRSCHEN
;UPDATE NODE JSYS SYMBOLS
;<4.MONITOR>NSPSRV.MAC.354, 10-Jan-79 12:11:18, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.353,  8-Jan-79 20:25:37, EDIT BY KIRSCHEN
;permit duplicate task names within the same job
;<4.MONITOR>NSPSRV.MAC.352,  4-Jan-79 09:21:45, EDIT BY KIRSCHEN
;ADD NSPERR ROUTINE
;<4.MONITOR>NSPSRV.MAC.351,  3-Jan-79 16:56:31, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.350,  3-Jan-79 15:37:35, EDIT BY KIRSCHEN
;ADD NOOP AT NSPTSK FOR PERFORMANCE ANALYSIS
;<4.MONITOR>NSPSRV.MAC.349, 29-Dec-78 14:30:11, EDIT BY KIRSCHEN
;ADD NSP TO TOPS20 ERROR CODE TRANSLATION TABLE
;<4.MONITOR>NSPSRV.MAC.348, 21-Dec-78 13:44:23, EDIT BY KIRSCHEN
;TEST CORRECT AC AT VFYNOD+6
;<4.MONITOR>NSPSRV.MAC.347, 21-Dec-78 11:17:28, EDIT BY ENGEL
;FIX BAD CHANNEL CHECKING AT NDSIC
;<4.MONITOR>NSPSRV.MAC.346, 18-Dec-78 08:57:07, EDIT BY KIRSCHEN
;DO NOT PASS LS SEND FAILURE TO DRIVER; TRY AGAIN WHEN ACK RECEIVED
;<4.MONITOR>NSPSRV.MAC.345, 15-Dec-78 13:56:27, EDIT BY KIRSCHEN
;FIX UNLOCKING OF NODLOK IN VFYNOD
;<4.MONITOR>NSPSRV.MAC.344, 11-Dec-78 13:59:34, EDIT BY ENGEL
;ADD SOS TO REMNOD
;<4.MONITOR>NSPSRV.MAC.343,  8-Dec-78 09:00:02, EDIT BY KIRSCHEN
;REMOVE NODE AT MCBDED WITH ADDINT NOT ADDNOD
;<4.MONITOR>NSPSRV.MAC.342,  6-Dec-78 15:13:55, EDIT BY ENGEL
;ADD NEIGHBOR INFORMATION TO TOPOLOGY TABLE
;<4.MONITOR>NSPSRV.MAC.341,  1-Dec-78 12:02:00, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.340,  1-Dec-78 11:56:04, EDIT BY KIRSCHEN
;ADD NDVFY FUNCTION
;<4.MONITOR>NSPSRV.MAC.339, 29-Nov-78 10:15:03, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.338, 21-Nov-78 09:52:32, EDIT BY KIRSCHEN
;FIX DUPLICATE USE OF NAME NODMAX
;<4.MONITOR>NSPSRV.MAC.337, 15-Nov-78 15:28:51, EDIT BY KIRSCHEN
;DO NOT ACK INTERRUPT MESSAGES TWICE
;<4.MONITOR>NSPSRV.MAC.336,  9-Nov-78 08:58:37, EDIT BY KIRSCHEN
;DO NOT DELETE LINK BLOCK ON FAILURE FROM CRTLNK
;<4.MONITOR>NSPSRV.MAC.335,  6-Nov-78 11:06:35, EDIT BY ENGEL
;MAKE NDGLI USE 1/2 WORD LENGTH
;<4.MONITOR>NSPSRV.MAC.333, 27-Oct-78 17:29:43, EDIT BY OSMAN
;SET UP OURCNT IN .NDSLN
;<4.MONITOR>NSPSRV.MAC.332, 26-Oct-78 11:47:59, EDIT BY OSMAN
;use PARNDU instead of PARNOD
;<4.MONITOR>NSPSRV.MAC.331, 25-Oct-78 15:22:38, EDIT BY KIRSCHEN
;RETURN ERROR CODE IF ARG BLOCK TOO SMALL IN .NDGNT FUNCTION
;<4.MONITOR>NSPSRV.MAC.330, 25-Oct-78 10:37:47, EDIT BY ENGEL
; FIX THE .NDGLI FUNCTION
;<4.MONITOR>NSPSRV.MAC.329, 24-Oct-78 16:39:17, EDIT BY OSMAN
;MAKE NODE JSYS CALL PARNOD
;<4.MONITOR>NSPSRV.MAC.328, 17-Oct-78 16:57:48, EDIT BY ENGEL
;CHANGE OFFSETS IN .NDGLI
;<4.MONITOR>NSPSRV.MAC.327, 13-Oct-78 18:16:11, EDIT BY MILLER
;FIX NTMVOP TO CHECK FOR BYTE POINTER OF FORM -1,,N
;<4.MONITOR>NSPSRV.MAC.326, 13-Oct-78 13:49:23, EDIT BY ENGEL
;ZERO NAME ENTRY IN ITSNAM WHEN MCB DIES
;<4.MONITOR>NSPSRV.MAC.325, 12-Oct-78 15:44:24, EDIT BY ENGEL
;FIX CAME COMPARE FOR NTCTAB+NTCMAX-1
;<4.MONITOR>NSPSRV.MAC.324, 10-Oct-78 10:26:02, EDIT BY ENGEL
;CHANGE .BTSTS TO .BTLST IN GET LINE INFO NODE JSYS
;<4.MONITOR>NSPSRV.MAC.323,  6-Oct-78 16:01:17, EDIT BY ENGEL
;<4.MONITOR>NSPSRV.MAC.322,  6-Oct-78 15:36:10, EDIT BY ENGEL
;ADD NODE JSYS FUNCTIONS
;<4.MONITOR>NSPSRV.MAC.321,  3-Oct-78 17:03:12, EDIT BY KIRSCHEN
;DO NOTE NOTIFY DRIVER IN TELDIS IF LINK DISSOCIATED FROM PROCESS
;<4.MONITOR>NSPSRV.MAC.320, 24-Sep-78 11:35:38, EDIT BY HALL
;TCO 1900 - MAKE NSPTST CALL CKATSQ TO CHECK FOR ATS WORK
; MAKE NSPTSK CALL DOATSQ TO PROCESS ATS QUEUES
;<4.MONITOR>NSPSRV.MAC.319, 22-Sep-78 09:34:36, EDIT BY ENGEL
;<4.MONITOR>NSPSRV.MAC.318, 22-Sep-78 09:26:16, EDIT BY ENGEL
;FIX BAD REGISTER USAGE AT GOTMCB:
;<4.MONITOR>NSPSRV.MAC.317, 21-Sep-78 14:48:32, EDIT BY ENGEL
;UNLOCK TREE FOR +1 RETURN FROM OBJSRC AT DEDMC1+3
;<4.MONITOR>NSPSRV.MAC.316, 21-Sep-78 11:01:14, EDIT BY ENGEL
;MAKE DEDMCB RUN IN THE NSP BACKGROUND TASK
;<4.MONITOR>NSPSRV.MAC.315, 21-Sep-78 08:36:49, EDIT BY ENGEL
;FIX DEDMCB: DECLOCK WITH ATS
;<4.MONITOR>NSPSRV.MAC.314, 20-Sep-78 15:51:18, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.313,  6-Sep-78 14:09:14, EDIT BY KIRSCHEN
;FIX REMOVAL OF NODES FROM KNOWN NODE TABLE
;<4.MONITOR>NSPSRV.MAC.312,  5-Sep-78 13:21:54, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.311,  5-Sep-78 09:17:44, EDIT BY KIRSCHEN
;FIXES FOR DISCONNECT MSGS W/O ROUTING HDR
;REMOVE DN20'S FROM NODTBL AFTER THEY CRASH
;<4.MONITOR>NSPSRV.MAC.310, 30-Aug-78 16:50:28, EDIT BY KIRSCHEN
;NOTE IF A LINK IS LOCAL WHEN CI MSG RECEIVED
;<4.MONITOR>NSPSRV.MAC.309, 28-Aug-78 09:18:02, EDIT BY KIRSCHEN
;CHANGE TSTLCL TO USE NEW LLLOC FLAG
;<4.MONITOR>NSPSRV.MAC.308, 28-Aug-78 08:43:52, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.307, 23-Aug-78 15:51:37, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.306, 23-Aug-78 10:03:04, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.305, 23-Aug-78 09:12:24, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.304, 22-Aug-78 18:06:51, EDIT BY OPERATOR
;FIX NTMVOP TO CHECK FOR NEG COUNT
;<4.MONITOR>NSPSRV.MAC.303, 22-Aug-78 13:23:23, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.302, 22-Aug-78 13:17:55, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.301, 22-Aug-78 10:47:04, EDIT BY MILLER
;CHECK FO R BAD OPTDATA FIELD IN CC MESSAGE
;<4.MONITOR>NSPSRV.MAC.300, 22-Aug-78 10:05:43, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.299, 22-Aug-78 08:17:06, EDIT BY MILLER
;REWRITE SKPFLD TO BE MORE EFFICIENT. SAVES SCEHDULER CYCLES
;<4.MONITOR>NSPSRV.MAC.298, 21-Aug-78 13:43:18, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.297, 18-Aug-78 15:38:54, EDIT BY MILLER
;FIX TYPEO
;<4.MONITOR>NSPSRV.MAC.296, 18-Aug-78 13:49:05, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.295, 18-Aug-78 10:11:37, EDIT BY KIRSCHEN
;RETURN ARGS IN CORRECT AC'S ON READ INTERRUPT MSG
;<4.MONITOR>NSPSRV.MAC.294, 18-Aug-78 09:07:23, EDIT BY MILLER
;FIX SKPFLD TO PASS NUMBER TO GTASCI
;<4.MONITOR>NSPSRV.MAC.293, 18-Aug-78 08:19:03, EDIT BY MILLER
;ADD MAXHST TO EXTN LIST
;<4.MONITOR>NSPSRV.MAC.292, 18-Aug-78 08:10:54, EDIT BY MILLER
;MAKE GTASCI AND GTBNRY CHECK FOR REASONABLE STRING SIZES
;<4.MONITOR>NSPSRV.MAC.291, 16-Aug-78 13:06:33, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.290, 14-Aug-78 13:23:15, Edit by HURLEY
;<4.MONITOR>NSPSRV.MAC.289, 11-Aug-78 13:56:00, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.288, 11-Aug-78 13:44:19, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.287, 11-Aug-78 13:28:05, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.286, 11-Aug-78 13:17:10, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.285, 11-Aug-78 12:09:09, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.284,  9-Aug-78 11:53:57, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.283,  9-Aug-78 11:33:54, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.282,  7-Aug-78 09:47:14, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.281,  2-Aug-78 08:55:43, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.280,  1-Aug-78 11:49:18, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.279,  1-Aug-78 11:46:17, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.277,  1-Aug-78 09:59:40, Edit by KIRSCHEN
;ADD NEW R4 NODE JSYS FUNCTIONS
;<4.MONITOR>NSPSRV.MAC.275, 31-Jul-78 10:31:18, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.274, 31-Jul-78 09:09:28, Edit by KIRSCHEN
;ADD ININOD ROUTINE
;<4.MONITOR>NSPSRV.MAC.272, 26-Jul-78 11:45:18, Edit by KIRSCHEN
;CLEAR LLQUE AT OUTSND WHEN REMOVING BLOCK FROM OUTQUE
;<4.MONITOR>NSPSRV.MAC.271, 21-Jul-78 11:13:22, EDIT BY HALL
;CHANGE LLNAM TO LLFNM IN CRTLNK
;<4.MONITOR>NSPSRV.MAC.270, 18-Jul-78 15:43:30, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.269, 17-Jul-78 16:37:24, Edit by KIRSCHEN
;FAIL AT SETIBF IF DRIVER ALREADY REFUSED TO PROVIDE A BUFFER
;<4.MONITOR>NSPSRV.MAC.268, 17-Jul-78 08:38:39, Edit by KIRSCHEN
;UPDATE COUNTS IN INTSET EVEN IF SOME DATA WOULD NOT FIT IN BUFFER
;<4.MONITOR>NSPSRV.MAC.267, 26-Jun-78 13:36:35, Edit by KIRSCHEN
;AWAKEN ATS BACKROUND PROCESS ON TIMER EXPIRATION
;<4.MONITOR>NSPSRV.MAC.266, 26-Jun-78 13:30:26, Edit by KIRSCHEN
;FIX BUG IN MTRDIN - DO NOT CLOBBER ADR OF MESSAGE BEFORE RELEASING IT
;<4.MONITOR>NSPSRV.MAC.265, 26-Jun-78 09:49:47, Edit by KIRSCHEN
;FIX AC TEST IN SQILS WHEN CHECKING NEED FOR LS MSG
;<4.MONITOR>NSPSRV.MAC.264, 23-Jun-78 09:32:27, Edit by KIRSCHEN
;DEFER SENDING VERIFICATION MSG UNTIL NODE INITS COMPLETED
;<4.MONITOR>NSPSRV.MAC.263, 21-Jun-78 17:12:29, EDIT BY MILLER
;GET LARGER BLOCK AT GETTSK
;<4.MONITOR>NSPSRV.MAC.262, 20-Jun-78 16:21:57, Edit by KIRSCHEN
;RETURN NSPX2 WHEN LLLKUP FAILS
;<4.MONITOR>NSPSRV.MAC.261, 16-Jun-78 15:11:28, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.260, 14-Jun-78 08:25:41, Edit by KIRSCHEN
;REMOVE LINK BLOCK FROM OUTQUE IN DELNOD
;<4.MONITOR>NSPSRV.MAC.259, 13-Jun-78 15:42:28, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.258, 13-Jun-78 15:22:29, Edit by KIRSCHEN
;ADD REMQUE ROUTINE
;<4.MONITOR>NSPSRV.MAC.257, 12-Jun-78 11:26:04, Edit by KIRSCHEN
;PROVIDE FOR SENDING OPTIONAL DATA ON CLOSE IN CLZSDI
;<4.MONITOR>NSPSRV.MAC.256, 12-Jun-78 09:59:06, Edit by KIRSCHEN
;DO NOT CLOBBER T1 IN NTMVOP
;<4.MONITOR>NSPSRV.MAC.255,  8-Jun-78 13:20:10, Edit by KIRSCHEN
;MAKE NTMVOP CALLABLE FOR INTERNAL LINKS
;<4.MONITOR>NSPSRV.MAC.254,  8-Jun-78 10:58:22, Edit by KIRSCHEN
;ADD SOME INTERNALIZING
;<4.MONITOR>NSPSRV.MAC.253,  7-Jun-78 12:14:30, Edit by KIRSCHEN
;CALL NRM TO DO NRM PROTOCOL IF NEEDED IN BACKGROUND TASK
;<4.MONITOR>NSPSRV.MAC.252,  7-Jun-78 08:01:16, EDIT BY MILLER
;MAKE NSPTSK STAY IN BALSET A LONG TIME
;<4.MONITOR>NSPSRV.MAC.251,  5-Jun-78 13:49:46, Edit by KIRSCHEN
;SUBROUTINIZE SENDING OF DI IN CLOSE, MAKE ROUTINE INTERNAL
;<4.MONITOR>NSPSRV.MAC.250,  5-Jun-78 08:53:35, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.249,  5-Jun-78 08:48:23, Edit by KIRSCHEN
;DONT TURN ON BLKF IN SNDDI (NOW DONE BY CALLERS)
;<4.MONITOR>NSPSRV.MAC.248,  1-Jun-78 10:45:44, Edit by KIRSCHEN
;MAKE CHKEMP INTERNAL
;<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
;<KIRSCHEN>NSPSRV.MAC.2, 26-May-78 11:53:28, Edit by KIRSCHEN
;<KIRSCHEN>NSPSRV.MAC.1, 26-May-78 11:49:45, Edit by KIRSCHEN
;REMOVE INTERNAL INTERFACE CODE
;<4.MONITOR>NSPSRV.MAC.245, 26-May-78 11:18:38, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.244, 24-May-78 09:28:46, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.243, 23-May-78 17:17:54, 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
;<4.MONITOR>NSPSRV.MAC.241, 23-May-78 08:51:19, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.240, 19-May-78 14:10:28, EDIT BY OPERATOR
;FIX STRMSG NOT TO USE ACVAR
;<4.MONITOR>NSPSRV.MAC.239, 19-May-78 08:55:49, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.237, 18-May-78 10:42:57, Edit by MCCLURE
; Change KMCTSK to KDPTSK
;<4.MONITOR>NSPSRV.MAC.236, 17-May-78 13:23:46, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.235, 16-May-78 17:37:00, Edit by HALL
;TCO 1900 - MOVED CMPSTR TO FUTILI
;<4.MONITOR>NSPSRV.MAC.234, 16-May-78 16:52:51, Edit by ENGEL
;<4.MONITOR>NSPSRV.MAC.233, 16-May-78 13:52:39, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.232, 16-May-78 13:50:31, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.231, 15-May-78 10:20:02, Edit by KIRSCHEN
;BREAK OUT NSPPAR CODE
;<4.MONITOR>NSPSRV.MAC.230, 12-May-78 20:20:06, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.229, 12-May-78 08:25:18, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.228, 10-May-78 09:43:38, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.227, 10-May-78 09:42:18, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.226,  9-May-78 15:23:05, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.225,  9-May-78 14:12:37, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.224,  9-May-78 09:23:33, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.223,  9-May-78 09:18:11, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.222,  8-May-78 16:52:20, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.221,  8-May-78 14:23:41, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.220,  8-May-78 11:18:39, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.219,  5-May-78 14:00:52, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.218,  5-May-78 10:13:12, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.217,  4-May-78 09:22:02, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.216,  3-May-78 09:03:28, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.215,  3-May-78 08:39:03, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.214,  2-May-78 15:13:15, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.212,  1-May-78 10:22:30, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.211, 28-Apr-78 15:32:20, EDIT BY MILLER
;CHECK FOR DATA IN FILE SYSTEM AT CHKRAW
;<4.MONITOR>NSPSRV.MAC.210, 28-Apr-78 12:25:21, Edit by MCCLURE
; Add error codes in NDSLP
;<4.MONITOR>NSPSRV.MAC.209, 26-Apr-78 09:55:17, EDIT BY MILLER
;CHANGE .DCX40 TO .DCX39 IN DEDMCB
;<4.MONITOR>NSPSRV.MAC.208, 26-Apr-78 09:25:42, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.207, 25-Apr-78 11:14:49, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.206, 25-Apr-78 11:08:10, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.205, 25-Apr-78 09:11:09, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.204, 24-Apr-78 14:02:18, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.203, 24-Apr-78 13:31:14, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.202, 24-Apr-78 10:05:37, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.201, 24-Apr-78 08:32:53, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.200, 20-Apr-78 12:05:43, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.199, 20-Apr-78 12:04:18, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.198, 16-Apr-78 14:44:07, EDIT BY MILLER
;ADD GJFX50 ERROR CODES FOR BAD ATTRIBUTE ARGS
;<4.MONITOR>NSPSRV.MAC.197, 14-Apr-78 08:06:57, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.196, 13-Apr-78 16:29:43, EDIT BY MILLER
;ADD DECR LLDMT IF VERSEG FAILS
;<4.MONITOR>NSPSRV.MAC.195, 13-Apr-78 08:11:51, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.194, 12-Apr-78 13:31:36, Edit by MILLER
;<4.MONITOR>NSPSRV.MAC.193, 12-Apr-78 08:41:26, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.192, 12-Apr-78 08:23:03, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.191, 12-Apr-78 08:17:33, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.190, 11-Apr-78 15:40:12, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.189, 11-Apr-78 15:34:27, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.188, 10-Apr-78 14:47:05, EDIT BY MILLER
;CLEAR LINK WORD AT LSINT1
;<4.MONITOR>NSPSRV.MAC.187, 10-Apr-78 13:46:54, Edit by KIRSCHEN
;<4.MONITOR>MONSYM.MAC.1, 10-Apr-78 12:04:27, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.185,  7-Apr-78 09:36:51, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.184,  7-Apr-78 09:24:11, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.183,  7-Apr-78 09:20:04, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.182,  6-Apr-78 13:52:26, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.180,  5-Apr-78 15:25:26, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.179,  5-Apr-78 12:28:53, EDIT BY MILLER
;FIX ANOTHER TYPEO IN NTRCOB
;<4.MONITOR>NSPSRV.MAC.178,  5-Apr-78 12:01:28, EDIT BY KIRSCHEN
;FIX NTRCOB TO USE PROPER FIELD
;<4.MONITOR>NSPSRV.MAC.177,  5-Apr-78 11:05:28, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.176,  5-Apr-78 10:38:53, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.175,  5-Apr-78 08:15:56, Edit by KIRSCHEN
;CHANGE FAL TO BE OBJECT 21
;<4.MONITOR>NSPSRV.MAC.174,  4-Apr-78 16:07:07, EDIT BY MILLER
;MORE FIXES TO NTMVOP
;<4.MONITOR>NSPSRV.MAC.173,  4-Apr-78 12:20:09, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.172,  4-Apr-78 09:43:44, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.171,  3-Apr-78 14:30:13, Edit by KIRSCHEN
;SEND NODE VERIFICATION MESSAGE IF REQUESTED AT NODE INIT
;<4.MONITOR>NSPSRV.MAC.170,  3-Apr-78 12:46:00, EDIT BY MILLER
;CHECK FOR MAX OPTDATA SIZE IN NTMVOP
;<4.MONITOR>NSPSRV.MAC.169,  3-Apr-78 12:10:34, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.168,  3-Apr-78 11:27:55, Edit by HALL
;ADD ATS AND NRM TO OBJPRO
;<3A.MONITOR>NSPSRV.MAC.32, 30-Mar-78 11:48:09, EDIT BY MILLER
;ALLOW DEST OBJECT FORMAT OF TWO. IF SO, IGNORE GROUP,USER
;<4.MONITOR>NSPSRV.MAC.166, 29-Mar-78 10:38:40, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.165, 29-Mar-78 08:11:12, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.164, 28-Mar-78 12:29:03, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.163, 24-Mar-78 12:32:04, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.162, 23-Mar-78 10:34:49, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.161, 23-Mar-78 09:20:11, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.160, 23-Mar-78 08:39:54, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.159, 23-Mar-78 08:29:36, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.158, 22-Mar-78 14:15:58, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.157, 22-Mar-78 11:04:36, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.156, 22-Mar-78 09:16:37, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.155, 21-Mar-78 15:43:34, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.154, 21-Mar-78 12:46:26, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.153, 21-Mar-78 10:13:57, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.152, 20-Mar-78 09:33:49, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.151, 16-Mar-78 09:11:39, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.149, 15-Mar-78 14:55:45, Edit by MCCLURE
; ADD LOOPBACK FOR 2020
;<4.MONITOR>NSPSRV.MAC.148, 15-Mar-78 12:19:19, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.147, 14-Mar-78 15:46:54, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.146, 14-Mar-78 14:55:44, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.145, 14-Mar-78 13:05:31, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.144, 14-Mar-78 10:13:22, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.143, 13-Mar-78 09:25:59, EDIT BY MILLER
;FIX UP VERSION NUMBERS IN NODE INIT MESSAGE
;<4.MONITOR>NSPSRV.MAC.142,  9-Mar-78 15:37:15, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.141,  9-Mar-78 10:18:55, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.140,  9-Mar-78 09:57:14, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.139,  8-Mar-78 16:56:31, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.138,  8-Mar-78 16:11:47, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.137,  7-Mar-78 16:40:07, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.136,  7-Mar-78 10:48:21, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.135,  6-Mar-78 14:48:38, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.134,  6-Mar-78 09:21:29, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.133,  2-Mar-78 09:52:33, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.132,  1-Mar-78 14:31:40, EDIT BY MILLER
;CHANGE RANGE CHECK ON NODE NUMBER IN NODE JSYS
;<4.MONITOR>NSPSRV.MAC.131,  1-Mar-78 12:05:49, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.130, 28-Feb-78 14:48:16, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.129, 28-Feb-78 10:30:37, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.128, 27-Feb-78 11:05:23, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.127, 27-Feb-78 10:42:56, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.126, 27-Feb-78 10:22:45, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.125, 24-Feb-78 14:13:20, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.124, 24-Feb-78 14:12:44, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.123, 24-Feb-78 14:10:59, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.122, 24-Feb-78 10:11:37, EDIT BY MILLER
;DEFINE OURNUM AND NODNUM AS EXTN'S
;<4.MONITOR>NSPSRV.MAC.121, 24-Feb-78 09:41:12, EDIT BY MILLER
;FIX SETTING OF NODE NUMBER IN NSPINI
;<4.MONITOR>NSPSRV.MAC.120, 24-Feb-78 09:02:10, EDIT BY MILLER
;ADD OURNUM. ADD FUNCTIONS TO NODE JSYS TO SET AND READ IT
;<4.MONITOR>NSPSRV.MAC.119, 22-Feb-78 15:16:36, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.118, 22-Feb-78 12:24:34, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.117, 22-Feb-78 12:17:48, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.116, 22-Feb-78 11:58:53, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.115, 21-Feb-78 09:48:36, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.114, 21-Feb-78 09:33:04, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.113, 20-Feb-78 13:52:15, Edit by PORCHER
;Fix typos in last edit
;<4.MONITOR>NSPSRV.MAC.112, 20-Feb-78 11:21:39, EDIT BY MILLER
;ADD LABEL QCK050
;<4.MONITOR>NSPSRV.MAC.111, 17-Feb-78 16:49:46, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.110, 17-Feb-78 11:23:57, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.109, 17-Feb-78 11:00:29, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.108, 16-Feb-78 11:13:46, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.107, 15-Feb-78 10:23:30, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.106, 15-Feb-78 10:17:16, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.105, 15-Feb-78 09:49:24, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.104, 15-Feb-78 09:06:11, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.103, 14-Feb-78 16:11:02, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.102, 14-Feb-78 11:34:26, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.101, 13-Feb-78 12:45:01, Edit by MCCLURE
;<4.MONITOR>NSPSRV.MAC.100, 13-Feb-78 09:44:56, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.99,  6-Feb-78 16:52:14, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.98,  3-Feb-78 10:37:54, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.97,  2-Feb-78 15:09:15, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.96,  2-Feb-78 15:07:23, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.95,  2-Feb-78 11:08:31, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.94,  1-Feb-78 12:49:01, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.93,  1-Feb-78 12:13:04, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.92,  1-Feb-78 12:09:54, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.91, 31-Jan-78 14:44:55, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.90, 31-Jan-78 13:11:36, Edit by HURLEY
;<4.MONITOR>NSPSRV.MAC.89, 30-Jan-78 13:20:57, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.88, 30-Jan-78 11:14:54, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.87, 30-Jan-78 11:09:34, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.86, 30-Jan-78 09:33:48, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.85, 28-Jan-78 23:06:14, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.84, 28-Jan-78 22:59:38, Edit by KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.83, 27-Jan-78 16:53:49, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.82, 27-Jan-78 16:35:42, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.81, 27-Jan-78 16:30:46, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.80, 27-Jan-78 15:52:49, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.79, 27-Jan-78 11:20:17, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.78, 27-Jan-78 11:15:13, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.77, 27-Jan-78 11:06:40, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.76, 27-Jan-78 10:34:58, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.75, 26-Jan-78 22:22:01, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.74, 26-Jan-78 15:08:35, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.73, 26-Jan-78 14:09:08, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.72, 26-Jan-78 14:06:43, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.71, 26-Jan-78 14:04:56, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.69, 26-Jan-78 12:23:34, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.68, 26-Jan-78 12:07:53, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.67, 26-Jan-78 10:43:06, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.66, 26-Jan-78 10:20:30, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.65, 26-Jan-78 10:10:13, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.64, 25-Jan-78 17:00:54, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.63, 25-Jan-78 16:12:33, EDIT BY KIRSCHEN
; .
; .
; .
;<4.MONITOR>NSPSRV.MAC.14,  9-Jan-78 11:54:54, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.13,  8-Jan-78 13:14:56, EDIT BY MILLER
;SET UP FOR INPUT AT NTMTOP
;<4.MONITOR>NSPSRV.MAC.12,  6-Jan-78 16:28:03, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.11,  6-Jan-78 13:50:47, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.10,  6-Jan-78 12:54:39, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.9,  6-Jan-78 12:50:29, EDIT BY KIRSCHEN
;FIX BUG IN TSKLOK - DO NOT ASSUME TRVAR IS SET UP
;<4.MONITOR>NSPSRV.MAC.8,  5-Jan-78 15:57:39, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.7,  4-Jan-78 15:49:30, EDIT BY KIRSCHEN
;MAKE OBJLOK INTERNAL
;<4.MONITOR>NSPSRV.MAC.6,  4-Jan-78 13:44:12, EDIT BY MILLER
;<4.MONITOR>NSPSRV.MAC.5, 30-Dec-77 16:47:10, EDIT BY MILLER
;FIX CREATION OF ACCESS FIELDS
;<4.MONITOR>NSPSRV.MAC.4, 28-Dec-77 15:26:17, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.3, 28-Dec-77 14:36:26, EDIT BY KIRSCHEN
;<4.MONITOR>NSPSRV.MAC.2, 28-Dec-77 11:08:04, EDIT BY KIRSCHEN
;MOVE SOME FILESYSTEM ROUTINES TO MODULE FILNSP


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

	SEARCH NSPPAR,PROLOG,PROKL
	TTITLE (NSPSRV,,< - Network Services Protocol Interface to TOPS20	>)


	EXTN <ADDOUT,OUTSEG,NODTBL,MAXHST>
	EXTN <ASGWDW,BLKASG,CMPLEN,DCNNAM,DCNSET,EXTSET,ITSID>
	EXTN <ITSNAM,ITSNUM,LASTSK,LLBIT,LLBITS,LLHEAD,LLLLCK>
	EXTN <MAXBLK,MAXEXP,MAXLNK,MCBDTE,MSGQ,NAKCNT,NETDIR>
	EXTN <NETSR1,NETSQ1,NETUIN,NETUOU,NODNUM,NSPLPB,NSPMAX>
	EXTN <OBJMAX,OBJTBL,OPNDNC,OPNSRC,OURNUM>
	EXTN <PRSNAM,RMSGQ,SMSGQ,SRCNAM,SRNSET,VERSET>
;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.


;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)
	DEFAC (STS,P1)
	DEFAC (JFN,P2)
	DEFAC (DEV,P4)
	DEFAC (F1,P5)
SUBTTL	NSP Initialization


;NAMINI INITIALIZES NODE NAME TO "TOPS20"

NAMINI::DMOVE T1,[ASCIZ /TOPS20/] ;GET OUR DEFAULT NODE NAME
	DMOVEM T1,OURNAM	;SET IT (ASSUME SETSPD HASN'T RUN YET!)
	MOVEI T1,6		;COUNT OF CHARS IN "OURNAM"
	MOVEM T1,OURCNT		;STORE IT (OURNAM COPIED TO LLSR EVEN ON
				;NON-DECNET SYSTEMS, AND .SJLL,
				;.JILLO REFERENCE IT!)
	MOVEI T1,NODNUM		;GET OUR DEFAULT NODE NUMBER
	MOVEM T1,OURNUM		;SET IT
	RET

;ROUTINE TO INIT NETWORK DATA BASES,ETC.

	SWAPCD			;SWAPPABLE
NSPINI::UNLOCK LLLLCK		;UNLOCK LOCK
	UNLOCK OUTLOK		;INITIALIZE LOCK ON BACKGROUND TASK'S QUEUE
	UNLOCK NODLOK		;INITIALIZE LOCK ON NODTBL
	MOVX T1,INIWAT		;GET TIME BEFORE BLOCKED OUTPUT RETRY
	MOVEM T1,OUTIVL		;SAVE DEFAULT TIME INTERVAL
	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 (NSPFRK,<<T1,REASON>>)
	MOVEI T2,TSKINI		;THE STARTING ADDRESS
	MSFRK			;START IT
	MOVX T2,FRKRUN		;SAY FORK IS RUNNING
	IORM T2,MCBDTE		;SET FLAG
	CALL ININOD		;INITIALIZE KNOWN NODE TABLE
	 BUG(NDINIT)
	RET			;DONE
; INITIALIZE TABLE OF KNOWN NODES

ININOD:	NOINT			;DO NOT PERMIT INTERRUPTS WHILE ASSIGNING SPACE
	MOVX T1,MAXNOD+2	;NEED 1 WORD PER NODE PLUS FREE BLOCK HEADER
				;  PLUS TBLUK HEADER
	CALL ASGSWP		;ALLOCATE SOME SPACE FOR NODE TABLE
	 RETBAD (,<OKINT>)	;FAILED
	OKINT			;PERMIT INTERRUPTS AGAIN
	ADDI T1,1		;POINT PAST FREE BLOCK HEADER
	MOVEM T1,NODTBL		;SAVE ADDRESS OF NODE TABLE
	MOVX T4,MAXNOD		;GET MAX NUMBER OF ENTRIES IN TABLE
	MOVEM T4,(T1)		;INITIALIZE TBLUK HEADER
	MOVEI T1,OURNAM		;GET POINTER TO OUR NODE NAME
	MOVX T2,.NDSON		;STATE IS ON
	SETZ T3,		;NO NEIGHBOR NODE
	CALL ADDINT		;ADD US TO THE KNOWN NODES
	 RETBAD ()		;FAIL
	RETSKP			;DONE, RETURN SUCCESS
;ADDNOD - ROUTINE TO ADD A NODE TO THE TABLE OF KNOWN NODES
;
;ACCEPTS IN T1/	ADDRESS OF ASCIZ NODE NAME
;	    T2/	STATE OF NODE
;	    T3/ POINTER TO NEARER NEIGHBOR NODE (FOR STATE OF "ON")
;		CALL ADDNOD
;RETURNS: +1	 FAILED
;	  +2	SUCCESS, NODE ADDED IF NOT ALREADY IN TABLE

ADDNOD:	ASUBR <ADNADR,ADNSTA,ADNABR,ADHLD>

; SEE IF NODE IS TO BE ADDED OR REMOVED FROM KNOWN NODE TABLE

	HRRZ T3,ADNSTA		;GET NODE STATE
	CAIN T3,.NDSOF		;NODE OFF ?
	JRST [	CALL REMNOD	;REMOVE NODE FROM TABLE OF KNOWN NODES
		 RET		;FAILURE - RETURN
		JRST ADDTEL]	;NOTIFY INTERESTED USERS THAT TOPOLOGY CHANGED

; CHECK TO SEE IF THE NODE IS ALREADY IN THE TABLE

	NOINT			;DO NOT PERMINT INTERRUPTS WITH TABLE LOCKED
	LOCK NODLOK		;LOCK THE TABLE
	HRRZ T2,ADNADR		;GET ADDRESS OF NODE NAME STRING
	HRLI T2,(POINT 7,)	;FORM POINTER TO NODE NAME STRING
	MOVE T1,NODTBL		;GET ADDRESS OF NODE TABLE
	TBLUK			;SEE IF THE NODE IS IN THE TABLE OF KNOWN NODES
	 ERJMP [UNLOCK NODLOK	;UNLOCK THE TABLE
		OKINT		;PERMIT INTERRUPTS AGAIN
		RET]		;AND RETURN FAILURE
	TXNN T2,TL%EXM		;ALREADY IN TABLE (EXACT MATCH) ?
	JRST ADDIT		;NO - ADD THIS NODE NAME

; NODE ALREADY EXISTS. CHECK THE NEIGHBOR

	MOVEM T1,ADHLD		;YES - SAVE THE ENTRIES TABLE LOCATION
	MOVE T1,ADNABR		;GET POINTER TO NEIGHBOR NAME
	JUMPE T1,ADDND1		;IF ZERO => NO NEIGHBOR
	CALL NABROK		;CHECK FOR EXISTENCE OF NEIGHBOR
	 JRST [	UNLOCK NODLOK	;NONEXISTANT NEIGHBOR - ERROR
		OKINT		;ALLOW INTERRUPTS
		RET]		;ERROR RETURN
	MOVE T2,ADHLD		;GET NODE ADDRESS
	HLRZ T1,(T1)		;GET ADDRESS OF NEIGHBOR NAME
ADDND1:	HRRM T1,(T2)		;ADD NEIGHBOR NAME TO NODE TABLE

; SINCE NODE WAS ALREADY IN TABLE WE CAN FREE THE NAME STRINGS

	HRRZ T1,ADNADR		;GET ADDRESS OF STRINGS
	SOS T1			;POINT TO START OF BLOCK
	CALL RELMES		;FREE THE SPACE
	UNLOCK	NODLOK		;UNLOCK THE NODE TABLE
	OKINT			;ALLOW INTERRUPTS
	RETSKP
; ADD THE NODE TO THE TABLE OF KNOWN NODES

ADDIT:	MOVE T1,ADNABR		;GET ADDRESS OF NEIGHBOR NAME STRING
	JUMPE T1,ADDIT1		;IF ZERO => NO NEIGHBOR
	CALL NABROK		;CHECK FOR IT'S EXISTENCE
	 JRST [	UNLOCK NODLOK	;UNLOCK THE NODE TABLE
		OKINT		;ALLOW INTERRUPTS
		RET]
	HLRZ T1,(T1)		;GET ADDRESS OF NEIGHBOR NAME
ADDIT1:	HRL T2,ADNADR		;GET ADDRESS OF NODE NAME STRING
	HRR T2,T1		;GET NODES NEIGHBOR NAME
	MOVE T1,NODTBL		;GET ADDRESS OF NODE TABLE
	TBADD			;ADD THE NODE TO TABLE OF KNOWN NODES
	 ERJMP [UNLOCK NODLOK	;UNLOCK THE TABLE
		OKINT		;PERMIT INTERRUPTS AGAIN
		RET]		;AND RETURN FAILURE
	UNLOCK NODLOK		;UNLOCK THE TABLE
	OKINT			;PERMIT INTERRUPTS AGAIN

;HERE TO NOTIFY INTERESTED USERS THAT TOPOLGY HAS CHANGED

ADDTEL:	MOVEM Q1,ADNADR		;SAVE Q1
	MOVEI Q1,NTCTAB		;START LOOKING AT TOP OF TABLE
NTCIN1:	SKIPN (Q1)		;IS THERE AN ENTRY?
	JRST NTCIN2		;NO. KEEP LOOKING.
	LOAD T2,NTCFRK,(Q1)	;GET FORK NUMBER
	LOAD T1,NTCCHN,(Q1)	;GET THE CHANNEL NUMBER
	CALL PSIRQ		;INTERRUPT USER
NTCIN2:	CAIE Q1,NTCTAB+<NTCMAX-1>	;DID WE SEARCH WHOLE TABLE?
	AOJA Q1,NTCIN1		;NO - CHECK NEXT ENTRY
	MOVE Q1,ADNADR		;RESTORE Q1
	RETSKP
;REMNOD - ROUTINE TO REMOVE A NODE FROM THE TABLE OF KNOWN NODES
;
;ACCEPTS IN T1/	POINTER TO ASCIZ NODE NAME
;		CALL REMNOD
;RETURNS: +1	 FAILED
;	  +2	SUCCESS

REMNOD:	ASUBR <RMNNAM>

	NOINT			;DO NOT PERMINT INTERRUPTS WITH TABLE LOCKED
	LOCK NODLOK		;LOCK THE TABLE
	MOVE T1,NODTBL		;GET ADR OF HEADER OF KNOWN NODE TABLE
	MOVE T2,RMNNAM		;GET NAME OF NODE
	TBLUK			;FIND THE NAME IN THE KNOWN NODE TABLE
	 ERJMP REMNDX		;FAILED
	TXNN T2,TL%EXM		;IN TABLE (EXACT MATCH) ?
	JRST REMNDX		;NO - FAIL
	CALL NODDEL		;YES - DELETE NODE AND REST OF TREE
	 JRST REMNDX		;ERROR - FAIL
	MOVE T1,RMNNAM		;FREE THE BUFFER
	SOS T1			;BACK-UP TO HEADER WORD
	CALL RELMES
	UNLOCK NODLOK		;UNLOCK THE TABLE
	OKINT			;PERMIT INTERRUPTS AGAIN
	RETSKP			;DONE, RETURN SUCCESS


; HERE ON AN ERROR

REMNDX:	UNLOCK NODLOK		;UNLOCK THE DATABASE
	OKINT			;PERMIT INTERRUPTS AGAIN
	RET			;FAIL
;ADDINT - ROUTINE TO ADD A NODE TO KNOWN NODE TABLE, NAME STRING ALREADY
;	    IN MONITOR.
;
;ACCEPTS IN T1/	POINTER TO NODE NAME STRING
;	    T2/	NODE STATE
;	    T3/ POINTER TO NEARER NEIGHBOR NODE (OR ZERO)
;		CALL ADDINT
;RETURNS: +1	 FAILED
;	  +2	SUCCESS

ADDINT:	ASUBR <ADIPTR,ADISTA,ADINBR,ADIBLK>

; COPY THE STRING INTO A FREE BLOCK

	NOINT			;DO NOT PERMIT INTERRUPTS WHILE ASSIGNING SPACE
	MOVX T1,2*<<NODMAX+12>/5> ;ASSIGN SPACE FOR NODE NAMES
	CALL ASGSWP		;GET SOME SPACE
	 RETBAD (,<OKINT>)	;FAILED
	ADDI T1,1		;POINT TO WHERE STRING GOES
	MOVEM T1,ADIBLK		;SAVE DESTINATION ADDRESS OF STRING
	MOVE T2,ADIPTR		;GET SOURCE STRING ADDRESS
	MOVX T3,NODMAX		;MAX SIX CHARS
	CALL MOVSTR		;MOVE STRING INTO FREE BLOCK
	MOVE T1,ADIBLK		;NOW MOVE THE NEIGHBOR NAME
	ADDI T1,<NODMAX+12>/5	;POINT TO SECOND SLOT
	MOVX T3,NODMAX		;MAXIMUM NODE NAME
	SKIPE T2,ADINBR		;COPY NEIGHBOR (IF THERE)
	CALL MOVSTR		;MOVE NEIGHBOR NAME

; ADD NODE TO TABLE OF KNOWN NODES

	MOVE T1,ADIBLK		;GET ADDRESS OF NODE NAME STRING
	MOVE T2,ADISTA		;GET NODE STATE
	SKIPE T3,ADINBR		;PASS T3=0 IF NO NEIGHBOR
	MOVEI T3,<<NODMAX+12>/5>(T1)	;POINT TO NEIGHBOR NAME
	CALL ADDNOD		;ADD NODE TO KNOWN NODE TABLE
	 JRST ADIN10		;FAILED, CLEAN UP
	OKINT			;PERMIT INTERRUPTS AGAIN
	RETSKP			;DONE, RETURN SUCCESS

; HERE ON AN ERROR

ADIN10:	MOVEM T1,ADISTA		;SAVE ERROR CODE
	MOVE T1,ADIBLK 		;ADDRESS OF BLOCK
	SOS T1			;POINT TO HEADER
	CALL RELMES		;RELEASE THE BLOCK
	OKINT			;PERMIT INTERRUPTS AGAIN
	MOVE T1,ADISTA		;RESTORE ERROR CODE
	RETBAD () 		;FAIL
;NODDEL - ROUTINE TO DELETE A GIVEN ENTRY FROM THE NODE TABLE

;ACCEPTS:	T1/ ADDRESS OF ENTRY IN NODE TABLE (WITH NODTBL LOCKED)

;RETURNS:	+1,ALWAYS, ALL AC'S PRESERVED

;*** N.B. *** THIS ROUTINE IS RECURSIVE. ***

;NODTBL IS REALLY A TREE OF NODES.  EACH NODE HAS THE ADDRESS OF A NEARER 
;NEIGHBOR (I.E. NEARER TO US THAN IT).  WHEN REMOVING A NODE WE MUST REMOVE
;ALL THE NODES THAT HAVE IT AS A NEIGHBOR.  THINGS BECOME RECURSIVE BECAUSE
;WHEN WE REMOVE THE SECONDARY NODES THEY COULD ALSO BE NEIGHBORS TO OTHER
;NODES.

NODDEL:	SAVET
	STKVAR <DELHLD>
	MOVE T3,(T1)		;GET ENTRY WE ARE DELETING
	MOVEM T3,DELHLD		;SAVE NODTBL POINTER
	HLRZ T3,(T1)		;GET ADDRESS OF NODE NAME
	MOVE T1,NODTBL		;GET ADDRESS OF NODE TABLE
	MOVE T4,NODTBL		;HOLD FOR LOOP DECISION

; FIND ANY ENTRIES HAVING CURRENT NODE AS NEAREST NEIGHBOR

NODDL1:	AOS T1			;POINT TO NEXT ENTRY
	HRRZ T2,0(T1)		;GET THE NEIGHBOR ADDRESS
	CAMN T2,T3		;IS THE CURRENT NODE THE NEIGHBOR
	JRST [	HLRZ T2,0(T1)	;YES - IS THIS A POINTING TO SELF CASE?
		CAMN T2,T3	;???
		JRST .+1	;YES - THEN DO NOTHING
		CALL NODDEL	;YES - REMOVE THAT NODE ***RECURSION***
		 RETBAD		;ERROR - FAIL
		MOVE T1,NODTBL	;START AT TOP OF TABLE
		JRST NODDL1]	;SEARCH WHOLE TABLE AGAIN
	HLRZ T2,0(T4)		;GET CURRENT LENGTH OF TABLE
	ADD T2,T4		;T2<= ADDRESS OF LAST ENTRY
	CAML T2,T1		;ARE WE FINISHED
	JRST NODDL1		;NO - KEEP LOOKING
	;...
	;...

; HAVE CLEARED ALL ENTRIES DOWN THE TREE FROM HERE - DELETE THIS NODE

	HLR T1,(T4)		;GET COUNT OF ENTRIES
	MOVE T2,DELHLD		;LOOKING FOR THIS ENTRY
NODDL2:	AOS T4			;BUMP TO NEXT ENTRY
	CAMN T2,(T4)		;THE ONE WE WANT?
	JRST NODDL3		;YES - DELETE IT
	SOJG T1,NODDL2		;NO - KEEP LOOKING
	BUG (NDBDEL)
	RETBAD
NODDL3:	MOVE T2,T4		;GET THE NODE TABLE ENTRY
	HLRZ T4,(T2)		;GET ADDRESS OF FREE BLOCK HOLDING STRINGS
	MOVE T1,NODTBL		;POINT TO NODE TABLE
	TBDEL			;DELETE THE ENTRY
	 ERJMP [RETBAD]		;ERROR - HANDLE
	MOVE T1,T4		;RELEASE THE STRING BLOCK
	SOS T1			;POINT TO FIRST WORD OF FREE BLOCK
	CALL RELMES		;FREE IT
	RETSKP
;NABROK - ROUTINE TO CHECK FOR EXISTENCE OF A NODE

;ACCEPTS:	T1/POINTER TO NODE STRING

;RETURNS:	+1,NODE DOES NOT EXIST
;		+2,NODE EXISTS
;			T1/ADDRESS OF NODTBL ENTRY

NABROK:	MOVE T2,T1		;MOVE POINTER TO NODE NAME
	MOVE T1,NODTBL		;POINT TO TABLE OF NODES
	TBLUK			;IS IT THERE
	 ERJMP [RET]		;ERROR  - RETURN
	TXNN T2,TL%EXM		;EXACT MATCH?
	RET			;NO - INDICATE NODE DOES NOT EXIST
	RETSKP			;YES - INDICATE EXISTENCE
SUBTTL	Routines to Manipulate Logical Link Blocks and Object Tables

	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::SAVEAC (T4)		;PRESERVE TEMP AC
	NOSKED			;PREVENT RACES
	JE LLRCT,(T1),BLKLK0	;IF FIRST LOCKER, NO CHECKS NEEDED
	LOAD T4,LLRFK,(T1)	;GET PREVIOUS LOCKER'S ID
	CAME T4,FORKX		;WERE WE PREVIOUS LOCKER
	JRST BLKLK1		;NO, FAIL RETURNING SCHED TEST
BLKLK0:	INCR LLRCT,(T1)		;OK TO LOCK (EITHER FIRST LOCKER OR LAST WAS US)
	MOVE T4,FORKX		;GET OUR FORK ID
	STOR T4,LLRFK,(T1)	;STORE OUR ID AS LAST LOCKER
	NOINT			;PREVENT INTERRUPT WHILE BLOCK LOCKED
	OKSKED			;PERMIT SCHEDULING AGAIN
	RETSKP			;DONE, BLOCK NOW LOCKED

; HERE IF LOCK WILL NOT BE PERMITTED - RETURN A SCHEDULER TEST

BLKLK1:	OKSKED			;PERMIT SCHEDULING
	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::NOSKED		;PREVENT SCHEDULING
	DECR LLRCT,(T1)		;UNDO PREVIOUS LOCK
	JN LLRCT,(T1),BLKUL1	;UNDOING INITIAL LOCK ?
	SETZRO LLRFK,(T1)	;YES, CLEAR ID OF LOCKER ALSO
BLKUL1:	OKINT			;PERMIT INTERRUPT AGAIN
	OKSKED			;AND PERMIT SCHEDULING AGAIN
	RET			;DONE, RETURN



;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
;LOKPIP - ROUTINE TO LOCK AN ATS DATA DATA OR CONTROL PIPE
;
;ACCEPTS IN T3/	ATS PIPE IDENTIFIER
;		CALL LOKPIP
;RETURNS: +1	 FAILED, SCHEDULER TEST IN T1
;	  +2	SUCCESS, PROCESS NOINT AND PIPE LOCKED

LOKPIP::TRVAR <LKPCOD,LKPLLB>
	MOVEM T3,LKPCOD		;SAVE ATS ID

; GET THE ADDRESS OF THE LOGICAL LINK BLOCK

	LLLOCK			;LOCK THE LOGICAL LINK TREE
	MOVEI T1,CHKPIP		;GET COROUTINE TO FIND ATS PIPE
	SETOM T2		;ANY LINK
	CALL OBJSRC		;GO FIND BLOCK
	 JRST [	LLLULK		;DOES NOT EXIST
		BUG(NSPPWA)
		RET ]		;UNLOCK THE TREE AND RETURN FAILURE
	MOVEM T1,LKPLLB		;SAVE LOGICAL LINK BLOCK ADDRESS

; LOCK THE BLOCK

	MOVE T1,LKPLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKLOK		;GO LOCK THE LOGICAL LINK BLOCK
	 JRST [	LLLULK		;CANNOT LOCK IT NOW, UNLOCK THE TREE
		RET ]		;RETURN SCHED TEST
	LLLULK			;BLOCK IS NOW RESERVED. UNLOCK THE TREE
	RETSKP			;DONE, RETURN WITH PIPE LOCKED



;CHKPIP - COROUTINE TO FIND ATS LINK BLOCK WITH GIVEN ATS DATA PIPE
;
;ACCEPTS IN TRVAR LKPCOD/ ATS ID FOR PIPE
;	    T1/	ADDRESS OF LINK BLOCK TO CHECK
;		CALL CHKPIP
;RETURNS: +1	 NOT DESIRED BLOCK
;	  +2	SUCCESS, FOUND BLOCK WITH REQUESTED ID

CHKPIP:	SAVET			;PRESERVE TERMPORARY AC'S
	JE LLINT,(T1),R		;LOOK AT INTERNAL LINKS ONLY
	LOAD T2,LLDRV,(T1)	;GET DRIVER CORRELATION CODE
	CAME T2,LKPCOD		;DESIRED ATS ID ?
	RET			;NO, RETURN FAILURE
	RETSKP			;YES, RETURN SUCCESS
;ULKPIP - ROUTINE TO UNLOCK AN ATS DATA OR CONTROL PIPE
;
;ACCEPTS IN T3/	ATS PIPE IDENTIFIER
;		CALL ULKPIP
;RETURNS: +1 ALWAYS, WITH PIPE UNLOCKED

ULKPIP::TRVAR <LKPCOD>
	MOVEM T3,LKPCOD		;SAVE ATS ID FOR COROUTINE
	LLLOCK			;LOCK THE LOGICAL LINK TREE
	MOVEI T1,CHKPIP		;GET COROUTINE ADDRESS
	SETOM T2		;ANY LINK
	CALL OBJSRC		;GO FIND BLOCK
	 JRST [	LLLULK		;DOES NOT EXIST
		BUG(NSPPHV)
		RET ]		;UNLOCK THE TREE AND RETURN FAILURE
	LLLULK			;UNLOCK THE TREE
	CALLRET BLKULK		;UNLOCK PIPE AND RETURN
;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?
	RETBAD (NSPX2)		;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
	 RETBAD (NSPX2)		;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 /ATS/],,3
	[ASCIZ /FAL/],,21
	[ASCIZ /NCU/],,23
	[ASCIZ /NRM/],,7
	[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
;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 OR 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
	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

;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::STKVAR <MVSPTR>
	MOVE T4,[POINT 7,0(T1)]	;FORM STRING POINTER
	MOVEM T4,MVSPTR		;SAVE POINTER
MOVST2:	ILDB T4,T2		;GET A BYTE
	IDPB T4,MVSPTR		;STORE IT
	SOJG T3,MOVST2		;DO ALL BYTES
	RET			;DONE
SUBTTL	Logical Link Creation

; ROUTINES TO SET INPUT/OUTPUT FLAGS IN LOGICAL LINK BLOCKS
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;		CALL SETOPI/SETOPW
;RETURNS: +1 ALWAYS

SETOPI::SETONE LLOPI,(T1) 	;SET INPUT FLAG
	RET			;DONE, RETURN


SETOPW::SETONE LLOPW,(T1)	;SET OUTPUT FLAG
	RET			;DONE, RETURN


; ROUTINES TO TEST THE DIRECTION OF I/O
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS

SKPFLO::JE LLFLO,(T1),R		;NON-SKIP IF FLOW NOT FROM FILE-SYSTEM
	RETSKP			;SKIP IF FLOW IS FROM THE FILE-SYSTEM


SKPFLI::JE LLFLI,(T1),R		;NON-SKIP IF FLOW NOT TO THE FILE-SYSTEM
	RETSKP			;SKIP if FLOW IS TO THE FILE-SYSTEM


; ROUTINES TO SET/CLEAR DIRECTION-OF-FLOW BITS

CLRFLO::SETZRO LLFLO,(T1) 	;SWITCH FLOW TO BE "TO THE NETWORK"
	RET			;DONE, RETURN

SETFLO::SETONE LLFLO,(T1) 	;SWITCH FLOW TO BE "FROM FILE-SYSTEM"
	RET			;DONE, RETURN


;GETBSZ - ROUTINE TO OBTAIN THE BYTE SIZE FOR A LOGICAL LINK
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;	    	CALL GETBSZ
;RETURNS: +1 ALWAYS, WITH T3/ BYTE SIZE
;
; PRESERVES LOGICAL LINK BLOCK ADDRESS IN T1

GETBSZ::LOAD T3,LLBSZ,(T1)	;GET BYTE SIZE
	RET			;DONE, RETURN


;GETSTA - ROUTINE TO RETURN CURRENT STATE OF A LOGICAL LINK
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;		CALL GETSTA
;RETURNS: +1 ALWAYS, WITH T2/ LINK STATE
;
; PRESERVES LOGICAL LINK BLOCK ADDRESS IN T1

GETSTA::LOAD T2,LLSTA,(T1)	;GET CURRENT STATE
	RET



;SETEOM - ROUTINE TO SET "END-OF-MESSAGE-NEEDED" FLAG FOR A LOGICAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL SETEOM
;RETURNS: +1 ALWAYS

SETEOM::SETONE LLFEM,(T1)	;SAY SHOULD GET EOM ON OUTPUT
	RET			;DONE, RETURN


;GETMXS - ROUTINE TO GET MAX SEGMENT SIZE
;
;ACCEPTS IN T1/ LOGICAL LINK BLOCK ADDRESS


GETMXS::LOAD T4,LLSWG,(T1)	;GET MAX SEG SIZE
	RET			;DONE, RETURN
;WORK ROUTINES TO OPEN DCN: OR SRV:
;
;	OPNDWK - OPEN A FILESYSTEM DCN: LINK
;	OPNSWK - OPEN A FILESYSTEM SRV: LINK
;	OPNIWK - OPEN AN INTERNAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF TASK STRING
;	    T2/	BYTE SIZE OF OPEN
;		CALL OPNSWK/OPNDWK
;RETURNS: +1	 FAILED, ERROR CODE IN T1
;	  +2	SUCCESS, WITH T1/ ADDRESS OF LOGICAL LINK BLOCK

OPNDWK::MOVEI T3,LKSIZE		;BASIC LL BLOCK SIZE
	JRST OPNWRK		;CALL WORK ROUTINE
OPNSWK::MOVEI T3,LKSIZE+LKOBJS	;BASIC SIZE PLUS WORDS NEEDED FOR SRV: LINKS
	JRST OPNWRK		;CALL WORK ROUTINE
OPNIWK::MOVEI T3,LKSIZE+LKISIZ	;BASIC SIZE PLUS WORDS NEEDED FOR INTERNAL LINKS
	JRST OPNWRK		;GO DO THE OPEN
;OPNWRK - WORK ROUTINE TO OPEN A LOGICAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF TASK STRING
;	    T2/	BYTE SIZE OF OPEN
;	    T3/	SIZE OF LOGICAL LINK BLOCK NEEDED
;		CALL OPNWRK
;RETURNS: +1	 FAILED, ERROR CODE IN T1
;	  +2	SUCCESS, WITH T1/ ADDRESS OF LOGICAL LINK BLOCK

OPNWRK:	TRVAR <SAVBLK,SAVERR,SAVSTR,SAVBSZ>
				; NOTE: TRVAR IS NEEDED HERE INSTEAD OF STKVAR
				;	BECAUSE COROUTINES ACCESS THE VARIABLES.
	MOVEM T1,SAVSTR		;SAVE STRING BLOCK ADDRESS
	MOVEM T2,SAVBSZ		;SAVE BYTE SIZE
	MOVX T2,FRKRUN		;SEE IF NETWORK IS INTIALIZED
	TDNN T2,MCBDTE		;IS IT?
	RETBAD (DCNX11)		;NO. ILLEGAL TO USE IT THEN
	MOVE T1,T3		;COPY # OF ADDITIONAL WORDS NEEDED FOR LL BLOCK
	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
	MOVE T1,SAVSTR		;GET POINTER TO EXTENSION BLOCK
	JUMPE T1,OPNDFT		;NONE. GO DEFAULT TASK NAME
	LDB T2,[POINT 7,(T1),6] ;GET FIRST BYTE
	JUMPE T2,OPNDFT		;IF NULL EXTENSION. GO DEFAULT TASK NAME
	; ..
;USER SPECIFIED EXTENSION. CHECK FOR DUPLICATE

	HRLI T1,(POINT 7,)	;FORM POINTER TO THE STRING
	MOVX T3,MAXLC		;GET MAX SIZE OF EXTENSION
	CALL CMPLEN		;COMPUTE ACTUAL NUMBER OF BYTES IN STRING
	IDIVI T3,5		;COMPUTE NUMBER OF WORDS IN STRING
	SKIPE T4		;AND ROUND RESULT UP
	ADDI T3,1		; IF NEEDED
	MOVE T1,T3		;COPY SIZE OF STRING
	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
	MOVE T2,SAVSTR		;GET STRING BLOCK
	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
	MOVE T3,SAVBSZ		;GET BYTE SIZE
	STOR T3,LLBSZ,(T1)	;SAVE BYTE SIZE IN LOGICAL LINK BLOCK
	CAIE T3,44		;WORD MODE?
	JRST OPENX1		;NO. GO ON
	SETONE LLFDI,(T1)	;YES. REMEMBER THIS
OPENX1:	RETSKP			;DONE, RETURN SUCCESS WITH T1/ LL BLOCK ADDRESS
;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
	HLRZ T2,FKJOB(T2)	;GET FORK'S JOB NUMBER
	MOVE T4,FORKX		;GET THIS FORK'S NUMBER
	HLRZ T4,FKJOB(T4)	;GET THIS FORK'S JOB NUMBER
	CAMN T2,T4		;IS IT?
	RET			;YES. NO NEED TO CHECK ANYMORE
	LOAD T2,LLTSK,(T1)	;GET THIS ONE'S ADDRESS
	JUMPE T2,R		;IF NONE, CAN'T BE IT
	MOVE T1,SAVERR		;GET TASK BLOCK ADDRESS
	CALLRET CMPSTR		;GO DO THE COMPARE
SUBTTL	Routines to Manipulate the Logical Link Tree

;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 (DELNDF)
	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:	CALL REMQUE		;REMOVE BLOCK FROM OUTQUE OF NEEDED
	CALLRET RELRES		;FREE BLOCK AND RETURN

DELREL:	SAVET
	NOINT			;PREVENT INTERRUPTS WHILE DEASSIGNING SPACE
	MOVE T1,T2		;GET BLOCK ADDRESS
	CALL RELBLK		;FREE BLOCK
	OKINT			;PREMIT INTERRUPTS AGAIN
	RET			;RETURN
;REMQUE - ROUTINE TO REMOVE A LINK FROM OUTQUE
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL REMQUE
;RETURNS: +1 ALWAYS, WITH LINK REMOVED IF QUEUED

REMQUE:	JE LLQUE,(T1),R		;NOTHING TO DO IF THIS LINK WAS NOT QUEUED

; INITIALIZATION

	LOCK OUTLOK		;LOCK THE QUEUE
	MOVEI T4,0		;INITIALIZE CURRENT QUEUE ITEM
	HRRZ T3,OUTQUE		;GET ITEM AT HEAD OF QUEUE

; SEARCH THE QUEUE FOR THE DESIRED LINK

RMQ010:	CAMN T3,T1		;FOUND DESIRED ITEM ?
	JRST RMQ020		;YES, GO REMOVE IT FROM THE QUEUE
	MOVE T4,T3		;NO, SAVE CURRENT ITEM AS PREVIOUS ITEM
	LOAD T3,LLOUT,(T3)	;MAKE NEXT ITEM CURRENT ITEM
	JUMPN T3,RMQ010		;AND GO CHECK NEW CURRENT ITEM
	BUG(NSPLNQ)
	RET			;SHOULD NEVER HAPPEN

; HERE WITH THE DESIRED LINK ADDRESS IN T3, PREVIOUS ITEM IN T4

RMQ020:	HLRZ T2,OUTQUE		;GET POINTER TO TAIL OF QUEUE
	CAMN T2,T3		;REMOVING TAIL OF QUEUE ?
	HRLM T4,OUTQUE		;YES, SAVE POINTER TO NEW TAIL OF QUEUE
	LOAD T2,LLOUT,(T3)	;GET POINTER TO NEXT BLOCK
	SKIPN T2		;REMOVING HEAD OF QUEUE ?
	JRST [	HRRM T2,OUTQUE	;YES, SAVE NEXT BLOCK AS NEW HEAD
		JRST RMQ030 ]	;AND CLEAN UP
	STOR T2,LLOUT,(T4)	;STORE NEXT BLOCK IN PREVIOUS

; HERE WITH ITEM REMOVED FROM QUEUE

RMQ030:	SETZRO LLQUE,(T1)	;CLEAR "LINK ON OUTQUE" FLAG
	UNLOCK OUTLOK		;UNLOCK THE QUEUE
	RET			;DONE, RETURN
;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 (ADDONF)
	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
SUBTTL	More Link Creation Routines

;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

;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
	 RETBAD ()		;FAILED, RETURN ERROR CODE
	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:	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
;CRTLNK - ROUTINE TO CREATE A LOGICAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;	    T2/	ADDRESS OF ATRIBUTE LIST
;	    T3/	OBJECT,,COUNT OF BYTES IN DESCRIPTOR
;	    T4/	POINTER TO DESCRIPTOR STRING
;	 TRVARS -- NTCNT,NTPNT,NTOBJ,NTDSC,NTDSS,NTHST,NTHSC
;
;		CALL CRTLNK
;RETURNS: +1	 FAILED, ERROR CODE IN T1
;	  +2	SUCCESS

CRTLNK::ACVAR <W1,W2,W3>	;GET A WORK REGISTER
	STKVAR <CRLATR,CRLCIB,CRLCNT,CRLOBJ,CRLHST,CRLHSC,CRLDSS,CRLDSC>

; SAVE INPUT ARGUMENTS

	MOVE W1,T1		;SAVE LL BLOCK ADDRESS
	MOVEM T2,CRLATR		;SAVE ATTRIBUTE LIST POINTER
	HLRZM T3,CRLOBJ		;SAVE OBJECT
	HRREM T3,CRLDSC		;SAVE COUNT OF BYTES IN DESCRIPTOR
	MOVEM T4,CRLDSS		;SAVE DESCRIPTOR POINTER

	MOVE T1,CRLOBJ		;GET OBJECT
	STOR T1,LLFNM,(W1)	;SAVE IT
	SKIPG T3,CRLDSC		;ANY DESCRIPTOR GIVEN
	JRST DSCNUL		;NO, SKIP MOVING STRING
	LOAD T1,LLFDS,(W1)	;GET DESCRIPTOR BLOCK
	MOVE T2,CRLDSS		;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
	 RETBAD ()		;FAILED, RETURN ERROR
	MOVEM T1,CRLCIB		;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
	MOVE T1,W1		;LL BLOCK ADDRESS
	MOVEI T2,CNMRFL+CNMCI	;MESSAGE FLAGS
	CALL RTHDCI		;PUT ON ROUTING HEADER AND FLAGS
	CALL DOSRVS		;INSERT LL ADDRESSES AND STANDARD SERVICES
	;..
	; ..

;NOW BUILD OBJECT ADDRESSING FIELDS

	SKIPG CRLDSC		;HAVE A COUNT FOR DESCRIPTOR
	JRST [	MOVEI T2,OBJZRO	;GET OBJECT TYPE ZERO INDICATOR
		CALL ONEBYT
		MOVE T2,CRLOBJ	;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,CRLOBJ		;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

	MOVE T1,W1		;GET LOGICAL LINK BLOCK ADDRESS
	MOVE T2,CRLATR		;GET ADDRESS OF ATTRIBUTE LIST
	CALL INSATR		;GO INSERT ATTRIBUTES IN MESSAGE

	MOVEI T2,LLSCIS		;GET NEW STATE
	STOR T2,LLSTA,(T1)	;STORE NEW STATE
	LLLULK			;RELEASE TREE NOW
	MOVE T2,CRLCIB		;GET BLOCK ADDRESS
	CALL SNDCTL		;SEND MESSAGE TO THE NETWORK
	RETSKP			;AND DONE FOR NOW
;INSATR - ROUTINE TO INSERT ATTRIBUTE VALUES INTO THE CI MESSAGE
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;	    T2/	ADDRESS OF ATTRIBUTE TABLE
;		CALL INSATR
;RETURNS: +1 ALWAYS

INSATR:	STKVAR <INALLB,INAATR,INAPNT,INACNT>
	MOVEM T1,INALLB		;SAVE LOGICAL LINK ADDRESS
	MOVEM T2,INAATR		;SAVE ATTRIBUTE LIST ADDRESS

	MOVE T1,INALLB		;GET LOGICAL LINK BLOCK ADDRESS
	SETZ T2,		;DEFAULT MENU BYTE
	CALL ONEBYT		;PUT IT IN
	MOVE T3,LLBPTR(T1)	;GET POINTER TO MENU
	MOVEM T3,INAPNT		;SAVE IT
	MOVEI T2,1		;ASSUME WILL BE PRESENT
	MOVEM T2,INACNT		;SET IT
	MOVEI T2,.PFUDT		;SEE IF USER I.D. GIVEN
	MOVE T3,INAATR		;GET ATTRIBUTE LIST ADDRESS
	CALL GETATR		;IS IT?
	 JRST [	SETZM T2	;NOT THERE.
		CALL ONEBYT	;SAY IS NULL
		JRST DOSPW1]	;AND GO ON TO PASSWORD
	CALL ASCIIZ		;PUT IN THE DATA
DOSPW1:	MOVEI T2,.PFPWD		;SEE IF A PASSWORD IS GIVEN
	MOVE T3,INAATR		;GET ATTRIBUTE LIST ADDRESS
	CALL GETATR		;IS IT?
	 JRST [	MOVEI T2,.PFBPW	;NO. SEE ABOUT ALTERNATE FORM
		MOVE T3,INAATR	;GET ATTRIBUTE LIST ADDRESS
		CALL GETATR	;IS IT?
		 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
	MOVE T3,INAATR		;GET ATTRIBUTE LIST ADDRESS
	CALL GETATR		;IS IT?
	 MOVEI T3,[0]		;NO. PUT IN NULL STRING
	CALL ASCIIZ		;YES. PUT IT IN
	; ..
	; ..

	MOVEI T2,.PFOPT		;HAVE OPTIONAL USER DATA?
	MOVE T3,INAATR		;GET ATTRIBUTE LIST ADDRESS
	CALL GETATR		;IS IT?
	 JRST [	MOVEI T2,.PFBOP	;NO. TRY OTHER FORM
		MOVE T3,INAATR	;GET ATTRIBUTE LIST ADDRESS
		CALL GETATR	;IS IT?
		 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,INACNT		;TO THE MENU
	CALL 0(T4)		;INSERT IT
INMENU:	MOVE T2,INACNT		;GET FINAL MENU
	DPB T2,INAPNT		;PUT IT IN THE MESSAGE
	RET			;DONE, RETURN
;STRSAV - ROUTINE TO SAVE NAME STRINGS ON LINK CREATION
;
;ACCEPTS IN TRVARS:	NTHST, NTHSC, NTDSS, NTDSC, NTOBJ
;	    T1/	ADDRESS OF LL BLOCK
;	    T2/	COUNT OF HOST STRING BYTES,,COUNT OF DESCRIPTOR STRING BYTES
;	    T3/	POINTER TO HOST NAME STRING
;	    T4/	POINTER TO DESCRIPTOR STRING
;		CALL STRSAV
;RETURNS: +1	 FAILED, ERROR CODE IN T1
;	  +2	SUCCESS, STRINGS SAVED

STRSAV::ACVAR <W1,W2,W3>
	STKVAR <SSVHST,SSVHSC,SSVDSC,SSVDSS>
	HLREM T2,SSVHSC		;SAVE HOST STRING BYTE COUNT
	HRREM T2,SSVDSC		;SAVE DESCRIPTOR BYTE COUNT
	MOVEM T3,SSVHST		;SAVE HOST NAME STRING POINTER
	MOVEM T4,SSVDSS		;SAVE DESCRIPTOR STRING POINTER
	MOVE W1,T1		;SAVE LL BLOCK ADDRESS
	SKIPG T3,SSVHSC		;HAVE A HOST NAME?
	JRST [	SETONE LLLOC,(W1) ;NOTE THIS IS A LOCAL LINK
		SKIPL W2,NSPLPB	;GET PORT FOR LOOPBACK
		RETSKP		;NOT ACTIVE
		MOVE T2,[POINT 7,OURNAM] ;POINT TO OUR NAME
		MOVE T3,OURCNT	;LENGTH OF OUR NAME
		JRST DCNOP8 ]	;USE LOOPBACK PORT FOR LINK
	CAME T3,OURCNT		;SAME COUNT AS OUR NAME?
	JRST DCNOP0		;NO. CAN'T BE US THEN
	MOVE T1,SSVHST		;GET BLOCK POINTER
	MOVE T2,[POINT 7,OURNAM] ;GET POINTER TO OUR NAME
	CALL COMPAR		;SEE IF THE SAME
	 JRST DCNOP0		;NO. SAVE IT THEN
	SETONE LLLOC,(W1)	;YES, NOTE LOCAL LINK
	SKIPL W2,NSPLPB		;GET PORT FOR LOOPBACK
	RETSKP			;NONE SO JUST RETURN
	JRST DCNOP7		;HAVE PORT TO USE
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,SSVHSC		;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
	HRLI T2,(POINT 7,)	;FORM POINTER TO NAME
	MOVE T1,SSVHST		;GET BLOCK POINTER AGAIN
	CALL COMPAR		;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?
	RETBAD (DCNX13)		;NO, FAIL
DCNOP7:	MOVE T2,SSVHST		;GET POINTER TO STRING TO BE MOVED
	MOVE T3,SSVHSC		;GET COUNT
DCNOP8:	STOR W2,LLPRT,(W1)	;SAVE PORT #
	LOAD T1,LLHST,(W1)	;GET ADDRESS OF HOST STRING
	CALL MOVST1		;AND MOVE IT
	RETSKP			;DONE, ALL STRINGS SAVED. RETURN SUCCESS.
;LOCAL ROUTINE FOR STRSAV TO COMPARE TWO STRINGS
;ACCEPTS:	T1/ POINTER TO STRING 1
;		T2/ POINTER TO STRING 2
;		T3/ COUNT
;RETURNS:	+1 NO MATCH
;		+2 MATCH

COMPAR:	ACVAR <W1,W2,W3>	;GET SOME REGS
	MOVE W1,T1		;COPY POINTER TO FIRST STRING
	MOVE W2,T2		;COPY POINTER TO SECOND STRING
	MOVE W3,T3		;SAV COUNT
CMPRLP:	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,CMPRLP		;DO ENTIRE STRING
	RETSKP			;A MATCH!!!!
;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:	STKVAR <MSGFLG>
	MOVEM T2,MSGFLG		;SAVE FLAGS
	CALL PUTLLA		;PUT IN LL ADDRESSES
	MOVEI T2,CISRVS+CIMSCT	;ASSUME SEG COUNTS
	OPSTR <SKIPE>,LLIMS,(T1) ;WANT MESSAGE COUNTS?
	MOVEI T2,CISRVS+CIMCNT	;YES
	CALL ONEBYT		;PUT IN SERVICES BYTE
	MOVEI T2,LNKPRI		;GET DEFAULT PRIORITY
	CALL ONEBYT
	MOVE T2,MSGFLG		;GET MESSAGE TYPE
	CAIE T2,CIMMFL		;IS IT A CI?
	JRST [LOAD T2,LLSWG,(T1)  ;NO, A CC - GET CI'S SEG SIZE
	      CAIG T2,SEGSIZ	;IS IT BIGGER THAN OURS?
	      JRST DOSRV1	;NO. USE IT ON THE LINK
	      JRST .+1]		;YES, USE OURS ON THE LINK
	MOVEI T2,SEGSIZ		;GET SEGMENT SIZE
DOSRV1:	STOR T2,LLSWG,(T1)	;PUT SEG SIZE IN LL BLOCK
	OPSTR <SKIPE>,LLFDI,(T1) ;OPEN IN WORD MODE?
	MOVEI T2,WSEGSZ		;YES. GET PROPER SEG SIZE
	JN LLINT,(T1),[	MOVEI T2,ISEGSZ ;IF INTERNAL LINK USE DIFFERENT
			JRST .+1 ]	; SEGMENT SIZE
	SETZRO LLFDI,(T1)	;INIT THIS FLAG
	CALLRET TWOBYT
;ROUTINE TO BUILD A ROUTING HEADER.
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ PROPER MESSAGE FLAGS

RTHDCI:	SAVEAC (T2)		;PRESERVE THE FLAGS
	STKVAR <MSGFLG>		;TO SAVE THE FLAGS
	MOVEM T2,MSGFLG		;SAVE FLAGS
	CALL TSTLCL
	 JRST RTHDC1
	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 ASCIIZ		;PUT IT IN
RTHDC1:	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
	CALLRET GETATR		;GO FIND ATTRIBUTE


;GETATR - ROUTINE TO FIND AN ATTRIBUTE
;
;ACCEPTS IN T2/	PREFIX VALUE
;	    T3/	ADDRESS OF ATTRIBUTE LIST
;		CALL GETATR
;RETURNS: +1	 FAILED, NO SUCH PREFIX
;	  +2	SUCCESS, WITH T3/ POINTER TO VALUE STRING

GETATR:	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 GETATR]	;AND LOOK AT IT
	MOVEI T3,1(T3)		;GET POINTER TO BLCOK
	RETSKP			;AND SAY WE FOUND IT


;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
SUBTTL	MTOPR Utility Functions


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

;RDSTS - GET LINK STATUS
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK (ASSUMED LOCKED)
;		CALL RDSTS
;RETURNS: +1 ALWAYS, WITH T3/ LINK STATUS

RDSTS::	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 ;IF LINK WAS CONNECTED, SO NOTE
		       JRST .+1] ;CONTINUE
	RET			;DONE, RETURN

;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
	CALL TELINT		;GO NOTIFY DRIVER IF THIS IS AN INTERNAL LINK
	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



;TELINT - ROUTINE TO NOTIFY THE DRIVER WHEN AN INTERRUPT MSG IS RECEIVED
;	  FOR AN INTERNAL LOGICAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL TELINT
;RETURNS: +1 ALWAYS, WITH DRIVER NOTIFIED

TELINT:	JE LLINT,(T1),R		;IF NOT AN INTERNAL LINK, THEN DONE
	SAVET			;PRESERVE TEMPORARY AC'S
	LOAD T4,LLVEC,(T1)	;GET DRIVER VECTOR ADDRESS
	LOAD T1,LLDRV,(T1)	;GET DRIVER CORRELATION CODE
	CALLRET @.NSINT(T4)	;NOTIFY DRIVER AND RETURN
;MORE MTORP FUNCTIONS...

;RECEIVE INTERRUPT MESSAGE

MTRDIN::MOVE T2,[IFIW![	XCTBUU [IDPB T2,3] ;ROUTINE TO RETURN BYTE
			RET ]]	; AND DONE
	UMOVE T3,3		;GET USER'S DESTINATION POINTER
	CALL RDINT		;GO READ AN INTERRUPT MESSAGE
	 JRST [	JUMPE T2,SQOBAD	;FAILED, RETURN ERROR
		JRST ULKRET ]	; OR BLOCK IF NEEDED
	UMOVEM T3,4		;RETURN BYTE POINTER
	UMOVEM T4,3		;RETURN COUNT TO USER
	CALL BLKULK		;DONE WITH BLOCK
	MOVE T1,T2		;GET FREE SPACE ADDRESS
	CALL RELRES		;RELEASE MESSAGE
	RETSKP			;AND DONE




;ULKRET - ROUTINE TO UNLOCK LOGICAL LINK BLOCK AND GIVE BLOCK-NEEDED RETURN
;
;ACCEPTS IN JFN/ ADDRESS OF JFN BLOCK
;		JRST ULKRET
;RETURNS TO CALLER WITH BLKF SET

ULKRET:	TQO <BLKF>		;NOTE BLOCK IS NEEDED
	EXCH T1,FILLLB(JFN)	;SAVE ERROR. GET BLOCK ADDRESS
	CALL BLKULK		;FREE BLOCK
	EXCH T1,FILLLB(JFN)	;GET BACK ERROR
	RETBAD ()		;AND DONE
;RDINT - ROUTINE TO READ AN INTERRUPT MESSAGE
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;	    T2/	ADDRESS OF ROUTINE TO STORE BYTES
;			(SHOULD ASSUME BYTE POINTER IS IN T3)
;	    T3/	DESTINATION BYTE POINTER
;		CALL RDINT
;RETURNS: +1	 FAILED, T2/ 0 => DO NOT BLOCK, T2/ -1 => BLOCK
;	  +2	SUCCESS, INTERRUPT MESSAGE DELIVERED, WITH
;		T2/ ADDRESS OF MESSAGE
;		T3/ UPDATED COUNT
;		T4/ UPDATED POINTER

RDINT::	ACVAR <W1>
	STKVAR <RDICNT,RDIPTR,RDIRTN>
	MOVEM T2,RDIRTN		;SAVE ROUTINE TO STORE BYTES
	MOVEM T3,RDIPTR		;SAVE DESTINATION BYTE POINTER
	CALL MTRNCK		;CHECK STATE
	 JRST RDINX		;FAIL, NOT IN RUN STATE
	SKIPN T2,LLMSI(T1)	;HAVE AN INT MESSAGE?
	JRST [	MOVX T1,DCNX15	;NO INTERRUPT MESSAGE AVAILABLE
		JRST RDINX ]	;RETURN ERROR
	MOVEI T2,1		;ASK FOR ONE MORE
	MOVEI T3,MSLSI		; INTERRUPT MESSAGE
	CALL SNDLS		;SEND MESSAGE
	 JRST [	MOVX T1,NSPX6	;GET ERROR CODE
		JRST RDINB ]	;AND RETURN FAILURE
	MOVE T2,LLMSI(T1)	;GET BACK MESSAGE
	LOAD T4,MSDTC,(T2)	;GET COUNT
	MOVEM T4,RDICNT		;SAVE COUNT
	MOVEM T4,W1		;AND SAVE AS LOOP VARIABLE
	MOVE T3,RDIPTR		;GET DESTINATION POINTER SUPPLIED
	TLC T3,-1
	TLCN T3,-1
	HRLI T3,(<POINT 7,>)	;GET DEFAULT
	MOVEM T3,RDIPTR		;SAVE POINTER
	MOVE T4,MSBPTR(T2)	;GET POINTER TO MESSAGE DATA
	JRST MTRDI2		;GO MOVE DATA
MTRDI1:	ILDB T2,T4		;GET NEXT BYTE
	CALL @RDIRTN		;STORE A BYTE
MTRDI2:	SOJGE W1,MTRDI1		;DO THEM ALL
	MOVE T2,LLMSI(T1)	;GET BACK MESSAGE
	SETZM LLMSI(T1)		;NONE NOW
	MOVE T3,RDICNT		;RESTORE COUNT
	MOVE T4,RDIPTR		;RESTORE POINTER
	RETSKP			;DONE, RETURN SUCCESS

; HERE ON AN ERROR

RDINX:	TDZA T2,T2		;NOTE BLOCK NOT WANTED
RDINB:	SETOM T2		;BLOCK NEEDED
	RET			;FAIL
;MORE MTOPR'S....  SEND INTERRUPT MESSAGE

MTSNIN::UMOVE T4,4		;GET COUNT
	UMOVE T3,3		;GET BP
	UMOVE T4,4		;GET COUNT
	MOVE T2,[IFIW![	XCTBUU [ILDB T2,3]
			RET]]	;ROUTINE TO GET BYTES
	CALL SNINT		;SEND THE INTERRUPT MESSAGE
	 JRST SQOBAD		;FAILED, RETURN ERROR
	UMOVEM T3,3		;STORE UPDATED BYTE POINTER
	MOVE T1,FILLLB(JFN)	;GET BACK BLOCK ADDRESS
	CALL BLKULK		;UNLOCK THE LOGICAL LINK BLOCK
	RETSKP			;DONE, RETURN SUCCESS


;SNINT - ROUTINE TO SEND AN INTERRUPT MESSAGE
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;	    T2/	ADDRESS OF ROUTINE TO GET BYTES
;			(PLACES BYTE IN T2, ASSUMES PTR IN T3)
;	    T3/	BYTE POINTER FOR GETTING BYTES
;	    T4/	COUNT OF BYTES TO SEND
;		CALL SNINT
;RETURNS: +1	 FAILED, ERROR CODE IN T1
;	  +2	SUCCESS, WITH T3/ UPDATED BYTE POINTER

SNINT::	ACVAR <W1>		;CAN SEND IT
	STKVAR <SIMLLB,SIMRTN,SIMPTR,SIMCNT>
	MOVEM T2,SIMRTN		;SAVE ROUTINE ADDRESS
	MOVEM T3,SIMPTR		;SAVE POINTER FOR GETTING BYTES
	MOVEM T4,SIMCNT		;SAVE COUNT OF BYTES TO SEND
	CALL MTRNCK		;MAKE SURE IS RUNNING
	 RET			;NOT IN RUN STATE, FAIL
	MOVE T4,SIMCNT		;GET COUNT
	CAILE T4,MAXDSC		;WITHIN RANGE?
	JRST [	MOVEI T1,DCNX12	;ARG TOO LARGE
		RET ]		;RETURN ERROR
	JE LLMIC,(T1),[	MOVEI T1,DCNX14 ;ANY QUOTA?
			RET ]	;NO, FAIL
	MOVEI T1,INTLEN+MSHDR	;LENGTH
	CALL GETRES		;GET SOME SPACE
	 RET			;NO SPACE, FAIL
	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 RTHDCI		;PUT ON ROUTE HEADER AND FLAGS
	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
	MOVE T4,SIMCNT		;GET COUNT
	MOVE T3,SIMPTR		;GET POINTER
	TLC T3,-1
	TLCN T3,-1
	HRLI T3,(<POINT 7,>)	;FORM DEFAULT
	MOVEM T3,SIMPTR		;SAVE UPDATED POINTER
	JRST MSTSN2		;GO SEND THEM
MSTSN1:	CALL @SIMRTN		;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 T3,SIMPTR		;RETURN UPDATED POINTER
	RETSKP			;DONE, RETURN SUCCESS
;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   REASON,,.MOCLZ
	HLRZS T2		;GET TYPE OF CLOSE
	SKIPE T2		;SYNCHRONOUS DISCONNECT?
	JRST [	CALL FLUSH	;NO, 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
	UMOVE T2,4		;GET COUNT
	UMOVE T4,3		;GET USER'S POINTER
	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 DONE
;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
	UMOVE T2,4		;GET COUNT
	UMOVE T4,3		;GET USER'S POINTER
	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
	 JRST [	TQO <BLKF>	;SCHED TEST ALREADY IN T1, NOTE BLOCK NEEDED
		RET ]		;COME BACK AGAIN LATER
	CALL SNDCTL		;SEND THE MESSAGE
	RETSKP			;AND DONE

;ROUTINE TO COPY OPTDATA TO A BUFFER AND RETURN PROPER OPTDATA
;ARG
;	T2/ INPUT BYTE COUNT
;	T3/ BUFFER ADDRESS
;	T4/ INPUT POINTER
;RETURNS:	+1 TOO LONG
;		+2 DONE

NTMVOP::ACVAR <W1,W2,W3>
	STKVAR <NMVCNT,NMVPTR>
	TLC T4,-1		;CHECK FOR SPECIAL POINTER
	TLCN T4,-1		;IS IT?
	HRLI T4,(<POINT 7,>)	;YES. CONVERT IT THEN
	MOVEM T4,NMVPTR		;SAVE POINTER TO INPUT
	MOVEM T2,NMVCNT		;SAVE COUNT OF BYTES
	MOVE W3,T3		;SAVE BUFFER ADDRESS
	SETZM T3		;ASSUME NO DATA
	MOVE T4,NMVCNT		;GET COUNT
	JUMPE T4,RSKP		;IF NONE, NO ARG
	SKIPL T4		;COUNT MUST BE POSITIVE
	CAILE T4,MAXDSC		;WITHING LIMITS
	RETBAD (DCNX12)		;NO. TOO LONG
	STOR T4,CNTFLD,W3	;BUILD RETURN ARG
	MOVE W2,[POINT 8,0(W3)]	;GET POINTER TO SOURCE
	MOVE T3,NMVPTR		;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
SUBTTL	Routines to CLose a Logical Link


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
CLZDIQ:	SETZM T2		;ASSUME SYNCHRONOUS CLOSE
	TXNE W2,CZ%ABT		;ABORT CLOSE ?
	SETOM T2		;YES, NOTE SO
	SETZM T3		;NO OPTIONAL DATA
	CALL CLZSDI		;GO SEND DI FOR CLOSE
	 JRST [	TXNE W2,CZ%ABT	;ABORT?
		JRST CLZABT	;YES. GO RELEASE BLOCK THEN
		TQO <BLKF>	;COULD NOT SEND DI, MUST TRY AGAIN LATER
		JRST SQOBAD ]	;BLOCK AND TRY AGAIN
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
;CLZSDI - ROUTINE TO SEND A DI FOR A CLOSE
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;	    T2/	0 IF SYNCHRONOUS CLOSE, -1 IF ABORT
;	    T3/	COUNT OF BYTES IN OPTIONAL DATA (0 IF NONE)
;	    T4/	ADDRESS OF OPTIONAL DATA BUFFER
;		CALL CLZSDI
;RETURNS: +1	 FAILED, COULD NOT SEND DI
;	  +2	SUCCESS, WITH DI SEND

CLZSDI::ASUBR <CDILLB,CDIFLG,CDICNT,CDIBUF>
	STKVAR <<CDIOPT,4>>

	MOVE T1,CDILLB		;GET LOGICAL LINK BLOCK ADDRESS
	MOVEI T2,LLSDIQ		;DI IS NOW QUEUED
	STOR T2,LLSTA,(T1)	;MARK STATE CHANGE
	SETZM T3		;START BY ASSUMING NO OPTIONAL DATA
	SKIPE CDICNT		;ANY OPTIONAL DATA ?
	JRST [	MOVEI T3,CDIOPT	;YES, GET DESTINATION BUFFER ADDRESS
		MOVE T2,CDICNT	;GET NUMBER OF BYTES IN OPTIONAL DATA
		MOVE T4,CDIBUF	;GET SOURCE BUFFER ADDRESS
		HRLI T4,(POINT 8,) ;AND FORM A POINTER TO OPTIONAL DATA
		CALL NTMVOP	;CHECK OPTIONAL DATA, SETUP T3 WITH COUNT
		 RETBAD ()	;FAILED, RETURN ERROR TO USER
		JRST .+1]	;T3 SET UP, CONTINUE WITH SETUP FOR DI MESSAGE
	LOAD T2,LLRSN,(T1)	;GET OUR REASON
	MOVEI T4,CNMRFL+CNMDI	;IS A DI
	CALL SNDDI		;GO SEND DI
	 JRST [	SKIPN CDIFLG	;ABORT ?
		RETBAD ()	;NO. BLOCK THEN
		TQZ <BLKF>	;YES. UNDO BLOCK
		BUG (CLZDIN)
		MOVE T1,CDILLB	;GET BACK LOGICAL LINK BLOCK ADDRESS
		RETBAD ()]	;AND DONE
	CALL SNDCTL		;SEND THE MESSAGE
CLZDQ1:	MOVEI T2,LLSDIS		;SAY DI IS SENT
	STOR T2,LLSTA,(T1)
	RETSKP			;DONE, RETURN SUCCESS
;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>
	MOVX T1,DILEN+MSHDR	;GET A BLOCK FOR THE DI
	CALL GETRES		;GET IT
	 JRST TIMWAT		;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 AND FLAGS
	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
	CALL [	SETZB T1,FILLEN(JFN) ;NO. NO BYTES THEN
		TQZ <FILINP>	;AND SAY NO GOOD DATA IN JFN BLOCK
		RET]		;DONE
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
SUBTTL	Sequential I/O JSYS's

;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
	CALL SKPFLO		;IS FLOW FROM THE FILE-SYSTEM
	 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

	CALL CLRFLO		;SWITCH FLOW TO THE NETWORK
	CALL GETBSZ		;GET BYTE SIZE FOR THIS LINK
	HLRZ T1,FILWND(JFN)	;GET WINDOW ADDRESS
	CALL MAKPTR		;GET MAX BYTES IN BUFFER
	MOVEM T1,FILBFO(JFN)	;PUT IN STARTING BYTE POINTER
	HLRZ T3,FILBCT(JFN)	;GET REMAINING COUNT
	SUBI T2,0(T3)		;COMPUTE BYTES IN THE BUFFER
	MOVE T1,FILLLB(JFN)	;get logical link block address
	CALL GETBSZ		;GO GET BYTE SIZE FOR THIS LINK
	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
	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,[CALL SETFLO	;NONE - SWITCH FLOW TO FILE-SYSTEM
		CALL GETBSZ	;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
	CALL SNDCHK		;GO SEE IF ANOTHER SEGMENT CAN BE SENT
OUTWAT:	 JRST [	TQNE <ERRF>	;ERROR?
		JRST SQOBAD	;YES. GO AWAY
		CALL MAKTST	;MAKE A STANDARD TEST WORD
		TQO <BLKF>	;REQUEST BLOCK
		CALLRET SQOBAD]	;AND FINISH UP

;CAN SEND SOME DATA

OUTRR2:	HLRZ T3,FILBCT(JFN)	;GET # OF BYTES REMAINING
	CALL GETMXS		;GO GET MAX SEGMENT 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
	CALL MAKFLG		;GO MAKE FLAGS FOR THIS MESSAGE
	MOVE T3,MBLOCK		;GET MESSAGE BLOCK ADDRESS
	MOVE T4,MSIZE		;GET MESSAGE COUNT
	CALL MAKMSG		;GO ASSEMBLE NON-DATA PARTS OF MESSAGE
	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 T4,MSIZE		;GET NO. OF DATA BYTES
	ADDI T4,2		;INCLUDE SEGNUM BYTES IN THE COUNT
	STOR T4,MSDTC,(T2);	;PUT NO. OF DATA BYTES IN THE 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
TIMWAT::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


;MAKMSG - ROUTINE TO ASSEMBLE THE NON-DATA PORTIONS OF A MESSAGE
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;	    T2/	MESSAGE FLAGS BYTE
;	    T3/	MESSAGE BLOCK ADDRESS
;	    T4/	MESSAGE SIZE
;		CALL MAKMSG
;RETURNS: +1 ALWAYS, WITH NON-DATA PORTIONS OF MESSAGE ASSEMBLED
;
; PRESERVES LOGICAL LINK BLOCK ADDRESS IN T1

MAKMSG::STKVAR <MBLOCK>
	MOVEM T3,MBLOCK		;LOCAL STORAGE FOR LL BLOCK ADDRESS
	STOR T2,MSMFL,(T3)	;SAVE MESSAGE FLAGS
	CALL RTHDCI		;PUT ON ROUTE HEADER AND FLAGS
	CALL PUTLLA		;PUT IN LL ADDRESSES
	MOVE T3,MBLOCK		;GET ADDRESS OF MESSAGE BLOCK
	MOVE T2,LLBPTR(T1)	;GET CURRENT BYTE POINTER
	MOVEM T2,MSBPTR(T3)	;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,(T3)	;SAVE SEG # IN DATA BLOCK
	CALL TWOBYT		;PUT IN SEGNUM
	ADDM T4,LLBPCT(T1)	;AND COUNT UP MESSAGE SIZE
	RET			;DONE, RETURN
;MAKFLG - ROUTINE TO MAKE THE FLAGS BYTE FOR A MESSAGE
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;	    T2/	NUMBER OF BYTES LEFT TO SEND IN SUBSEQUENT MESSAGES
;		CALL MAKFLG
;RETURNS: +1 ALWAYS, WITH T2/ MESSAGE FLAGS BYTE
;
; PRESERVES LOGICAL LINK BLOCK ADDRESS IN T1

MAKFLG::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) ;IS THIS START OF MESSAGE?
			TXO T4,DATBOM     ;YES. SET BOM THEN
			JRST MKFL10]      ;KEEP BOM

MKFL10:	OPSTR <SKIPE>,LLFEM,(T1) ;WANT EOM?
	SKIPE T2		;IS THIS LAST SEGMENT OF MESSAGE?
	JRST [	CAIN T3,2	;MESSAGE FLOW CONTROL?
		JRST MKFL30	;YES. SKIP FLOW ADJUSTMENT
		JRST MKFL20]	;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

MKFL20:	JUMPE T3,MKFL30		;IF NO FLOW CONTROL, SKIP ADJUSTMENT
	NOSKED			;PREVENT RACES
	CALL DECMSM		;ADJUST FLOW CONTROL
	OKSKED			;AND ALLOW SCHEDULING AGAIN
MKFL30:	MOVE T2,T4		;COPY MESSAGE FLAGS
	RET
;SNDCHK - ROUTINE TO SEE IF ANOTHER SEGMENT CAN BE SENT ON A LOGICAL LINK
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS
;		CALL SNDCHK
;RETURNS: +1	 FAILED, WITH T2/ ADDRESS OF SCHEDULER TEST ROUTINE
;	  +2	SUCCESS, ANOTHER SEGMENT CAN BE SENT
;

SNDCHK::JN LLBRP,(T1),[	MOVEI T2,CHKBRP ;IF FLOW CONTROL OFF, WAIT
NSBP01:			RET ]	;FAIL

	JN LLQUN,(T1),[NSBP02:	MOVEI T2,CHKSWD ;IF ANY NAK'ED SEGS
			RET ]	;FAIL

	LOAD T2,LLQOU,(T1)	;GET SEGS NOW IN THE QUEUER
	LOAD T3,LLMQO,(T1)	;GET MAX OUTPUT QUEUE LENGTH
NSBP10:	CAMLE T2,T3		;CAN WE PUT ANOTHER ONE IN?
	JRST [	MOVEI T2,CHKQTA ;WAIT FOR QUEUER COUNT TO COME DOWN
NSBP03:		RET ]		;FAIL

	LOAD T3,LLMFC,(T1)	;GET TYPE OF FLOW CONTROL
	SKIPN T3		;IF NO FLOW CONTROL, ALL SET
NSBP04:	RETSKP			;NO FLOW CONTROL
	LOAD T4,LLMSM,(T1)	;GET CURRENT FLOW COUNT
	JUMPE T4,[NSBP05:MOVEI T2,CHKSCT ;WAIT FOR SOME COUNT TO APPEAR
		  RET ]		;FAIL
	CAIE T3,2		;MESSAGE FLOW CONTROL?
	TRNN T4,200		;NO. SEGMENT. IS COUNT POSITIVE?
NSBP06:	RETSKP			;YES, CAN SEND A SEGMENT NOW.
NSBP07:	MOVEI T2,CHKSCP		;WAIT FOR COUNT TO GO POSITIVE
	RET			;RETURN SCHED TEST
;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 AND FLAGS
	CALL DOSRVS		;PUT IN LL ADDRESSES AND STANDARD 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:	STKVAR <CNFLNK>
	MOVEM T1,CNFLNK		;SAVE LINK BLOCK ADDRESS
	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 [	EXCH T1,CNFLNK		;SAVE SCHED TEST, GET LINK BLOCK ADR
		SETONE LLTRN,(T1) ;SAY STILL NEED LS
		MOVE T1,CNFLNK	;RESTORE SCHED TEST
		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 LLRCT,(T1),0(4)	;IF STILL NON-ZERO, 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
	LOAD T3,LLMQO,(T1)	;GET MAX QUEUE LENGTH
	CAMLE T2,T3		;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 SYSTEM BUFFER?
	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
;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>
	STKVAR <MSGLLB>
	MOVEM T1,MSGLLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	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
	MOVE T2,LLMSG(T1)	;GET HEADER AGAIN IN CASE IT CHANGED
	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 SEGMENT
		MOVE T1,T2	;GET SEGMENT ADDRESS
		CALL RELRES	;FREE IT UP
		MOVE T1,MSGLLB	;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
		 TQZ <BLKF>	; IGNORE ERROR
		MOVE T1,MSGLLB	;RESTORE ADDRESS
		JRST MOVSE1]	;AND PROCEED

;MESSAGE IS GOOD. PUT IT ON THE ORDERED QUEUE

	LOAD T4,LLMQI,(T1)	;GET MAXIMUM INPUT QUEUE LENGTH
	CAMLE T3,T4		;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,MSGLLB	;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,MSGLLB	;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

;ROUTINE TO SEND A NACK FOR THE LINK

MOVNAK:	STKVAR <MVNLLB>
	MOVEM T1,MVNLLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	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 [	MOVE T1,MVNLLB	;GET BACK LL BLOCK ADDRESS
		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
		AOS FILBYN(JFN)	;INDICATE WE TOOK 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 [	TQO <BLKF>	;REQUEST BLOCK
		CALLRET SQOBAD]	;AND FINISH UP
	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:	STKVAR <SQICNT>
	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:	MOVE T1,FILLLB(JFN)	;GET ADDRESS OF JFN BLOCK
	MOVE T2,FILBFI(JFN)	;GET BUFFER ADDRESS
	MOVEI T3,4000		;MAX NUMBER OF BYTES IN JFN BUFFERS
	CALL MOVMSG		;GO REMOVE MESSAGES FROM QUEUE AND PUT IN BUFFER
	 RETBAD ()		;FAILED
	MOVEM T1,FILBFI(JFN)	;STORE NEW BUFFER POINTER
	MOVEM T2,SQICNT		;SAVE COUNT OF BYTES MOVED
	MOVE T1,FILLLB(JFN)	;RESTORE LOGICAL LINK BLOCK ADDRESS
	; ..
;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 ADDRESS OF LOGICAL LINK BLOCK
	CALL SQIACK		;SEND ANY ACK'S REQUIRED
	 JRST CHKFRE		;FAILED, GO CHECK TYPE OF FAILURE
SQISN2:	MOVE T1,FILLLB(JFN)	;GET ADDRESS OF LOGICAL LINK BLOCK
	CALL SQILS		;SEND LS IF NEEDED
	 JRST [	MOVE T2,FILLLB(JFN) ;GET BACK LL BLOCK
		SKIPN LLMSG(T2)	;HAVE A MESSAGE NOW?
		JRST CHKFRE	;NO. MUST BLOCK THEN
		JRST SQI23]	;AND GO TRY AGAIN
	MOVE T1,FILLLB(JFN)	;RESTORE LOGICAL LINK BLOCK ADDRESS
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
;MOVMSG - ROUTINE TO REMOVE SEGMENTS FROM LLOMSG QUEUE AND PLACE INTO
;	  THE DESTINATION BUFFER.
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;	    T2/	BUFFER POINTER
;	    T3/	MAX # OF BYTES TO PUT INTO BUFFER
;		CALL MOVMSG
;RETURNS: +1	 FAILED
;	  +2	SUCCESS, WITH T1/ UPDATE BUFFER POINTER
;			      T2/ COUNT OF BYTES MOVED
;			      T3/ -1 IF SOME DATA WOULD NOT FIT IN BUFFER
;
; NOTE:  TRVAR'S MSGCNT AND MSGBYP ARE USED BY ROUTINES TO EXTRACT FIELDS
;	 FROM MESSAGES (E.G. GETTWO).

MOVMSG:	TRVAR <MSGCNT,MSGBYP>
	STKVAR <MVMLLB,MVMBFI,MVMCNT,MVMMAX,MVMFLG>
	MOVEM T1,MVMLLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	MOVEM T2,MVMBFI		;SAVE BUFFER ADDRESS
	MOVEM T3,MVMMAX		;SAVE MAX # OF BYTES TO BE PUT INTO BUFFER
	SETZM MVMCNT		;INITIALIZE COUNT
	SETZM MVMFLG		;ASSUME ALL DATA WILL FIT
MVM010:	CALL MOVSEG		;NO INPUT. GET ANY SEGS
	 RETBAD()		;ERROR
	SKIPN T2,LLOMSG(T1)	;GET TOPMOST SEGMENT
	JRST [	MOVE T1,MVMBFI	;RESTORE BUFFER ADDRESS
		MOVE T2,MVMCNT	;AND COUNT
		SETZM T3	;PROBLEM WAS NOT FITTING ALL DATA IN BUFFER
		RETSKP ]	;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 [	MOVE T1,MVMBFI	;RESTORE BUFFER ADDRESS
		MOVE T2,MVMCNT	;AND COUNT
		SETZM T3	;PROBLEM WAS NOT FITTING ALL DATA IN BUFFER
		RETSKP ]	;ALL DONE 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
;DESTINATION BUFFER

	MOVE T4,MSGCNT		;GET REMAINING COUNT
	ADD T4,MVMCNT		;COMPUTE BYTES TO BE IN BUFFER
	CAMLE T4,MVMMAX		;WILL THEY FIT?
	JRST [	MOVE T1,MVMBFI	;NO, RESTORE BUFFER ADDRESS
		MOVE T2,MVMCNT	;GET NUMBER OF BYTES MOVED
		SETOM T3	;NOTE NOT ALL DATA WOULD FIT
		RETSKP ]	;ALL DONE THEN
	MOVEM T4,MVMCNT		;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 [	CALL SQIWRD	;YES, GO MOVE WORDS THEN
		JRST SQIMV1 ]	;AND DONE
SQIMOV:	MOVE T3,T4		;GET COUNT
	MOVE T1,MSGBYP		;GET SOURCE POINTER
	MOVE T2,MVMBFI		;GET DESTINATION
	CALL NETMOV		;MOVE THE BYTES
	MOVEM T2,MVMBFI		;UPDATE DESTINATION POINTER
	MOVE T1,MVMLLB		;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,MVMLLB		;GET BACK LL ADDRESS
	DECR LLDMT,(T1)		;ONE LESS DATA MESSAGE
	OPSTR <SKIPN>,LLFIM,(T1) ;HAVE EOM?
	JRST MVM010		;AND TRY AGAIN
	MOVE T1,MVMBFI		;NO, GET UPDATED POINTER
	MOVE T2,MVMCNT		;AND COUNT
	SETZM T3		;NO PROBLEM FITTING ALL DATA IN BUFFER
	RETSKP			;DONE, RETURN SUCCESS
;ROUTINE TO MOVE WORDS FROM THE NETWORK TO AN INPUT BUFFER

SQIWRD:	STKVAR <<MDPTR,2>>
	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
	RET			;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:	TQO <BLKF>		;NOTE BLOCK NEEDED
	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
;SQILS - ROUTINE TO SEND ANY LS MESSAGES NEEDED AFTER INPUT HAS BEEN PROCESSED
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL SQILS
;RETURNS: +1	 FAILED TO SEND LS
;	  +2	SUCCESS

SQILS:	STKVAR <SQLLLB>
	MOVEM T1,SQLLLB		;SAVE BLOCK ADDRESS
	LOAD T2,LLLSC,(T1)	;GET SEGS TO REQUEST
	JUMPE T2,RSKP		;IF NONE, JUMP OFF
	MOVEI T3,MSDAT		;ON THE DATA CHANNEL
	SETONE LLLSA,(T1)	;TELL SCHED TRYING FOR LS SEND
	CALL SNDLS		;SEND MESSAGE
	 RET			;FAILED, RETURN FAILURE
	MOVE T1,SQLLLB		;RESTORE LINK BLOCK ADDRESS
	SETZRO <LLLSC,LLLSA>,(T1) ;CLEAR ALL LS INDICATORS
	RETSKP			;DONE, RETURN SUCCESS



;SQIACK - ROUTINE TO SEND ANY ACK'S NEEDED AFTER INPUT HAS BEEN PROCESSED
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL SQIACK
;RETURNS: +1	 FAILED, COULD NOT SEND THE ACK
;	  +2	SUCCESS

SQIACK:	STKVAR <SQALLB>
	MOVEM T1,SQALLB		;SAVE ADDRESS OF LOGICAL LINK BLOCK
	LOAD T2,LLIDN,(T1)	;GET SEG # TO ACK
	MOVEI T3,MSDAT		;ON THE DATA CHANNEL
	OPSTR <SKIPE>,LLFNN,(T1) ;NEED A NACK?
NSBP08:	TXO T2,ACKBIT		;YES.
	CALL SNDACK		;SEND IT
	 JRST [	MOVE T2,SQALLB	;FAILED, GET ADDRESS OF LOGICAL LINK BLOCK
		SETONE LLFNA,(T2) ;SAY NEED TO DO IT AGAIN
		RET ]		;RETURN FAILURE
	SETZRO <LLFNA,LLFNN>,(T1) ;CLEAR ACK FLAGS
	RETSKP			;DONE, RETURN SUCCESS
;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
	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
	STOR W1,LLMSM,(T1)	;NEW COUNT
	RET			;DONE
;NOW DEFINE STATE TRANSITION TABLES

;FOR SEQUENTIAL OUTPUT

	SWAPCD			;ALL OF THESE ARE SWAPPABLE
SQOSTA::IFIW!SQOLIS		;LISTENING - BLOCK UNTIL CONNECTED
	IFIW!SQOLIS		;CIS - SAME HERE
	IFIW!SQOCNF		;CIR - GO CONFIRM CIR
	IFIW!NETSQ1		;RUN - ALL SET TO GO
	IFIW!SQODIS		;DIS - LINK IS CLOSED. GIVE ERROR
	IFIW!SQODIS		;DIQ - SAME HERE
	IFIW!SQODIR		;DIR - SEE IF ABORT OR CLOSE
	IFIW!SQOABT		;ABORTED - 

;FOR SOUTR CALL

SQOOTR::IFIW!SQOLIS		;LISTENING - BLOCK UNTIL CONNECTED
	IFIW!SQOLIS		;CIS - BLOCK UNTIL CONNECTED
	IFIW!SQOCN2		;CIR - GO CONFIRM
	IFIW!NETSR1		;RUN - NORMAL STUFF
	IFIW!SQODIS		;DIS - LINK IS CLOSED
	IFIW!SQODIS		;DIQ - ""
	IFIW!SQODIR		;DIR - 
	IFIW!SQOABT		;ABORTED -

;FOR SEQUENTIAL INPUT

SQISTA:	IFIW!SQOLIS		;LISTENING - WAIT FOR CONNECT
	IFIW!SQOLIS		;CIS - WAIT FOR CONNECT
	IFIW!SQICNF		;CIR - CONFIRM CONNECTION
	IFIW!SQI1		;RUN - ALL SET
	IFIW!SQODIS		;DIS - GIVE ERROR
	IFIW!SQODIS		;DIQ - GIVE ERROR
	IFIW!SQIDIR		;DIR -
	IFIW!SQOABT		;ABORTED -

;TABLE FOR CC RECEIVED

CCREC:	IFIW!CCJECT		;LISTENING - CAN'T CONFIRM A LISTENER
	IFIW!CCGUD		;CIS - GOOD CC
	IFIW!CCDON		;CIR - IGNORE IT
	IFIW!CCDON		;RUN - IGNORE IT
	IFIW!CCDON		;DIS - IGNORE IT
	IFIW!CCDON		;DIQ - IGNORE IT
	IFIW!CCDON		;DIR - IGNORE IT
	IFIW!CCJECT		;ABORTED -

;TABLE FOR DI RECEIVED

DIREC:	IFIW!CCJECT		;LISTENING - ILLEGAL ADDRESS
	IFIW!CONREJ		;CIS - CONNECT BEING REJECTED
	IFIW!CCDON		;CIR - IGNORE
	IFIW!DIMSG2		;RUN - CLOSING DOWN THE LINK
	IFIW!DIABT		;DIS - ABORT IT
	IFIW!DIABT		;DIQ - ABORT IT
	IFIW!DIABT		;DIR - ABORT IT
	IFIW!DCDCS		;ABORTED - SEND DC AND IGNORE IT

;TABLE FOR DC RECEIVED

DCREC:	IFIW!CCDON		;LISTENING - IGNORE FOR LISTENER
	IFIW!CHKIDL		;CIS - CHECK FOR VALID DC
	IFIW!CCDON		;CIR - IGNORE
	IFIW!DCRUN		;RUN - SHUTTING DOWN
	IFIW!DCABT		;DIS - VALID REPLY TO DI SENT
	IFIW!DCABT		;DIQ - ABORT THE LINK
	IFIW!DCABT		;DIR - ABORT THE LINK
	IFIW!CCDON		;ABORTED - IGNORE IT

;CLOSF

CLZSTA:	IFIW!CLZDON		;LISTENING - JUST GET RID OF A LISTENER
	IFIW!CLZDON		;CIS - SAME FOR CIS
	IFIW!CLZDI		;CIR - NEED TO REFUSE CONNECTION
	IFIW!CLZRUN		;RUN - NORMAL STATE
	IFIW!CLZWDC		;DIS - WAIT FOR DC
	IFIW!CLZDIQ		;DIQ -
	IFIW!CLZDIR		;DIR -
	IFIW!CLZABT		;ABORTED - 

;ACK RECEIVED

ACKSTA:	IFIW!CCJECT		;LISTENING - 
	IFIW!ACKCIS		;CIS - 
	IFIW!CCDON		;CIR - 
	IFIW!ACKRUN		;RUN - 
	IFIW!CCDON		;DIS - 
	IFIW!CCDON		;DIQ - 
	IFIW!CCDON		;DIR - 
	IFIW!CCDON		;ABORTED - 

;DATA,INT OR LS MESSAGE

DATSTA:	IFIW!CCJECT		;LISTENING - ERROR
	IFIW!CCDON		;CIS - IGNORE
	IFIW!CCDON		;CIR - IGNORE
	IFIW!DATRUN		;RUN - GOOD MESSAGE
    REPEAT 4,<
	IFIW!CCDON>		;DIS,DIQ,DIR,ABORTED - IGNORE
SUBTTL	NSP Error Code to TOPS20 Error Code Translation

;NSPERR - ROUTINE TO CONVERT AN NSP ERROR CODE INTO A TOPS20 ERROR CODE
;
;ACCEPTS IN T1/	NSP ERROR CODE
;		CALL NSPERR
;RETURNS: +1	 FAILED, NO SUCH NSP ERROR CODE
;	  +2	SUCCESS, WITH T1/ TOPS20 ERROR CODE

NSPERR::MOVSI T4,-ERRLEN	;SET UP TO LOOP THRU ERROR TABLE

NSPER1:	HLRZ T2,ERRTAB(T4)	;GET AN NSP ERROR CODE
	CAMN T2,T1		;FOUND NSP ERROR CODE TO BE TRANSLATED ?
	JRST NSPER2		;YES, GO GET CORRESPONDING TOPS20 CODE
	AOBJN T4,NSPER1		;NO, LOOP OVER ENTIRE TABLE
	RETBAD (MONX03)		;NO SUCH NSP ERROR CODE, RETURN FAILURE

; HERE HAVING FOUND THE NSP ERROR CODE

NSPER2:	HRRZ T1,ERRTAB(T4)	;GET CORRESPONDING TOPS20 ERROR CODE
	RETSKP			;DONE, RETURN SUCCESS



; TABLE OF NSP/TOPS20 ERROR CODE CORRESPONDENCE

ERRTAB:	.DCX0,,NSPX00
	.DCX1,,NSPX01
	.DCX2,,NSPX02
	.DCX3,,NSPX03
	.DCX4,,NSPX04
	.DCX5,,NSPX05
	.DCX6,,NSPX06
	.DCX7,,NSPX07
	.DCX8,,NSPX08
	.DCX9,,NSPX09
	.DCX24,,NSPX10
	.DCX32,,NSPX11
	.DCX33,,NSPX12
	.DCX34,,NSPX13
	.DCX35,,NSPX14
	.DCX36,,NSPX15
	.DCX37,,NSPX16
	.DCX38,,NSPX17
	.DCX39,,NSPX18
	.DCX40,,NSPX19
	.DCX41,,NSPX20
	.DCX42,,NSPX21
	.DCX43,,NSPX22
ERRLEN==.-ERRTAB
SUBTTL	NSP Background Task - Main Dispatching Loop


;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:
	SKIPE MSGQ		;ANYTHING ON THE QUEUE?
	CALL DOMSGQ		;YES, GO PROCESS NSP TASK'S QUEUE
	SKIPE KDPFLG		;DOES KMC11 WANT SERVICE
	CALL KDPTSK		;YES SO CHECK IT
	CALL OUTCHK		;TIME TO SEND PREVOUSLY BLOCKED OUTPUT ?
	 CALL OUTSND		;YES, GO SEND REMAINING OUTPUT
	NOP			;NOOP FOR PERFORMANCE ANALYSIS
	CALL DOATSQ		;HANDLE THE ATS QUEUES IF THERE ARE ANY
	SKIPE NSPMCB		;ANY DEAD MCB'S TO CLEAN UP?
	CALL MCBDED		;YES - GO CLEAN THEM UP
	MOVEI T1,NSPTST		;REST UNTIL WORK TO DO
	HDISMS (^D1500)		;WAIT, BUT STAY IN BALSET
	JRST NSPTSK		;AND TRY AGAIN


;TEST ROUTINE FOR NSPTSK

	RESCD
NSPTST:	CALL CKATSQ		;CHECK THE ATS QUEUES
	 JRST 1(T4)		;NEED TO DO SOMETHING
	SKIPE KDPFLG		;DOES KMC11 WANT SERVICE
	JRST 1(4)		;YES
	CALL OUTCHK		;CHECK "RETRY BLOCKED OUTPUT" TIMER
	 JRST 1(4)		;YES, WAKE UP
	SKIPE MSGQ		;ANY MESSAGES TO DO?
	JRST 1(4)		;YES, WAKE UP
	SKIPE NSPMCB		;ANY DEAD LINES TO CLEAN UP?
	JRST 1(4)		;YES, WAKE UP
	JRST 0(4)		;NO, WAIT SOME MORE
	SWAPCD
;OUTCHK - ROUTINE TO DETERMINE IF PREVIOUSLY BLOCKED OUTPUT SHOULD BE
;	  RETRIED.
;
;CALL:		CALL OUTCHK
;RETURNS: +1	 TIME TO CHECK THE "OUTPUT REMAINING" QUEUE
;	  +2	NOT TIME TO RETRY YET

	RESCD
OUTCHK:	SKIPN OUTTIM		;ANY TIMER SET ?
	RETSKP			;NO
	SAVET
	MOVE T1,OUTTIM		;GET NEXT TIME TO WAKE UP
	CAMG T1,TODCLK		;TIMER EXPIRE ?
	RET			;YES, INDICATE SO
	RETSKP			;NO, NOTE NOT TIME YET
SUBTTL	NSP Background Task - MSGQ Processing

	SWAPCD
DOMSGQ:	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 LOCAL IN TRVAR
	OPSTR <SKIPN>,MSLCL,(T1) ;DID IT COME FROM DRIVER?
	JRST [SKIPL T3,NSPLPB	;YES, IS THERE A LOOPBACK LINE RUNNING?
	      JRST DOMSG1	;NO
	      HRRZS T3		;GET RID OF LOOPBACK FLAGS
	      LOAD T4,MSPRT,(T1);GET PORT OF MESSAGE
	      CAME T3,T4	;IS IT THE LOOPER?
	      JRST DOMSG1	;NO
	      SETONE MSLCL,(T1)	;YES, SAY LOCAL IN THE MESSAGE BLOCK
	      JRST .+1]
	SETOM MSGLCL		;SAY LOCAL IN TRVAR
DOMSG1:	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
	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 T2,MSPRT,(T1)	;GET PORT I.D.
	BUG (NSPRTH,<<T1,MSGADR>,<T2,DTE>>)
	CALL PROOFF		;TURN OFF THE INT THAT DID IT
	JRST CIDON		;AND GIVE UP
;GOT A STARTUP MESSAGE

;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,(Q1)		;GET PORT
	ADDI T3,ITSNAM(Q1)	;POINT TO NAME FOR NEIGHBOR(2 WDS / PORT)
	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 REQUESTED
	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
	CALL GTASCI		;GET IT
	 JRST BADSTR
	HRRM Q1,MCBDTE(Q1)	;SAVE PORT WE INITED ON
	LOAD T1,NAMCN,MCBDTE(Q1) ;GET LENGTH OF ITS NAME
	CAME T1,OURCNT		;SAME LENGTH AS OURS ?
	JRST STRMS6		;NAMES ARE NOT THE SAME
	MOVEI T1,(Q1)		;COPY PORT NUMBER
	ADDI T1,ITSNAM(Q1)	;POINT TO PORTS 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 FOR LOOPBACK
	CAIE Q1,(T1)		;IS THIS PORT INTENDED FOR LOOPBACK ?
	JRST BADSTR		;NOT SUPPOSED TO BE IN LOOPBACK
	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
	MOVEI T1,(Q1)		;GET PORT
	ADDI T1,ITSNAM(Q1)	;POINT TO NAME FOR NEIGHBOR(2 WDS / PORT)
	MOVX T2,.NDSON		;STATE IS ON
	SETZ T3,		;NO NEIGHBOR NODE
	CALL ADDINT		;ADD NODE TO TABLE OF KNOWN NODES
	 BUG(NSPSTR)
	JRST CIDON		;AND GO TO IT

BADSTR:	CALL PROOFF		;TURN OFF FE
	BUG (ILLSTR,<<Q1,DTE>>)
	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
;ROUTINE USED TO SHUT ALL LINKS TO AN MCB THAT HAS DIED.
;ACCEPTS:	T1/ PORT NUMBER

DEDMCB::SKIPL MCBDTE(T1)	;WAS THAT OURS
	RET			;NO
	SKIPL T1		;IS PORT NUMBER OUT OF RANGE
	CAIL T1,35
	JRST [	BUG (NSPBPN,<<T1,BADDTE>>)
		RET]
	MOVE T1,BITS(T1)	;GET THE PROPER BIT NUMBER
	IORM T1,NSPMCB		;AND SET IT. THIS WILL WAKE NSP BCKGRND TASK
	RET
;ROUTINE TO CLOSE ALL LINKS ON ALL DEAD MCB'S

MCBDED:	TRVAR <WAITER,DEDPRT,<DEDDUM,14>,MSGW1>
MCBDE1:	SKIPE T1,NSPMCB		;GET VECTOR OF DEAD MCB'S
	JFFO T1,GOTMCB		;IS THERE ANY MORE WORK
	RET			;NO - ALL DONE
GOTMCB:	MOVE T1,BITS(T2)	;CLEAR BIT WE'RE WORKING ON
	ANDCAM T1,NSPMCB	;AND SAVE
	MOVEM T2,DEDPRT		;SAVE PORT
	SETZRO <INISNT,INIRCV,REQVER>,MCBDTE(T2)
	MOVEI T1,ITSNAM(T2)	;FORM ADDRESS OF NODE NAME OF
	ADD T1,DEDPRT		;  CRASHED DN20
	HRLI T1,(POINT 7,)	;FORM POINTER TO NAME
	MOVX T2,.NDSOF		;NODE STATE IS NOW OFF
	SETZ T3,		;SHOW NO NEIGHBOR NODE
	CALL ADDINT		;REMOVE NODE FROM KNOWN NODE TABLE
	 JFCL			;FAILED, NOT IMPORTANT.
	MOVE T2,DEDPRT		;GET PORT NUMBER
	SETZM ITSNAM(T2)	;CLEAR NAME
	SETZM ITSNAM+1(T2)	; ENTRY
	MOVEI T2,.DCX39		;GET ERROR
	MOVEM T2,MSGW1		;SAVE REASON
DEDMC1:	LLLOCK			;LOCK TREE
	MOVE T1,[DEDCOR]	;COROUTINE
	SETOM T2		;ALL LINKS
	CALL OBJSRC
	 JRST [	LLLULK		;UNLOCK THE TREE
		JRST  MCBDE1]	;SEE IF ANY MORE MCB'S
	SKIPN T1,WAITER		;IS WAIT TEST IS ZERO THEN WE AREN'T DONE
	JRST DEDMC1		;YES - START AT TOP OF TREE AGAIN
	MDISMS			;NO - WAIT FOR LINK
	JRST DEDMC1		;AND PROCEED
;COROUTINE TO DO THE WORK FOR MCBDED

DEDCOR:	SAVET
	LOAD T2,LLPRT,(T1)	;GET PORT
	CAME T2,DEDPRT		;THIS ON THIS MCB?
	RET			;NO
	JN LLDED,(T1),R		;DON'T PROCESS IF ALREADY PROCESSED
	CALL BLKLOK		;YES. LOCK IT
	 JRST [	LLLULK		;CAN'T.UNLOCK TREE
		MOVEM T1,WAITER	;STORE WAIT
		RETSKP]		;AND STOP NOW
	LOAD T2,LLSTA,(T1)	;GET LINK STATE
	CAILE T2,LLSLIS		;DONE IF THIS IS A LISTENING LINK
	CALL TSTLCL		;IS IT LOCAL?
	 CALLRET BLKULK		;YES. NOT INTERESTED
	LLLULK			;UNLOCK THE TREE
	LOAD T2,LLSTA,(T1)	;GET STATE
	SETONE LLDED,(T1)	;INDICATE THIS BLOCK PROCESSED FOR DEAD MCB
	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
	SETZM WAITER		;FLAG INDICATES "CONTINUE AT TOP OF TREE"
	JN LLSDE,(T1),[	OKINT	;IF DISASSOCIATED
			CALL DELNOD ;RELEASE NODE
			RETSKP]	;NEED TO START AT TOP OF TREE
DEDMC2:	CALL BLKULK		;RELEASE BLOCK AND RETURN
	RETSKP			;NEED TO START AT TOP OF TREE
;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
	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
	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 [SETONE LLLOC,(T1)	;YES, NOTE THIS IS A LOCAL LINK
	      JRST HOSTNL]	;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
	CALL GTASCI		;GET IT
	 JRST BADUDT		;BADLY FORMED
	LOAD T3,LLPSW,(T1)	;WHERE TO PUT PASSWORD
	MOVEI T4,^D8		;MAX SIZE OF PASSWORD
	CALL GTBNRY		;GET OCTETS
	 JRST BADUDT		;BADLY FORMED
	STOR T2,LLPCT,(T1)	;SAVE COUNT
	LOAD T3,LLACT,(T1)	;GET ACCOUNT DATA
	MOVEI T4,MAXDSC
	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
	CALL GTBNRY		;GET OCTETS
	 JRST BADUDT		;BADLY FORMED
	STOR T2,LLUCT,(T1)	;SAVE COUNT
NODATA:	CALL INTTST		;GO SEE IF THIS IS CONNECTED TO AN INTERNAL LINK
DSCMV1:	CALL CONINT		;GIVE INTERRUPT
	CALL BLKULK		;RELEASE THE BLOCK
BADMSG:				;IGNORE THE MESSAGE
CIDON:	MOVE T1,MSGBLK		;GET BACK MESSAGE BLOCK
	CALL RELRES		;FREE THE BLOCK
	RET			;RETURN TO BACKGROUND TASK DISPATCHER
;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
	STKVAR <CNTLLB,CNTSTS>
	MOVEM T1,CNTLLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	JN LLINT,(T1),CONIN1	;IF INTERNAL LINK GO NOTIFY DRIVER OF CONNECT
	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

; HERE FOR INTERNAL LINKS

CONIN1:	CALL RDSTS		;GO GET LINK STATUS
	MOVEM T3,CNTSTS		;SAVE STATUS
	HRRZ T1,CNTSTS		;GET NSP ERROR CODE
	CALL NSPERR		;CONVERT TO TOPS20 ERROR CODE
	 JFCL			;USE TRANSLATION ROUTINE'S ERROR CODE
	HRR T2,T1		;GET TOPS20 ERROR CODE
	HLL T2,CNTSTS		;GET STATUS FLAGS
	MOVE T1,CNTLLB		;RESTORE LOGICAL LINK BLOCK ADDRESS
	LOAD T4,LLVEC,(T1)	;GET ADDRESS OF DRIVER FUNCTION VECTOR
	LOAD T1,LLDRV,(T1)	;GET DRIVER CORRELATION CODE
	CALL @.NSCND(T4)	;NOTIFY DRIVER OF CONNECTION
	RET			;DONE, RETURN
;INTTST - ROUTINE TO DETERMINE IF CONNECTED TO AN INTERNAL LINK
;
;ACCEPTS IN TRVARS MSGLCL/ LOCAL-FOREIGN FLAG
;		   MSGSRC/ LINK ID OF SOURCE OF CI MESSAGE
;		   MSGLLB/ LOGICAL LINK BLOCK ADDRESS OF DESTINATION LINK
;		CALL INTTST
;RETURNS: +1 ALWAYS, WITH LLCIL SET IF CONNECTED TO AN INTERNAL LINK

INTTST:	ACVAR <W1>

	SAVET			;PRESERVE LOCAL AC'S
	SKIPN MSGLCL		;LOCAL CONNECTION ?
	RET			;NO, DONE

; LOCK SOURCE LOGICAL LINK BLOCK AND SEE IF IT IS AN INTERNAL LINK

INTT10:	LLLOCK			;LOCK LOGICAL LINK TREE
	MOVE T1,MSGSRC		;GET SOURCE LINK ID
	SETOM T2		;NO SPECIAL CRITERIA
	CALL LLLKUP		;FIND THE LINK ADDRESS
	 JRST [	LLLULK		;FAILED, UNLOCK THE TREE
		RET ]		;RETURN, LINK MUST HAVE DISAPPEARED
	MOVEM T1,W1		;SAVE LOGICAL LINK BLOCK ADDRESS OF SOURCE
	CALL BLKLOK		;LOCK THE SOURCE LINK BLOCK
	 JRST [	LLLULK		;CANNOT LOCK IT, UNLOCK THE TREE
		MDISMS		;WAIT UNTIL AVAILABLE
		JRST INTT10 ]	;GO TRY TO LOCK BLOCK AGAIN
	LLLULK			;UNLOCK LOGICAL LINK TREE
	JE LLINT,(W1),INTT20	;IF SOURCE IS NOT AN INTERNAL LINK, WE ARE DONE
	MOVE T4,MSGLLB		;GET LOGICAL LINK BLOCK ADDRESS OF DESTINATION
	SETONE LLCIL,(T4)	;NOTE CONNECTED TO AN INTERNAL LINK

; HERE WHEN DONE, UNLOCK BLOCK AND RETURN

INTT20:	MOVE T1,W1		;RESTORE LOGICAL LINK BLOCK ADDRESS
	CALL BLKULK		;UNLOCK THE BLOCK
	RET			;DONE, RETURN
;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
	LLLOCK			;LOCK THE TREE
	CALL LLLKUP		;AND LOOK UP THE BLOCK
	 JRST [	LLLULK		;FREE THE TREE
		MOVEI T2,.DCX41	;NO MATCH
		JRST CIDC]	;GO DC THE LINK
	MOVEM T1,MSGLLB		;SAVE LINK BLOCK ADR
	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 [	EXCH T1,MSGLLB	;SAVE SCHED TEST, GET LINK BLOCK ADR
		CALL BLKULK	;FREE THIS BLOCK
		MOVE T1,MSGLLB	;RESTORE SCHED TEST
		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 A GOOD CC WAS RECEIVED
	LOAD T3,LLOPT,(T1)	;SEE IF ANY OPTDATA
	MOVEI T4,MAXDSC
	CALL GTBNRY
	 JRST [	JUMPE T2,CCGUD2	;IF NO OPTDATA, OK
		JRST BADUDT]	;BAD MESSAGE
	STOR T2,LLUCT,(T1)	;YES. SAVE COUNT
CCGUD2:	MOVEI T2,1		;INITIAL COUNT FOR LS/INT
	STOR T2,LLMIC,(T1)	;STASH IT
	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 [SKIPL NSPLPB	;YES, IS THERE A RUNNING LOOPBACK LINE?
	      JRST CIDCLC	;NO
	      JRST .+1]		;YES
	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:	SKIPE T4,MSGHSN		;ANY HOST NAME ?
	MOVEI T4,MSGHSN		;YES, 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
	CALL SNDDI		;BUILD THE MESSAGE
	 JRST [	TQO <BLKF>	;NOTE BLOCK NEEDED
		RET ]		;AND RETURN
	RETSKP			;DONE, RETURN SUCCESS
;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
	MOVEM T1,MSGLLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	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
	JN LLINT,(T1),[CALL SQILS ;INTERNAL LINK, TRY LS SEND AGAIN
			MOVE T1,MSGLLB	;FAILED, RESTORE LINK BLOCK ADDRESS
		       JRST CCDON]
	OPSTR <SKIPE>,LLLSA,(T1) ;WANT TO RETRY A LS SEND?
	CALL DATINR		;YES. MAKE PROCESS WAKE NOW THEN
	JRST CCDON		;AND DONE
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 LLLKUP		;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
	CALL FLUSH		;CLEAR OUT LINK'S QUEUES
	CALLRET TELDIS		;NOTIFY DRIVER IF THIS IS AN INTERNAL LINK

;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
		CALL FLUSH	;AND CLEAN UP LINK
		JRST SHUT10]	;GO NOTIFY DRIVER IF INTERNAL LINK
	SETONE LLFDI,(T1)	;YES. SAY SO
SHUT10:	CALLRET TELDIS		;NOTIFY DRIVER IF AN INTERNAL LINK



;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
;TELDIS - ROUTINE TO NOTIFY A DRIVER OF A DISCONNECT ON AN INTERNAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL TELDIS
;RETURNS: +1 ALWAYS, WITH DRIVER NOTIFIED

TELDIS:	SAVET
	STKVAR <TDSLLB,TDSSTS>
	MOVEM T1,TDSLLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	JE LLINT,(T1),R		;DONE IF NOT AN INTERNAL LINK
	JN LLSDE,(T1),R		;DONE IF LINK DISSOCIATED FROM PROCESS
	CALL RDSTS		;GO GET LINK STATUS
	MOVEM T3,TDSSTS		;SAVE STATUS
	HRRZ T1,TDSSTS		;GET NSP ERROR CODE
	CALL NSPERR		;CONVERT TO TOPS20 ERROR CODE
	 JFCL			;FAILED, USE ERROR CODE FROM TRANSLATION ROUTINE
	HRR T2,T1		;GET TOPS20 ERROR CODE
	HLL T2,TDSSTS		;GET STATUS BITS
	MOVE T1,TDSLLB		;RESTORE LOGICAL LINK BLOCK ADDRESS
	LOAD T4,LLVEC,(T1)	;GET ADDRESS OF DRIVER FUNCTION VECTOR
	LOAD T1,LLDRV,(T1)	;GET DRIVER CORRELATION CODE
	CALLRET @.NSDIS(T4)	;NOTIFY DRIVER OF DISCONNECT
;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
	LLLOCK			;LOCK THE TREE
	CALL LLLKUP		;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		;SOURCE NODE FIELD MBZ, IS IT?
	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:	JN LLINT,(T1),INTRUN	;IF THIS IS AN INTERNAL LINK, GO ASSEMBLE DATA
	CALL BLKULK		;NOT INTERNAL, FREE BLOCK
	RET			;RETURN TO BACKGROUND TASK DISPATCHER

; HERE FOR INTERNAL LINKS - ASSEMBLE DATA INTO DRIVER'S BUFFER

INTRUN:	CALL INTSET		;GO DO INPUT FOR INTERNAL LINK
	 JFCL			;FAILED, IGNORE FAILURE FOR NOW
	CALL BLKULK		;UNLOCK THE LOGICAL LINK BLOCK
	RET			;AND RETURN TO BACKGROUND TASK'S DISPATCHER
; NOT A DATA MESSAGE - MUST BE INTERRUPT OR LINK SERVICES MESSAGE

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
	 JFCL			;IGNORE BLOCK REQUEST
	MOVE T1,MSGLLB		;GET BACK LL BLOCK
	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:	JN LLINT,(T1),[	CALL INTOUT ;IF INTERNAL LINK SEND ANY OUTPUT STILL LEFT
			 JFCL	;IGNORE FAILURE HERE
			JRST .+1] ;CONTINUE
	CALL BLKULK		;FREE THE BLOCK
	JRST CIDON		;AND DONE
;INTSET - ROUTINE TO DO INPUT ON INTERNAL LINKS
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL INTSET
;RETURNS: +1	 FAILED
;	  +2	SUCCESS

INTSET::SAVET
	STKVAR <INSLLB,INSCNT,INSFLG>
	MOVEM T1,INSLLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	SETZM INSFLG		;INITIALIZE "ALL DATA FIT IN BUFFER" FLAG

; SET UP INPUT BUFFER IF NOT ALREADY SET UP, AND PUT SEGMENTS ON ORDERED QUEUE

INS010:	MOVE T1,INSLLB		;GET LOGICAL LINK BLOCK ADDRESS
	SETZRO LLFIM,(T1)	;START BY ASSUMING NOT END OF MESSAGE
	CALL MOVSEG		;PLACE SEGMENTS ON ORDERED MESSAGE QUEUE
	 RET			;FAILED, RETURN ERROR
	MOVE T1,INSLLB		;RESTORE LOGICAL LINK BLOCK
	SKIPN LLOMSG(T1)	;ANY MESSAGES TO PROCESS ?
	RETSKP			;NO, DONE.
	MOVE T1,INSLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL SETIBF		;SET UP BUFFER IF REQUIRED
	 RETSKP			;FAILED, WAIT FOR BUFFER FROM DRIVER

; IF TRUNCATING CURRENT NSP MESSAGE, DISCARD THIS SEGMENT

	MOVE T1,INSLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	JN LLTRM,(T1),[	CALL TRNMSG ;GO DISCARD THIS SEGMENT
			 RET	;FAILED
			JRST INS030] ;GO SEND ANY ACK'S OR LS MESSAGES NEEDED

; COPY DATA IN RECEIVED SEGMENTS INTO DRIVER'S BUFFER

	MOVE T1,INSLLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T2,LLBPI,(T1)	;GET CURRENT BUFFER POINTER
	LOAD T3,LLICT,(T1)	;GET MAX NUMBER OF CHARACTERS IN INPUT BUFFER
	CALL MOVMSG		;GO COPY DATA INTO DRIVER'S BUFFER
	 RET			;FAILED, RETURN ERROR
	MOVE T4,INSLLB		;RESTORE LOGICAL LINK BLOCK ADDRESS
	MOVEM T2,INSCNT		;SAVE NUMBER OF BYTES THAT WERE INPUT
	MOVEM T3,INSFLG		;SAVE FLAG NOTING WHETHER ALL DATA FIT IN BUFFER
	STOR T1,LLBPI,(T4)	;STORE NEW BUFFER POINTER
	SKIPG INSCNT		;ANY BYTES INPUT ?
	JRST INS020		;NO, DO NOT UPDATE COUNT
	LOAD T3,LLICT,(T4)	;GET PREVIOUS COUNT
	SUB T3,T2		;COMPUTE NUMBER OF BYTES LEFT IN BUFFER
	STOR T3,LLICT,(T4)	;UPDATE NUMBER OF BYTES REMAINING
	; ..
	; ..

; IF SEGMENT DID NOT FIT IN BUFFER, SEE IF DRIVER WANTED TO TRUNCATE

INS020:	MOVE T2,INSFLG		;GET FLAG INDICATING IF ALL DATA FIT IN BUFFER
	CAMN T2,[-1]		;DID LAST SEGMENT FIT IN THE BUFFER ?
	JRST [	JE LLTRC,(T4),.+1 ;NO. JUST CONTINUE IF NOT TRUNCATING MESSAGES
		SETONE LLTRM,(T4) ;REMAINDER OF THIS MESSAGE NOT NEEDED
		JRST .+1]	;AND CONTINUE

; CALL DRIVER IF EITHER BUFFER WAS FILLED OR A COMPLETE MESSAGE WAS RECEIVED

	MOVE T1,INSLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	MOVE T2,INSCNT		;GET NUMBER OF BYTES INPUT
	MOVE T3,INSFLG		;GET FLAG NOTING IF ALL DATA FIT IN BUFFER
	CALL TELDAT		;NOTIFY DRIVER THAT DATA HAS ARRIVED

; IF NO BYTES WERE INPUT, ALL DONE.  RETURN TO DISPATCHER

	SKIPN INSCNT		;WERE ANY BYTES INPUT ?
	RETSKP			;NO, ALL DONE THEN

; SEND ANY ACK MESSAGES OR LINK SERVICES MESSAGES NEEDED

INS030:	MOVE T1,INSLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	CALL SQIACK		;SEND ANY ACK'S NEEDED
	 RET			;FAILED, RETURN ERROR
	MOVE T1,INSLLB		;GET ADDRESS OF LOGICAL LINK BLOCK AGAIN
	CALL SQILS		;SEND ANY LINK SERVICES MESSAGES NEEDED
	 JFCL			;IGNORE FAILURE, ACK'S WILL CAUSE RETRY
	JRST INS010		;GO SEE IF THERE ARE MORE MESSAGES TO PROCESS
;TELDAT - ROUTINE TO ADVISE THE DRIVER IF A COMPLETE MESSAGE HAS ARRIVED
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;	    T2/	NUMBER OF BYTES INPUT, -1 IF NOT ENOUGH ROOM IN BUFFER
;		CALL TELDAT
;RETURNS: +1 ALWAYS, WITH DRIVER NOTIFIED IF NEEDED

TELDAT:	STKVAR <TLDLLB,TLDCNT,TLDFLG>
	MOVEM T1,TLDLLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	MOVEM T2,TLDCNT		;SAVE COUNT OF BYTES INPUT
	MOVEM T3,TLDFLG		;SAVE FLAG NOTING IF ALL DATA FIT IN BUFFER

; DETERMINE IF DRIVER MUST BE NOTIFIED

	MOVE T4,TLDLLB		;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T3,LLICT,(T4)	;GET # OF BYTES LEFT IN BUFFER
	JUMPE T3,TLDT10		;IF NONE, BETTER TELL DRIVER !
	MOVE T2,TLDFLG		;GET FLAG
	CAME T2,[-1]		;INSUFFICIENT ROOM IN BUFFER FOR THIS MSG ?
	JRST [	JE LLFIM,(T1),R	;NO, RETURN UNLESS A COMPLETE MESSAGE RECEIVED
		JRST TLDT10 ]	;...

; COMPUTE NUMBER OF BYTES IN BUFFER AND NOTIFY DRIVER OF DATA ARRIVAL

TLDT10:	LOAD T4,LLVEC,(T1)	;GET ADDRESS OF DRIVER FUNCTION VECTOR
	LOAD T3,LLIIC,(T1)	;YES, GET INITIAL COUNT OF BYTES IN BUFFER
	LOAD T2,LLICT,(T1)	;GET CURRENT COUNT OF BYTES LEFT FOR INPUT
	SUB T3,T2		;COMPUTE NUMBER OF BYTES ALREADY INPUT
	JN LLFIM,(T1),[TXO T3,NS%MSG ;BUFFER BEING RETURNED BECAUSE EOM SEEN
		       JRST .+1] ;...
	LOAD T2,LLBFI,(T1)	;GET ADDRESS OF DRIVER'S BUFFER
	LOAD T1,LLDRV,(T1)	;GET DRIVER CORRELATION CODE
	CALL @.NSDAT(T4)	;ADVISE DRIVER THAT INPUT HAS ARRIVED
	MOVE T4,TLDLLB		;RESTORE LOGICAL LINK BLOCK ADDRESS
	JUMPN T1,[JN LLFIM,(T4),.+1	;ONLY SET TRUNCATE IF NOT FULL MSG
		  SETONE LLTRM,(T4) ;NOTE TRUNCATION IF DRIVER REQUESTED IT
		  JRST .+1]	;...

; UPDATE APPROPRIATE COUNTS AND RETURN

	MOVE T1,TLDLLB		;RESTORE LOGICAL LINK BLOCK ADDRESS
	SETZRO <LLICT,LLIIC>,(T1) ;CLEAR BYTE COUNTS
	SETZRO LLBFI,(T1)	;NOTE WE NO LONGER HAVE AN INPUT BUFFER
	RET			;DONE, RETURN
;TRNMSG - ROUTINE TO DISCARD A SEGMENT BECAUSE MESSAGE IS BEING TRUNCATED
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL TRNMSG
;RETURNS: +1	 FAILED
;	  +2	SUCCESS, SEGMENT THROWN AWAY

TRNMSG:	STKVAR <TMSLLB>
	MOVEM T1,TMSLLB		;SAVE LOGICAL LINK BLOCK ADDRESS

TRNM10:	MOVE T1,TMSLLB		;GET LOGICAL LINK BLOCK ADDRESS
	MOVE T2,[POINT 0,0,2]	;GET NUL POINTER (THROW BYTES AWAY)
	MOVX T3,.INFIN		;NO LIMIT ON NUMBER TO DISCARD
	CALL MOVMSG		;DISCARD THE DATA
	 RET			;FAILED
	MOVE T1,TMSLLB		;RESTORE LOGICAL LINK BLOCK ADDRESS
	JE LLFIM,(T1),RSKP	;IF STILL DON'T HAVE ENTIRE MESSAGE THEN DONE
	SETZRO LLTRM,(T1)	;MESSAGE ENTIRELY DISCARDED, STOP TRUNCATING
	RETSKP			;DONE, RETURN SUCCESS
;SETIBF - ROUTINE TO SET UP AN INPUT BUFFER FOR AN INTERNAL LINK
;
;ACCEPTS IN T1/	LOGICAL LINK BLOCK ADDRESS (LINK ASSUMED LOCKED)
;		CALL SETIBF
;RETURNS: +1	 FAILED, COULD NOT SET UP BUFFER NOW
;	  +2	SUCCESS, WITH BUFFER INFO STORED IN LINK BLOCK

SETIBF:	JN LLBFI,(T1),RSKP	;IF ALREADY HAVE A BUFFER THEN DONE
	JN LLDRB,(T1),R		;FAIL IFDRIVER ALREADY REFUSED TO PROVIDE BFR
	ASUBR <SBFLLB>
	LOAD T4,LLVEC,(T1)	;GET DRIVER FUNCTION VECTOR ADDRESS
	LOAD T1,LLDRV,(T1)	;GET DRIVER CORRELATION CODE FOR THIS LINK
	CALL @.NSBFR(T4)	;REQUEST DRIVER TO SUPPLY A BUFFER
	 JRST [	MOVE T1,SBFLLB	;RESTORE LOGICAL LINK BLOCK ADDRESS
		SETONE LLDRB,(T1) ;NOTE THAT DRIVER REFUSED TO PROVIDE BUFFER
		RET ]		;AND DONE
	MOVE T4,SBFLLB		;RESTORE LOGICAL LINK BLOCK ADDRESS
	STOR T1,LLBFI,(T4)	;STORE BUFFER ADDRESS
	STOR T2,LLICT,(T4)	;STORE COUNT OF BYTES CURRENTLY LEFT IN BUFFER
	STOR T2,LLIIC,(T4)	;ALSO STORE AS INITIAL COUNT OF BYTES IN BUFFER
	HRLI T1,(POINT 8,)	;FORM POINTER TO FIRST BYTE IN THIS BUFFER
	STOR T1,LLBPI,(T4)	;SAVE AS POINTER TO NEXT BYTE TO BE INPUT
	TXNE T2,NS%TRN		;DRIVER WANT MESSAGES TRUNCATED IF TOO LONG ?
	JRST [	SETONE LLTRC,(T4) ;YES, NOTE TRUNCATION DESIRED
		JRST .+1 ]	;AND CONTINUE
	RETSKP			;DONE, RETURN WITH BUFFER INFO IN LINK BLOCK
;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 [	TQO <BLKF>		;NOTE BLOCK NEEDED
		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
;			T1/ SCHEDULER TEST WORD
;		+2 SUCCESS. MESSAGES SENT
;			T1/ LL BLOCK ADDRESS (UNCHANGED)

TURNON:	JE LLOPI,(T1),RSKP	;IF NOT OPEN FOR READ, DON'T SEND LS
	MOVEI T3,MSDAT		;ON THE DATA SUBCHANNEL
	LOAD T2,LLMQI,(T1)	;GET MAX QUEUE VALUE
	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::	JN LLLOC,(T1),R		;RETURN IF LOCAL
	RETSKP			;SKIP RETURN IF NOT LOCAL
;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 COUNT 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 COUNT WORD
		RET]		;DONE
	CAMLE T2,T4		;WITHIN RANGE?
	RET			;NO.
	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:	CALL GETBYT		;GET IMAGE COUNT
	 RET			;BADLY FORMED
	JUMPE T2,RSKP		;IF NO BYTES, DONE
	MOVN T4,T2		;GET NEG OF COUNT
	ADDB T4,MSGCNT		;COMPUTE RESIDUE
	JUMPL T4,R		;IF MESSAGE TOO SMALL, ERROR
	ADJBP T2,MSGBYP		;MODIFY BYTE POINTER
	MOVEM T2,MSGBYP		;AND UPDATE IT
	RETSKP			;DONE

;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 CIPSR1		;NO, CHECK FOR SEGMENT SIZE ADJUSTMENT
	MOVEM T2,MSGW2		;SAVE IT
	RETSKP			;ALL GOOD

CIPSR1:	SAVEAC (T3)		;PRESERVE T3
	MOVE T3,MSGBLK		;GET ADDRESS OF MESSAGE BLOCK
	LOAD T3,MSMFL,(T3)	;GET MESSAGE FLAGS
	CAIN T3,CIMMFL		;IS IT A CI?
	RET			;YES, NOTHING TO DO
	CAIG T2,SEGSIZ		;NO, A CC - THEIR SEG SIZE BIGGER THAN OURS?
	RET			;NO, USE THEIR'S
	MOVEI T2, SEGSIZ	;YES, USE OURS
	RET			;DONE
;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
SNDSG0:	LOAD T1,LLPRT,(T1)	;GET PORT I.D.
;	HRLI T1,MSGPST		;POSTING ADDRESS
	HRLI T1,RELRES		;MAKE DRIVER 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
	SKIPGE T4,NSPLPB	;IS THERE A RUNNING LOOPBACK LINE?
	JRST [STOR T4,LLPRT,(T1);YES, SAY WHICH PORT
	      JRST SNDSG0]	;GIVE "LOCAL MESSAGE" TO DRIVER FOR LOOPBACK
	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.
LPBSEG:	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
	SKIPGE T4,NSPLPB	;IS THERE A RUNNING LOOPBACK LINE?
	JRST [STOR T4,LLPRT,(T1);YES, SAY WHICH PORT
	      JRST LPBSEG]	;GIVE "LOCAL MESSAGE" TO DRIVER FOR LOOPING
	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 [	LLLULK		;RELEASE THE TREE
		JRST SNDBAD ]	;NOT THERE
	LLLULK			;RELEASE THE TREE
	MOVE T2,SNMSG		;GET MESSAGE BLOCK
	NOSKED			;PROTECT LINK STATE
	JN LLINT,(T1),SNDBA1	;IF INTERNAL LINK, PUT ON BACKGOUND TASK'S QUEUE
	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
	LOAD T4,LLMQI,(T1)	;GET MAXIMUM INPUT QUEUE LENGTH
	CAMLE T3,T4		;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?
	 JRST [SKIPL NSPLPB	;YES, IS THERE A RUNNING LOOPBACK LINE?
	       JRST ACKDON	;NO
	       JRST .+1]	;YES, MESSAGE MUST BE QUEUED AS REMOTE
	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 SUBCHANLEL?
	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:	JN LLINT,(T1),[	CALL INTOUT ;IF INTERNAL LINK SEND ANY OUTPUT STILL LEFT
			 JFCL	;IGNORE FAILURE HERE
			JRST .+1] ;CONTINUE
	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?
	RET			;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
	RET			;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>
NSBP09:	CALL TSTLCL		;SEE IF A LOCAL CONNECTION
	 JRST [	SKIPGE NSPLPB	;YES, IS THERE A RUNNING LOOPBACK LINE?
	        JRST ACKRMT	;YES, GIVE MESSAGE TO DRIVER
	        JE LLCIL,(T1),RSKP ;NO, DONE IF NOT CONNECTED TO INTERNAL LINK
		CALL SKDOUT	;INTERNAL LINK, SCHEDULE OUTPUT
		RETSKP ]	;DONE, RETURN
	JRST ACKRMT		;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 TIMWAT		;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 AND FLAGS
	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 LOCAL 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,SEGSIZ		;OUR SEG SIZE
	CALL TWOBYT
	MOVEI T2,SEGSIZ		;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
	CALL ONEBYT
;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 TO SEND AN LS MESSAGE

;ACCEPTS:
;	T1/ LL BLOCK ADDRESS
;	T2/ COUNT OF SEGS TO REQUEST
;	T3/ SUBCHANNEL

;	CALL SNDLS

;RETURNS +1: FAILURE
;		T1/ SCHEDULER TEST WORD
;	 +2: SUCCESS
;		T1/ LL BLOCK ADDRESS (UNCHANGED)

SNDLS:	ASUBR <SNDLBL,SNDLCT,SNDLTP,SNDLMS>
	CALL TSTLCL		;LOCAL?
	 JRST [SKIPL NSPLPB	;YES, IS THERE A RUNNING LOOPBACK LINE?
	       JRST SNDLSL	;NO
	       JRST .+1]	;YES, MESSAGE MUST GO TO DRIVER
	LOAD T2,LLQOU,(T1)	;GET SEGS IN QUEUER
	LOAD T3,LLMQO,(T1)	;GET MAXIMUM OUTPUT QUEUE LENGTH
	CAILE T2,1(T3)		;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 TIMWAT		;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 RTHDCI		;PUT ON ROUTE HEADER AND FLAGS
	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
	JE LLINT,(T1),RSKP	;SENDER OF LS CONNECTED TO AN INTERNAL LINK ?
	CALL SKDOUT		;YES, NOTE CAN SEND MORE NOW
	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
SUBTTL	NSP Background Task - Output on Internal Links

;OUTSND - ROUTINE TO CHECK "OUTPUT REMAINING" QUEUE AND SEND ANY REMAINING DATA
;
;	  CALLED PERIODICALLY FROM NSP BACKGROUND TASK DISPATCHER (NSPTSK)

	SWAPCD
OUTSND:	SAVEPQ
	SETZM OUTTIM		;RESET TIME AT WHICH TASK SHOULD AWAKEN
	LOCK OUTLOK		;LOCK THE QUEUE WHILE PROCESSING ENTRIES
	HRRZ Q1,OUTQUE		;GET ADR OF FIRST LINK BLOCK TO PROCESS
	MOVEI Q2,0		;INITIALIZE "PREVIOUS BLOCK" ADDRESS

; LOCK THE LOGICAL LINK BLOCK AND SEND REMAINING OUTPUT

OUTCK0:	JUMPE Q1,[UNLOCK OUTLOK	;IF END OF QUEUE, UNLOCK THE QUEUE
		  RET]		; AND RETURN
	MOVE T1,Q1		;GET ADR OF CURRENT LOGICAL LINK BLOCK
	CALL BLKLOK		;GO LOCK THE LOGICAL LINK
	 JRST [	CALL SKDOUT	;FAILED, SCHEDULE OUTPUT FOR LATER
		MOVE Q2,Q1	;MAKE PREVIOUS BLOCK THE CURRENT
		LOAD Q1,LLOUT,(Q1) ;MAKE CURRENT BLOCK THE NEXT ONE
		JRST OUTCK0 ]	;GO DO OUTPUT FOR NEXT LOGICAL LINK
	MOVE T1,Q1		;GET ADR OF CURRENT LOGICAL LINK BLOCK
	CALL INTOUT		;DO REMAINING OUTPUT FOR THIS LINK
	 JRST [	CALL SKDOUT	;FAILED, SCHEDULE OUTPUT FOR LATER
		JRST OUTCK1 ]	;GO DO OUTPUT FOR NEXT LOGICAL LINK
	JN LLOCT,(Q1),[	CALL SKDOUT  ;IF MORE OUTPUT, SCHEDULE FOR LATER
			JRST OUTCK1] ;GO HANDLE NEXT BLOCK ON QUEUE

; ALL REMAINING OUTPUT SENT, REMOVE THE BLOCK FROM THE QUEUE

	SETZRO LLQUE,(Q1)	;NOTE BLOCK NO LONGER ON QUEUE
	HLRZ T4,OUTQUE		;GET POINTER TO TAIL OF QUEUE
	CAMN T4,Q1		;PROCESSING TAIL OF QUEUE ?
	HRLM Q2,OUTQUE		;YES, SAVE PREVIOUS BLOCK AS NEW TAIL
	LOAD T4,LLOUT,(Q1)	;GET ADDRESS OF NEXT BLOCK ON QUEUE
	SETZRO LLOUT,(Q1)	;CLEAR ADR OF NEXT BLOCK ON QUEUE
	SKIPN Q2		;PROCESSING HEAD OF QUEUE ?
	JRST [	HRRM T4,OUTQUE	;YES, SAVE NEXT BLOCK AS NEW HEAD
		JRST OUTCK1 ]	; AND GO DO OUTPUT FOR NEXT LOGICAL LINK
	STOR T4,LLOUT,(Q2)	;NO, SAVE ADR OF NEXT BLOCK IN PREVIOUS

OUTCK1:	MOVE Q2,Q1		;MAKE CURRENT BLOCK THE PREVIOUS
	MOVE T1,Q1		;GET ADDRESS OF CURRENT LINK BLOCK
	LOAD Q1,LLOUT,(T1)	;GET ADDRESS OF NEXT BLOCK ON QUEUE
	CALL BLKULK		;UNLOCK THE CURRENT BLOCK
	JRST OUTCK0		;GO PROCESS NEXT BLOCK ON QUEUE
;SKDOUT - ROUTINE TO SCHEDULE OUTPUT FOR AN INTERNAL LINK
;
;CALL:		CALL SKDOUT
;RETURNS: +1 ALWAYS, WITH ALL AC'S PRESERVED

SKDOUT::SAVET
	MOVE T4,TODCLK		;GET CURRENT TIME
	ADD T4,OUTIVL		;GET TIME INTERVAL TO WAIT BEFORE TRYING AGAIN
	MOVEM T4,OUTTIM		;SCHEDULE WAKEUP AT LATER TIME
	RET			;DONE, RETURN
;INTOUT - ROUTINE TO PERFORM OUTPUT FOR AN INTERNAL LINK
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL INTOUT
;RETURNS: +1	 FAILED, MORE OUTPUT WILL HAVE TO BE DONE LATER
;	  +2	SUCCESS, ALL REMAINING OUTPUT HAS BEEN SENT
;
; ASSUMES LOGICAL LINK BLOCK IS LOCKED. PRESERVES LINK BLOCK ADR IN T1

INTOUT:	ASUBR <INOLLB>

; PROCESS ANY OUTSTANDING ACK'S FOR THIS LINK

	MOVE T1,INOLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL MOVSEG		;PROCESS OUTSTANDING ACK'S
	 RET			;FAILED, TRY AGAIN LATER
	MOVE T1,INOLLB		;GET LOGICAL LINK BLOCK ADDRESS
	JE LLOCT,(T1),RSKP	;IF NO DATA LEFT, ALL DONE

; CHECK TO SEE IF THERE IS ANY MORE OUTPUT TO SEND

INO020:	MOVE T1,INOLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	JN LLOCT,(T1),INO025	;IF DATA LEFT, GO TRY TO SEND IT
	MOVE T1,INOLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL TELOBE		;GO TELL DRIVER THAT OUTPUT BUFFER NOW EMPTY
	MOVE T1,INOLLB		;GET ADDRESS OF LOGICAL LINK BLOCK
	CALL TELOOK		;GO ADVISE DRIVER OUTPUT CAN BE DONE
	MOVE T1,INOLLB		;RESTORE LOGICAL LINK BLOCK ADDRESS
	RETSKP			;DONE, RETURN

;CHECK TO SEE IF ANY SEGMENTS CAN BE SENT NOW

INO025:	MOVE T1,INOLLB		;GET LOGICAL LINK BLOCK ADDRESS
	CALL SNDCHK		;CAN ANY SEGMENTS BE SENT ?
	 RET			;NO, TRY AGAIN LATER
	MOVE T1,INOLLB		;YES, GET LOGICAL LINK BLOCK ADDRESS
	CALL OUTSEG		;SEND THE SEGMENT
	 RET			;FAILED, TRY AGAIN LATER
	JRST INO020		;CHECK TO SEE IF ANOTHER SEGMENT CAN BE SENT
;TELOOK - ROUTINE TO CHECK TO SEE IF NECESSARY TO NOTIFY DRIVER THAT
;	  OUTPUT MAY NOW BE SENT
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL TELOOK
;RETURNS: +1 ALWAYS, DRIVER NOTIFIED THRU FUNCTION VECTOR IF NEEDED

TELOOK:	JE LLNDO,(T1),R		;RETURN IF DRIVER DOES NOT NEED NOTIFICATION
	SETZRO LLNDO,(T1)	;NO LONGER NEED NOTIFICATION FLAG LIT
	LOAD T4,LLVEC,(T1)	;GET DRIVER FUNCTION VECTOR ADDRESS
	MOVX T2,.NSOMO		;GET "OUTPUT CAN BE SENT" TYPE CODE
	LOAD T1,LLDRV,(T1)	;GET DRIVER'S CORRELATION CODE
	CALLRET @.NSOOK(T4)	;NOTIFY DRIVER AND RETURN



;TELOBE - ROUTINE TO NOTIFY THE DRIVER THAT AN OUTPUT BUFFER IS NOW EMPTY
;
;ACCEPTS IN T1/	ADDRESS OF LOGICAL LINK BLOCK
;		CALL TELOBE
;RETURNS: +1 ALWAYS, WITH DRIVER NOTIFIED THRU ITS FUNCTION VECTOR

TELOBE::ASUBR <OBELLB>
	LOAD T4,LLVEC,(T1)	;DATA SENT, GET DRIVER FCN VECTOR ADR
	LOAD T2,LLBFO,(T1)	;GET DRIVER'S BUFFER ADDRESS
	LOAD T1,LLDRV,(T1)	;GET DRIVER CORRELATION CODE
	CALL @.NSOBE(T4)	;TELL DRIVER IT CAN HAVE BUFFER BACK
	MOVE T1,OBELLB		;GET LOGICAL LINK BLOCK ADDRESS
	SETZRO LLBFO,(T1)	;NOTE THAT BUFFER IS NOW GONE
	RET			;DONE, RETURN.
SUBTTL	Scheduler Interface

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

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

; MESSAGE PARSED - PLACE MESSAGE ON APPROPRIATE QUEUE FOR LATER HANDLING

	MOVE T1,MSGDST		;GET OUR NAME
	MOVE T2,MSGSRC		;GET ITS NAME
	CALL LLLKUP		;FIND THE LINK
	 JRST NSPMSE		;COULDN'T.
	JN LLINT,(T1),NSPMSE	;IF INTERNAL LINK, PUT MESSAGE ON TASKS'S QUEUE
	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	The 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,NDTLEN		; 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 NDSLN		;(0) SET LOCAL NODE NAME
	EXP NDGLN		;(1) GET LOCAL NODE NAME
	EXP NDSNM		;(2) SET LOCAL NODE NUMBER
	EXP NDGNM		;(3) GET LOCAL NODE NUMBER
	EXP NDSLP		;(4) SET LOOPBACK PORT
	EXP NDCLP		;(5) CLEAR LOOPBACK PORT
	EXP NDFLP		;(6) FIND LOOPBACK PORT
	EXP NDSNT		;(7) SET NETWORK TOPOLOGY INFO
	EXP NDGNT		;(10) GET NETWORK TOPOLOGY INFO
	EXP NDSIC		;(11) SET ITERRUPT CHANNEL FOR TOPOLOGY CHANGE
	EXP NDCIC		;(12) CLEAR ITERRUPT CHANNEL FOR TOPOLOGY CHANGE
	EXP NDGVR		;(13) GET NSP VERSION INFORMATION
	EXP NDGLI		;(14) GET LINE INFORMATION
	EXP NDVFY		;(15) VERIFY NODE NAME


NDTLEN==.-NODTAB
;NDSLN - ROUTINE TO SET THE LOCAL NODE NAME

NDSLN:	STKVAR <<NODNAM,WPN>>
	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
	MOVEI T2,NODNAM		;WE'LL WRITE PARSED NAME TO "NODNAM"
	CALL PARNDU		;MAKE SURE NODE NAME IS KOSHER
	 RETBAD			;FAILED, TELL CALLER WHY
	MOVEM B,OURCNT		;REMEMBER LENGTH OF NAME
	DMOVE T1,NODNAM		;GET NODE NAME *** DMOVE IS CHEATING BECAUSE IT ASSUMES WPN=2!
	DMOVEM T1,OURNAM	;STORE FOR NSP
	RETSKP			;SUCCESS RETURN
;NDGLN - RETURN LOCAL NODE NAME

NDGLN:	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

NDSNM:	UMOVE T2,2
	UMOVE T2,0(T2)		;GET NUMBER
	CAIL T2,2
	CAILE T2,177		;WITHIN RANGE?
	RETBAD()		;NO
	MOVEM T2,OURNUM		;SET IT
	RETSKP			;DONE

;GET LOCAL NODE NUMBER

NDGNM:	UMOVE T2,2
	MOVE T3,OURNUM
	UMOVEM T3,0(T2)		;STORE NUMBER
	RETSKP			;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
; SET NETWORK TOPOLOGY INFO

NDSNT:	STKVAR <<SNTBLK,MAXNOD>,SNTCNT>

; CHECK CAPABILITIES

	MOVE T1,CAPENB		;GET CURRENTLY ENABLED CAPABILITIES
	TXNN T1,SC%WHL!SC%OPR	;WHEEL, OPERATOR CAPABILITY REQUIRED
	RETBAD (CAPX1)		;WHEEL OR OPERATOR capability required

; CHECK NUMBER OF ITEMS TO BE ENTERED AND COPY POINTERS TO NODE BLOCKS

	UMOVE T2,2		;GET ADDRESS OF USER'S ARGUMENT BLOCK
	UMOVE T1,.NDCNT(T2)	;GET NUMBER OF ITEMS SUPPLIED IN NODE BLOCKS
	CAIGE T1,.NDNXT+1	;AT LEAST NAME, STATE, AND NEIGHBOR REQUIRED
	RETBAD (ARGX17)		;FAIL, NODE BLOCKS TOO SMALL
	UMOVE T1,.NDNND(T2)	;GET NUMBER OF NODES TO BE ENTERED
	CAIL T1,0		;WITHIN VALID
	CAILE T1,MAXNOD		; RANGE ?
	RETBAD (ARGX17)		;NO, INVALID ARGUMENT BLOCK LENGTH
	MOVEM T1,SNTCNT		;SAVE NUMBER OF NODES TO BE ADDED
	ADDI T2,.NDBK1		;POINT TO FIRST WORD TO BE MOVED
	MOVEI T3,SNTBLK		;GET ADDRESS OF BLOCK TO HOLD POINTERS
	CALL BLTUM1		;COPY POINTERS TO NODE BLOCKS

; LOOP, ADDING EACH NODE TO THE TABLE OF KNOWN NODES

	XMOVEI Q1,SNTBLK	;GET ADDRESS OF BLOCK OF POINTERS
	MOVE Q2,Q1		;COPY STARTING ADDRESS  OF BLOCK
	ADD Q1,SNTCNT		;COMPUTE FIRST ADR PAST END OF BLOCK
NDSN10:	CAML Q2,Q1		;ANOTHER NODE TO ADD ?
	RETSKP			;NO, DONE
	MOVE T1,(Q2)		;GET POINTER TO NODE BLOCK IN USER SPACE
	CALL INSNOD		;INSERT NODE IN TABLE OF KNOWN NODES
	 RETBAD ()		;FAILED
	ADDI Q2,1		;POINT TO NEXT ITEM IN ARG BLOCK
	JRST NDSN10		;LOOP OVER ALL ENTRIES IN TABLE
; SET INTERRUPT CHANNEL FOR NETWORK TOPOLOGY CHANGE
NDSIC:	UMOVE T3,T2		;GET USER BLOCK ADDRESS
	XCTU [ MOVEI T1,.NDCHN(T3)]	;POINT TO CHANNEL NUMBER WORD
	UMOVE T1,(T1)		;GET THE CHANNEL NUMBER
	SKIPGE T1		;VALIDATE CHANNEL NUMBER
	RETBAD (ARGX13)		;NEGATIVE CHANNEL NUMBERS ARE ILLEGAL
	CAILE T1,^D35		;CHANNEL NUMBER TOO HIGH
	RETBAD (ARGX13)		;NEGATIVE CHANNEL NUMBERS ARE ILLEGAL
	CAIL T1,.ICAOV		;SKIP IF GOOD NUMBER
	CAILE T1,.ICNXP		;SKIP IF BAD NUMBER
	JRST CHANOK		;CHANNEL NUMBER OK.
	RETBAD (ARGX13)		;BAD CHANNEL NUMBER

CHANOK:	SETZ T4,		;T4 WILL HOLD ADDRESS OF FREE ENTRY
	MOVEI T2,NTCTAB		;POINT TO TOP OF TABLE OF WAITING FORKS

;HERE TO DETERMINE IF FORK ALREADY HAS SET THE INTERRUPT ONCE

CHNOK1:	SKIPN (T2)		;SKIP IF ENTRY IS BEING USED
	 JRST [	MOVE T4,T2	;SAVE FOR FORK NOT CURRENTLY ACTIVATED
		JRST CHNOK2]	;TRY NEXT ENTRY
	LOAD T3,NTCFRK,(T2)	;GET THE FORK NUMBER
	CAMN T3,FORKX		;DOES THIS ENTRY BELONG TO THIS FORK
	JRST [	STOR T1,NTCCHN,(T2)	;YES. PUT NEW CHANNEL NUMBER IN
		RETSKP]
CHNOK2:	CAIE T2,NTCTAB+<NTCMAX-1>	;HAVE WE LOOKED AT WHOLE TABLE
	AOJA T2,CHNOK1		;NO - KEEP LOOKING
	SKIPN T4		;DID WE FIND AN ENTRY?
	RETBAD (MONX01)		;SHOW WE HAVE NO MORE ROOM
	STOR T1,NTCCHN,(T4)	;SAVE THE CHANNEL NUMBER
	MOVE T1,FORKX		;NOW GET THE FORK NUMBER
	STOR T1,NTCFRK,(T4)	;AND SAVE
	SETONE FKNTC,(T1)	;FLAG IN FORK DATA BASE
	RETSKP

;NDCIC - CLEAR INTERRUPT CHANNEL FOR NETWORK TOPOLOGY CHANGE

NDCIC:
NTCOFF::MOVEI T1,NTCTAB		;FIND THE FORK'S ENTRY
NDCIC1:	LOAD T2,NTCFRK,(T1)	;GET THE FORK NUMBER FOR THIS ENTRY
	CAMN T2,FORKX		;THIS FORKS ENTRY
	JRST [	SETZM (T1)	;CLEAR ENTRY
		MOVE T1,FORKX	;GET FORK INDEX
		SETZRO FKNTC,(T1)	;CLEAR THE ITEM IN FORK DATA BASE
		RETSKP]
	CAIE T1,NTCTAB+<NTCMAX-1>	;AT END OF TABLE
	AOJA T1,NDCIC1		;NO - KEEP LOOKING
	RETSKP			;INDICATE SUCCESS EVEN WHEN NEVER SET
;NDGVR - GET NSP VERSION INVORMATION

NDGVR:	UMOVE T3,T2		;GET THE USER BLOCK POINTER
	MOVX T2,2		;GET NUMBER OF VERSIONS TO RETURN
	UMOVEM T2,.NDNVR(T3)	;STORE IN USER ARGUMENT BLOCK
	UMOVE T1,.NDCVR(T3)	;GET THE ADDRESS OF THE COMMUNICATION BLOCK
	MOVEI T2,COMVER		;COMMUNICATION VERSION NUMBER
	UMOVEM T2,.NDVER(T1)	;SAVE IN USER SPACE
	MOVEI T2,COMECO		;COMMUNICATION ECO
	UMOVEM T2,.NDECO(T1)	;SAVE IN USER SPACE
	MOVEI T2,COMCST		;GET THE CUSTOMER CHANGE NUMBER
	UMOVEM T2,.NDCST(T1)	;SAVE IN USER SPACE

;NOW GIVE USER THE ROUTING VERSION INFORMATION

	UMOVE T1,.NDRVR(T3)	;GET THE ADDRESS OF THE ROUTING BLOCK
	MOVEI T2,ROUVER		;ROUTING VERSION NUMBER
	UMOVEM T2,.NDVER(T1)	;SAVE IN USER SPACE
	MOVEI T2,ROUECO		;ROUTING ECO
	UMOVEM T2,.NDECO(T1)	;SAVE IN USER SPACE
	MOVEI T2,ROUCST		;GET THE CUSTOMER CHANGE NUMBER
	UMOVEM T2,.NDCST(T1)	;SAVE IN USER SPACE
	RETSKP			;RETURN
;INSNOD - ROUTINE TO INSERT NODE INTO TABLE OF KNOWN NODES
;
;ACCEPTS IN T1/	ADDRESS OF NODE BLOCK IN USER SPACE
;		CALL INSNOD
;RETURNS: +1	 FAILED
;	  +2	SUCCESS, NODE ADDED IF NOT ALREADY IN TABLE

INSNOD:	ASUBR <INDBLK,INDSTA,INDADR,INDERR>
	MOVE T4,INDBLK		;GET ADDRESS OF NODE BLOCK
	UMOVE T2,.NDNAM(T4)	;GET ADDRESS OF NODE NAME STRING
	 ERJMP R		;FAILED
	JUMPE T2,R		;FAIL IF NO NAME SPECIFIED
	UMOVE T1,.NDSTA(T4)	;GET NODE STATE
	 ERJMP R		;FAIL IF NON-EX USER PAGE
	MOVEM T1,INDSTA		;SAVE STATE
	MOVX T1,2*<<NODMAX+12>/5> ;ASSIGN SPACE FOR NODE NAME
	NOINT
	CALL ASGSWP		;GET SOME SPACE
	 RETBAD ()		;FAILED
	MOVEM T1,INDADR		;SAVE ADDRESS OF BLOCK
	MOVE T2,INDBLK		;GET BACK ADDRESS OF NODE BLOCK
	UMOVE T2,.NDNAM(T2)	;GET ADDRESS OF NODE NAME STRING
	 ERJMP INSERR		;FAIL IF NON-EX USER PAGE
	MOVX T3,NODMAX		;MAX # OF CHARS IN NODE NAME
	CALL CPYFU2		;GET STRING FROM USER
	 JRST INSERR		;ERROR - HANDLE
	MOVE T1,INDADR		;GET ADDRESS OF BUFFER
	ADDI T1,<NODMAX+12>/5	;POINT TO SECOND SLOT
	MOVE T2,INDBLK		;GET ADDRESS OF BLOCK
	UMOVE T2,.NDNXT(T2)	;GET ADDRESS OF NEIGHBOR NODE NAME STRING
	 ERJMP INSERR		;FAIL IF NON-EX USER PAGE
	JUMPE T2,INSND1		;NO NEIGHBOR - NO NEED TO COPY
	MOVX T3,NODMAX		;MAX # OF CHARS IN NODE NAME
	CALL CPYFU2		;GET STRING FROM USER
	 JRST INSERR		;ERROR - HANDLE
	SETOM T2		;SHOW THERE EXISTS A NEIGHBOR
INSND1:	MOVE T1,INDADR		;GET ADDRESS OF BUFFER
	AOS T1			;POINT TO START OF MESSAGE
	SKIPE T3,T2		;MAKE T3 ZERO IF NO NEIGHBOR
	MOVEI T3,<<NODMAX+12>/5>(T1)	;POINT TO NEIGHBOR NAME
	MOVE T2,INDSTA		;RESTORE STATE
	CALL ADDNOD		;ADD NODE TO TABLE OF KNOWN NODES
	 JRST INSERR		;ERROR - HANDLE
	OKINT
	RETSKP			;DONE, RETURN

INSERR:	MOVEM T1,INDERR		;SAVE ERROR CODE
	MOVE T1,INDADR 	;ADDRESS OF BLOCK
	CALL RELMES		;RELEASE THE BLOCK
INSER1:	MOVE T1,INDERR		;RESTORE ERROR CODE
	OKINT
	RETBAD () 		;FAIL
; GET NETWORK TOPOPLOGY INFORMATION

NDGNT:	STKVAR <<GNTBLK,MAXNOD>,GNTCNT>

; SET UP TO LOOP OVER EACH NODE

	UMOVE T4,2		;GET ADDRESS OF USER'S ARGUMENT BLOCK
	UMOVE T1,.NDNND(T4)	;GET NUMBER OF WORDS IN BLOCK
	ADD T1,T4		;COMPUTE LAST ADDRESS TO USE
	MOVEM T1,GNTCNT		;SAVE LAST ADDRESS IN USER SPACE TO STORE INTO
	MOVEI Q1,.NDBK1(T4)	;SET UP ADDRESS OF NEXT POINTER TO USE
	MOVE T2,NODTBL		;GET ADDRESS OF KNOWN NODE TABLE
	JUMPE T2,RSKP		;IF NO NODE LIST, THEN DONE
	HLRZ T3,(T2)		;GET NUMBER OF ITEMS IN KNOWN NODE TABLE
	JUMPE T3,RSKP		;IF NONE, THEN ALL DONE
	MOVE Q2,Q1		;COPY STARTING ADDRESS OF NODE BLOCK POINTERS
	ADD Q2,T3		;COMPUTE STARTING ADDRESS OF NODE BLOCK AREA
	CAMLE Q2,GNTCNT		;ENOUGH ROOM FOR ALL THE NODE BLOCK POINTERS ?
	RETBAD (ARGX04)		;NO, FAIL
	XCTU [HRLM T3,.NDNND(T4)] ;YES, STORE COUNT OF ITEMS RETURNED
	MOVN Q3,T3		;COMPUTE -NUMBER OF NODES
	HRLZ Q3,Q3		;FORM AOBJN POINTER TO NODE TABLE
	HRRI Q3,1(T2)		;FORM AOBJN POINTER TO FIRST ENTRY
	MOVX T1,.NDNBS		;GET SIZE OF A NODE BLOCK
	UMOVEM T1,.NDCNT(T4)	;STORE IN USER ARG BLOCK

; LOOP OVER EACH KNOWN NODE

	NOINT			;DO NOT PERMIT INTERRUPTS WITH LOCK LOCKED
	LOCK NODLOK		;LOCK THE TABLE
NDGN10:	UMOVEM Q2,(Q1)		;STORE POINTER TO NODE BLOCK
	 ERJMP NDGNX		;FAILED, CLEAN UP AND RETURN ERROR
	MOVEI T1,.NDNBS(Q2)	;COMPUTE ADDRESS AFTER THIS NODE BLOCK
	CAML T1,GNTCNT		;ENOUGH ROOM FOR THIS NODE BLOCK AND NAME ?
	JRST [	MOVX T1,ARGX04	;NO, GET "ARG BLOCK TOO SMALL" CODE
		JRST NDGNX ]	;RETURN ERROR TO USER
	MOVX T1,.NDSON		;GET NODE STATE ("ON" IF IN KNOWN NODE TABLE)
	UMOVEM T1,.NDSTA(Q2)	;STORE STATE IN NODE BLOCK IN USER SPACE
	HRRI T3,.NDNBS(Q2)	;GET ADDRESS WHERE NAME WILL GO
	HRLI T3,(POINT 7,)	;FORM POINTER TO NODE NAME DESTINATION
	UMOVEM T3,.NDNAM(Q2)	;STORE POINTER TO NODE NAME IN USER SPACE
	HLRZ T1,(Q3)		;GET ADDRESS OF NODE NAME STRING
	HRLI T1,(POINT 7,)	;FORM POINTER TO NODE NAME
	CALL STONOD		;STORE NODE NAME STRING IN USER SPACE
	 JRST NDGNX		;FAILED
	ADDI Q1,1		;INCREMENT ADDRESS OF NEXT NODE BLOCK POINTER
	HRRI Q2,1(T3)		;GET ADDRESS OF NEXT NODE BLOCK
	AOBJN Q3,NDGN10		;LOOP OVER EACH NODE NAME TO BE RETURNED

; HERE WHEN ALL INFO RETURNED TO USER - STORE COUNT OF ITEMS RETURNED

NDGN30:	UNLOCK NODLOK		;UNLOCK THE NODE TABLE
	OKINT			;PERMIT INTERRUPTS AGAIN

NDGN40:	RETSKP			;DONE, RETURN SUCCESS
; HERE ON AN ERROR

NDGNX:	UNLOCK NODLOK		;UNLOCK NODE TABLE
	OKINT			;PERMIT INTERRUPTS AGAIN
	RET			;FAIL
; GET LINE INFORMATION INFORMATION

NDGLI:	STKVAR <<LITBLK,MAXNOD>,LITCNT>

; SET UP TO LOOP OVER EACH NODE

	XCTU [	HRRZ T2,2]	;GET ADDRESS OF USER'S ARGUMENT BLOCK
	XCTU [	HRRZ T1,.NDNLN(T2)]	;GET NUMBER OF WORDS IN BLOCK
	ADD T1,T2		;COMPUTE LAST ADDRESS TO USE
	MOVEM T1,LITCNT		;SAVE LAST ADDRESS IN USER SPACE TO STORE INTO
	MOVEI Q1,.NDNLN+1(T2)	;SET UP ADDRESS OF NEXT POINTER TO USE
	MOVEI T3,DCN		;GET MAXIMUM NUMBER OF POSSIBLE LINES
	JUMPE T3,[SETZM T4	;IF NO INFO, RETURN 0
		  JRST NDLI40 ]	; IN THE USER ARGUMENT BLOCK
	UMOVE T4,2		;GET ADDRESS OF USER'S ARGUMENT BLOCK
	XCTU [HRLM T3,.NDNLN(T4)] ;STORE COUNT OF ITEMS RETURNED
	MOVE Q2,Q1		;COPY STARTING ADDRESS OF LINE BLOCK POINTERS
	ADD Q2,T3		;COMPUTE STARTING ADDRESS OF LINE BLOCK AREA
	CAMLE Q2,LITCNT		;ENOUGH ROOM FOR ALL THE LINE BLOCK POINTERS ?
	RETBAD (ARGX04)		;NO, FAIL
	MOVN Q3,T3		;COMPUTE -NUMBER OF LINES
	HRLZ Q3,Q3		;FORM AOBJN POINTER TO LINE TABLE

; LOOP OVER EACH KNOWN LINE

NDLI10:	UMOVEM Q2,(Q1)		;STORE POINTER TO LINE BLOCK
	MOVEI T1,.NDLSZ+2(Q2)	;COMPUTE ADDRESS AFTER THIS LINE BLOCK
	CAMLE T1,LITCNT		;ENOUGH ROOM FOR THIS LINE BLOCK AND NAME ?
	RETBAD(ARGX04)		;NO, FAIL
	MOVEI T1,.BTSTS		;USE BOOT JSYS TO GET STATUS OF LINE
	MOVEI T2,3		;HAVE IT PUT DATA IN AC'S
	HRRZ T3,Q3		;GET LINE NUMBER
	UMOVEM T3,.NDLNM(Q2)	;SAVE THE PORT NUMBER
	BOOT
	 ERJMP [ MOVE T1,LSTERR	;GET THE LAST ERROR MESSAGE
		 RETBAD()]
	MOVEI T3,.NDLON		;TRANSLATE BOOT CODE TO NODE JSYS CODE
	CAIE T4,.VNMCB		;IS IT RUNNING MCB
	CAIN T4,.VNDDC		;NO - IS IT RUNNING DDCMP
	JRST NDLI11		;YES - THEN IT IS ON
	MOVEI T3,.NDLCN		;IS IT CONTROLLER LOOPBACK?
	CAIN T4,.VNCNL		;???
	JRST NDLI11		;YES
	MOVEI T3,.NDLCB		;CABLE LOOPBACK?
	CAIN T4,.VNCBL		;??
	JRST NDLI11		;YES
	MOVEI T3,.NDLOF		;SEE IF IT'S OFF
NDLI11:	UMOVEM T3,.NDLST(Q2)	;STORE STATE IN LINE BLOCK IN USER SPACE
	HRRI T3,.NDLSZ(Q2)	;GET ADDRESS WHERE NAME WILL GO
	HRLI T3,(POINT 7,)	;FORM POINTER TO LINE NAME DESTINATION
	UMOVEM T3,.NDLND(Q2)	;STORE POINTER TO LINE NAME IN USER SPACE
	HRRZ T1,Q3		;ITSNAM INDEX IS TWICE THE LINE NUMBER
	LSH T1,1
	HRRI T1,ITSNAM(T1)	;GET ADDRESS OF LINE NAME STRING
	HRLI T1,(POINT 7,)	;FORM POINTER TO LINE NAME
	CALL STONOD		;STORE LINE NAME STRING IN USER SPACE
	 JRST NDLI40		;FAILED
	ADDI Q1,1		;INCREMENT ADDRESS OF NEXT LINE BLOCK POINTER
	HRRI Q2,1(T3)		;GET ADDRESS OF NEXT LINE BLOCK
	AOBJN Q3,NDLI10		;LOOP OVER EACH LINE NAME TO BE RETURNED

; HERE WHEN ALL INFO RETURNED TO USER

NDLI40:	RETSKP			;DONE, RETURN SUCCESS




;STONOD - ROUTINE TO STORE NODE NAME STRING IN USER SPACE
;
;ACCEPTS IN T1/	POINTER TO SOURCE STRING
;	    T3/	POINTER TO DESTINATION IN USER SPACE
;		CALL STONOD
;RETURNS: +1	 FAILED
;	  +2	SUCCESS

STONOD:

; LOOP OVER EACH CHARACTER IN NODE NAME

NDGN20:	ILDB T2,T1		;GET A BYTE
	JUMPE T2,NDGN25		;IF NULL, ALL DONE
	XCTBU [IDPB T2,T3]	;STORE BYTE
	 ERJMP R		;FAILED, RETURN ERROR
	JRST NDGN20		;DO THEM ALL
NDGN25:	XCTBU [IDPB T2,T3]	;APPEND A NULL
	 ERJMP R		;FAILED, RETURN ERROR
	RETSKP			;DONE, RETURN SUCCESS
; NDVFY - VERIFY NODE NAME IS IN MONITOR'S DATABASE OF KNOWN NODES

NDVFY:	SAVEAC (Q1)
	STKVAR <<NDVNOD,WPN>>

; GET NODE NAME FROM USER SPACE

	UMOVE Q1,T2		;GET ADDRESS OF USER ARGUMENT BLOCK
	UMOVE T1,.NDNAM(Q1)	;GET POINTER TO NODE NAME IN USER SPACE
	MOVEI T2,NDVNOD		;GET ADDRESS OF DESTINATION FOR NAME
	CALL PARNDU		;GET THE NODE NAME FROM USER SPACE
	 RETBAD ()		;FAILED

; VERIFY THAT THE NODE IS KNOWN TO THE MONITOR

	HRRI T1,NDVNOD		;GET ADDRESS OF NODE NAME
	HRLI T1,(POINT 7,)	;FORM POINTER TO NODE NAME
	CALL VFYNOD		;VERIFY NODE NAME
	 TDZA T1,T1		;FAILED, NOT A KNOWN NODE
	MOVX T1,ND%EXM		;SUCCESS, NODE IS KNOWN
	UMOVEM T1,.NDFLG(Q1)	;STORE RESULT IN USER SPACE
	RETSKP			;DONE, RETURN SUCCESS



;VFYNOD - ROUTINE TO VERIFY THAT A NODE IS KNOWN TO THE MONITOR
;
;ACCEPTS IN T1/	POINTER TO NODE NAME
;		CALL VFYNOD
;RETURNS: +1	 FAILED, NODE IS NOT KNOWN TO THE MONITOR
;	  +2	SUCCESS, NODE IS IN MONITOR'S DATABASE

VFYNOD:	LOCK NODLOK		;LOCK THE KNOWN NODE TABLE
	MOVE T2,T1		;COPY POINTER TO NODE NAME
	MOVE T1,NODTBL		;GET ADDRESS OF KNOWN NODE TABLE
	TBLUK			;LOOK UP THE NODE NAME
	 ERJMP [UNLOCK NODLOK	;FAILED, UNLOCK THE TABLE
		RET ]		;RETURN "NOT KNOWN"
	UNLOCK NODLOK		;UNLOCK THE TABLE
	TXNN T2,TL%EXM		;EXACT MATCH ?
	RET			;NO, RETURN "NOT KNOWN"
	RETSKP			;YES, RETURN "KNOWN NODE"

	TNXEND
	END