Google
 

Trailing-Edge - PDP-10 Archives - BB-H311D-RM - monitor-sources/nspsrv.mac
There are 31 other files named nspsrv.mac in the archive. Click here to see a list.
; UPD ID= 5073, SNARK:<6.MONITOR>NSPSRV.MAC.148,   8-Nov-84 12:31:12 by GRANT
;TCO 6.2277 - In UNQTIM, remove obsolete ASUBR; remove OWGBP stuff and
;references to MSPTP.
; UPD ID= 4861, SNARK:<6.MONITOR>NSPSRV.MAC.147,  20-Sep-84 15:25:20 by TBOYLE
;TCO 6.2223 - Prevent NSPTSK from staying in balance set all the time.
; UPD ID= 4818, SNARK:<6.MONITOR>NSPSRV.MAC.146,  17-Sep-84 10:14:26 by PURRETTA
;Update copyright notice
; UPD ID= 4736, SNARK:<6.MONITOR>NSPSRV.MAC.145,  24-Aug-84 07:06:33 by GRANT
;TCO 6.2198 - In CLZDI, make sure all bytes are sent
; UPD ID= 4622, SNARK:<6.MONITOR>NSPSRV.MAC.144,  28-Jul-84 17:37:07 by GLINDELL
;More TCO 6.2060 - fix typo bug
; UPD ID= 4408, SNARK:<6.MONITOR>NSPSRV.MAC.143,  29-Jun-84 10:24:25 by GRANT
;QAR 706017 - In SRCOPN, add another TRVAR location for the LL block and use
;it in OPNUNQ
; UPD ID= 4355, SNARK:<6.MONITOR>NSPSRV.MAC.142,  18-Jun-84 11:49:06 by GRANT
;In NSPSPC, wrong AC as index register
; UPD ID= 4272, SNARK:<6.MONITOR>NSPSRV.MAC.141,  30-May-84 21:21:01 by MOSER
;TCO 6.2060 - MAKE MTOPRS FASTER
; UPD ID= 4242, SNARK:<6.MONITOR>NSPSRV.MAC.140,  25-May-84 06:15:26 by GRANT
;TCO 6.2068 - try to prevent resident free space deadly embrace
; UPD ID= 4127, SNARK:<6.MONITOR>NSPSRV.MAC.139,  25-Apr-84 11:06:47 by LOMARTIRE
;TCO 6.2046 - Record the job 0 fork number of NSP fork in DNTFRK
; UPD ID= 4033, SNARK:<6.MONITOR>NSPSRV.MAC.138,  31-Mar-84 20:54:07 by GRANT
;Use LLDBUG under NSPSW for debugging LL blocks being clobbered
; UPD ID= 3964, SNARK:<6.MONITOR>NSPSRV.MAC.137,  23-Mar-84 16:40:40 by NICHOLS
;Add TCO number to previous edit.
; UPD ID= 3962, SNARK:<6.MONITOR>NSPSRV.MAC.136,  23-Mar-84 15:50:26 by NICHOLS
;TCO 6.2009 - Ignore Phase IV Retransmitted CI messages quietly rather
;than giving NSPBAD BUGINFs for each one received.  Add code to BADMSG
;to keep most recent message which caused NSPBAD BUGINF, pointer in BADMSP.
; UPD ID= 3428, SNARK:<6.MONITOR>NSPSRV.MAC.135,   9-Jan-84 14:53:47 by GRANT
;Turn off NSPSW
; UPD ID= 3391, SNARK:<6.MONITOR>NSPSRV.MAC.134,  30-Dec-83 07:08:08 by GRANT
;In BLKLOK, put lock and context checking under NSPSW debugging switch.
;Replace JSR BUGHLTs with defined BUGHLTs.
;TCO 6.1920 - In debugging mode (NSPSW=1), use LLMSIT instead of LLMSG.
; UPD ID= 3352, SNARK:<6.MONITOR>NSPSRV.MAC.133,  20-Dec-83 15:02:36 by CJOHNSON
;TCO 6.1907 Make TURNON have WRONLY DCN: send 0 xmit alloc 
; UPD ID= 3218, SNARK:<6.MONITOR>NSPSRV.MAC.132,  28-Nov-83 09:45:39 by LEACHE
;TCO 6.1641 Move swappable freespace out of section zero
; UPD ID= 2603, SNARK:<6.MONITOR>NSPSRV.MAC.131,  20-Jun-83 15:49:03 by HALL
;TCO 6.1689 - Move fork tables to extended section
;	Reference FKJOB via DEFSTR
; UPD ID= 2586, SNARK:<6.MONITOR>NSPSRV.MAC.130,  15-Jun-83 13:25:56 by GRANT
;TCO 6.1687 - In STRMSG, make sure it is a node init
; UPD ID= 2520, SNARK:<6.MONITOR>NSPSRV.MAC.129,  25-May-83 14:03:59 by GRANT
;TCO 6.1667 - use EP. for network management counter references
; UPD ID= 2446, SNARK:<6.MONITOR>NSPSRV.MAC.128,   9-May-83 11:34:12 by GRANT
;TCO 6.1642 - Use SIZ39 in GTSBLK
; UPD ID= 2210, SNARK:<6.MONITOR>NSPSRV.MAC.127,   8-Apr-83 06:48:18 by GRANT
;TCO 6.1605 - make INTINT resident
; UPD ID= 2103, SNARK:<6.MONITOR>NSPSRV.MAC.126,  28-Mar-83 17:44:42 by MURPHY
;TCO 6.1472 - Minor cleanup re. LSTERR
; UPD ID= 2053, SNARK:<6.MONITOR>NSPSRV.MAC.125,  21-Mar-83 18:05:59 by MURPHY
;GET RID OF OBSOLETE SEARCH PROKL
; UPD ID= 2048, SNARK:<6.MONITOR>NSPSRV.MAC.124,  21-Mar-83 14:07:45 by GRANT
;TCO 6.1560 - insert check against BIGNOD in CI message processing
; UPD ID= 2024, SNARK:<6.MONITOR>NSPSRV.MAC.123,  19-Mar-83 06:16:06 by GRANT
;TCO 6.1558 - After ILLSTR BUGINF, go to TOSMSG instead of BADMSG
; UPD ID= 1897, SNARK:<6.MONITOR>NSPSRV.MAC.122,   1-Mar-83 15:40:25 by HALL
;TCO 6.1502 - Allow free space outside of section 0
;	At least temporarily, make all callers request section 0
; UPD ID= 1854, SNARK:<6.MONITOR>NSPSRV.MAC.121,  22-Feb-83 12:04:04 by GRANT
;TCO 6.1481 - support for incoming messages in non-PC section
; UPD ID= 1801, SNARK:<6.MONITOR>NSPSRV.MAC.120,  14-Feb-83 15:04:00 by HALL
;TCO 6.1502 - Allow resident free space in non-PC section
;	Instead of testing free space availability directly, call routine
;	in FREE to do it
; UPD ID= 1787, SNARK:<6.MONITOR>NSPSRV.MAC.119,  10-Feb-83 16:26:30 by COBB
;Add a comment to NTCOFF about is never RETing, only RETSKPing.
; UPD ID= 1738, SNARK:<6.MONITOR>NSPSRV.MAC.118,   2-Feb-83 13:27:18 by GRANT
;TCO 6.1491 - In MTGSS, return segment size in more cases
; UPD ID= 1736, SNARK:<6.MONITOR>NSPSRV.MAC.117,   2-Feb-83 07:26:58 by GRANT
;TCO 6.1486 - Make ONSRVQ and UNQSRV run NOSKED
; UPD ID= 1726, SNARK:<6.MONITOR>NSPSRV.MAC.116,  31-Jan-83 10:07:53 by GRANT
;More of 6.1435 - Change routine BADNOD
; UPD ID= 1724, SNARK:<6.MONITOR>NSPSRV.MAC.115,  31-Jan-83 07:29:06 by GRANT
;Change STKVAR name in previous edit
; UPD ID= 1723, SNARK:<6.MONITOR>NSPSRV.MAC.114,  28-Jan-83 22:20:08 by GRANT
;TCO 6.1483 - In DCDCS, fix management of LL block lock
; UPD ID= 1697, SNARK:<6.MONITOR>NSPSRV.MAC.113,  26-Jan-83 09:42:27 by GRANT
;More TCO 6.1455
; UPD ID= 1685, SNARK:<6.MONITOR>NSPSRV.MAC.112,  20-Jan-83 08:31:26 by GRANT
;TCO 6.1469 - implement node parameter "state"
; UPD ID= 1671, SNARK:<6.MONITOR>NSPSRV.MAC.111,  16-Jan-83 21:50:28 by GRANT
;TCO 6.1454 - Split off NTMAN% into its own module
; UPD ID= 1648, SNARK:<6.MONITOR>NSPSRV.MAC.110,  13-Jan-83 07:18:12 by GRANT
;Fix bug in UPD ID=1256 - in NSPTM5, retrieve message address earlier
; UPD ID= 1647, SNARK:<6.MONITOR>NSPSRV.MAC.109,  13-Jan-83 06:44:45 by GRANT
;TCO 6.1455 - don't assemble internal links code
; UPD ID= 1635, SNARK:<6.MONITOR>NSPSRV.MAC.108,  10-Jan-83 08:09:44 by GRANT
;TCO 6.1442 - don't assemble 2020 loopback code
; UPD ID= 1627, SNARK:<6.MONITOR>NSPSRV.MAC.107,   7-Jan-83 08:30:46 by GRANT
;TCO 6.1443 - In INTLS, remove setting of inactivity timer.  In INACOR, reorder
; the tests to make elimination faster.
; UPD ID= 1618, SNARK:<6.MONITOR>NSPSRV.MAC.106,   5-Jan-83 07:02:36 by GRANT
;TCO 6.1435 - rewrite part of incoming CI message processing
; UPD ID= 1588, SNARK:<6.MONITOR>NSPSRV.MAC.105,  28-Dec-82 07:57:25 by GRANT
;TCO 6.1430 - redo the logic in ACKRUN and DATRUN
; UPD ID= 1578, SNARK:<6.MONITOR>NSPSRV.MAC.104,  27-Dec-82 10:56:33 by GRANT
;TCO 6.1429 - add missing OKINT in DCDCS
; UPD ID= 1577, SNARK:<6.MONITOR>NSPSRV.MAC.103,  27-Dec-82 10:45:56 by GRANT
;TCO 6.1428 - remove extraneous instruction in MTSNIN
; UPD ID= 1576, SNARK:<6.MONITOR>NSPSRV.MAC.102,  27-Dec-82 08:52:40 by GRANT
;TCO 6.1427 - add support for "seconds since last zeroed"
; UPD ID= 1528, SNARK:<6.MONITOR>NSPSRV.MAC.101,  10-Dec-82 13:02:05 by GRANT
;TCO 6.1411 - use the table LLIDS to store logical links block addresses
; UPD ID= 1514, SNARK:<6.MONITOR>NSPSRV.MAC.100,   7-Dec-82 13:08:06 by GRANT
;TCO 6.1404 - rewrite CHKSCT
; UPD ID= 1403, SNARK:<6.MONITOR>NSPSRV.MAC.99,   2-Nov-82 11:26:49 by GRANT
;Minor fix to TCO 5.1.1089
; UPD ID= 1396, SNARK:<6.MONITOR>NSPSRV.MAC.98,   1-Nov-82 13:23:43 by GRANT
;TCO 6.1341 - release swappable block in CLRBLK
; UPD ID= 1338, SNARK:<6.MONITOR>NSPSRV.MAC.97,  13-Oct-82 20:58:37 by GRANT
;More of TCO 5.1.1074
; UPD ID= 1333, SNARK:<6.MONITOR>NSPSRV.MAC.96,  13-Oct-82 07:14:41 by GRANT
;More of TCO 5.1.1089 - In MCBCQ, don't need to fake a JFN block anymore
; UPD ID= 1321, SNARK:<6.MONITOR>NSPSRV.MAC.95,  11-Oct-82 10:18:35 by GRANT
;TCO 5.1.1092 - Change a few IFNSK. to IFSKP.
; UPD ID= 1311, SNARK:<6.MONITOR>NSPSRV.MAC.94,   9-Oct-82 10:21:22 by GRANT
;TCO 5.1.1089 - Rewrite MCBCQ, process link IDs rather than LL blocks
; UPD ID= 1299, SNARK:<6.MONITOR>NSPSRV.MAC.93,   8-Oct-82 10:04:25 by GRANT
;TCO 5.1.1087 - Add call to DELNOD in NSPTMO
; UPD ID= 1298, SNARK:<6.MONITOR>NSPSRV.MAC.92,   8-Oct-82 08:58:25 by GRANT
;TCO 5.1.1086 - In RELLNK and DEDMCB, lock LL tree before calling DELNOD
; UPD ID= 1292, SNARK:<6.MONITOR>NSPSRV.MAC.91,   7-Oct-82 13:36:47 by GRANT
;TCO 5.1.1085 - In UNQSEG, stop incorrect removal from the resend queue
; UPD ID= 1280, SNARK:<6.MONITOR>NSPSRV.MAC.90,   6-Oct-82 08:56:30 by GRANT
;TCO 5.1.1074 - Add debugging code for verifying logical link blocks
; UPD ID= 1270, SNARK:<6.MONITOR>NSPSRV.MAC.89,   1-Oct-82 17:56:30 by GRANT
;TCO 5.1.1080 - In NSPMSG, toss messages which have LLDED set
; UPD ID= 1269, SNARK:<6.MONITOR>NSPSRV.MAC.88,   1-Oct-82 14:37:01 by GRANT
;TCO 5.1.1079 - Use MOVE instead of LOAD in NSPNXT
; UPD ID= 1256, SNARK:<6.MONITOR>NSPSRV.MAC.87,  28-Sep-82 19:09:34 by GRANT
;TCO 5.1.1072 - don't retransmit data segments when flow is turned off
; UPD ID= 1220, SNARK:<6.MONITOR>NSPSRV.MAC.86,  23-Sep-82 12:15:29 by GRANT
;TCO 5.1.1067 - Don't send a disconnect when a link times out
; UPD ID= 1218, SNARK:<6.MONITOR>NSPSRV.MAC.85,  23-Sep-82 09:38:18 by GRANT
;TCO 5.1.1066 - If link has been aborted, have synchronous CLOSF return success
; UPD ID= 1216, SNARK:<6.MONITOR>NSPSRV.MAC.84,  22-Sep-82 20:41:49 by CDUNN
;Put back the END (at the end of the source) statement which seems to have
;been lost two edits ago.
; UPD ID= 1206, SNARK:<6.MONITOR>NSPSRV.MAC.83,  21-Sep-82 13:34:53 by GRANT
;TCO 5.1.1063 - In NSNSCH, return characteristics by parameter number
; UPD ID= 1204, SNARK:<6.MONITOR>NSPSRV.MAC.82,  21-Sep-82 11:04:04 by GRANT
;Fix bug in SNDCTL introduced by an incorrect test in TCO 5.1.1057
; UPD ID= 1200, SNARK:<6.MONITOR>NSPSRV.MAC.81,  20-Sep-82 15:57:27 by MCINTEE
;More TCO 6.1251 - clean up NDGNT
; UPD ID= 1147, SNARK:<6.MONITOR>NSPSRV.MAC.80,   7-Sep-82 09:15:06 by MCINTEE
;TCO 6.1251 - Change code in NDGNT not to use so much stack.
; UPD ID= 1121, SNARK:<6.MONITOR>NSPSRV.MAC.79,  30-Aug-82 14:34:32 by MCINTEE
;TCO 5.1.1058 - Change error code at MTOBJ1
; UPD ID= 1116, SNARK:<6.MONITOR>NSPSRV.MAC.78,  27-Aug-82 07:05:35 by GRANT
;TCO 5.1.1057 - make proper check for remote node's NSP version
; UPD ID= 1112, SNARK:<6.MONITOR>NSPSRV.MAC.77,  25-Aug-82 11:55:01 by GRANT
;TCO 5.1.1055 - check for CC sent state in MTRDCK
; UPD ID= 1111, SNARK:<6.MONITOR>NSPSRV.MAC.76,  25-Aug-82 10:13:46 by GRANT
;TCO 5.1.1054 - prevent CLZRUN from wrongly sending 0-length data messages
; UPD ID= 1107, SNARK:<6.MONITOR>NSPSRV.MAC.75,  25-Aug-82 06:05:29 by GRANT
;TCO 6.1236 - change FILBFI to FILBNO
; UPD ID= 1091, SNARK:<6.MONITOR>NSPSRV.MAC.74,  18-Aug-82 09:24:55 by GRANT
;TCO 5.1692 - incorrect test at SQI4
; UPD ID= 1074, SNARK:<6.MONITOR>NSPSRV.MAC.73,  10-Aug-82 12:01:31 by GRANT
;TCO 5.1.1051 - Change RETBAD to JRST SRCFAL in SRCOPN
; UPD ID= 1073, SNARK:<6.MONITOR>NSPSRV.MAC.72,  10-Aug-82 11:30:21 by GRANT
;TCO 5.1.1050 - Change RETERR to RET in DCNOPN's GTOKM
; UPD ID= 1059, SNARK:<6.MONITOR>NSPSRV.MAC.71,   9-Aug-82 15:43:59 by PAETZOLD
;TCO 6.1219 - Extend DCNDTB and SRVDTB for RLJFD
; UPD ID= 993, SNARK:<6.MONITOR>NSPSRV.MAC.70,  18-Jul-82 13:51:26 by MURPHY
;TCO 5.1.1048 - Check LLTTA when closing; keep LL block locked until return
;  from TTSETH.
; UPD ID= 987, SNARK:<6.MONITOR>NSPSRV.MAC.69,  15-Jul-82 09:17:51 by GRANT
;TCO 5.1.1045 - In NTSNH, unlock LL block when call to TTYSRV fails
; UPD ID= 974, SNARK:<6.MONITOR>NSPSRV.MAC.68,   6-Jul-82 09:27:02 by GRANT
;TCO 5.1.1042 - Make NSLDWS resident
; UPD ID= 969, SNARK:<6.MONITOR>NSPSRV.MAC.67,  30-Jun-82 08:39:54 by GRANT
;TCO 5.1.1037 - setting local node number requires privileges
; UPD ID= 943, SNARK:<6.MONITOR>NSPSRV.MAC.66,  17-Jun-82 09:46:33 by GRANT
;TCO 5.1.1035 - make interrupt messages work again
; UPD ID= 871, SNARK:<6.MONITOR>NSPSRV.MAC.65,   8-Jun-82 08:23:02 by GRANT
;Rewrite UNQSEG
; UPD ID= 869, SNARK:<6.MONITOR>NSPSRV.MAC.64,   7-Jun-82 16:57:32 by GRANT
;More fixing of TCO 5.1.1022
; UPD ID= 854, SNARK:<6.MONITOR>NSPSRV.MAC.63,   7-Jun-82 08:06:03 by GRANT
;TCO 5.1.1033 - Return proper error message in NANUE2
; UPD ID= 836, SNARK:<6.MONITOR>NSPSRV.MAC.62,   4-Jun-82 21:49:06 by GRANT
;Fix bug in TCO 5.1.1022 change - RESBAZ and RESCHK problems fixed
; UPD ID= 833, SNARK:<6.MONITOR>NSPSRV.MAC.61,   4-Jun-82 16:02:27 by MURPHY
;Now put all BUGs in-line.
; UPD ID= 823, SNARK:<6.MONITOR>NSPSRV.MAC.59,   3-Jun-82 13:31:10 by PAETZOLD
;Fix assembly error due to new and improved bug handling
; UPD ID= 818, SNARK:<6.MONITOR>NSPSRV.MAC.58,   3-Jun-82 07:30:02 by GRANT
;TCO 6.1153 - Fix protocol error of sending data before LS ACK
; UPD ID= 804, SNARK:<6.MONITOR>NSPSRV.MAC.57,   1-Jun-82 11:32:27 by MURPHY
;TCO 6.1147 - Move bug defs from BUGS.MAC to here.
; UPD ID= 703, SNARK:<6.MONITOR>NSPSRV.MAC.56,   9-May-82 11:41:47 by HALL
;TCO 6.1000- Support the 2080
;	At TSKINI, establish full word of user flags
; UPD ID= 684, SNARK:<6.MONITOR>NSPSRV.MAC.55,   4-May-82 12:03:37 by GRANT
;TCO 5.1.1032 - turn off LLNLS and LLALS in ACKLI not in SNDACK
; UPD ID= 673, SNARK:<6.MONITOR>NSPSRV.MAC.54,  30-Apr-82 13:27:28 by GRANT
;TCO 5.1.1031 - make NTMAN% set and read retransmit factor
; UPD ID= 666, SNARK:<6.MONITOR>NSPSRV.MAC.53,  28-Apr-82 10:42:22 by GRANT
;TCO 5.1.1029 - Process all incoming, non-control messages at scheduler level
; UPD ID= 656, SNARK:<6.MONITOR>NSPSRV.MAC.52,  22-Apr-82 13:54:26 by GRANT
;TCO 5.1.1028 - apply Local Delay Factor in proper place
; UPD ID= 650, SNARK:<6.MONITOR>NSPSRV.MAC.51,  16-Apr-82 12:26:47 by GRANT
;TCO 5.1.1027 - Unlock LL block when CALL ASMCB fails
; UPD ID= 649, SNARK:<6.MONITOR>NSPSRV.MAC.50,  16-Apr-82 07:45:42 by GRANT
;TCO 5.1.1026 - Let background task wake up whenever it has a message to process
; UPD ID= 641, SNARK:<6.MONITOR>NSPSRV.MAC.49,  14-Apr-82 11:16:11 by GRANT
;Performance improvement to TCO 5.1.1022
; UPD ID= 635, SNARK:<6.MONITOR>NSPSRV.MAC.48,  13-Apr-82 15:18:11 by GRANT
;TCO 5.1.1025 - Make Local Delay Factor and Local Delay Weight settable and
;readable by NTMAN%
; UPD ID= 634, SNARK:<6.MONITOR>NSPSRV.MAC.47,  13-Apr-82 14:29:02 by GRANT
;Slight modification to TCO 5.1.1023 - send LS messgae earlier
; UPD ID= 602, SNARK:<6.MONITOR>NSPSRV.MAC.46,   6-Apr-82 10:52:37 by GRANT
;Undo more debugging code
; UPD ID= 562, SNARK:<6.MONITOR>NSPSRV.MAC.45,  31-Mar-82 14:17:24 by GRANT
;TCO 5.1.1024 - Impose a minimum on the round trip calculation
; UPD ID= 560, SNARK:<6.MONITOR>NSPSRV.MAC.44,  31-Mar-82 14:00:04 by GRANT
;TCO 5.1.1023 - Fix free space bug in NETSET
;TCO 5.1.1022 - don't time messages on Phase II links
;More of TCO 5.1.1020
;Remove debugging BUGHLTs
; UPD ID= 548, SNARK:<6.MONITOR>NSPSRV.MAC.43,  23-Mar-82 06:50:05 by GRANT
;Undo previous edit
; UPD ID= 547, SNARK:<6.MONITOR>NSPSRV.MAC.42,  22-Mar-82 11:28:12 by GRANT
;TCO 5.1.1021 - Release message block in DCDCS
; UPD ID= 543, SNARK:<6.MONITOR>NSPSRV.MAC.41,  21-Mar-82 18:24:36 by GRANT
;TCO 5.1.1020 - NAK "too new" segments from Phase II nodes
; UPD ID= 539, SNARK:<6.MONITOR>NSPSRV.MAC.40,  19-Mar-82 17:33:57 by MURPHY
;TCO 5.1.1019 - Make NSPTST wake up less often.
; UPD ID= 518, SNARK:<6.MONITOR>NSPSRV.MAC.39,  17-Mar-82 13:12:31 by GRANT
;TCO 5.1.1018 - Check for CCS state in NTMTCZ
; UPD ID= 509, SNARK:<6.MONITOR>NSPSRV.MAC.38,  16-Mar-82 09:36:51 by GRANT
;TCO 5.1.1017 - Change state transition table for CLOSF in CCS state
; UPD ID= 508, SNARK:<6.MONITOR>NSPSRV.MAC.37,  16-Mar-82 09:16:24 by GRANT
;TCO 5.1.1016 - Remove check for 0 bytes in CLZRUN
; UPD ID= 486, SNARK:<6.MONITOR>NSPSRV.MAC.36,  15-Mar-82 08:59:45 by GRANT
;TCO 5.1.1015 - CALL FLUSH in DCDCS
; UPD ID= 470, SNARK:<6.MONITOR>NSPSRV.MAC.35,  12-Mar-82 08:10:22 by GRANT
;Minor change to UPD 461
; UPD ID= 467, SNARK:<6.MONITOR>NSPSRV.MAC.34,  11-Mar-82 21:35:48 by GRANT
;Fix typo in UPD 450
; UPD ID= 463, SNARK:<6.MONITOR>NSPSRV.MAC.33,  11-Mar-82 16:34:13 by GRANT
;TCO 5.1.1014 - CALL BLKLLK in DATCSS
; UPD ID= 462, SNARK:<6.MONITOR>NSPSRV.MAC.32,  11-Mar-82 16:20:00 by GRANT
;TCO 5.1.1012 - Reset inactivity wake up even if nothing to do
; UPD ID= 461, SNARK:<6.MONITOR>NSPSRV.MAC.31,  11-Mar-82 16:04:23 by GRANT
;TCO 5.1.1013 - Don't turn off inactivity timer unless LS message gets sent
; UPD ID= 460, SNARK:<6.MONITOR>NSPSRV.MAC.30,  11-Mar-82 15:56:40 by GRANT
;TCO 5.1.1011 - Make scheduler send ACKs every 200 milliseconds.
;Previous edit should be TCO 5.1.1010
; UPD ID= 459, SNARK:<6.MONITOR>NSPSRV.MAC.29,  11-Mar-82 15:45:52 by GRANT
;TCO 5.1.1011 - Always go to LLSRVR upon leaving NSPCH7
; UPD ID= 450, SNARK:<6.MONITOR>NSPSRV.MAC.28,   9-Mar-82 14:40:34 by GRANT
;TCO 5.1.1009 - Make .NDGNT function of NODE% return info even on failure
; UPD ID= 449, SNARK:<6.MONITOR>NSPSRV.MAC.27,   9-Mar-82 09:58:50 by GRANT
;Add missing ENDIF. in UPD 445
; UPD ID= 446, SNARK:<6.MONITOR>NSPSRV.MAC.26,   6-Mar-82 21:32:44 by GRANT
;TCO 5.1.1008 - Use BLKSIZ in node init
; UPD ID= 445, SNARK:<6.MONITOR>NSPSRV.MAC.25,   6-Mar-82 21:17:09 by GRANT
;TCO 5.1.1006 - Rewrite ONTIMQ and UNQTIM
; UPD ID= 409, SNARK:<6.MONITOR>NSPSRV.MAC.24,  17-Feb-82 16:07:22 by GRANT
;TCO 5.1.1005 - ACKCCS needs to use CALL BLKLLK instead of CALL BLKLOK
; UPD ID= 398, SNARK:<6.MONITOR>NSPSRV.MAC.23,  12-Feb-82 15:53:44 by GRANT
;TCO 5.1729 - NSPINT no longer loaded, remove calls to OUTSEG
; UPD ID= 388, SNARK:<6.MONITOR>NSPSRV.MAC.22,   6-Feb-82 21:10:53 by GRANT
;Undo duplicated code in NTMAN% - probably caused by REDIT
; UPD ID= 387, SNARK:<6.MONITOR>NSPSRV.MAC.21,   6-Feb-82 14:14:19 by LEACHE
;TCO 5.1721  Make NODE JSYS function .NDGLN use 30-bit addressing
; UPD ID= 381, SNARK:<6.MONITOR>NSPSRV.MAC.20,   5-Feb-82 09:25:35 by GRANT
;TCO 5.1.1004 - put in call to the new code
; UPD ID= 380, SNARK:<6.MONITOR>NSPSRV.MAC.19,   5-Feb-82 08:04:49 by GRANT
;TCO 5.1.1004 - figure out "number of active links" in the NTMAN% JSYS
; UPD ID= 271, SNARK:<6.MONITOR>NSPSRV.MAC.18,   5-Jan-82 08:57:37 by GRANT
;TCO 5.1649 - Add null message handling
; UPD ID= 251, SNARK:<6.MONITOR>NSPSRV.MAC.17,  13-Dec-81 10:55:23 by GRANT
;TCO 5.1636 - use SEGSZ
; UPD ID= 239, SNARK:<6.MONITOR>NSPSRV.MAC.16,   7-Dec-81 12:09:50 by GRANT
;TCO 5.1.1002 - return scheduler test when ACKRMT fails
; UPD ID= 233, SNARK:<6.MONITOR>NSPSRV.MAC.15,   4-Dec-81 14:06:10 by GRANT
;More TCO 5.1503 - make consistent use of symbols
; UPD ID= 231, SNARK:<6.MONITOR>NSPSRV.MAC.14,   4-Dec-81 08:54:48 by GRANT
;TCO 5.1626 - In NODINI, make an extensible field for the node number.
;Another attempt at TCO 5.1510
; UPD ID= 198, SNARK:<6.MONITOR>NSPSRV.MAC.13,   9-Nov-81 11:25:44 by GRANT
;TCO 5.1.1001 - add explicit check for 8-bit bytes in NTMAN%
; UPD ID= 197, SNARK:<6.MONITOR>NSPSRV.MAC.12,   9-Nov-81 10:47:57 by GRANT
;Under DN20SW, enhance checking for multiple MCBs
; UPD ID= 193, SNARK:<6.MONITOR>NSPSRV.MAC.11,   6-Nov-81 13:40:52 by MURPHY
;Make monitor fork start in section 1.
; UPD ID= 182, SNARK:<6.MONITOR>NSPSRV.MAC.10,   4-Nov-81 08:58:45 by GRANT
;TCO 5.1604 - Only do inactivity checking when link is in the run state
; UPD ID= 156, SNARK:<6.MONITOR>NSPSRV.MAC.9,  22-Oct-81 09:01:53 by GRANT
;TCO 5.1593 - Defensive code in RESEND to prevent looping caused by bad counter
; UPD ID= 148, SNARK:<6.MONITOR>NSPSRV.MAC.8,  21-Oct-81 12:07:45 by GRANT
;TCO 5.1594 - Create TTGETS and TTREMS for TTYSRV to use
; UPD ID= 147, SNARK:<6.MONITOR>NSPSRV.MAC.7,  21-Oct-81 10:09:19 by GRANT
;TCO 5.1592 - Fix failure return in LLSRVR
; UPD ID= 126, SNARK:<6.MONITOR>NSPSRV.MAC.6,  19-Oct-81 10:17:14 by GRANT
;TCO 5.1587 - fix segment number wrap around in VERSEG
; UPD ID= 125, SNARK:<6.MONITOR>NSPSRV.MAC.5,  19-Oct-81 10:00:37 by MCINTEE
;Make entry point for monitor in NDVFY (for GTJFN)
; UPD ID= 109, SNARK:<6.MONITOR>NSPSRV.MAC.4,  15-Oct-81 14:18:49 by GRANT
;Fix bug in TCO 5.1534
;<6.MONITOR>NSPSRV.MAC.3,  9-Oct-81 17:43:51, EDIT BY MURPHY
;Change DTB format, eliminate double skips, etc.
;Put source into M60:
; UPD ID= 230, SNARK:<5.MONITOR>NSPSRV.MAC.111,  29-Sep-81 10:30:51 by GRANT
;Typo in previous edit - LLCIR should be LLSCIR
; UPD ID= 221, SNARK:<5.MONITOR>NSPSRV.MAC.110,  28-Sep-81 12:51:18 by GRANT
;TCO 5.1534 - make RDSTS reflect MO%WFC correctly
; UPD ID= 220, SNARK:<5.MONITOR>NSPSRV.MAC.109,  28-Sep-81 12:40:10 by GRANT
;TCO 5.1537 - smarter calculation of time out value on retransmission
; UPD ID= 215, SNARK:<5.MONITOR>NSPSRV.MAC.108,  24-Sep-81 22:05:34 by GRANT
;PREVIOUS EDIT NEEDS EXPANDED ACVAR IN NSPTMR
; UPD ID= 214, SNARK:<5.MONITOR>NSPSRV.MAC.107,  24-Sep-81 16:52:00 by GRANT
;TCO 5.1533 - New resend algorithm in NSPTMR.
;Comments added in VERSEG and ONRAWQ.
;Reorganize so scheduler related routines are in one place.
; UPD ID= 207, SNARK:<5.MONITOR>NSPSRV.MAC.106,  22-Sep-81 22:59:02 by GRANT
;TCO 5.1528 - FIX THE CHECK FOR "NEEDS AN ACK" IN LLSRVR
;TCO 5.1529 - FIX THE OUT-OF-ORDER MESSAGE PROCESSING IN GOTSEG
; UPD ID= 203, SNARK:<5.MONITOR>NSPSRV.MAC.105,  21-Sep-81 16:34:29 by GRANT
;More TCO 5.1490 - In DELNOD, CALL UNQSRV so old addresses don't remain on LLSRVQ
; UPD ID= 201, SNARK:<5.MONITOR>NSPSRV.MAC.104,  21-Sep-81 10:09:06 by GRANT
;Fix DSCMOV to accommodate TCO 5.1503 (bigger userid, password, account)
; UPD ID= 194, SNARK:<5.MONITOR>NSPSRV.MAC.103,  17-Sep-81 13:23:21 by GRANT
;TCO 5.1490 - Create a pool of free space blocks reserved for sending ACKs
;Piggyback ACKs in data segments
;Eliminate raw queue, do ACKs in scheduler
; UPD ID= 178, SNARK:<5.MONITOR>NSPSRV.MAC.102,  15-Sep-81 13:54:42 by GRANT
;More of TCO 5.1508
; UPD ID= 177, SNARK:<5.MONITOR>NSPSRV.MAC.101,  15-Sep-81 11:55:12 by GRANT
;TCO 5.1510 - Fix Network Management counter "number of active links"
; UPD ID= 174, SNARK:<5.MONITOR>NSPSRV.MAC.100,  14-Sep-81 16:38:16 by GRANT
;TCO 5.1508 - LL not cleaned up on abort close if other side doesn't answer
; UPD ID= 170, SNARK:<5.MONITOR>NSPSRV.MAC.99,  14-Sep-81 10:53:00 by GRANT
;TCO 5.1503 - Allow user ids, passwords, and accounts to be up to 39 chars
; UPD ID= 169, SNARK:<5.MONITOR>NSPSRV.MAC.98,  14-Sep-81 09:23:33 by GRANT
;TCO 5.1502 - Fix cause of ILLUUO BUGHLT caused by NODE JSYS
; UPD ID= 83, SNARK:<5.MONITOR>NSPSRV.MAC.93,  28-Jul-81 11:48:23 by GRANT
;Move test for NSSNTQ empty from NSPTSK to NSPTMR - prevents unnecessary wakeups
; UPD ID= 39, SNARK:<5.MONITOR>NSPSRV.MAC.92,  16-Jul-81 17:09:25 by GRANT
;Use symbols in NDRNM function of NODE JSYS
; UPD ID= 28, SNARK:<5.MONITOR>NSPSRV.MAC.91,  13-Jul-81 14:50:17 by GRANT
;Add resend queue checking interval to NSPTST
; UPD ID= 21, SNARK:<5.MONITOR>NSPSRV.MAC.90,  12-Jul-81 21:23:54 by GRANT
;IN DATCCS AND IN ACKCCS, RELEASE FREE SPACE AFTER DEQUEUING MESSAGE
; UPD ID= 2297, SNARK:<5.MONITOR>NSPSRV.MAC.89,   6-Jul-81 14:15:47 by GRANT
;TCO 5.1394 - Return correct error when OBJSRC fails in DSCNO2
; UPD ID= 2273, SNARK:<5.MONITOR>NSPSRV.MAC.88,  30-Jun-81 11:47:55 by GRANT
;Add inactivity checking interval to NSPTST
; UPD ID= 2266, SNARK:<5.MONITOR>NSPSRV.MAC.87,  27-Jun-81 22:10:21 by GRANT
;CHANGE BADMSG TO TOSMSG IN ACKMSG ROUTINE - JUST THROW AWAY A CA
;CHANGE BADMSG TO TOSMSG IN DOMSGQ ROUTINE - JUST THROW AWAY TRANSPORT INITS
; UPD ID= 2254, SNARK:<5.MONITOR>NSPSRV.MAC.86,  25-Jun-81 07:20:52 by GRANT
;TCO 5.1385 - Remove CIDON, revise BADMSG, add TOSMSG
;Don't zero LLLSC in INACOR
; UPD ID= 2215, SNARK:<5.MONITOR>NSPSRV.MAC.85,  18-Jun-81 16:53:15 by GRANT
;Fix bugs in NODE JSYS function NDGNT failure returns
; UPD ID= 2204, SNARK:<5.MONITOR>NSPSRV.MAC.84,  17-Jun-81 09:50:15 by GRANT
;Send ACKs to background task
;TCO 5.1371 - Check for resident free space threshold in OPNWRK, NSPSPC, and SNDCHK
; UPD ID= 2186, SNARK:<5.MONITOR>NSPSRV.MAC.83,  11-Jun-81 15:54:37 by MURPHY
;CHANGE TQNx TO TMNx REFLECTING CHANGE IN MACSYM
; UPD ID= 2172, SNARK:<5.MONITOR>NSPSRV.MAC.82,  10-Jun-81 15:48:23 by MURPHY
;MAKE TEMP BUGCHK'S INTO BUGHLT'S
; UPD ID= 2136, SNARK:<5.MONITOR>NSPSRV.MAC.81,   7-Jun-81 21:41:13 by GRANT
;ADD CHECKING INTERVAL TO NSPTMR
;MORE INTELLIGENCE NEEDED IN COMPAR
; UPD ID= 2105, SNARK:<5.MONITOR>NSPSRV.MAC.80,  28-May-81 14:59:02 by GRANT
;Remove calls to RETIDN - Network Management will handle this parameter
;Minor fixes in NTNRAC
; UPD ID= 2096, SNARK:<5.MONITOR>NSPSRV.MAC.79,  28-May-81 09:48:17 by GRANT
;Add range checking on timer value in NSNIAT
; UPD ID= 2092, SNARK:<5.MONITOR>NSPSRV.MAC.78,  27-May-81 16:49:37 by GRANT
;Implement NSP 3.2 logical link inactivity timers
;NTMAN% - add return list of active nodes
; UPD ID= 2043, SNARK:<5.MONITOR>NSPSRV.MAC.77,  20-May-81 09:20:14 by GRANT
;Eliminate DELNDF BUGxxx
; UPD ID= 1980, SNARK:<5.MONITOR>NSPSRV.MAC.76,  12-May-81 16:15:47 by GRANT
;Fix BP bug in NDXLT2 debug conditional
; UPD ID= 1968, SNARK:<5.MONITOR>NSPSRV.MAC.75,   8-May-81 16:41:07 by GRANT
;Give PSI when a message is retransmitted due to timeout
; UPD ID= 1960, SNARK:<5.MONITOR>NSPSRV.MAC.74,   7-May-81 11:52:29 by GRANT
;Obtain a new block of space for the remote descriptor in CLRBLK
; UPD ID= 1936, SNARK:<5.MONITOR>NSPSRV.MAC.73,   5-May-81 13:05:45 by GRANT
;Put CHKLLT in RJECT1 and NSPTMO
; UPD ID= 1933, SNARK:<5.MONITOR>NSPSRV.MAC.72,   4-May-81 15:25:16 by GRANT
;Fix failure returns from CALL SNDLS in RDINT and from CALL SNDDI in NSPTMO
;Add caller's PC as optional data to DELNDF
; UPD ID= 1907, SNARK:<5.MONITOR>NSPSRV.MAC.71,  30-Apr-81 08:37:38 by GRANT
;Generate PSI when LL is squashed due to timeout
; UPD ID= 1906, SNARK:<5.MONITOR>NSPSRV.MAC.70,  29-Apr-81 11:59:26 by GRANT
;Just return after a DELNDF BUGINF
; UPD ID= 1895, SNARK:<5.MONITOR>NSPSRV.MAC.69,  28-Apr-81 16:23:53 by GRANT
;Fix resident free space bugs - DIs and CCs not getting cleaned up
;<5.MONITOR>NSPSRV.MAC.68, 26-Apr-81 22:09:27, EDIT BY GRANT
; UPD ID= 1889, SNARK:<5.MONITOR>NSPSRV.MAC.67,  26-Apr-81 21:01:20 by GRANT
;TCO 5.1279 - DECNET PHASE II+ STUFF (TOPOLOGY, NETWORK MANAGEMENT, AND
;NSP MESSAGE TIMER)
;UPD ID= 1430, SNARK:<5.MONITOR>NSPSRV.MAC.62,   9-Jan-81 17:47:22 by MURPHY
;MOVE STMXDF HERE FROM NSPINT
; UPD ID= 1408, SNARK:<5.MONITOR>NSPSRV.MAC.61,   6-Jan-81 15:02:35 by MURPHY
;MAKE CERTAIN CODE RESIDENT THAT MAY NOW BE CALLED FROM SKED
; UPD ID= 1372, SNARK:<5.MONITOR>NSPSRV.MAC.60,  22-Dec-80 09:48:02 by GRANT
;TCO 5.1218 - Change error message in OPNDFT
; UPD ID= 1360, SNARK:<5.MONITOR>NSPSRV.MAC.59,  17-Dec-80 15:46:00 by MURPHY
;CHKLLT INSTEAD OF CHKMCB
; UPD ID= 1348, SNARK:<5.MONITOR>NSPSRV.MAC.58,  12-Dec-80 11:19:45 by MURPHY
;CHKMCB AT LSIDON
; UPD ID= 1318, SNARK:<5.MONITOR>NSPSRV.MAC.57,  26-Nov-80 07:17:11 by GRANT
;TYPO IN PREVIOUS EDIT
; UPD ID= 1316, SNARK:<5.MONITOR>NSPSRV.MAC.56,  25-Nov-80 16:58:23 by GRANT
;New version of NTMAN% JSYS - NSP node counters and formatted data return
; UPD ID= 1312, SNARK:<5.MONITOR>NSPSRV.MAC.55,  25-Nov-80 09:43:28 by GRANT
;TCO 5.1202 - Verification of message flags subtype field
; UPD ID= 1309, SNARK:<5.MONITOR>NSPSRV.MAC.54,  24-Nov-80 16:49:42 by MURPHY
;Make abort close release LL block immediately
;Certain subroutines need to be resident
; UPD ID= 1299, SNARK:<5.MONITOR>NSPSRV.MAC.53,  19-Nov-80 16:59:45 by MURPHY
;XON, XOFF OPTION FOR NVT
; UPD ID= 1291, SNARK:<5.MONITOR>NSPSRV.MAC.52,  18-Nov-80 16:45:58 by MURPHY
;NRT BUGS
; UPD ID= 1283, SNARK:<5.MONITOR>NSPSRV.MAC.51,  18-Nov-80 14:04:39 by GRANT
;TCO 5.1159 - more, don't shut off line if a Phase III transport msg appears,
; just throw the message away
; UPD ID= 1281, SNARK:<5.MONITOR>NSPSRV.MAC.50,  18-Nov-80 11:14:34 by GRANT
;TCO 5.1159 - again, put test in a better place
; UPD ID= 1274, SNARK:<5.MONITOR>NSPSRV.MAC.49,  14-Nov-80 17:52:09 by MURPHY
;NRT BUGS
; UPD ID= 1266, SNARK:<5.MONITOR>NSPSRV.MAC.48,  11-Nov-80 17:53:58 by MURPHY
;NRT bug - MCBQC
; UPD ID= 1225, SNARK:<5.MONITOR>NSPSRV.MAC.47,   3-Nov-80 16:29:36 by GRANT
;TCO 5.1187 - Make segment size calculation in STRMSG
; UPD ID= 1191, SNARK:<5.MONITOR>NSPSRV.MAC.46,  23-Oct-80 16:08:38 by GRANT
;Fix GETBYM arguments in GTASC0
; UPD ID= 1186, SNARK:<5.MONITOR>NSPSRV.MAC.45,  21-Oct-80 15:46:05 by GRANT
;Add segment size check to DOSRVS and FILLIN
; UPD ID= 1183, SNARK:<5.MONITOR>NSPSRV.MAC.44,  21-Oct-80 09:12:26 by GRANT
;TCO 5.1177 - Rewrite DEDCOR to fix bug and become more efficient
; UPD ID= 1178, SNARK:<5.MONITOR>NSPSRV.MAC.43,  20-Oct-80 17:12:20 by MURPHY
;MAKE GETBYT OPEN CODE (GETBYM MACRO)
; UPD ID= 1168, SNARK:<5.MONITOR>NSPSRV.MAC.42,  15-Oct-80 16:14:55 by GRANT
;Add flow control threshold logic in SQI
; UPD ID= 1150, SNARK:<5.MONITOR>NSPSRV.MAC.41,  10-Oct-80 16:19:28 by GRANT
;More of previous edit
; UPD ID= 1140, SNARK:<5.MONITOR>NSPSRV.MAC.40,   8-Oct-80 10:51:01 by GRANT
;TCO 5.1169 - Make PRSNAM call PARNO1
;<5.MONITOR>NSPSRV.MAC.39,  6-Oct-80 13:31:25, EDIT BY MURPHY
;<5.MONITOR>NSPSRV.MAC.38,  6-Oct-80 11:43:48, EDIT BY MURPHY
; UPD ID= 1124, SNARK:<5.MONITOR>NSPSRV.MAC.37,   5-Oct-80 15:02:30 by MURPHY
;DITTO
; UPD ID= 1119, SNARK:<5.MONITOR>NSPSRV.MAC.36,   3-Oct-80 12:21:08 by MURPHY
;DITTO
; UPD ID= 1111, SNARK:<5.MONITOR>NSPSRV.MAC.35,   3-Oct-80 01:00:34 by MURPHY
;MAKE NSP NOTIFY TTYSRV UPON RECEIPT OF DATA AND ACKS
; UPD ID= 1105, SNARK:<5.MONITOR>NSPSRV.MAC.34,   2-Oct-80 09:35:12 by MURPHY
;DITTO
; UPD ID= 1092, SNARK:<5.MONITOR>NSPSRV.MAC.33,   1-Oct-80 13:35:09 by MURPHY
;FIX ACVAR
; UPD ID= 1067, SNARK:<5.MONITOR>NSPSRV.MAC.32,  30-Sep-80 11:02:43 by GRANT
;TCO 5.1160 - make NSPRTH BUGCHK more meaningful
; UPD ID= 1065, SNARK:<5.MONITOR>NSPSRV.MAC.31,  30-Sep-80 10:46:39 by GRANT
;TCO 5.1159 - must reject Phase III Transport init message
; UPD ID= 1064, SNARK:<5.MONITOR>NSPSRV.MAC.30,  30-Sep-80 10:31:05 by GRANT
;Fix sequential input again and init NMAPLK in NSPINI
; UPD ID= 1061, SNARK:<5.MONITOR>NSPSRV.MAC.29,  30-Sep-80 10:16:15 by MURPHY
;NVT bugs
; UPD ID= 1059, SNARK:<5.MONITOR>NSPSRV.MAC.28,  26-Sep-80 13:30:48 by GRANT
;Add NTMAN% JSYS
; UPD ID= 1056, SNARK:<5.MONITOR>NSPSRV.MAC.27,  26-Sep-80 12:12:52 by MURPHY
;Make BLKULK preserve T2; fix various NVT bugs
; UPD ID= 1036, SNARK:<5.MONITOR>NSPSRV.MAC.26,  24-Sep-80 11:48:18 by GRANT
;TCO 5.1153 - NETSQI must save T2 over the call to BLKULK
; UPD ID= 1023, SNARK:<5.MONITOR>NSPSRV.MAC.25,  16-Sep-80 16:07:18 by GRANT
;Change MONX01 to NSPX26 in NDSIC routine
; UPD ID= 1019, SNARK:<5.MONITOR>NSPSRV.MAC.24,  16-Sep-80 15:34:14 by GRANT
;TCO 5.1146 - Fix free space bug in MTRDIN
; UPD ID= 1007, SNARK:<5.MONITOR>NSPSRV.MAC.23,  11-Sep-80 18:17:22 by GRANT
;Change MONX01 to MONX06 in GETBLK routine
; UPD ID= 943, SNARK:<5.MONITOR>NSPSRV.MAC.21,  20-Aug-80 20:09:04 by MURPHY
;Merge FILNSP into NSPSRV
; UPD ID= 920, SNARK:<5.MONITOR>NSPSRV.MAC.20,  19-Aug-80 15:17:32 by MURPHY
;File open mode 1 for small segsiz
; UPD ID= 902, SNARK:<5.MONITOR>NSPSRV.MAC.19,  14-Aug-80 22:54:49 by MURPHY
;Locks again
; UPD ID= 892, SNARK:<5.MONITOR>NSPSRV.MAC.18,  13-Aug-80 18:21:01 by MURPHY
;Handle locks at scheduler level
; UPD ID= 846, SNARK:<5.MONITOR>NSPSRV.MAC.17,   6-Aug-80 17:32:48 by MURPHY
;ULOKLL again
; UPD ID= 845, SNARK:<5.MONITOR>NSPSRV.MAC.16,   6-Aug-80 14:25:32 by MURPHY
;BUGCHK at ULOKLL if lock not already locked; make few more routines resident
; UPD ID= 820, SNARK:<5.MONITOR>NSPSRV.MAC.15,   1-Aug-80 13:21:31 by GRANT
;TCO 5.1119 - Fix cause of "overly OKINT" BUGCHKs when DN20 gets reloaded
; UPD ID= 790, SNARK:<5.MONITOR>NSPSRV.MAC.14,  23-Jul-80 20:13:13 by MURPHY
;MORE OF THE SAME
; UPD ID= 777, SNARK:<5.MONITOR>NSPSRV.MAC.13,  22-Jul-80 17:07:09 by MURPHY
;MAKE A FEW ROUTINES GLOBAL
; UPD ID= 753, SNARK:<5.MONITOR>NSPSRV.MAC.12,  11-Jul-80 17:05:41 by MURPHY
;MAKE VARIOUS THINGS RESIDENT WITH VIEW TOWARD MAKING THEM RUN AT SKED LEVEL
; UPD ID= 623, SNARK:<5.MONITOR>NSPSRV.MAC.11,  11-Jun-80 11:06:36 by GRANT
;Wrong AC being loaded in PRUNE
; UPD ID= 621, SNARK:<5.MONITOR>NSPSRV.MAC.10,  10-Jun-80 13:23:07 by MURPHY
; UPD ID= 606, SNARK:<5.MONITOR>NSPSRV.MAC.9,   5-Jun-80 10:23:04 by GRANT
;More of UPD ID= 330
; UPD ID= 605, SNARK:<5.MONITOR>NSPSRV.MAC.8,   5-Jun-80 08:40:19 by ENGEL
;MAKE ASCIIZ RESIDENT
; UPD ID= 593, SNARK:<5.MONITOR>NSPSRV.MAC.7,   3-Jun-80 09:44:15 by ENGEL
;MAKE NODINI RESIDENT
; UPD ID= 590, SNARK:<5.MONITOR>NSPSRV.MAC.6,   3-Jun-80 09:03:33 by ENGEL
;FIX ONEBYT
; UPD ID= 588, SNARK:<5.MONITOR>NSPSRV.MAC.5,   2-Jun-80 17:24:28 by ENGEL
;MAKE PORTIONS OF NODINI CODE RESIDENT
; UPD ID= 502, SNARK:<5.MONITOR>NSPSRV.MAC.4,   1-May-80 15:02:52 by GRANT
;TCO 5.1031 - Make CI processing distinguish between busy and non-existent
; UPD ID= 477, SNARK:<5.MONITOR>NSPSRV.MAC.3,  24-Apr-80 16:52:51 by GRANT
;In DEDMCB, use DCN instead of DTEN for valid port number test -
;DTEN won't work on the 2020
; UPD ID= 455, SNARK:<5.MONITOR>NSPSRV.MAC.2,  22-Apr-80 14:02:03 by MURPHY
;FIX UP ENTRY SEQUENCE IN INFERIOR FORK
; UPD ID= 351, SNARK:<4.1.MONITOR>NSPSRV.MAC.421,  25-Mar-80 08:58:26 by GRANT
;Undo the previous edit
; UPD ID= 339, SNARK:<4.1.MONITOR>NSPSRV.MAC.420,  17-Mar-80 18:11:26 by GRANT
;At OUTRR7, don't include SEGNUM bytes in MSDTC count
; UPD ID= 330, SNARK:<4.1.MONITOR>NSPSRV.MAC.419,  14-Mar-80 09:58:02 by GRANT
;In STRSAV, reverse the search order of the DTEs when looking for the MCB
; UPD ID= 226, SNARK:<4.1.MONITOR>NSPSRV.MAC.418,  25-Jan-80 13:30:56 by GRANT
;TCO 4.2599 - DEDMCB should not clear the loopback word
; UPD ID= 190, SNARK:<4.1.MONITOR>NSPSRV.MAC.417,   8-Jan-80 13:34:55 by GRANT
;Fix DTE range check in DEDMCB
; UPD ID= 124, SNARK:<4.1.MONITOR>NSPSRV.MAC.416,  10-Dec-79 15:40:10 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= 85, SNARK:<4.1.MONITOR>NSPSRV.MAC.412,   3-Dec-79 15:06:50 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
;Previous edit lines removed
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT  (C)  DIGITAL  EQUIPMENT  CORPORATION  1976, 1984.
;ALL RIGHTS RESERVED.


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

;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
NSPSW==1			;SWITCH FOR DEBUGGING

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	Device Dispatch Vectors for SRV: and DCN: Devices

;FOR DEVICE SRV

	SWAPCD

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

;FOR THE DCN DEVICE

DCNDTB::DCNDTL
	DTBDSP (NETDIR)		;DIR SET
	DTBDSP (DCNSET)		;NAME LOOKUP
	DTBDSP (EXTSET)		;EXTENSION LOOKUP
	DTBDSP (VERSET)		;VERSION LOOKUP
   REPEAT 3,<
	DTBBAD (DESX9)>	;ILLEGAL FUNCTIONS
	DTBDSP (DCNOPN)		;OPEN
	DTBDSP (NETSQI)		;INPUT
	DTBDSP (NETSQO)		;OUTPUT
	DTBDSP (NETCLZ)		;CLOSE
   REPEAT 7,<
	DTBBAD (DESX9)>	;ILLEGAL FUNCTIONS
	DTBDSP (NTMTOP)		;MTOPR
   REPEAT 2,<DTBBAD (DESX9)>	;ILLEGAL FUNCITONS
	DTBDSP (NETSQR)		;SOUTR
	DTBDSP (RFTADN)		;NO TIME AND DATE
	DTBDSP (SFTADN)		;NO TIME AND DATE
	DTBDSP (NETINP)		;SET FOR INPUT
	DTBDSP (NETOUP)		;SET FOR OUTPUT
	DTBDSP (NETATR)		;PARSE ATTRIBUTES
	DTBSKP			;RELEASE JFN
	DCNDTL==:.-DCNDTB
SUBTTL	GTJFN Routines

;ROUTINES CALLED FROM GTJFN PROCESSING TO LOOK UP FILE NAMES

;NAME LOOKUP FOR SRC DEVICE

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

;ROUTINE TO DO NAME LOOKUP FOR DCN DEVICE

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

;EXTENSION CHECKER

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

;ROUTINE TO LOOK UP DIRECTORY COMPONENT IN NETWORK FILE SPEC

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

;VERSION LOOKUP

VERSET::TQNN <STEPF>		;TRYING TO STEP?
	JRST OKRET		;NO. ALLOW IT THEN
	JUMPGE T1,OKRET		;IF NOT STEPPING, OKAY
	RETBAD (GJFX18,<OKINT>)	;ALL ELSE IS WRONG
;ROUTINE TO ASSIGN WINDOW PAGES TO A JFN.
;ACCEPTS:	NORMAL FILE SYSTEM REGISTER (JFN,ETC...)
;RETURNS:	+1	FAILED
;		+2	SUCCESS.

ASGWDW::SETZM FILWND(JFN)
	SETZM FILBCT(JFN)	;AND CLEAR COUNTS
	TQNN <READF>		;WANT READ ON THIS FILE?
	JRST ASGWRT		;NO. TRY WRITE
	CALL ASGPAG		;GET A JSB PAGE
	 RETBAD (MONX02)	;COULDN'T
	HRRM T1,FILWND(JFN)	;SAVE WINDOW PAGE
	LDB T3,PBYTSZ		;GET BYTE SIZE
	CALL MAKINP		;GET A POINTER FOR INPUT
	MOVEM T1,FILBNO(JFN)	;INIT INPUT POINTER
ASGWRT:	TQNN <WRTF>		;WANT WRITE
	RETSKP			;NO ALL DONE
	CALL ASGPAG		;GET A PAGE FOR OUTPUT
	 JRST [	SKIPE T1,FILWND(JFN) ;FAILED. HAVE READ WINDOW?
		CALL RELPAG	;RELEASE THE INPUT PAGE
		SETZM FILWND(JFN) ;NOTE NO PAGE WAS ASSIGNED
		SETZM FILBNO(JFN) ;PREVENT RELEASE OF FREE SPACE BY RLJFN
		RETBAD (MONX02)] ;AND FAIL
	HRLM T1,FILWND(JFN)	;STORE WINDOW
	RETSKP			;AND DONE
;ROUTINE TO COMPUTE NUMBER OF USEFUL BYTES IN A JSB STRING.
;CALLED FROM ROUTINES THAT PROCESS NETWORK FILE NAMES.
;ACCEPTS:	T1/FREE BLOCK ADDRESS
;	TRVAR <NTCNT,NTPNT,.....>
;RETURNS:	+1 ALWAYS WITH COUNT IN NTCNT AND POINTER IN NTPNT

COMPUT:	HRRZ T3,0(T1)		;GET COUNT OF WORDS IN BLOCK
	SOS T3			;DISCOUNT THE HEADER
	IMULI T3,5		;GET BYTE COUNT
	AOS T3			;ADD IN FINAL TERMINATOR
	HRLI T1,(<POINT 7,0,35>) ;GET STRING POINTER TO THE BLOCK
	MOVEM T1,NTPNT		;AND SAVE THE STARTING POINTER
	CALL CMPLEN		;GET LENGTH OF STRING
	MOVEM T3,NTCNT		;SAVE COUNT
	RET			;DONE, RETURN


;CMPLEN - ROUTINE TO COMPUTE LENGTH OF STRINGS
;
;ACCEPTS IN T1/ POINTER TO START OF STRING
;	    T3/	MAX NUMBER OF BYTES IN STRING
;		CALL CMPLEN
;RETURNS: +1 ALWAYS, WITH T3/ ACTUAL NUMBER OF BYTES IN STRING

CMPLEN::STKVAR <CPLCNT>
	MOVEM T3,CPLCNT		;STARTING COUNT
	MOVE T2,[POINT 0,0,2]	;GET DUMMY POINTER
	SETZ T4,
	SIN			;FIND NUMBER OF USEFUL BYTES IN THE STRING
	JUMPE T3,R		;IF NO NULLS, ALL SET
	SUB T3,CPLCNT		;FOUND A NULL THEN. GET CHARACTERS SKIPPED
	MOVNS T3		;GET COUNT
	RET			;AND DONE

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

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

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

;	WITH TRVAR'S FILLED IN

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

DCNNAM::CALL COMPUT		;FIND COUNT
	CALLRET PRSNAM		;GO PARSE NAME FIELD



;PRSNAM - ROUTINE TO DO THE PARSING OF THE NAME
;
;ACCEPTS:	IN TRVAR'S
;	NTPNT	CURRENT TEXT POINTER
;	NTCNT	CURRENT BYTE COUNT
;		CALL PRSNAM
;RETURNS: +1	 FAILED, SYNTAX ERROR
;	  +2	SUCCESS, WITH APPROPRIATE TRVARS FILLED IN

PRSNAM::CALL NETDSH		;GO PICK OFF HOST NAME
	SKIPN NTCNT		;MORE IN THE STRING?
	RETBAD (DCNX1)		;NO. SYNTAX ERROR THEN
	SETOM NTHSC		;ASSUME LOCAL CONNECTION
	SOSG T3			;HAVE A REAL STRING?
	JRST DCNOBJ		;NO. GO LOOK FOR OBJECT THEN
	CAILE T3,MAXHST		;WITHIN BOUNDS?
	RETBAD (COMX19)		;NO. STRING TOO LONG
	MOVEM T1,NTHST		;SAVE POINTER TO HOST
	MOVEM T3,NTHSC		;AND SAVE COUNT
	AOS T1			;POINT TO THE ACTUAL TEXT
	HRLI T1,440700		;MAKE A BYTE POINTER FOR PARSING
	MOVE T2,T3		;GET NODE NAME CHARACTER COUNT
	CALL PARNO1		;SEE IF VALID NODE NAME SYNTAX
	 RETBAD ()		;INVALID NODE NAME - RETURN THE ERROR
DCNOBJ:	CALL NETDSH		;GO FIND OBJECT
	CAIG T3,1		;HAVE A REAL STRING?
	RETBAD (DCNX3)		;NO. INVALID OBJECT THEN
	LDB T4,NTPNT		;GET BACK TERMINATOR
	MOVEM T4,NTOBJ		;SAVE IT
	SETZ T4,		;GET A NULL
	DPB T4,NTPNT		;TIE OFF STRING
	CALL OBJLOK		;GO LOOK UP THE OBJECT
	 RETBAD (DCNX3)		;NO SUCH
	EXCH T1,NTOBJ		;SAVE OBJECT
	DPB T1,NTPNT		;AND PUT BACK TERMINATOR
	JRST SRCNOB		;FINISH UP ON DESCRIPTOR

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

NETEXT:	CALL COMPUT		;GET COUNT
	MOVE T1,NTCNT		;GET THE COMPUTED COUNT
	CAILE T1,TSKMAX		;WITHING RANGE
	RETBAD (DCNX12)		;NO. TOO LONG
	RETSKP			;AND DONE
SUBTTL	Routines to open DCN: or SRV: links

;COMMON ROUTINE FOR OPENF JSYS. THIS CODE IS CALLED BY BOTH SRCOPN
;AND DCNOPN TO ASSIGN A LL BLOCK, ASSIGN A LL ADDRESS, AND FILL
;IN COMMON VALUES.
;	RETURNS +1	FAILED. T1/ ERROR CODE
;		+2 SUCCESS	T1/ LL BLOCK ADDRESS
;			 AND LL TREE LOCKED

OPNDNC::TDZA T4,T4		;NOTE OPENING DCN:
OPNSRC::SETOM T4		;NOTE OPENING SRV:
	TQZE <RNDF>		;WANT APPEND?
	TQO <WRTF>		;YES. FORCE ON WRITE THEN
	TQNN <READF,WRTF>	;WANT SOME FORM OF ACCESS?
	RETBAD (OPNX14)		;NO. ILLEGAL OPEN
	LDB T2,PBYTSZ		;LOOK AT REQUESTED BYTE SIZE
	CAIE T2,10		;BYTES?
	CAIN T2,7		;OR ASCII?
	JRST BYTGUD		;YES. ACCEPTS IT
	CAIE T2,44		;-10 WORD MODE?
	RETBAD (SFBSX2)		;NO. ILLEGAL BYTE SIZE
BYTGUD:	HRRZ T1,FILNEN(JFN)	;GET ADDRESS OF STRING BLOCK
	ADDI T1,1		;GET ADDRESS OF STRING
	LDB T2,PBYTSZ		;GET BYTESIZE OF OPENF
	SKIPE T4		;OPENING DCN: ?
	JRST [	CALL OPNSWK	;NO, CALL WORK ROUTINE TO OPEN SRV:
		 RETBAD ()	;FAILED, RETURN ERROR CODE
		JRST SAVLLB ]	;GO SAVE LL BLOCK ADDRESS IN JFN BLOCK
	CALL OPNDWK		;CALL WORK ROUTINE TO OPEN DCN:
	 RETBAD ()		;FAILED, RETURN ERROR CODE


SAVLLB:	MOVEM T1,FILLLB(JFN)	;SAVE BLOCK ADDRESS
   IFN NSPSW,<
	MOVEI T2,LLSIGN		;GET LL BLOCK UNIQUE INDICATOR
	MOVEM T2,LLDBUG(T1)	;PUT IT IN BLOCK (LLMSIT IS NOT USED)
   >
	TQNE <READF>		;WANT BI-DIRECTIONAL LINK?
	CALL SETOPI		;SET INPUT FLAG FOR LOGICAL LINK
	TQNE <WRTF>		;WANT WRITE?
	CALL SETOPW		;SET OUTPUT FLAG FOR LOGICAL LINK
	CALL STMXDF		;SET INPUT/OUTPUT MAX QUEUE DEFAULTS
	RETSKP			;AND DONE
;STMXDF - SET MAX INPUT/OUTPUT QUEUE DEFAULTS
;
;ACCEPTS:	T1/ ADDRESS OF LOGICAL LINK BLOCK
;
;RETURNS:	+1,ALWAYS
;
;DESTROYS T2

STMXDF::MOVEI T2,MAXSEG		;ASSUME READ ONLY
	OPSTR <SKIPE>,LLOPW,(T1) ;OPEN FOR WRITE AS WELL?
	MOVEI T2,MAXSG1		;YES. USE A SMALLER NUMBER
	STOR T2,LLMQI,(T1)	;SAVE THE INPUT QUEUE LENGTH (ALSO FLOW CONTROL)
	MOVEI T2,MAXSGQ		;SET OUTPUT QUEUE LENGTH
	STOR T2,LLMQO,(T1)	;SAVE IN LINK BLOCK
	RET


;VERIFY A LOGICAL LINK BLOCK
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;RETURNS:	+1 PASSED THE TEST

   IFN NSPSW,<
	RESCD

LLSIGN==101010			;THE VERIFICATION SYMBOL

CHKLLB:	PUSH P,T2		;PRESERVE T2
	MOVE T2,LLDBUG(T1)	;GET THE VERIFICATION WORD
	CAIE T2,LLSIGN		;IS IT GOOD?
	BUG. (HLT,NSPLLC,NSPSRV,SOFT,<NSPSRV: Logical link block check failed>,<<T1,BADBLK>>,<

Cause:	Logical link block verification failed.  NSP believes a resident free
	space block contains a logical link block but something is wrong.
	Most likely, resident free space has been clobbered.

Data:	BADBLK - the address of the block

>)
	POP P,T2		;OK, RETRIEVE T2
	RET			;YES

	SWAPCD
   >
;ROUTINE CALLED FROM THE OPENF JSYS TO OPEN A DCN NETWORK CONNECTION

DCNOPN::TRVAR <NTCNT,NTPNT,NTOBJ,NTDSC,NTDSS,NTHST,NTHSC,NTCIB>
	GTOKM (.GODNA,,[RET]) ;ASK ACJ TO GIVE ITS BLESSING
	HLRZ T1,FILNEN(JFN)	;GET NAME FOR THE CONNECTION
	CALL DCNNAM		;GO PARSE THE NAME FIELD
	 RETBAD ()		;FAILED
	CALL OPNDNC		;GO DO COMMON SETUP
	 RETBAD () 		;FAILED
	CALL ASGWDW		;NOW SET UP WINDOWS
	 RETBAD (,<CALL CLENUP>) ;FAILED, RETURN ERROR
	MOVE T1,FILLLB(JFN)	;GET ADDRESS OF LOGICAL LINK BLOCK
	HRL T2,NTHSC		;GET COUNT OF HOST STRING BYTES
	HRR T2,NTDSC		;GET COUNT OF DESCRIPTOR STRING BYTES
	MOVE T3,NTHST		;GET ADDRESS OF BLOCK HOLDING HOST NAME STRING
	MOVE T4,NTDSS		;GET POINTER TO DESCRIPTOR STRING
	CALL STRSAV		;GO MOVE PERMANENT LL STRINGS
	 RETBAD (,<CALL CLENUP>) ;FAILED, RETURN ERROR
	MOVE T1,FILLLB(JFN)	;GET LOGICAL LINK BLOCK ADDRESS
	LOAD T2,FLATL,(JFN)	;GET POINTER TO ATTRIBUTE LIST
	HRL T3,NTOBJ		;GET OBJECT
	HRR T3,NTDSC		;GET DESCRIPTOR COUNT
	MOVE T4,NTDSS		;GET DESCRIPTOR POINTER
	CALL CRTLNK		;GO CREATE THE LOGICAL LINK
	 RETBAD (,<CALL CLENUP>) ;FAILED
	RETSKP			;DONE, RETURN SUCCESS


;CLENUP - ROUTINE TO CLEAN UP JFN BLOCK IF OPEN OF DCN: FAILS
;
;ACCEPTS IN JFN/ OFFSET TO JFN BLOCK
;		CALL CLENUP
;RETURNS: +1 ALWAYS

CLENUP:	STKVAR <CLNERR>
	MOVEM T1,CLNERR		;SAVE ERROR CODE
	DECR DCCUR		;ONE LESS LINK ON FAILURE
	MOVE T1,FILLLB(JFN)	;GET ADDRESS OF LOGICAL LINK BLOCK
	CALL DELNOD		;FREE THE NODE
	HLRZ T1,FILWND(JFN)	;GET WINDOW PAGE ADDRESS
	SKIPE T1		;ANY WINDOW PAGE ASSIGNED YET ?
	CALL RELPAG		;YES, RELEASE IT
	HRRZ T1,FILWND(JFN)	;GET OTHER WINDOW PAGE
	SKIPE T1		;ANY ASSIGNED ?
	CALL RELPAG		;YES, RELEASE IT ALSO
	SETZM FILBNO(JFN)	;PREVENT RELEASE OF SPACE BY RLJFN
	CALL ULOKLL		;UNLOCK THE LL TREE
	MOVE T1,CLNERR		;RESTORE ERROR CODE
	RET
SUBTTL	MTOPR Routines

NTMTOP:	TQNN <OPNF>		;CHECK FOR OPENED
	RETBAD (CLSX1)		;NO IT IS ILLEGAL
	CALL NETINP		;SET UP FOR INPUT
	MOVE T1,FILLLB(JFN)	;MUST LOCK UP BLOCK
	CALL BLKLLK		;DO IT
	 JRST [	TQO BLKF	;CANNOT LOCK IT, INDICATE BLOCK NEEDED
		RET ]		;RETURN AND TRY AGAIN LATER
	XCTU [HRRZ T2,2]	;GET FUNCTION CODE
	CAIL T2,.MOACN		;TOO SMALL?
	CAILE T2,.MOSNH		;OR TOO BIG?
	SKIPA			;ILLEGAL RETURN AN ERROR
	CALLRET @NTMTTB-.MOACN(T2) ;DO THE FUNCTION
	MOVE T1,FILLLB(JFN)	;ILLEGAL, GET LOGICAL LINK BLOCK ADDRESS
	CALL BLKULK		;UNLOCK THE BLOCK
	RETBAD (MTOX1)		;FAIL

NTMTTB: DTBDSP (MTASGN)		;24 - .MOASN - ASSIGN CONNECT INTERRUPT CHANNEL
	DTBDSP (NTSTS)		;25 - .MORLS - READ LINK STATUS
	DTBDSP (NTRHN)		;26 - .MORHN - READ FOREIGN HOST NAME
	DTBDSP (NTRTN)		;27 - .MORTN - READ LINK TASK NAME
	DTBDSP (NTRUS)		;30 - .MORUS - READ USER STRING
	DTBDSP (NTRPW)		;31 - .MORPW - READ PASSWORD
	DTBDSP (NTRAC)		;32 - .MORAC - READ ACCOUNT STRING
	DTBDSP (NTRDA)		;33 - .MORDA - READ OPTIONAL DATA
	DTBDSP (NTRCN)		;34 - .MORCN - READ CONNECT OBJECT NUMBER
	DTBDSP (MTRDIN)		;35 - .MORIM - READ INT MESSAGE
	DTBDSP (MTSNIN)		;36 - .MOSIM - SEND INT MESSAGE
	DTBDSP (NTRCOB)		;37 - .MOROD - READ OBJ-DESC OF CONNECT OBJECT
	DTBDSP (NTMTCZ)		;40 - .MOCLZ - CLOSE/REJECT A CONNECTION
	DTBDSP (NTACPT)		;41 - .MOCC - ACCEPT A CONNECTION
	DTBDSP (MTGSS)		;42 - .MORSS - GET LINK SEGMENT SIZE
	DTBDSP (NTANT)		;43 - .MOANT - ATTACH NETWORK TERMINAL
	DTBDSP (NTSNH)		;44 - .MOSNH - SET NETWORK HOST FOR TERMINAL
;ATTACH NETWORK TERMINAL TO JOB
; JFN, etc. setup by .MTOPR entry code
;returns with LL connected to terminal and JFN released
; T2/ terminal line number assigned

NTANT:	MOVE T1,FILLLB(JFN)	;GET LL BLOCK
	CALL ASMCB		;ASSIGN "MCB" TERMINAL AND CONNECT TO LL
	IFNSK.			;COULDN'T
	   MOVE T1,FILLLB(JFN)	;RETRIEVE LL BLOCK
	   CALL BLKULK		;RELEASE THE LOCK
	   RETBAD (ANTX01)	;RETURN ERROR
	ENDIF.
	UMOVEM T1,T2
	SETZ T1,
	EXCH T1,FILLLB(JFN)	;DISASSOCIATE JFN FROM LL
	SETONE LLFRK,(T1)	;NO FORK
	SETZRO <LLDRC,LLPII,LLPIC>,(T1) ;NO INTERRUPTS
	CALL BLKULK		;UNLOCK LL
	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 FILBNO(JFN)
	CALL RELJFN
	RETSKP

;SET NETWORK HOST
; T1/ JFN of LL (JFN, STS, etc setup at .MTOPR entry)
; T2/ ptr to arg block:
;	0 - size in words (including this one)
;	1 .SHTTY - terminal ident
;	2 .SHESC - flags,,escape char
; returns with line connected to LL, JFN unchanged

NTSNH:	SAVEAC <Q1>
	UMOVE Q1,T3		;GET ARG PTR
	UMOVE T1,.SHTTY(Q1)
	CALL [	SAVEAC <JFN,STS,DEV> ;KEEP THESE FOR ORIGINAL JFN
		CALLRET CHKTTM]	;GET LINE NUMBER IN T2
	IFNSK.			;COULDN'T
	   MOVE T1,FILLLB(JFN)	;RETRIEVE LL BLOCK
	   CALL BLKULK		;RELEASE THE LOCK
	   RETBAD (ANTX01)	;RETURN ERROR
	ENDIF.
	MOVE T1,FILLLB(JFN)
	UMOVE T3,.SHESC(Q1)	;GET ESC CHAR AND FLAGS
	CALL TTSETH
	IFNSK.
	  CALL BLKULK		;FAILED, UNLOCK LL
	  RETBAD()
	ENDIF.
	CALL BLKULK		;UNLOCK LL
	RETSKP
;SET INTERRUPT CHANNEL NUMBERS

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

; HERE ON AN ERROR SETTING THE INTERRUPT CHANNELS

NTMERR:	EXCH T1,FILLLB(JFN)	;SAVE ERROR CODE, GET LL BLOCK ADDRESS
	CALL BLKULK		;UNLOCK THE BLOCK
   IFN NSPSW,<
	CALL CHKLLB
   >
	EXCH T1,FILLLB(JFN)	;RESTORE LL BLOCK ADDRESS, GET ERROR CODE
	RETBAD ()		;FAIL

	ENDAV.			;END ACVAR
;READ LINK STATUS

NTSTS:	CALL RDSTS		;GO GET THE STATUS
	UMOVEM T3,3		;RETURN RESULT
	CALL BLKULK		;FREE BLOCK
	RETSKP			;AND DONE
;UNDO OUTPUT

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

;UNDO INPUT

NETUIN::TQZN <FILINP>		;NOW DOING INPUT?
	RET			;NO. ALL DONE
	MOVE T1,FILLLB(JFN)	;GET LL BLOCK
	CALL SKPFLI		;IS FLOW TO THE FILE-SYSTEM ?
	 RET			;NO. ALL DONE
	MOVE T1,FILCNT(JFN)	;GET COUNT
	SKIPGE T1		;VALID COUNT?
	SETZM T1		;ONLLY ALLOW DOWN TO ZERO
	HRRM T1,FILBCT(JFN)	;SAVE IT
	MOVE T1,FILBYT(JFN)	;GET BYTE POINTER
	MOVEM T1,FILBNO(JFN)	;SAVE IT
	RET			;AND DONE
SUBTTL	Sequential I/O JSYS's.

;SEQUENTIAL OUTPUT.

NETSQO:	ASUBR <NETCHR>		;SAVE THE CHARACTER
	MOVE T1,FILLLB(JFN)	;GET LL BLOCK ADDRESS
	CALL BLKLLK		;LOCK IT UP
	 JRST [	TQO <BLKF>	;CANNOT LOCK IT,
		RETBAD() ]	; WAIT UNTIL LOCK IS FREE
	CALL GETSTA		;GO GET CURRENT LOGICAL LINK STATE
	JRST @SQOSTA-1(T2)	;AND DO PROPER THING

NETSQ1::SOSGE FILCNT(JFN)	;HAVE ANY CHARACTERS?
	JRST [	CALL OUTRR	;AND SEND SOME MESSAGES
		 RETBAD()	;FAILED
		CALL NETOUP	;SET UP FOR OUTPUT
		MOVE T1,FILLLB(JFN) ;GET BACK LL BLOCK
		JRST NETSQ1]	;AND TRY AGAIN
	MOVE T2,NETCHR		;GET BYTE
	IDPB T2,FILBYT(JFN)	;STASH BYTE
	CALLRET BLKULK		;RELEASE BLOCK AND RETURN

;FORCE OUT ALL BUFFERED CHARACTERS. CALLED FROM SOUTR

NETSQR:	MOVE T1,FILLLB(JFN)	;GET LL BLOCK ADDRESS
	CALL BLKLLK		;LOCK IT
	 JRST [	TQO <BLKF>	;CANNOT LOCK IT,
		RETBAD() ]	; WAIT UNTIL LOCK IS FREE
	CALL GETSTA		;GO GET CURRENT LOGICAL LINK STATE
	JRST @SQOOTR-1(T2)	;DO WORK

NETSR1::CALL SETEOM		;NOTE THAT NEXT OUTPUT IS AN ENTIRE MESSAGE
	CALL OUTRR		;DO THE WORK
	 RETBAD()		;FAILED
	MOVE T1,FILLLB(JFN)	;GET BACK LL BLOCK
	CALL BLKULK		;UNLOCK BLOCK
	RETSKP			;AND RETURN GOOD
SUBTTL	NSP Initialization


;NAMINI INITIALIZES NODE NAME TO "TOPS20"

	RESCD

NAMINI::UNLOCK NODLOK		;INIT THE "REACHABLE NODES TABLE" LOCK
	UNLOCK NMAPLK		;INIT THE "NODE NAME MAPPING TABLE" LOCK
	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
	CALL ININOD		;INIT REACHABLE NODES TABLE
	 BUG.(INF,NDINIT,NSPSRV,SOFT,<NSP - Could not add first entry to node table>,,<

Cause:	This BUG is not documented yet.

Action:

Data:

>)
	RET

;ROUTINE TO INIT NETWORK DATA BASES,ETC.

	SWAPCD			;SWAPPABLE

NSPINI::ACVAR <INDEX>		;INDEX INTO ACKLST
	MOVEI INDEX,AKLSTL-1	;GET LENGTH OF ACK LIST
NSPIN1:	MOVEI T1,ACKLEN+MSHDR	;GET NUMBER OF WORDS NEEDED FOR AN ACK MSG
	CALL GETRES		;GET THE SPACE
	IFSKP.			;OK
	   MOVEM T1,ACKLST(INDEX)  ;SAVE THE ADDRESS
	ELSE.			;COULDN'T GET SPACE
	   SETZM ACKLST(INDEX)	;NO ENTRY IN LIST
	ENDIF.
NSPIN2:	SOJGE INDEX,NSPIN1	;IF NOT DONE, GO GET ANOTHER
	UNLOCK LLLLCK		;UNLOCK LOCK
;	UNLOCK OUTLOK		;INITIALIZE LOCK ON BACKGROUND TASK'S QUEUE
;	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
	MOVEI T1,SEGSIZ		;GET DEFAULT SEGMENT SIZE
	MOVEM T1,SEGSZ		;SET IT UP
	MOVEI T1,NSINTM		;GET DEFAULT INACTIVITY TIMEOUT VALUE
	MOVEM T1,NSINAC		;SET IT UP
	MOVEI T1,NSLDWD		;GET DEFAULT LOCAL DELAY WEIGHT
	MOVEM T1,NSLDWS		;SET IT
	MOVEI T1,NSLDFD		;GET DEFAULT LOCAL DELAY FACTOR
	MOVEM T1,NSLDFS		;SET IT
	MOVEI T1,NSTRYD		;GET DEFAULT RETRANSMIT COUNT
	MOVEM T1,NSTRYS		;SET IT
	SETZM LSTINT		;INIT THE INACTIVITY TIME CHECKER
	SETZM LLNUM		;INIT THE IN-USE LL COUNT
	MOVX T1,1B1		;MAKE FORK HAVE ALL CAPS
	SETZ T2,
	CFORK			;GET A FORK
	 BUG.(HLT,NSPFRK,NSPSRV,SOFT,<NSPINI-CFORK FAILED>,<<T1,REASON>>,<

Cause:	When the system comes up, a fork is created under JOB 0 in which
	the DECnet NSP background task runs.  The monitor was unable to
	create the fork.

Data:	REASON - the reason code returned by the CFORK JSYS when it failed.

>)
	MOVE T2,[MSEC1,,TSKINI]	;THE STARTING ADDRESS
	MSFRK			;START IT
	MOVX T1,.NDOFF		;SAY WE ARE
	STOR T1,SCSTA		; OFF - NML MUST TURN US ON
	RET			;DONE

	ENDAV.
; INITIALIZE TABLE OF KNOWN NODES

ININOD:	NOINT			;NO INTERRUPTIONS
	LOCK NODLOK		; WHILE TABLE IS LOCKED
	SETZM NODTBL		;ZERO
	HRLI T1,NODTBL		; THE
	HRRI T1,NODTBL+1	;  ENTIRE
	BLT T1,NODTBL+<BIGNOD/22>  ;   TABLE
	UNLOCK NODLOK		;DONE WITH
	OKINT			; THE LOCK
	MOVE T1,OURNUM		;GET OUR NODE NUMBER
	MOVX T2,.NDSON		;SAY NODE IS TO BE ADDED
	MOVEI T3,2		;WE ARE PHASE II
	CALL ADDNOD		;PUT US IN
	 RETBAD ()		;FAILED
	RETSKP			;SUCCESS
;ADDNOD - ROUTINE TO ADD A NODE TO THE TABLE OF REACHABLE NODES
;
;ACCEPTS: T1/ NODE NUMBER
;	  T2/ STATE OF NODE
;	  T3/ 2 - IF DECNET PHASE II
;	      3 - IF DECNET PHASE III
;
;RETURNS: +1	FAILED
;	  +2	SUCCESS, NODE ADDED IF NOT ALREADY IN TABLE

ADDNOD:	CAIN T2,.NDSOF		;NODE OFF?
	JRST [CALL REMNOD	;YES, REMOVE FROM REACHABLE NODES TABLE
	       RET		;FAILED
	      JRST ADDTEL]	;NOTIFY INTERESTED USERS OF TOPOLOGY CHANGE
	NOINT			;NO INTERRUPTIONS
	LOCK NODLOK		; WHILE TABLE LOCKED
	MOVE T4,[POINT 2,NODTBL]  ;MAKE BYTE POINTER TO TABLE
	ADJBP T1,T4		;POINT TO THE NODE BEING ADDED
	DPB T3,T1		;INSERT DECNET PHASE
	UNLOCK NODLOK		;DONE WITH
	OKINT			; THE LOCK

;HERE TO NOTIFY INTERESTED USERS THAT TOPOLGY HAS CHANGED

ADDTEL:	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
	RETSKP
;REMNOD - ROUTINE TO REMOVE A NODE FROM THE TABLE OF REACHABLE NODES
;
;ACCEPTS IN T1/	NODE NUMBER
;
;RETURNS: +1	FAILED
;	  +2	SUCCESS

REMNOD:	NOINT			;NO INTERRUPTIONS
	LOCK NODLOK		; WHILE TABLE LOCKED
	MOVE T2,[POINT 2,NODTBL]  ;MAKE BYTE POINTER TO TABLE
	ADJBP T1,T2		;POINT TO THE NODE WE WANT
	SETZ T3,		;INIT TEST WORD
	DPB T3,T1		; NO LONGER REACHABLE
	UNLOCK NODLOK		;DONE WITH
	OKINT			; THE LOCK
	RETSKP
SUBTTL	Routines to Manipulate Logical Link Blocks and Object Tables

	RESCD			;CALLED ONLY IN PROCESS CONTEXT

;ROUTINES USED TO LOCK AND UNLOCK LL TREE

LOKLL::
	SKIPN INSKED		;SKED LEVEL?
	NOINT			;PREVENT INTS
	LOCK LLLLCK,<CALL LCKTST> ;LOCK UP THE TREE
	RET			;DONE

ULOKLL::SKIPGE LLLLCK		;NOW LOCKED?
	JRST [	BUG.(CHK,LLLKBD,NSPSRV,SOFT,<UNLOCK LL LOCK WHEN NOT LOCKED>,,<

Cause:	Call to unlock logical link lock when it was not locked.

Action: Continue.

Data:	None
>)
		RET]
	UNLOCK LLLLCK
	SKIPN INSKED
	OKINT
	RET
;ROUTINES TO LOCK AND UNLOCK INDIVIDUAL LL BLOCKS

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

;ENTRY POINT IF LLLLCK NOT LOCKED

BLKLLK::NOINT
	LOCK LLLLCK,<JRST [
		MOVEI T1,LLLCKT	;BUSY, RETURN TEST
		RET]>
	CALL BLKLOK
	 CALLRET ULOKLL		;UNLOCK AND GIVE UP
	CALL ULOKLL
	RETSKP

;ENTRY POINT IF LLLLCK ALREADY LOCKED

BLKLOK::SAVEAC <T4>		;PRESERVE TEMP AC
   IFN NSPSW,<
	SKIPGE LLLLCK		;ENSURE OUTER LOCK ALREADY SET
	BUG. (HLT,NSPLOK,NSPSRV,SOFT,<NSPSRV: Can't lock logical link block>,,<

Cause:	An attempt is being made to obtain the lock on a logical link block
	without already owning the master lock.  This is illegal.

>)
	SKIPE INSKED		;MAKE SURE ONLY PROPER SCHEDULER CONTEXT
	SKIPGE FORKX
	SKIPA
	BUG. (HLT,NSPCON,NSPSRV,SOFT,<NSPSRV: Can't lock logical link block>,,<

Cause:	An attempt is being made to obtain the lock on a logical link block
	but we are in an improper scheduler context.  Code calling this routine
	from scheduler level should already have realized this.
>)
   >				;END IFN NSPSW
	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
	SKIPN INSKED
	NOINT			;PREVENT INTERRUPT WHILE BLOCK LOCKED
	RETSKP			;DONE, BLOCK NOW LOCKED

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

BLKLK1:	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::SAVEAC <T2>		;BE TRANSPARENT
	LOAD T2,LLRCT,(T1)	;GET LOCK COUNT
	CAIE T2,1		;OUTERMOST?
	JRST [	DECR LLRCT,(T1)	;NO, JUST DECREMENT
		JRST BLKUK1]
	SETZRO LLRFK,(T1)	;LOCK BECOMING CLEAR, CLEAR LAST FORK
	SETZRO LLRCT,(T1)
BLKUK1:	SKIPN INSKED
	OKINT
	RET

;SCHED TEST FOR ABOVE

LLLCKT:	SKIPL LLLLCK
	JRST 0(T4)		;STILL BUSY
	JRST 1(T4)		;FREE
;ROUTINE TO INIT LL ADDRESS BIT TABLE. CALLED AT SYSTEM STARTUP

LLINIT:	MOVSI T1,-LLBIT		;GET WORDS IN BIT TABLE
	SETOM LLBITS(T1)	;SAY THEY ARE
	AOBJN T1,.-1		; ALL AVAILABLE
	MOVSI T1,400000		;  EXCEPT
	ANDCAM T1,LLBITS	;   LL 0
	RET
;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

REPEAT 0,<

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.(CHK,NSPPWA,NSPSRV,HARD,<LOKPIP - Pipe went away>,,<

Cause:	This BUG is not documented yet.

Action:

Data:

>)
		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.(CHK,NSPPHV,NSPSRV,HARD,<ULKPIP - Pipe has vanished>,,<

Cause:	This BUG is not documented yet.

Action:

Data:

>)
		RET ]		;UNLOCK THE TREE AND RETURN FAILURE
	LLLULK			;UNLOCK THE TREE
	CALLRET BLKULK		;UNLOCK PIPE AND RETURN

>				;END OF REPEAT 0 AT LOKPIP
;ROUTINE TO FIND LOGICAL LINK BLOCK
;ACCEPTS:	T1/ LOGICAL LINK ID
;		T2/ FOREIGN LINK I.D. -1 FOR ANY
;RETURNS:	+1 FAILED. LINK NOT FOUND
;		+2 SUCCESS. T1/ ADDRESS OF LL BLOCK
;PRESERVES T4

	RESCD			;NEEDS TO BE RESIDENT

LLLKUP::MOVE T3,T1		;PRESERVE LINK ID
	ANDI T1,MAXLNK		;GET THE LOCAL PART
	SKIPN T1,LLIDS(T1)	;IS THERE AN LL BLOCK?
	RET			;NO
	OPSTR <CAME T3,>,LLLNK,(T1)  ;YES, THE RIGHT ONE?
	RET			;NO
	SKIPGE T2		;YES, WANT REMOTE LINK MATCH?
	RETSKP			;NO
	OPSTR <CAME T2,>,LLHLK,(T1)  ;YES, DOES IT MATCH?
	RETBAD (NSPX2)		;NO
	RETSKP			;YES
;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 ID TABLE. WILL ALSO DO SCAN OF ENTIRE TABLE
;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/ LOGICAL LINK BLOCK ADDRESS
;		T2/ LOGICAL LINK I.D.

;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 BLOCK
;	ALL OF THE P 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::ACVAR <LUP,TRY,GUD>
	SETZB TRY,GUD		;INIT "GOOD OBJECT" FLAG AND NUMBER TRIED COUNT
	DMOVE T3,T1		;SAVE ARGS
	SKIPE LLNUM		;ANY LINKS IN USE?
	IFSKP.
	   MOVEI T2,.DCX4	;NO, GO NO FURTHER
	   RET
	ENDIF.
	MOVSI LUP,-MAXLNK	;AOBJN WORD TO SEARCH ID TABLE
	AOS LUP			;LINK IDS BEGIN WITH 1
OBJSR1:	SKIPN T1,LLIDS(LUP)	;THIS ID IN USE?
	JRST OBJSR3		;NO
	AOS TRY			;INCR COUNTER
	JUMPL T4,OBJSR2		;IF ANY MATCH, TRY THIS ONE
	JE LLFOB,(T1),OBJSR3	;MUST BE OBJECT, IF NOT AN OBJECT, MOVE ON
	SKIPG T4		;HAVE TO BE LISTENING?
	IFSKP.
	   LOAD T2,LLSTA,(T1)	;YES, GET THE STATE OF THE LINK
	   CAIE T2,LLSLIS	;LISTENING?
	   JRST OBJSR3		;NO
	ENDIF.
OBJSR2:	SKIPN T3		;HAVE A COROUTINE?
	IFSKP.
	   CALL (T3)		;YES, GO DO IT
	    JRST OBJSR3		;DON'T WANT THIS ONE
	ENDIF.
	SETOM GUD		;FOUND A GOOD OBJECT
	LOAD T2,LLLNK,(T1)	;GET LINK ID
	RETSKP
OBJSR3:	CAMGE TRY,LLNUM		;TRIED ALL LINKS IN USE?
	AOBJN LUP,OBJSR1	;NO, DO NEXT LINK ID
	MOVEI T2,.DCX4		;SERVER DOESN'T EXIST
	SKIPE GUD		;DID WE FIND THE RIGHT TYPE OF SERVER?
	MOVEI T2,.DCX33		;YES, SAY SERVER IS BUSY
	RET

	ENDAV.
;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 ASGDCN		;GO GET A BLOCK
	 RET			;NO MORE SPACE
	MOVEM T1,TSKBLK		;SAVE ADDRESS
GETTS1:	MOVE T4,T1		;GET ADDRESS IN T4
	HRLZI T1,(<POINT 7,(T4)>) ;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

	ENDAV.			;END ACVAR

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

FRELNK:	ANDI T1,MAXLNK		;ISOLATE LOCAL INDEX
	SETZM LLIDS(T1)		;FREE THE SLOT
	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
	SOS LLNUM		;ONE LESS LINK IN USE
	RET			;AND DONE

;ROUTINE TO GET A RESIDENT FREE SPACE BLOCK
;ACCEPTS:	T1/ SIZE REQUIRED
;RETURNS:	+1 FAILED,  T1/ ERROR CODE
;		+2 SUCCESS, T1/ ADDRESS OF FREE SPACE BLOCK

	RESCD

GETRES::SKIPE RESNET		;LOW ON SPACE?
	RETBAD (MONX07)		;YES
	HRLI T1,.RESP3		;NO, ASSUME PROCESS CONTEXT
	SKIPE INSKED		;SKED CONTEXT?
	HRLI T1,.RESP2		;YES, NO PAGE FAULTS PLEASE
	MOVE T2,[RS%SE0!.RESNP]	;FROM THE NETWORK
	CALL ASGRES		;GET SOME SPACE
	 RETBAD (MONX07)	;COULDN'T
	RETSKP			;GOT IT

	SWAPCD

;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::LOAD T3,SCSTA		;GET NODE STATE
	CAIE T3,.NDOFF		;ARE WE OFF?
	CAIN T3,.NDSHT		;OR SHUT?
	RETBAD (NSPX27)		;YES, LOCAL NODE SHUT
	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
	MOVEM T3,SAVERR		;SAVE SIZE OF BLOCK OVER SUBROUTINE CALL
	MOVE T1,SAVERR		;GET # OF ADDITIONAL WORDS NEEDED FOR LL BLOCK
	CALL GETRES		;(T1/T1) GET SPACE FOR LL BLOCK
	 RETBAD ()		;COULDN'T. MUST FAIL
	MOVEM T1,SAVBLK
	MOVEI T1,OPTSIZ		;SIZE OF OPTDATA BLOCK
	CALL ASGDCN		;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 RELDCN	;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

	INCR DCCUR		;INCREMENT COUNT
	LOAD T2,DCCUR		;GET IT
	LOAD T4,DCMAX		;GET MAX COUNT ALLOWED
	CAMLE T2,T4		;NO. ALLOWED TO MAKE ANOTHER LINK?
	JRST [	MOVE T3,CAPENB	;NO, SEE IF CAPS
		TXNE T3,SC%WHL!SC%OPR
		JRST .+1	;OK
		MOVEI T1,DCNX5	;NO. GIVE ERROR
		JRST OPNFAI]	;AND GO FAIL
	MOVE T2,SAVBLK		;GET LL BLOCK ADDRESS
	MOVEI T3,LLHNM1(T2)	;GET PLACE TO PUT REMOTE HOST NAME STRING
	STOR T3,LLHST,(T2)	;SET IT
	MOVEI T1,<MAXDSC+4>/4	;A BLOCK FOR REMOTE DESCRIPTOR
	CALL ASGDCN		;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 ASGDCN		;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 RELDCN	;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:	MOVEI T2,NSPTIM		;GET INITIAL RESEND TIME OUT VALUE
	MOVEM T2,LLTIMO(T1)	;PUT IT IN LL BLOCK
	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,MONX06	;"NO MORE SWAPPABLE FREE SPACE"
		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
	LOAD T2,FKJO%,(T2)	;GET FORK'S JOB NUMBER
	MOVE T4,FORKX		;GET THIS FORK'S NUMBER
	OPSTR <CAMN T2,>,FKJO%,(T4) ;SAME JOB NUMBER?
	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::MOVE T2,(P)		;GET CALLER'S ADDRESS
	ASUBR <SAVBLK,SAVCAL>	;SAVE BLOCK ADDRESS AND PC OF CALLER
	LOAD T1,LLLNK,(T1)	;GET ITS ADDRESS
	SETOM T2		;ANY MATCH
	CALL LLLKUP		;GO LOOK IT UP
	 JRST [
	    REPEAT 0,<
		MOVE T2,SAVCAL	;DIDN'T FIND IT, RETRIEVE CALLER'S PC
		BUG.(INF,DELNDF,NSPSRV,SOFT,<DELNOD-LLLKUP FAILED>,<<T2,CALLER>>,<

Cause:	An attempt to remove a DECnet logical link block from the data
	base failed.

ACTION:	THIS SHOULD BE EASILY RECOVERED FROM BY THE MONITOR.
	IF IT PERSISTS, CHANGE IT TO A BUGHLT AND LOOK AT THE DUMP.
	THE ROUTINE MAKING THE CALL TO DELNOD SHOULD BE A VERY GOOD
	CLUE AS TO WHY THIS IS OCCURRING.

Data:	CALLER - PC of the calling routine

>) > ;END REPEAT 0
		RET]		;ALL DONE
	LOAD T1,LLLNK,(T1)	;GET ADDRESS
	CALL FRELNK		;RELEASE THE LINK #
	MOVE T1,SAVBLK		;GET BACK BLOCK ADDRESS
	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,>,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
	CALL UNQSRV		;REMOVE LL BLOCK FROM "NEEDS SERVICE" QUEUE
	CALLRET RELRES		;FREE BLOCK AND RETURN

DELREL:	SAVET
	NOINT			;PREVENT INTERRUPTS WHILE DEASSIGNING SPACE
	MOVE T1,T2		;GET BLOCK ADDRESS
	CALL RELDCN		;FREE BLOCK
	OKINT			;PREMIT INTERRUPTS AGAIN
	RET			;RETURN

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

REPEAT 0,<

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.(CHK,NSPLNQ,NSPSRV,SOFT,<REMQUE - Link not queued>,,<

Cause:	This BUG is not documented yet.

Action:

Data:

>)
	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
>				;END REPEAT 0 AT REMQUE
;ROUTINE TO RESET AN LL BLOCK SO THAT IT CAN REVERT TO
;THE LISTENING STATE. USED WHEN A SERVER REJECTS A CONNECTION.
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;RETURNS:	+1 FAILED
;		+2 SUCCESS

CLRBLK:	ASUBR <CLRLLB>		;LL BLOCK ADDRESS
	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
	OPSTR <SKIPE T2,>,LLFDS,(T1)  ;HAVE A DESCRIPTOR?
	CALL DELREL		;YES, RELEASE THE SPACE
	MOVEI T1,<MAXDSC+4>/4	;MAX CHARS IN DESCRIPTOR
	CALL ASGDCN		;GET SWAPPABLE FREE SPACE BLOCK
	 RETBAD ()		;COULDN'T
	MOVE T2,T1		;POSITION THE ADDRESS
	MOVE T1,CLRLLB		;RETRIEVE THE LL BLOCK ADDRESS
	STOR T2,LLFDS,(T1)	;PUT BLOCK ADDRESS IN LL BLOCK
	SETZRO LLRSN,(T1)	;NO DISCONNECT REASON
	JE LLFOB,(T1),RSKP	;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
	RETSKP			;AND DONE
;ROUTINE TO GET A LL ADDRSS AND AND FILL IN LLIDS
;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 T3,T1		;PRESERVE UNIQUE 7 BITS
	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
	SKIPE LLIDS(T3)		;IS THERE ONE ALREADY THERE?
	BUG.(HLT,ADDONF,NSPSRV,SOFT,<ADDOBJ-LLLKUP FAILED>,,<

Cause:	An attempt was made to add a new DECnet logical link to the data
	base and it was discovered that the logical link was already there.

Action:	Look at the dump.  You should be able to tell which routine handed
	ADDLNK the bad block number.

>)
	MOVEM T1,LLIDS(T3)	;PUT LL BLOCK ADDRESS IN ID TABLE
	AOS LLNUM		;ONE MORE LINK ID IN USE
	RETSKP			;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

	ENDAV.			;END ACVAR

;THE ATTRIBUTE TABLE

ATTRTB:	ATTENT (.PFUDT,0,MAXUAP,0)
	ATTENT (.PFPWD,0,MAXUAP,.PFBPW)
	ATTENT (.PFBPW,1,MAXUAP,.PFPWD)
	ATTENT (.PFACN,0,MAXUAP,0)
	ATTENT (.PFOPT,0,MAXOPT,.PFBOP)
	ATTENT (.PFBOP,1,MAXOPT,.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,NTLLB>
	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
	MOVEM W1,NTLLB		;STASH IT FOR OBJSRC AND ITS COROUTINES
	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 ASGDCN		;GET ONE
	 JRST SRCFAL		;COULDN'T
	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?
	LOAD T2,FKJO%,(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
	MOVE T4,NTLLB		;GET LL BLOCK
	LOAD T2,LLNAM,(T1)	;GET OBJECT NUMBER
	OPSTR <CAME T2,>,LLNAM,(T4) ;SAME AS OURS?
	RET			;NO. NO CONFLICT THEN
	LOAD T1,LLDSC,(T1)	;GET ITS DESCRIPTOR
	LOAD T2,LLDSC,(T4)	;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 USER/PASSWORD/ACCOUNT

GTSBLK:	MOVEI T1,SIZ39		;THE PROPER SIZE
	CALL ASGDCN		;GET ONE
	 RET			;FAILED
	RETSKP			;GOT IT

	ENDAV.			;END ACVAR
;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 RELDCN	;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
	LOAD T3,LLHSN,(T1)	;GET NODE NUMBER
	AOS @[EP. NSCONS(T3)]	;INCR THE CONNECTS SEND COUNT
	CALL SNDCTL		;SEND MESSAGE TO THE NETWORK
	RETSKP			;AND DONE FOR NOW

	ENDAV.			;END ACVAR
;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/	ADDRESS OF HOST NAME STRING BLOCK
;	    T4/	ADDRESS OF DESCRIPTOR STRING BLOCK
;		CALL STRSAV
;RETURNS: +1	 FAILED, ERROR CODE IN T1
;	  +2	SUCCESS, STRINGS SAVED

STRSAV::SAVEQ
	STKVAR <SSVHST,SSVHSC>
	HLREM T2,SSVHSC		;SAVE HOST STRING BYTE COUNT
	MOVEM T3,SSVHST		;SAVE HOST NAME STRING POINTER
	MOVE Q1,T1		;SAVE LL BLOCK ADDRESS
	SKIPG T3,SSVHSC		;HAVE A HOST NAME?
	JRST [SETONE LLLOC,(Q1) ;NOTE THIS IS A LOCAL LINK
	      RETSKP]		;DONE
	CAME T3,OURCNT		;SAME COUNT AS OUR NAME?
	JRST DCNOP0		;NO. CAN'T BE LOCAL
	MOVE T1,SSVHST		;YES, COULD BE US - GET BLOCK POINTER
	AOS T1			;POINT TO ACTUAL TEXT STRING
	HRLI T1,440700		;MAKE A BYTE POINTER
	MOVE T2,[POINT 7,OURNAM] ;GET POINTER TO OUR NAME
	SETZ T4,		;NO OFFSET IN COMPARISON
	CALL COMPAR		;SEE IF THE SAME
	 JRST DCNOP0		;NO. SAVE IT THEN
	SETONE LLLOC,(Q1)	;YES, NOTE LOCAL LINK
	MOVE Q3,OURNUM		;GET LOCAL NODE NUMBER
	STOR Q3,LLHSN,(Q1)	;PUT IT IN LL BLOCK
	RETSKP			;DONE

;THE ATTEMPTED CONNECTION IS NOT LOCAL

DCNOP0:	MOVE T1,SSVHST		;GET ADDRESS OF STRING BLOCK
	AOS T1			;POINT TO ACTUAL TEXT
	HRLI T1,440700		;MAKE A BYTE POINTER
	MOVEM T1,SSVHST		;SAVE THE BYTE POINTER
	MOVNI Q2,BIGNOD		;MAKE
	HRLZS Q2		; AOBJN
	HRRI Q2,1		;  WORD
	MOVE T3,SSVHSC		;GET HOST NAME CHARACTER COUNT
	MOVEI T4,40		;COMPARE ASCII
	MOVNS T4		; TO SIXBIT
	NOINT			;NO INTERRUPTIONS
	LOCK NMAPLK		; WHILE TABLE LOCKED
DCNOP4:	MOVE T1,SSVHST		;RETRIEVE THE BYTE POINTER TO THE HOST
	HRLI T2,440600		;MAKE A BYTE POINTER
	HRRI T2,NODMAP(Q2)	; TO THE NAME IN THE TABLE
	TLO T3,400000		;MAY BE DIFFERENT LENGTH STRINGS
	CALL COMPAR		;ARE THEY THE SAME?
	 JRST [AOBJN Q2,DCNOP4	;NO, TRY FOR MORE
	       UNLOCK NMAPLK	;DONE WITH
	       OKINT		; THE LOCK
	       RETBAD (NSPX24)]	;DIDN'T FIND IT
	UNLOCK NMAPLK		;DONE WITH
	OKINT			; THE LOCK

;USER'S NODE NAME IS IN NODE NAME MAPPING TABLE

   IFN DN20SW,<			;LOOK FOR OTHER MCBS
	MOVEI Q3,2		;NEXT DTE TO CHECK
DCNOP7:	MOVE T2,Q3		;PRESERVE DTE NUMBER
	IMULI T2,2		;CALC CORRECT OFFSET FOR NODE NAME
	HRRI T2,ITSNAM(T2)	;MAKE A BP
	HRLI T2,440700		; TO THE NODE NAME
	MOVE T1,SSVHST		;GET BP TO HOST NAME
	MOVE T3,SSVHSC		;GET NO. OF CHARS IN HOST NAME
	SETZ T4,		;NO CONVERSION FACTOR
	CALL COMPAR		;DO THEY MATCH?
	 JRST DCNOP2		;NO, NOT FOR THIS MCB
	SKIPGE T2,MCBDTE(Q3)	;DTE ACTIVE?
	TXNE T2,NTSHUT		;YES, NODE SHUTTING DOWN?
	RETBAD (NSPX18)		;ERROR RETURN - NO PATH
	MOVEI Q3,(Q3)		;GET DTE #
	MOVEI T1,3		;SAY PHASE III NODE
	JRST DCNOP5		;MOVE ON
DCNOP2:	CAIGE Q3,3		;DONE ALL DTES YET?
	IFNSK.			;NO
	   AOS Q3		;MAKE NEXT DTE
	   JRST DCNOP7		;TRY IT
	ENDIF.
   >
	MOVE T1,[POINT 2,NODTBL]  ;POINT TO REACHABLE NODES TABLE
	HRRZ T2,Q2		;GET NODE NUMBER TO PLAY WITH
	ADJBP T2,T1		;POINT TO NODE
	LDB T1,T2		;GET ITS INFO
	SKIPN T1		;IS IT REACHABLE
	RETBAD (NSPX18)		;ERROR - NO PATH TO DESTINATION NODE

;NODE IS REACHABLE

	MOVSI Q3,-DCN		;MAKE AOBJN WORD FOR MCB SEARCH
DCNOP1:	SKIPGE T2,MCBDTE(Q3)	;IS THIS FE ACTIVE?
	TXNE T2,NOTMCB		;YES, IS IT AN MCB?
	JRST DCNOP3		;NO, CAN'T USE IT
	TXNN T2,NTSHUT		;YES, IS IT SHUTTING DOWN?
	JRST DCNOP5		;NO, EVERYTHING OK
	RETBAD (NSPX18)		;YES - NO PATH TO DESTINATION NODE
DCNOP3:	AOBJN Q3,DCNOP1		;TRY NEXT FE
	RETBAD (NSPX18)		;ERROR - NO PATH TO DESTINATION NODE

;STORE INFO IN LL BLOCK

DCNOP5:	CAIE T1,2		;PHASE II ROUTING?
	IFSKP.			;YES
	   MOVX T1,.NSP31	;SAY NSP 3.1
	ELSE.			;NO, PHASE III
	   MOVX T1,.NSP32	;SAY NSP 3.2
	ENDIF.
	STOR T1,LLLKP,(Q1)	;IN LL BLOCK
DCNOP6:	STOR Q3,LLPRT,(Q1)	;SAVE PORT NUMBER
	LOAD T1,LLHST,(Q1)	;GET PLACE TO PUT HOST'S NUMERIC NAME
	HRLI T1,440700		;MAKE A BYTE POINTER
	HRRZ T2,Q2		;GET THE NODE NUMBER
	STOR T2,LLHSN,(Q1)	;SAVE REMOTE HOST NUMBER
	MOVEI T3,^D10		;IN DECIMAL
	NOUT			;MAKE IT 7-BIT ASCII
	 JFCL
	RETSKP

	ENDSV.
;COMPARE TWO STRINGS
;ACCEPTS:	T1/ BYTE POINTER TO STRING 1
;		T2/ BYTE POINTER TO STRING 2
;		T3/ FLAGS ,, COUNT OF CHARS. IN STRING
;		    1B0 = STRINGS MAY BE OF DIFFERENT LENGTH
;		T4/ OFFSET (IF NEEDED)
;RETURNS:	+1 NO MATCH
;		+2 MATCH
;PRESERVES T3,T4

COMPAR: SAVEAC <STS,JFN,P3>	;SAVE SOME AC'S
	MOVE STS,T1		;COPY POINTER TO FIRST STRING
	MOVE JFN,T2		;COPY POINTER TO SECOND STRING
	HRRZ P3,T3		;SAVE COUNT
	SOS P3			;FIXUP COUNTER FOR THE LOOP
CMPRLP:	ILDB T1,STS		;GET NEXT BYTE
	ILDB T2,JFN		;GET THIS ONE'S NEXT
	SKIPE T4		;IS THERE AN OFFSET?
	ADD T1,T4		;YES, MAKE THE ADJUSTMENT
	CAME T1,T2		;MATCH?
	RET			;NO. NO MATCH THEN
	SOJGE P3,CMPRLP		;DO ALL THE BYTES
	TLZN T3,400000		;CHECKING WITH NODMAP?
	RETSKP			;NO, MATCH
	CAIL T3,6		;DONE MAX CHARACTERS IN A NODE NAME?
	RETSKP			;YES, MATCH
	ILDB P3,JFN		;NO, GET THE NEXT BYTE
	SKIPE P3		;ONE THERE?
	RET			;YES, NO MATCH
	RETSKP			;A MATCH!!!!

	ENDAV.
;ROUTINE TO INSERT THE LL ADDRESSES IN A MESSAGE.
;ACCEPTS:	T1/ LL BLOCK ADDRESS

	RESCD

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


	ENDAV.			;END ACVAR
	SWAPCD
;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
	TMNE LLIMS,(T1)		;WANT MESSAGE COUNTS?
	MOVEI T2,CISRVS+CIMCNT	;YES
	CALL ONEBYT		;PUT IN SERVICES BYTE
	MOVEI T2,LNKPRI		;GET DEFAULT PRIORITY
	CALL ONEBYT
	LOAD T3,IOMODE		;GET FILE OPEN MODE
	CAIN T3,.GSSMB		;SMALL BUFFER MODE?
	SKIPA T3,[SMLSEG]	;YES, USE SMALL SEGSIZ
	MOVE T3,SEGSZ		;NO, USE NORMAL SEGMENT SIZE
	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
		CAMLE T2,T3		;LESS THAN OURS?
		MOVE T2,T3		;NO, USE OURS
		TMNE LLLOC,(T1)		;LOCAL CONNECTION?
		JRST DOSRV1		;YES, NO NEED TO CHECK FURTHER
		LOAD T4,LLPRT,(T1)	;GET PORT NUMBER
		CAMLE T2,NSPMAX(T4)	;LESS THAN PORT'S SEGSIZ?
		MOVE T2,NSPMAX(T4)	;NO, USE PORT'S
		JRST DOSRV1]
	MOVE T2,T3		;USE SEGSIZE SELECTED ABOVE
DOSRV1:	STOR T2,LLSWG,(T1)	;PUT SEG SIZE IN LL BLOCK
	TMNE 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

	ENDSV.
;ROUTINE TO BUILD A ROUTING HEADER.
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ PROPER MESSAGE FLAGS

	RESCD

RTHDCI:	SAVEAC <T2>		;PRESERVE THE FLAGS
	STKVAR <MSGFLG>		;TO SAVE THE FLAGS
	MOVEM T2,MSGFLG		;SAVE FLAGS
	JN LLLOC,(T1),RTHDC1	;JUMP IF LOCAL
	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


	ENDAV.			;END ACVAR
	SWAPCD
;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

	ENDAV.			;END ACVAR
;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

	ENDAV.			;END ACVAR

;ROUTINES TO INSERT BYTES IN MESSAGE AND ACCOUNT FOR THEM

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

	RESCD
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
	SWAPCD
;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,FLATL,(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
	TMNE LLLOC,(T1)		;LOCAL LINK?
	 JRST [MOVEI T2,OURNAM  ;YES
	       CALLRET NTCPY]	;GO COPY OUR NAME TO USER
	LOAD T2,LLHSN,(T1)	;GET THE NODE NUMBER
	NOINT			;NO INTERRUPTIONS
	LOCK NMAPLK		; WHILE TABLE LOCKED
	HRLI T2,440600		;POINT TO NODE'S
	HRRI T2,NODMAP(T2)	; ALPHABETIC NAME
	UMOVE T3,3		;GET USER'S STRING POINTER
	CALL NTRNAM		;GO RETURN NAME TO USER
	UNLOCK NMAPLK		;DONE WITH
	OKINT			; THE LOCK
	CALL BLKULK		;UNLOCK THE LL BLOCK
	RETSKP


;RETURN A NODE NAME TO THE USER
;ACCEPTS:	2/ BP TO NODE NAME
;		3/ USER'S BP
;RETURNS:	+1

NTRNAM:	TLC T3,-1
	TLCN T3,-1		;WANT DEFAULT?
	HRLI T3,(<POINT 7,>)	;USE. DO IT
	ACVAR <W1>		;GET A WORK REG
	MOVEI W1,6		;MAX. OF 6 CHARS IN NAME
NTRHN1:	ILDB T4,T2		;GET A BYTE
	JUMPE T4,NTRHN2		;IF NULL, DONE
	ADDI T4,40		;CONVERT FROM 6-BIT TO 7-BIT
	XCTBU [IDPB T4,T3]	;GIVE IT TO USER
	SOJG W1,NTRHN1		;IF MORE, GO GET NEXT
	SETZ T4,		;PUT NULL ON END
NTRHN2:	UMOVEM T3,3		;UPDATE BYTE POINTER
	XCTBU [IDPB T4,T3]	;GIVE HIM THE NULL
	RET			;DONE

	ENDAV.
;WORKER ROUTINE TO COPY AN ASCII STRING TO THE USER.
;ACCEPTS:	2/ ADDRESS OF STRING
;RETURNS:	+1
;
;PRESERVES T1

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

	ENDAV.			;END ACVAR
;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
	TMNE 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
	CAIN T2,LLSLIS		;LISTENING?
	TXO T3,MO%WFC		;YES. WAITING FOR INCOMING CONNECT
	CAIN T2,LLSCIS		;CI SENT?
	TXO T3,MO%WCC		;YES, WAITING FOR CONNECTION TO COMPLETE
	CAIN T2,LLSCCS		;CC SENT?
	TXO T3,MO%WCC		;YES, WAITING FOR CONNECTION TO COMPLETE
	CAIN T2,LLSCIR		;CI RECEIVED?
	TXO T3,MO%WCC		;YES, WAITING FOR CONNECT TO COMPLETE
	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
	TMNE 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
	CAIE T2,LLSCIR		;IN CIR STATE?
	CAIN T2,LLSCCS		; OR CC SENT?
	RETSKP			;YES. IS GOOD THEN
MTRNCK::LOAD T2,LLSTA,(T1)	;GET STATE
	CAIN T2,LLSRUN		;RUNNING?
	RETSKP			;YES.
MTOBJ1:	RETBAD (DCNX8)		;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

	ENDAV.			;END ACVAR
;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
	SKIPE LLOMSG(T1)	;ANY 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

	RESCD

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

	SWAPCD

;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

REPEAT 0,<

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
>				;END REPEAT 0
;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
	PUSH P,T2		;STASH MESSAGE ADDRESS
	CALL BLKULK		;DONE WITH BLOCK
	POP P,T1		;RETRIEVE MESSAGE 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
   IFN NSPSW,<
	CALL CHKLLB
   >
	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 T1,W1		;SAVE LL BLOCK ADDRESS
	MOVEM T2,RDIRTN		;SAVE ROUTINE TO STORE BYTES
	MOVEM T3,RDIPTR		;SAVE DESTINATION BYTE POINTER
RDINT1:	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 [	MDISMS		;CAN'T, WAIT A BIT
		MOVE T1,W1	;RETRIEVE THE LL BLOCK ADDRESS
		JRST RDINT1]	;TRY IT AGAIN
	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

	ENDAV.			;END ACVAR
;MORE MTOPR'S....  SEND INTERRUPT MESSAGE

MTSNIN::UMOVE T4,4		;GET COUNT
	UMOVE T3,3		;GET BP
	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,MAXINT		;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
	 RETBAD ()		;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

	ENDAV.			;END ACVAR
;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

	ENDSV.
;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
	 JRST SQOBAD		;FAILED
	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,LLSCCS		;CONNECT SENT?
	CAIN T2,LLSRUN		;OR RUNNING?
	SKIPA			;YES, GO
	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 SEGMENT SIZE FOR THE LINK

MTGSS::	LOAD T2,LLSWG,(T1)	;GET SEG SIZE
	SKIPE T2		;SET UP YET?
	IFSKP.
	   MOVEI T1,DCNX16	;NO
	   JRST SQOBAD		;FAIL
	ENDIF.
	UMOVEM T2,3		;YES, 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,MAXOPT		;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

	ENDAV.			;END ACVAR
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 BLKLLK		;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
	IFQN. LLTTA,(T1)	;SET HOST IN EFFECT?
	  CALL TTCLSH		;(T1/) YES, CLEAR IT
	ENDIF.
	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
	TMNN LLFLO,(T1)		;FLOW NOW TO F/S?
	JRST [	JUMPE T3,CLZCMS	;YES, IF NO MORE BYTES TO SEND, MOVE ON
		JRST CLZDI0]	;GO FORCE OUT REMAINING BYTES
	JUMPE T2,CLZCMS		;NO, ANY BYTES TO SEND?
	SETONE LLFEM,(T1)	;YES, SAY EOM IN THIS BUFFER
CLZDI0:	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 BLKULK	;UNLOCK THE LL BLOCK
		JRST CLZDN1]	;AND GO FINISH UP
	MOVEI T2,CHKDCR		;WAIT FOR DC TO COME BACK
	JRST OUTWAT		;ALSO, REQUEST BLOCK
;MORE CLOSE ROUTINES
;DC HAS ARRIVED. FIND OUT IF IT WHAT WE WANTED

CLZDIR:				;CLOSE IN DI RECEIVED STATE
CLZABT:

REPEAT 0,<
	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 FILBNO(JFN)
	RETSKP			;AND DONE

	ENDAV.			;END ACVAR
;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.(INF,CLZDIN,NSPSRV,SOFT,<CLZSDI - Could not send DI>,,<

Cause:	This BUG is not documented yet.

Action:

Data:

>)
		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
	MOVE T1,LLBLK		;RETRIEVE LL BLOCK ADDRESS
	LOAD T3,LLLNK,(T1)	;GET LL ID
	MOVE T2,LLMSGB		;RETRIEVE MESSAGE ADDRESS
	STOR T3,MSLLA,(T2)	;PUT LL ID IN MESSAGE HEADER
	MOVE T3,DIFLGS		;GET THE MESSAGE FLAGS
	STOR T3,MSMFL,(T2)	;PUT FLAGS IN MESSAGE HEADER
	MOVEI T3,MSHDR(T2)	;GET TO START OF DATA PORTION
	HRLI T3,(<POINT 8,>)	;MAKE A BYTE POINTER
	MOVEM T3,LLBPTR(T1)	;SAVE POINTER IN LL BLOCK
	SETZM LLBPCT(T1)	;INIT THE BYTE 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 BLKLLK		;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
	TMNE 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,FILBNO(JFN)	;GET INPUT BYTE POINTER
	HRRZ T1,FILBCT(JFN)	;GET COUNT
	MOVE T3,FILLLB(JFN)	;GET LL BLOCK
	TMNE 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
	TMNN 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
	TMNN 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 OUTR0E		;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
	MOVE T1,FILLLB(JFN)	;GET LL BLOCK ADDRESS
	TMNN LLFEM,(T1)		;EOM?
	JUMPE T2,RSKP		;NO, DONE
	HRLM T2,FILBCT(JFN)	;STORE COUNT TO SEND
OUTR0E:	MOVE T1,FILLLB(JFN)	;GET LL BLOCK ADDRESS
	TMNN LLFEM,(T1)		;EOM?
	JRST OUTR00		;NO, GO BACK FOR MORE
	JRST OUTRR3		;YES, CONTINUE OUTPUT PROCESSING
	; ..
;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
OUTRR3:	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
;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
;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

	RESCD

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
	TMNE LLFNA,(T1)		;THIS LL NEED AN ACK?
	CALL MAKACK		;YES, PUT IT IN
	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 LAST SEG SENT
	AOS T2			;NEXT ONE
	ANDI T2,7777		;ONLY 12 BITS
	STOR T2,LLDSN,(T1)	;PUT IT BACK
	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:	TMNE 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
	DECR LLMSM,(T1)		;ADJUST FLOW CONTROL
MKFL30:	MOVE T2,T4		;COPY MESSAGE FLAGS
	RET


;MAKE THE ACKNUM (PIGGYBACKED ACK) FIELD IN A DATA SEGMENT
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;RETURNS:	+1
;PRESERVES T1

MAKACK:	LOAD T2,LLIDN,(T1)	;GET LAST DATA SEGMENT RECEIVED
	TXO T2,ACKIND		;PUT IN ACKNUM INDICATOR
	CALL TWOBYT		;PUT ACKNUM FIELD IN MESSAGE
	SETZRO <LLFNA,LLFNN>,(T1)  ;CLEAR THE "NEED TO ACK/NACK" 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
	TMNN <LLNLS,LLALS>,(T1)	;NEED TO ACK LS?
	IFSKP.			;YES, CAN'T SEND DATA THEN
	   MOVEI T2,CHKLSA	;RETURN WITH SCHEDULER TEST
	   RET
	ENDIF.
	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
;ROUTINE TO MAKE A STANDARD TEST WORD

MAKTST::LOAD T1,LLLNK,(T1)	;GET LL ADDRESS
	HRLS T1			;TO THE LH
	HRRI T1,0(T2)		;TEST ROUTINE
	RET			;DONE

;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

	SWAPCD
;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
	 RETBAD ()		;FAILED. WAIT FOR A WHILE
	MOVEM T1,SAVBLK
	MOVE T1,SAVLL		;RETRIEVE LL BLOCK ADDRESS
	LOAD T3,LLLNK,(T1)	;GET LL ID
	MOVE T2,SAVBLK		;RETRIEVE MESSAGE ADDRESS
	STOR T3,MSLLA,(T2)	;PUT LL ID IN MESSAGE HEADER
	MOVEI T3,CNMRFL+CNMCF	;GET CC FLAGS
	STOR T3,MSMFL,(T2)	;PUT FLAGS IN MESSAGE HEADER
	MOVEI T3,MSHDR(T2)	;GET START OF DATA
	HRLI T3,(<POINT 8,>)	;MAKE A BYTE POINTER
	MOVEM T3,LLBPTR(T1)	;PUT IT IN LL BLOCK
	SETZM LLBPCT(T1)	;INIT THE BYTE COUNT
	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
   IFN NSPSW,<
	CALL CHKLLB
   >
	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 IT
	TMNE LLLOC,(T1)		;IS THIS A LOCAL LINK?
	 JRST SQOCN1		;YES, "CC SENT" DOESN'T EXIST FOR LOCALS
	LOAD T2,LLLKP,(T1)	;GET NODE'S VERSION
	CAIN T2,.NSP31		;IS IT NSP 3.1?
	JRST SQOCN1		;YES, MOVE ON
	MOVEI T2,LLSCCS		;STATE IS NOW
	STOR T2,LLSTA,(T1)	; CC SENT
	RETSKP			;WAIT FOR RESPONSE TO CC

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
	CAIN T2,LLSLIS		;LISTENING?
	JRST 0(T4)		;YES, NOT CONNECTED
	CAIN T2,LLSCIS		;CI SENT?
	JRST 0(T4)		;YES, NOT CONNETCED
	CAIN T2,LLSCCS		;CC SENT?
	JRST 0(T4)		;YES, NOT CONNECTED
	JRST 1(T4)		;MUST BE 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:	SETOM T2		;ANY REMOTE LINK FOR NOW
	CALL LLLKUP		;GET LL BLOCK ADDRESS
	 JRST 1(T4)		;NOT THERE ANYMORE, WAKE
	LOAD T2,LLSTA,(T1)	;GET STATE OF LL
	CAIE T2,LLSRUN		;RUNNING?
	JRST 1(4)		;NO, WAKE
	JN LLMSM,(T1),1(4)	;YES, 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.
	TMNN 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 LL 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 LLOMSG(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)		;IF NO MORE LINK, THAT'S GOOD ENOUGH
	LOAD T2,LLSTA,(T1)	;GET STATE
	CAIE T2,LLSABT		;DC RECEIVED?
	CAIN T2,LLSDIR		;OR DI RECEIVED?
	JRST 1(4)		;YES. AWAKE
	JRST 0(4)		;NO. KEEP WAITING

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


;WAIT UNTIL ACKING OF LS MESSAGES IS NO LONGER NECESSARY

CHKLSA:	SETOM T2		;ANY MATCH
	CALL LLLKUP		;FIND LL BLOCK
	 JRST 1(4)		;BADNESS, WAKE UP
	TMNN <LLNLS,LLALS>,(T1)	;NEED LS ACK?
	JRST 1(4)		;NO, WAKE UP
	JRST 0(4)		;YES, KEEP WAITING
;ROUTINES FOR SEQUENTIAL INPUT

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

REPEAT 0,<

MOVSEG::ACVAR <W1,W2,W3>
	STKVAR <MSGLLB>
	MOVEM T1,MSGLLB		;SAVE LOGICAL LINK BLOCK ADDRESS
	TMNE LLFNN,(T1)		;NEED A NACK?
	CALL MOVNAK		;YES. SEND NACK
MOVSE1:	SKIPN T2,LLMSG(T1)	;HAVE ANY?
	RETSKP			;NO. MUST BE DONE THEN
	NOSKD1			;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
	OKSKD1			;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
		 NOP		; 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

	ENDAV.			;END ACVAR
;LOCAL ROUTINE TO HANDLE AN ACK FOUND ON LLOMSG 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

   >				;END REPEAT 0 AT MOVSEG

;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

	SWAPCD
;ROUTINE TO DO SEQUENTIAL INPUT.

NETSQI::MOVE T1,FILLLB(JFN)	;GET LL BLOCK ADDRESS
	CALL BLKLLK		;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	;GET BYTE IN PROPER PLACE
		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
	TMNN 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,FILBNO(JFN)	;SAVE BYTE POINTER
	SETZM SQICNT		;SAVE CURRENT COUNT
SQI22:	MOVE T1,FILLLB(JFN)	;GET ADDRESS OF LOGICAL LINK BLOCK
	LOAD T2,LLLSC,(T1)	;GET NO. OF SEGS RECEIVED SINCE LAST LS WAS SENT
	CAIGE T2,FLOHLD		;OVER THE THRESHOLD?
	IFSKP.			;YES
	   CALL SQILS		;SEND LS
	    JRST CHKFRE		;FAILED, WAIT A WHILE
	ENDIF.
SQI2:	MOVE T2,FILBNO(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,FILBNO(JFN)	;STORE NEW BUFFER POINTER
	MOVEM T2,SQICNT		;SAVE COUNT OF BYTES MOVED
	MOVE T1,FILLLB(JFN)	;RESTORE LOGICAL LINK BLOCK ADDRESS
	SKIPE T2		;ANY BYTES IN SEGMENT?
	JRST SQIEMP		;YES, ONWARD
	TMNE LLFIM,(T1)		;NO, EOM?
	IFNSK.			;YES, A NULL MESSAGE
	   SETZRO LLFIM,(T1)	;TURN OFF EOM
	   TQO <NSPNUL>		;SET THE FILSTS WORD
	   JRST SQIEM1		;FINISH PROCESSING THE MESSAGE
	ENDIF.
	; ..
;NETSQI CONTINUED....
;GOT ALL MESSAGES MOVED.

SQIEMP:	SKIPG SQICNT		;GET ANY BYTES?
	JRST SQINOB		;NO. NOTHING TO DO
SQIEM1:	LOAD T3,LLBSZ,(T1)	;GET BYTE SIZE
	HRRZ T1,FILWND(JFN)	;GET WINDOW ADDRESS
	CALL MAKPTR		;MAKE A POINTER
	MOVEM T1,FILBNO(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
	MOVE T1,FILLLB(JFN)	;GET ADDRESS OF LOGICAL LINK BLOCK
	SETONE LLFLI,(T1)	;FLOW IS NOW TO F/S
	RETSKP			;ALL DONE. WITH GOOD DATA

;COULDN'T FIND ANY BYTES

SQINOB:	SKIPE LLOMSG(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 LLOMSG(T1)	;ARE THERE ANY SEGMENTS?
	JRST MVMX		;NO, DONE
	MOVE T2,LLOMSG(T1)	;GET THE HEAD SEGMENT
	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
	TXNE T2,ACKIND		;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 [	SETOM T3	;NOTE NOT ALL DATA WOULD FIT
		JRST MVMY]	;EXIT
	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:	JE LLIMS,(T1),SQI4	;JUMP IF NOT MESSAGE INTERFACE
	TMNN LLFIM,(T1)		;AT EOM?
	JRST SQI5		;YES
SQI4:	INCR LLLSC,(T1)		;NEED ANOTHER BUFFER SENT
SQI5:	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		;RETRIEVE LL BLOCK
SQIMV1:	NOSKD1
	MOVE T2,LLOMSG(T1)	;GET EXPENDED MESSAGE
	LOAD T3,MSLNK,(T2)	;GET NEXT
	SKIPN T3		;QUEUE NOW EMPTY
	MOVEM T3,LLOMST(T1)	;YES, RESET THE TAIL
	MOVEM T3,LLOMSG(T1)	;NEW QUEUE HEAD
	OKSKD1
	MOVE T1,T2		;GET BACK MESSAGE
	CALL RELRES		;FREE IT
	MOVE T1,MVMLLB		;GET BACK LL ADDRESS
	DECR LLDMT,(T1)		;ONE LESS MESSAGE ON QUEUE
	JE LLFIM,(T1),MVM010	;HAVE EOM?
MVMX:	SETZM T3		;NO PROBLEM FITTING ALL DATA IN BUFFER
MVMY:	MOVE T1,MVMBFI		;NO, GET UPDATED POINTER
	MOVE T2,MVMCNT		;AND COUNT
	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,@FILBNO(JFN) ;STORE ODD WORD
		AOS FILBNO(JFN)	;MOVE TO NEXT WORD
		JRST SQIWR3]	;AND DONE
	DMOVEM Q1,@FILBNO(JFN)	;STORE BOTH WORDS
	MOVEI Q1,2		;INCREMENTER
	ADDM Q1,FILBNO(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
   IFN NSPSW,<
	CALL CHKLLB
   >
	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,  T1 PRESERVED

	RESCD

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
;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!SQOLIS		;CC SENT - BLOCK UNTIL CONNECTED
	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!SQOLIS		;CC SENT - BLOCK UNTIL CONNECTED
	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!SQOLIS		;CC SENT - BLOCK UNTIL CONNECTED
	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!CCDON		;CC SENT - 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!DIDIDC		;DIS - CLOSE LINK
	IFIW!DIMSG2		;DIQ - ABORT IT
	IFIW!DIMSG2		;DIR - ABORT IT
	IFIW!DIMSG2		;CC SENT - CONNECT BEING REJECTED
	IFIW!CCJECT		;ABORTED -

;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!DCGUD		;DIS - VALID REPLY TO DI SENT
	IFIW!DCABT		;DIQ - ABORT THE LINK
	IFIW!DCABT		;DIR - ABORT THE LINK
	IFIW!DCABT		;CC SENT - GET RID OF 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!CLZRUN		;CC SENT -
	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!ACKCCS		;CC SENT -
	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 3,<
	IFIW!CCDON>		;DIS,DIQ,DIR - IGNORE
	IFIW!DATCCS		;CC SENT - OPEN THE LINK
	IFIW!CCDON		;ABORTED
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

REPEAT 0,<

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
>				;END REPEAT 0
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:	MOVX T1,USRCTX
	MOVEM T1,FFL		;ESTABLISH USUAL JSYS CONTEXT
	SETZM FPC		;SET PC
	MCENTR			;GET INTO MONITOR CONTEXT
	MOVE T1,FORKX		;GET SYSTEM WIDE FORK NUMBER
	MOVEM T1,DNTFRK		;RECORD IT
	TRVAR <MSGCNT,MSGBYP,MSGSRC,MSGDST,MSGBLK,MSGLLB,MSGOBJ,<MSGDDC,5>,<MSGHSN,2>,MSGHNC,MSGW1,MSGW2,MSGSOB,<MSGSDC,5>,<MSGDML,LKSIZE>,MSGLCL,MSGLKP>
	MOVEI T1,MAXQ		;DON'T ALLOW THIS FORK TO BE "COMPUTE-BOUND"
	MOVEM T1,JOBBIT		;BY PREVENTING MAXQ SCHEDULING BEHAVIOR

;TOP OF LOOP

NSPTSK:	SKIPE MSGQ		;ANYTHING ON THE QUEUE?
	JRST [	CALL DOMSGQ	;YES, DO ONE
		JRST NSPTSK]	;TRY AGAIN UNTIL DONE
	CALL NSPTMR		;CHECK THE RESEND QUEUE
	CALL NSPINA		;CHECK ON INACTIVITY TIMERS
REPEAT 0,<
	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
>
	CALL MCBCQ		;CHECK ANY MCB LINKS TO CLEAN UP
	SKIPE NSPMCB		;ANY DEAD MCB'S TO CLEAN UP?
	CALL MCBDED		;YES - GO CLEAN THEM UP
	MOVEI T1,NSPTST		;REST UNTIL WORK TO DO
	MDISMS			;DISMISS, DO NOT STAY IN BALANCE SET
	JRST NSPTSK		;AND TRY AGAIN
;SEE IF ANY LL BLOCKS LEFT BY TTY TO CLOSE AND CLEAN UP

MCBCQ:	SAVEAC <F1>
	SETOM INNSPT		;SET "IN BACKGROUND TASK" INDICATOR
	SETZ F1,		;MAKE AOBJN
	HRLI F1,-NTTMCB		; WORD
MCBCQ1:	SKIPN T1,ULLCZQ(F1)	;A LINK ID HERE?
	JRST MCBCQ2		;NO
	LLLOCK			;YES, LOCK THE LL TREE
	SETO T2,		;ANY LINK
	CALL LLLKUP		;FIND THE LL BLOCK
	IFNSK.
	   LLLULK		;DOESN'T EXIST ANYMORE, GIVE UP TREE LOCK
	   JRST MCBCQ3		;ELIMINATE THIS LINK ID
	ENDIF.
	CALL BLKLOK		;GET LL BLOCK LOCK
	IFNSK.
	   LLLULK		;CAN'T RIGHT NOW, GIVE UP LL TREE LOCK
	   JRST MCBCQ2		;MOVE ON
	ENDIF.
	CALL FLUSH		;GET RID OF LINK'S MESSAGES
	CALL DELNOD		;GET RID OF THE LL BLOCK
	LLLULK			;GIVE UP THE LL TREE LOCK
	OKINT			;MATCH THE NOINT IN BLKLOK
	DECR DCCUR		;ONE LESS LL
MCBCQ3:	SETZM ULLCZQ(F1)	;GET RID OF THIS ENTRY
MCBCQ2:	AOBJN F1,MCBCQ1		;MORE TO DO?
	SETZM INNSPT		;CLEAR "IN BACKGROUND TASK" INDICATOR
	RET			;NO, DONE
;TEST ROUTINE FOR NSPTSK

	RESCD

NSPTST::
  REPEAT 0,<
	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
  >
	MOVE T1,LSTTMR		;GET LAST TIME RESEND QUEUE WAS CHECKED
	ADDI T1,CKNSTM		;ADD CHECKING INTERVAL
	CAMG T1,TODCLK		;TIME TO CHECK AGAIN?
	JRST 1(4)		;YES
	SKIPE MSGQ		;ANY MESSAGES TO DO?
	JRST 1(4)		;YES, WAKE UP
  REPEAT 0,<			;SHOULDN'T NEED ANY OF THIS
	MOVE T1,LSTINT		;GET LAST TIME INACTIVITY TIMERS WERE CHECKED
	ADDI T1,CKINTM		;ADD CHECKING INTERVAL
	CAMG T1,TODCLK		;TIME TO DO CHECKS AGAIN?
	JRST 1(T4)		;YES
   	SKIPE NSPMCB		;ANY DEAD LINES TO CLEAN UP?
	JRST 1(4)		;YES, WAKE UP
	SKIPE ULLCZQ		;LL'S TO CLEAN UP?
	JRST 1(T4)		;YES
  >
	JRST 0(4)		;NO, WAIT SOME MORE
SUBTTL NSP Background Task - NSP Message Timer

	SWAPCD

NSPTMR:	MOVE T1,LSTTMR		;GET LAST TIME QUEUE WAS CHECKED
	ADDI T1,CKNSTM		;ADD CHECKING INTERVAL
	CAMLE T1,TODCLK		;TIME TO CHECK AGAIN?
	RET			;NO
	MOVE T1,TODCLK		;YES, GET TIME
	MOVEM T1,LSTTMR		;SAVE AS NEXT TIME CHECKING IS NEEDED
	SKIPN NSSNTQ		;ANYTHING ON QUEUE?
	RET			;NO, DONE
	ACVAR <W1,W2,W3>	;W1 = LOOP COUNTER FOR MESSAGES PROCESSED
				;W2 = ADDRESS OF NEXT SEGMENT
				;W3 = TIMED OUT SEGMENT'S NUMBER
	MOVEI W1,4		;MAX NUMBER OF SEGMENTS TO PROCESS
	STKVAR <MSGADR,LLBLK>	;ADDRESS OF MESSAGE
				;LL BLOCK ADDRESS
	LLLOCK			;USE LL TREE LOCK TO PREVENT RACES
	SETOM INNSPT		;WE ARE NOW IN THE TIMER
NSPTM5:	SKIPN T2,NSSNTQ		;GET FIRST MESSAGE ON THE SENT QUEUE
	JRST [	SETZM INNSPT	;NO LONGER IN TIMER
		CALLRET ULOKLL]	;GIVE UP TREE LOCK
	MOVEM T2,MSGADR		;STASH THE MESSAGE ADDRESS
	LOAD T1,MSLLA,(T2)	;GET THE LL ID
	SETOM T2		;ANY MATCH
	CALL LLLKUP		;GET THE LL BLOCK ADDRESS
	 JRST [
	    REPEAT 0,<
		BUG.(INF,NSPGON,NSPSRV,SOFT,<NSP - Logical link look up failed>,,<

Cause:	The NSP timer has discovered a message on its resend queue and
	the logical link owning the message is no longer in the logical
	link data base.

Action:

>) > ;END REPEAT 0
		MOVE T1,MSGADR	;LINK GONE, GET BACK MESSAGE ADDRESS
		CALL UNQTIM	;REMOVE IT FROM TIMER QUEUE
		CALL RELRES	;DONE WITH IT
		JRST NSPTM3]	;MOVE ON
	MOVEM T1,LLBLK		;SAVE THE LL BLOCK ADDRESS
	CALL BLKLOK		;LOCK THE LL BLOCK
	 JRST [	SETZM INNSPT	;CAN'T, NO LONGER IN TIMER
		CALLRET ULOKLL]	;GIVE UP TREE LOCK
	LOAD T3,LLLKP,(T1)	;GET NODE'S VERSION
	CAIN T3,.NSP31		;IS IT NSP 3.1?
	JRST NSPTM7		;YES, DON'T TIME IT
	MOVE T2,MSGADR		;RETRIEVE THE MESSAGE ADDRESS
	TMNN LLBRP,(T1)		;NO, IS FLOW TURNED OFF?
	IFSKP.			;YES
	   LOAD T4,MSTOM,(T2)	;GET TYPE OF MSG
	   CAIN T4,MSDAT	;IS IT NORMAL DATA?
	   JRST NSPTM7		;YES, CAN'T RESEND NORMAL DATA WHEN FLOW IS OFF
	ENDIF.
	MOVE T3,LLTIMO(T1)	;GET TIME OUT VALUE FOR LINK
	IMUL T3,NSLDFS		;SCALE IT BY
	IDIVI T3,^D16		; LOCAL DELAY FACTOR
	ADD T3,MSTIM(T2)	;ADD TIME STAMP OF THE MESSAGE
	CAMG T3,TODCLK		;TIMED OUT ?
	JRST NSPTMO		;YES
	CALL BLKULK		;NO, UNLOCK THE LL BLOCK
	SETZM INNSPT		;NO LONGER IN TIMER
	CALLRET ULOKLL		;GIVE UP TREE LOCK

NSPTMO:	CALL DATINR		;GIVE INTERRUPT TO USER
	LOAD T4,LLHSN,(T1)	;GET THE REMOTE NODE NUMBER
	AOS @[EP. NSTIMO(T4)]	;INCR THE COUNT
	LOAD T4,MSTRY,(T2)	;GET NUMBER OF TIMES ALREADY RETRIED DUE TO TIME OUT
	CAMGE T4,NSTRYS		;ALREADY TRIED ENOUGH TIMES?
	JRST NSPTM2		;NO, DO IT AGAIN
	MOVEI T2,.DCX38		;REASON IS TIMED OUT
	STOR T2,LLRSN,(T1)	;SAVE IT
	MOVEI T2,LLSABT		;YES, SAY LINK ABORTED
	STOR T2,LLSTA,(T1)  	; IS ABORTED
	LOAD T4,LLHSN,(T1)	;GET THE REMOTE NODE NUMBER
	BUG.(INF,NSPLAT,NSPSRV,SOFT,<NSP response is LATE>,<<T4,NODE>>,<

Cause:	NSP has resent a message a number of times and received no response.

Action:	Normally this is caused by heavy network traffic or a highly
	congested node in the network;  the network software should continue
	to function without major difficulty.  If the condition persists,
	check the quality of the communication path to the node that is not
	responding.

Data:	NODE - the node number(OCTAL) to which we are trying to send
>)
	CALL CHKLLT		;CHECK FOR TTY ON THIS LINK
	CALL FLUSH		;GET RID OF THE LINK'S MESSAGES
	TMNN LLSDE,(T1)		;LINK DISASSOCIATED?
	JRST NSPTM7		;NO, GO TRY FOR MORE
	OKINT			;YES, MATCH THE NOINT IN BLKLOK
	CALL DELNOD		;GET RID OF THE LL BLOCK
	JRST NSPTM3		;MOVE ON

NSPTM2:	INCR MSTRY,(T2)		;ANOTHER TRY
	LOAD W3,MSSEG,(T2)	;SAVE SEGMENT # OF TIMED OUT MESSAGE
	LOAD W2,MSLNK,(T2)	;GET ADDRESS OF NEXT SEGMENT
NSPTM8:	SETZ T3,		;NO PREVIOUS MESSAGE
	MOVEI T4,LLSEGQ(T1)	;GET HEAD OF LL'S QUEUE
	CALL UNQSEG		;REMOVE CURRENT MESSAGE FROM QUEUE
	LLLULK			;GIVE UP LOCK WHILE TRYING TO SEND MESSAGE
	CALL SNDSE0		;AND SEND IT AGAIN
	LLLOCK			;GET LOCK AGAIN
	MOVE T1,LLBLK		;RETRIEVE THE LL BLOCK ADDR
	SKIPE W2		;ANY MORE TO RESEND?
	IFNSK.			;YES
	   MOVE T2,W2		;GET ADDRESS OF NEXT SEGMENT
	   LOAD W2,MSSEG,(T2)	;GET ITS SEGMENT NUMBER
	   CAMG W2,W3		;DONE THEM ALL YET?
	   JRST NSPTM7		;YES, MOVE ON
	   LOAD W2,MSLNK,(T2)	;NO, GET NEXT MESSAGE
	   JRST NSPTM8		;GO DO IT
	ENDIF.
NSPTM7:	CALL BLKULK		;UNLOCK THE LL BLOCK
NSPTM3:	SOSGE W1		;HAVE WE DONE OUR QUOTA?
	JRST NSPTM6		;YES, ALL DONE
	SKIPE NSSNTQ		;NO, ANYTHING ON THE QUEUE?
	JRST NSPTM5		;YES, GO DO SOME MORE
NSPTM6:	SETZM INNSPT		;NO LONGER IN TIMER
	CALLRET ULOKLL		;GIVE UP TREE LOCK

	ENDSV.
	ENDAV.
SUBTTL NSP BACKGROUND TASK - INACTIVITY TIMER CHECK

NSPINA:	MOVE T1,LSTINT		;GET LAST TIME INACTIVITY TIMERS WERE CHECKED
	ADDI T1,CKINTM		;ADD CHECKING INTERVAL
	CAMLE T1,TODCLK		;TIME TO DO CHECKS AGAIN?
	RET			;NO
	MOVE T1,TODCLK		;YES, GET TIME
	MOVEM T1,LSTINT		;SAY WE ARE CHECKING NOW
	SKIPN LLNUM		;ANY LINKS IN USE?
	RET			;NO
	LLLOCK			;LOCK THE LL TREE
	SETOM INNSPI		;NOW IN INACTIVITY TIMER
	MOVE T1,[INACOR]	;GET ADDRESS OF COROUTINE
	SETO T2,		;ALL LINKS
	CALL OBJSRC		;SEARCH THE LL TREE
	 JFCL			;DONE THEM ALL
	SETZM INNSPI		;NO LONGER IN INACTIVITY TIMER
	CALLRET ULOKLL		;UNLOCK THE LL TREE AND RETURN

INACOR:	SAVET
	STKVAR <INALLB>		;LL BLOCK ADDRESS
	MOVEM T1,INALLB		;SAVE THE LL BLOCK ADDRESS
	CALL BLKLOK		;LOCK THE LL BLOCK
	 RET			;CAN'T, BETTER LUCK NEXT TIME
	LOAD T2,LLSTA,(T1)	;GET STATE OF LINK
	CAIE T2,LLSRUN		;RUNNING?
	JRST INACOD		;NO
	LOAD T2,LLLKP,(T1)	;GET NSP VERSION
	CAIE T2,.NSP31		;NSP 3.1?
	SKIPN T2,LLINAC(T1)	;NO, INACTIVITY TIMER ON?
	JRST INACOD		;NO
	CAMLE T2,TODCLK		;YES, TIMED OUT?
	JRST INACOD		;NO
	SETZ T2,		;NO NEW PERMISSIONS
	MOVEI T3,MSDAT		;ON THE DATA CHANNEL
	CALL SNDLS		;FIRE OFF A LS MSG TO SEE IF THE OTHER
	 JRST [MOVE T1,INALLB	;COULDN'T SEND IT
	       CALLRET BLKULK]	;DONE WITH THIS LL
	MOVE T1,INALLB		;RETRIEVE THE LL BLOCK ADDRESS
	SETZM LLINAC(T1)	;OK, TURN OFF INACTIVITY TIMER
	SETZRO <LLLSA>,(T1)  	;CLEAR THE LS INDICATORS
INACOD:	CALLRET BLKULK		;DONE WITH THIS LL

	ENDSV.
SUBTTL NSP Background Task - Node Counters Bookkeeping

	RESCD

;ROUTINE TO DO NSP INPUT BOOKKEEPING - UPDATES THE FOLLOWING NSP COUNTERS
;	MESSAGES RECEIVED
;	BYTES RECEIVED
;ACCEPTS:	1/  LL BLOCK ADDRESS
;		2/  MESSAGE ADDRESS
;RETURNS:	+1
;
;PRESERVES T1,T2

NSINBK:	LOAD T3,LLHSN,(T1)	;GET NODE NUMBER
	AOS @[EP. NSMSGR(T3)]	;INCR THE COUNT
	LOAD T4,MSCNT,(T2)	;GET NUMBER OF BYTES IN MESSAGE
	ADDM T4,@[EP. NSBYTR(T3)] ;UPDATE THE COUNT
	RET


;ROUTINE TO DO NSP OUTPUT BOOKKEEPING - UPDATES THE FOLLOWING COUNTERS
;	MESSAGES SENT
;	BYTES SENT
;ACCEPTS:	1/ LL BLOCK ADDRESS
;RETURNS:	+1
;
;PRESERVES T1,T2

NSOUBK:	LOAD T3,LLHSN,(T1)	;GET THE NODE NUMBER
	AOS @[EP. NSMSGS(T3)]	;INCR THE COUNTER
	MOVE T4,LLBPCT(T1)	;GET THE NUMBER OF BYTES IN MESSAGE
	ADDM T4,@[EP. NSBYTS(T3)] ;UPDATE THE COUNTER
	RET
SUBTTL NSP Background Task


;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

   REPEAT 0,<
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:	NOSKD1			;GET SET TO PULL A MESSAGE OFF
	CHNOFF DLSCHN		;TURN OFF DTE
	MOVE T1,MSGQ		;GET FIRST MSG ON Q
	LOAD T2,MSLNK,(T1)	;GET NEXT MSG
	SKIPN T2		;WAS A MESSAGE THERE?
	MOVEM T2,MSGQ+1		;NO, RESET THE TAIL
	MOVEM T2,MSGQ		;MAKE NEW Q HEAD
	CHNON DLSCHN		;TURN ON DTE
	OKSKD1			;AND ALLOW SCHEDULING
	SETZM MSGLCL		;ASSUME LOCAL IN TRVAR
	TMNE MSLCL,(T1)		;DID IT COME FROM DRIVER?
   REPEAT 0,<			;2020 LOOPBACK
	TMNN 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]
   >				;END REPEAT 0
	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
	MOVEI T2,MSHDR(T1)	;GET TO START OF DATA
	HRLI T2,(<POINT 8,>)	;MAKE A BP TO IT
	MOVEM T2,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
	GETBYM (MSGCNT,MSGBYP,BADMSG)		;GET BYTE. IF BADLY FORMED, REJECT MSG
	TRNE T2,1		;IS THIS A PHASE III TRANSPORT MSG?
	JRST TOSMSG		;YES, IGNORE 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		;GET LOCATION OF REMOTE HOST NAME
	MOVEI T4,MAXHST		;MAXIMUM NUMBER OF CHARS. IN NAME
	CALL GTASCI		;AND GET ASCII FIELD
	 JRST BADMSG		;BADLY FORMED MESSAGE
	MOVEM T2,MSGHNC		;SAVE NO. OF CHARS. IN HOST NAME
	GETBYM (MSGCNT,MSGBYP,BADMSG) ;TO BADMSG IF BADLY FORMED
DOMSG:	MOVE T3,MSGBLK		;GET MESSAGE BLOCK
	STOR T2,MSMFL,(T3)	;SAVE FLAGS
	CAIN T2,RCIMFL		;IS THIS A PHASE IV RETRANSMITTED CI?
	JRST TOSMSG		;YES, IGNORE IT QUIETLY
	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!TOSMSG		;A NOOP. IGNORE IT
	IFIW!CIMSG		;CONNECT-INITIATE
	IFIW!CCMSG		;CONNECT-CONFIRM
	IFIW!DIMSG		;DI MESSAGE
	IFIW!DCMSG		;DC MESSAGE
	IFIW!STRMSG		;A STARTUP MESSAGE
	IFIW!BADMSG		;BADLY FORMED MESSAGE
	IFIW!BADMSG		;BADLY FORMED MESSAGE
;RECEIVED A MESSAGE WITH AN INVALID ROUTING HEADER.

INVHDR:	MOVE T1,MSGBLK		;GET MESSAGE
	LOAD T1,MSPRT,(T1)	;GET PORT I.D.
	BUG.(CHK,NSPRTH,NSPSRV,SOFT,<NSPTSK- INVALID ROUTING HEADER>,<<T1,LINE>,<T2,BADBYT>>,<

Cause:	An invalid routing header has been detected on a DECnet message.

Action:  If this BUGCHK happens frequently, inform your network administrator.

Data:	LINE - the number of the line which received the invalid message

	BADBYT - the invalid byte


>)
	JRST TOSMSG		;DONE

;RECEIVED AN UNINTELLIGIBLE MESSAGE

BADMSG:	BUG.(INF,NSPBAD,NSPSRV,SOFT,<NSP has received an unintelligible message>,,<

Cause:	An DECnet message has been received which was not in proper format.

Action:	A pointer to most recent message which caused an NSPBAD BUGINF
	is kept in BADMSP.  The message block is not freed until another
	NSPBAD occurs, so look in that message to find out why NSPSRV
	might reject it.

>)
	MOVE T1,MSGBLK		;GET MESSAGE ADDRESS
	EXCH T1,BADMSP		;SAVE MOST RECENT BAD MESSAGE FOR DEBUG
	JUMPE T1,R		;LEAVE IF NO OLD MSG TO FREE
	CALLRET RELRES		;FREE OLD BAD MESSAGE

RS BADMSP,1			;PLACE TO STORE PTR TO MOST RECENT BAD MSG

TOSMSG:	MOVE T1,MSGBLK		;GET MESSAGE ADDRESS
	CALLRET RELRES		;GIVE BACK SPACE
;GOT A STARTUP MESSAGE

STRMSG:	SKIPE MSGHSN		;ALREADY PARSED A NODE NAME?
	JRST BADMSG		;YES, THROW IT AWAY
	SETZM Q2		;NO, 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
	GETBYM (MSGCNT,MSGBYP,BADSTR)		;GET STARUP TYPE
	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
	GETBYM (MSGCNT,MSGBYP,BADSTR)		;GET SUPPORTED FUNCTIONS
	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
	GETBYM (MSGCNT,MSGBYP,BADSTR)		;GET ITS REQUIRED FUNCS
	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
	SUBI T2,NSPOVR		;YES. ACCOUNT FOR NSP OVERHEAD BYTES
	MOVEM T2,NSPMAX(Q1)	;SET UP NSPMAX (MAX USER BYTES IN A SEGMENT)
	MOVEI T4,10		;BYTES TO IGNORE
STRMS1:	GETBYM (MSGCNT,MSGBYP,BADSTR)		;GET A BYTE
	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
   REPEAT 0,<			;2020 LOOPBACK
	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:
   >				;END REPEAT 0
	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
	MOVE T1,ITSNUM(Q1)	;GET PORT'S NODE NUMBER
	MOVX T2,.NDSON		;SAY IT'S REACHABLE
	MOVEI T3,3		;IT'S PHASE III
	CALL ADDNOD
	 BUG.(INF,NSPSTR,NSPSRV,SOFT,<STRMSG - Could not add node to known node table>,,<

Cause:	This BUG is not documented yet.

Action:

Data:

>)
	JRST TOSMSG		;AND GO TO IT

BADSTR:	CALL PROOFF		;TURN OFF FE
	BUG.(INF,ILLSTR,NSPSRV,SOFT,<NSPTSK-ILLEGAL INIT MESSAGE>,<<Q1,DTE>>,<

Cause:	This BUG is not documented yet.

Action:

Data:

>)
	JRST TOSMSG		;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,DCN
	JRST [	BUG.(CHK,NSPBPN,NSPSRV,SOFT,<BAD NSP PORT NUMBER>,<<T1,BADDTE>>,<

Cause:	This BUG is not documented yet.

Action:

Data:

>)
		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,15>,MSGW1>  ;MONUMENT TO HACKERY
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)

   IFN DN20SW,<			;CHECK FOR MULTIPLE MCBS
	CAIE T2,1		;WAS IT THE PRIMARY MCB?
	JRST DEDMC3		;NO
   >

;RESET TOPOLOGY

	SETZM NODTBL		;CLEAR
	HRLI T1,NODTBL		; REACHABLE
	HRRI T1,NODTBL+1	;  NODES
	MOVEI T2,NODTSZ		;   TABLE
	BLT T1,NODTBL(T2)	;
	MOVE T1,OURNUM		;GET OUR NODE NUMBER
	MOVE T2,[POINT 2,NODTBL]  ;POINT TO BEGINNING OF TABLE
	ADJBP T1,T2		;OFFSET TO US
	MOVEI T2,2		;WE'RE PHASE II
	DPB T2,T1		;SAY SO
;
DEDMC3:	MOVE T2,DEDPRT		;GET PORT NUMBER

   IFN DN20SW,<			;CHECK FOR OTHER MCBS
	CAIE T2,1		;WAS IT THE PRIMARY MCB?
	JRST DEDMC4		;NO
	SKIPL MCBDTE(T2)	;IS ANOTHER MCB RUNNING?
	JRST DEDMC4		;NO
	MOVE T1,[440200,,NODTBL]  ;BP TO REACH TABLE
	MOVE T3,ITSNUM(T2)	;GET NODE NUMBER
	ADJBP T3,T1		;OFFSET INTO REACH
	MOVEI T1,3		;SAY PHASE III
	DPB T1,T3		;UPDATE TABLE
   >

DEDMC4:	MOVE T1,ITSNUM(T2)	;GET ITS NODE NUMBER
	SETZM ITSNUM(T2)	;CLEAR IT
	MOVEI T2,.NDSOF		;NODE IS OFF
	CALL ADDNOD		;REMOVE IT
	 JFCL
	MOVE T2,DEDPRT		;GET BACK PORT NUMBER
	IMULI T2,2		;POINT AT RIGHT PLACE
	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,LLSTA,(T1)	;GET THE LINK'S STATE
	CAIG T2,LLSLIS		;IS IT LISTENING?
	RET			;YES, NO CLEANUP NEEDED
	JN LLLOC,(T1),R		;IF LOCAL, NOTHING TO DO
	JN LLDED,(T1),R		;IF ALREADY PROCESSED, NOTHING TO DO
	LOAD T2,LLPRT,(T1)	;GET THE LNK'S PORT NUMBER
	CAME T2,DEDPRT		;THE DEAD ONE?
	RET			;NO, ALL DONE
	CALL BLKLOK		;YES. LOCK THE LL BLOCK
	 JRST [	LLLULK		;CAN'T.  UNLOCK TREE
		MOVEM T1,WAITER	;STORE WAIT
		RETSKP]		;AND STOP NOW
	LLLULK			;UNLOCK THE TREE
	LOAD T2,LLSTA,(T1)	;GET STATE AGAIN
	SETONE LLDED,(T1)	;INDICATE THIS BLOCK PROCESSED FOR DEAD MCB
	CAIG T2,LLSCCS		;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	;FOR DI REC
		CALL RJECT1]-2(T2) ;AND, FINALLY, FOR CC SENT
	SETZM WAITER		;FLAG INDICATES "CONTINUE AT TOP OF TREE"
	JN LLSDE,(T1),[	OKINT		;IF DISASSOCIATED
			CALL FLUSH  	;GET RID OF ALL MESSAGES
			LLLOCK		;LOCK UP THE LL TREE
			CALL DELNOD 	;RELEASE NODE
			LLLULK		;GIVE UP THE TREE LOCK
			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:	STKVAR <NDNUM>		;TEMP STORAGE FOR NODE NUMBER
	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
	GETBYM (MSGCNT,MSGBYP,INVPRC)		;GET FORMAT OF DEST OBJECT
	CAILE T2,OBJTWO		;IS IT A FORMAT WE UNDERSTAND?
INVPRC:	 JRST [	MOVEI T2,.DCX5
		JRST CIDC]	;AND ERROR
	MOVE T4,T2		;SAVE OBJECT TYPE
	GETBYM (MSGCNT,MSGBYP,INVPRC)		;GET OBJECT NUMBER
	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:	GETBYM (MSGCNT,MSGBYP,INVPRC)		;GET SOURCE OBJECT TYPE
	CAILE T2,OBJTWO		;VALID?
	 JRST INVPRC
	MOVE T4,T2		;SAVE IT
	GETBYM (MSGCNT,MSGBYP,INVPRC)		;GET OBJECT #
	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:	LOAD T2,SCSTA		;GET OUR NODE STATE
	CAIN T2,.NDON		;ARE WE ON?
	IFSKP.
	   MOVEI T2,.DCX3	;NO, "REMOTE NODE SHUTTING DOWN"
	   JRST CIDC		;AND REJECT THE CONNECT
	ENDIF.
DSCNO2:	MOVE T2,MSGBLK		;POINT TO MSG BLOCK AGAIN
	LOAD T2,MSPRT,(T2)	;GET PORT MESSAGE CAME FROM
	SKIPN MSGLCL		;LOCAL CONNECTION?
	IFSKP.
	   MOVE T2,OURNUM	;YES
	ELSE.
	   CALL NAMNUM		;NUMERIC NODE NAME?
	   IFNSK.
	      CALL DSCCNV	;NO, CONVERT NAME TO NUMBER
	       JRST BADNOD	;COULDN'T
	      JRST DSCNO4	;MOVE ON
	   ENDIF.
	   MOVEI T1,MSGHSN	;CONVERT
	   HRROS T1		; HOST STRING
	   MOVEI T3,^D10	;  TO A
	   NIN			;   NUMBER
	    JRST BADNOD		;MUST BE FUNNY
	   CAILE T2,BIGNOD	;THIS A LEGIT NODE?
	   JRST BADNOD		;NO
	ENDIF.
DSCNO4:	MOVEM T2,NDNUM		;STASH NODE NUMBER
	AOS @[EP. NSCONR(T2)]	;INCR THE CONNECTS RECEIVED COUNT
	AOS @[EP. NSMSGR(T2)]	;COUNT THIS MESSAGE
	MOVE T3,MSGBLK		;RETRIEVE MESSAGE ADDR
	LOAD T3,MSCNT,(T3)	;GET NUMBER OF BYTES IN MESSAGE
	ADDM T3,@[EP. NSBYTR(T2)] ;ADD THEM IN
DSCNO5:	MOVEI T1,CICOR		;COROUTINE ADDRESS
	MOVEI T2,1		;LOOK FOR LISTENING OBJECT ONLY
	LLLOCK			;LOCK THE TREE
	CALL OBJSRC		;GO LOOK FOR AVAILABLE OBJECT
	 JRST [	CAIE T2,.DCX4		;OBJECT EXIST?
		IFSKP.
		   MOVE T3,NDNUM	;NO, RETRIEVE NODE NUMBER
		   AOS @[EP. NSRCNE(T3)] ;COUNT IT
		ENDIF.
		LLLULK			;RELEASE TREE
		JRST CIDC]
	CALL BLKLOK		;LOCK THE BLOCK
	 JRST [	LLLULK		;COULDN'T.
		MDISMS		;WAIT HERE
		JRST DSCNO5]	;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
	SKIPN MSGLCL		;LOCAL CONNECTION?
	IFSKP.
	   SETONE LLLOC,(T1)	;YES, NOTE THIS IS A LOCAL LINK
	   MOVE T2,OURNUM	;GET OUR NODE NUMBER
	   STOR T2,LLHSN,(T1)	;PUT IT IN LL BLOCK
	ELSE.
	   MOVE T2,NDNUM	;RETRIEVE NODE NUMBER
	   MOVE T1,MSGLLB	;GET LL BLOCK ADDRESS
	   STOR T2,LLHSN,(T1)	;PUT NODE NUMBER IN LL BLOCK
	   LOAD T1,LLHST,(T1)	;PLACE TO PUT HOST'S NAME STRING
	   HRROS T1		;MAKE A BP TO IT
	   MOVEI T3,^D10	;IN DECIMAL
	   NOUT
	    JFCL
	   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
	ENDIF.
	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 RELDCN	;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:	GETBYM (MSGCNT,MSGBYP,NODATA)		;GET MENU BYTE
	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,MAXUAP		;MAX SIZE OF USERID
	CALL GTASCI		;GET IT
	 JRST BADUDT		;BADLY FORMED
	LOAD T3,LLPSW,(T1)	;WHERE TO PUT PASSWORD
	MOVEI T4,MAXUAP		;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,MAXUAP		;MAX SIZE OF ACCOUNT
	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,MAXOPT
	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
	MOVE T1,MSGBLK		;GET BACK MESSAGE BLOCK
	CALL RELRES		;FREE THE BLOCK
	RET			;RETURN TO BACKGROUND TASK DISPATCHER

	ENDSV.

;RECEIVED A MESSAGE FROM A NODE WHOSE NAME WE DON'T RECOGNIZE

BADNOD:	BUG.(INF,NSPNOD,NSPSRV,SOFT,<NSP got a message from an unknown node>,,<

Cause:	An incoming NSP connection attempt was from a node we don't know.
	Either, it was a Phase II node and its name is not in our data base
	or it was from a Phase III node and we were unable to interpret the
	node number.

Action:	The first case indicates that there is a node in the network whose
	node name has not been assigned through NCP.  If you want to
	communicate with the node  SET NODE number NAME name.

	The second case should be filtered by the DN20.  If it happens the
	DN20 has a bug in Transport.
>)
	MOVEI T2,.DCX7		;UNSPECIFIED ERROR
	JRST CIDC		;GO SEND DC
;TRY TO CONVERT THE NODE NAME TO A NODE NUMBER
;USES TRVAR MSGHSN,MSGHNC,MSGLLB
;RETURNS	+1  NO NAME ASSIGNED TO NODE NUMBER
;		+2  T2/ NODE NUMBER

DSCCNV:	SAVEQ
	MOVNI Q3,BIGNOD		;MAKE
	HRLS Q3			; AOBJN
	HRRI Q3,1		;  WORD
	SETZB T3,Q2		;PERMANENT VALUES THROUGH EXTEND LOOP
DSCCN1:	MOVE T1,[POINT 7,MSGHSN]  ;BP TO HOST NAME IN MSG
	MOVE T2,[POINT 6,]	;BP TO ENTRY
	HRRI T2,NODMAP(Q3)	; IN NODE NAME MAPPING TABLE
	MOVE T3,MSGHNC		;GET NUMBER OF CHARS. IN HOST NODE NAME
	TLO T3,400000		;SPECIAL CALL TO COMPAR
	MOVNI T4,40		;COMPARE ASCII TO SIXBIT
	CALL COMPAR		;DO THEY MATCH?
	IFSKP.
	   HRRZ T2,Q3		;YES, POSITION NODE NUMBER
	   RETSKP
	ENDIF.
	AOBJN Q3,DSCCN1		;NO, TRY ANOTHER
	RET			;DIDN'T FIND IT


;SEE IF IT'S A NODE NAME OR A NUMERIC NAME
;RETURNS:	+1  NOT NUMERIC
;		+2  NUMERIC

NAMNUM:	MOVE T1,[440700,,MSGHSN]  ;BP TO NAME IN MSG
	MOVE T2,MSGHNC		;GET NUMBER OF CHARS. IN NAME
NAMNU1:	ILDB T3,T1		;GET A CHAR.
	CAIL T3,"0"		;IS IT
	CAILE T3,"9"		; NUMERIC?
	RET			;NO
	SOJG T2,NAMNU1		;YES, ANY MORE TO CHECK
	RETSKP			;NO, NAME IS NUMERIC
;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,MSGLKP		;GET LINK PRIORITY
	STOR T2,LLLKP,(T1)	;SAVE IT IN LL BLOCK
	MOVE T2,MSGW1		;GET FC OPTION
	STOR T2,LLMFC,(T1)	;SAVE IT IN LL BLOCK
	MOVE T2,MSGW2		;GET SEGSIZE
	MOVE T3,MSGBLK		;GET MESSAGE ADDRESS
	LOAD T3,MSMFL,(T3)	;GET MESSAGE FLAGS
	CAIE T3,CIMMFL		;A CI?
	JRST [	LOAD T4,LLSWG,(T1)	;NO, A CC.  GET SEGSIZ OF CI
		CAMLE T2,T4		;OUR'S LESS?
		MOVE T2,T4		;NO, USE SEGSIZ OF CI
		TMNE LLLOC,(T1)		;LOCAL CONNECTION?
		JRST FILLI2		;YES, NO FURTHER CHECK NEEDED
		LOAD T4,LLPRT,(T1)	;GET PORT NUMBER
		CAMLE T2,NSPMAX(T4)	;OUR'S LESS THAN PORT'S?
		MOVE T2,NSPMAX(T4)	;NO, USE PORT'S SEGSIZ
		JRST FILLI2]
FILLI2:	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

   REPEAT 0,<
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

   REPEAT 0,<
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

	ENDAV.			;END ACVAR
   >
;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
	MOVE T2,MSGBLK		;GET MESSAGE ADDRESS
	CALL NSINBK		;DO BOOKKEEPING
	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,MAXOPT
	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 TOSMSG		;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 TOSMSG		;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:	CAIL T4,2		;VALID SUBTYPE?
	JRST TOSMSG		;NO, IGNORE IT
	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
	MOVE T2,MSGBLK		;GET MESSAGE ADDRESS
	CALL NSINBK		;DO BOOKKEEPING
	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
	CALL RJECT		;ABORT THE LINK
	JRST CCJEC1		;SEND THE DC
;IN CC SENT STATE

ACKCCS:	STKVAR <LLBLK>		;TEMP STORAGE FOR LL BLOCK ADDRESS
	MOVEM T1,LLBLK		;SAVE IT
ACKCC4:	CALL TURNON		;TRY TO SEND INITIAL LS MESSAGE
	 JRST[ PUSH P,T1	;SAVE SCHEDULER TEST
	       MOVE T1,LLBLK	;RETRIEVE LL BLOCK ADDRESS
	       SETONE LLTRN,(T1)  ;STILL NEED LS
	       CALL BLKULK	;UNLOCK THE LL BLOCK
	       POP P,T1		;RETRIEVE SCHEDULER TEST
	       CALL GENWAT	;AND WAIT HERE
	       MDISMS		;UNTIL FREE SPACE IS AVAILABLE
ACKCC5:	       MOVE T1,LLBLK	;GET LL BLOCK ADDRESS
	       CALL BLKLLK	;LOCK THE BLOCK
	        JRST [MDISMS	;CAN'T, WAIT
	              JRST ACKCC5]  ;AND TRY TO LOCK AGAIN
	       JRST ACKCC4]	;TRY TO SEND MESSAGE AGAIN
	SETZRO LLTRN,(T1)	;DON'T NEED LS ANYMORE
	MOVEI T2,LLSRUN		;NOW IN
	STOR T2,LLSTA,(T1)	; RUN STATE
	MOVEI T2,1		;SET INITIAL LS/INT
	STOR T2,LLMIC,(T1)	; REQUEST COUNT
ACKCC3:	MOVE T2,LLSEGQ(T1)	;GET ADDRESS OF FIRST MESSAGE ON LINK'S QUEUE
	JUMPE T2,ACKRUN		;IF NONE, ALL SET
	SETZ T3,		;NO PREVIOUS MESSAGE YET
ACKCC1:	LOAD T4,MSMFL,(T2)	;GET MESSAGE TYPE
	CAIN T4,CNMRFL+CNMCF	;IS IT A CC?
	JRST ACKCC2		;YES, GO REMOVE IT FROM THE QUEUE
	MOVE T3,T2		;MAKE THIS ONE PREVIOUS
	OPSTR <SKIPE T2,>,MSLNK,(T2)  ;GET ADDRESS OF NEXT
	JRST ACKCC1		;GO TRY IT
	JRST ACKRUN		;NO MORE TO TRY
ACKCC2:	MOVEI T4,LLSEGQ(T1)	;GET ADDRESS OF LINK'S SEGMENT QUEUE
	CALL UNQSEG		;REMOVE THE CC FROM THE SENT QUEUE
	MOVE T1,T2		;GET MESSAGE ADDRESS IN NECESSARY PLACE
	CALL RELRES		;GIVE BACK THE SPACE
	MOVE T1,LLBLK		;GET BACK THE LL BLOCK ADDRESS

;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
   REPEAT 0,<
	JN LLINT,(T1),[
		CALL SQILS	;INTERNAL LINK, TRY LS SEND AGAIN
		MOVE T1,MSGLLB	;FAILED, RESTORE LINK BLOCK ADDRESS
		JRST CCDON]
   >
	TMNE LLLSA,(T1)		;WANT TO RETRY A LS SEND?
	CALL DATINR		;YES. MAKE PROCESS WAKE NOW THEN
	JRST CCDON		;AND DONE

	ENDSV.
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
	MOVE T2,MSGBLK		;GET MESSAGE ADDRESS
	CALL NSINBK		;DO BOOKKEEPING
	LOAD T3,LLOPT,(T1)	;GET OPTDATA, IF ANY
	MOVEI T4,MAXOPT
	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 DCDCS		;SEND DC

;HERE FOR DI RECEIVED WHEN IN DIS STATE

DIDIDC:	TMNE LLLOC,(T1)		;LOCAL MESSAGES AREN'T
	 JRST DIMSG2		; ON SENT QUEUE
	MOVE T2,LLSEGQ(T1)	;GET ADDRESS OF FIRST MESSAGE IN QUEUE
	SETZ T3,		;NO PREVIOUS MESSAGE YET
DIDID1:	LOAD T4,MSMFL,(T2)	;GET MESSAGE TYPE
	CAIN T4,CNMRFL+CNMDI	;IS IT A DI?
	JRST DIDID2		;YES
	MOVE T3,T2		;NO, MAKE THIS MESSAGE PREVIOUS
	LOAD T2,MSLNK,(T2)	;GET ADDRESS OF NEXT MESSAGE
	JRST DIDID1		;GO TRY THIS ONE
DIDID2:	MOVEI T4,LLSEGQ(T1)	;GET ADDRESS OF SEGMENT QUEUE HEAD
	CALL UNQSEG		;REMOVE SEGMENT FROM QUEUE
	MOVE T1,T2		;GET ADDRESS OF OLD DI
	CALL RELRES		;GIVE BACK THE SPACE
	MOVE T1,MSGLLB		;RETRIEVE LL BLOCK ADDRESS
;DI RECEIVED IN RUN, DIQ, DIR, OR CCS

DIMSG2:	CALL CHKFRN		;SOURCE ADDR MUST MATCH
	 JRST CCJECT		;DOESN'T, SEND DC
	CALL SHUTLK		;SHUT DOWN LINK

;COMMON POINT FOR DI RECEIVED - RESPONSE IS ALWAYS REASON CODE 42

DCDCS:	STKVAR <DILLB>
	MOVEM T1,DILLB		;PRESERVE LL BLOCK ADDRESS
	MOVEI T2,.DCX42		;SAY REPLY TO DI
	CALL CIDC		;SEND DC
	MOVE T1,DILLB		;GET BACK LL BLOCK ADDRESS
	TMNE LLSDE,(T1)		;DISASSOCIATED?
	IFSKP.
	   CALL BLKULK		;NO, UNLOCK LL
	   RET			;DONE
	ENDIF.
	CALL FLUSH		;YES, GET RID OF ALL MESSAGES
	LLLOCK			;LOCK THE LL TREE
	CALL DELNOD		;GET RID OF THIS LL
	LLLULK			;UNLOCK THE TREE
	OKINT			;MATCH THE NOINT DONE IN BLKLOK
	DECR DCCUR		;GIVE BACK A LINK
	RET

	ENDSV.
;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
	CALL CHKLLT		;CHECK FOR TTY ON THIS LINK
;	CALL TELDIS		;NOTIFY DRIVER IF THIS IS AN INTERNAL LINK
	RET

;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:	CALL CHKLLT		;CHECK FOR TTY ON THIS LL
;	CALL TELDIS		;NOTIFY DRIVER IF AN INTERNAL LINK
	RET


;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

   REPEAT 0,<
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 TOSMSG]	;IGNORE THE MESSAGE
	MOVEM T1,MSGLLB		;SAVE THE LL BLOCK ADDRESS
	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 DIS STATE - MUST REMOVE THE DI FROM THE SENT QUEUE
;BEFORE CLOSING THE LINK

DCGUD:	TMNE LLLOC,(T1)		;LOCAL MESSAGES AREN'T
	 JRST DCABT		; ON SENT QUEUE
	MOVE T2,LLSEGQ(T1)	;GET ADDRESS OF FIRST MESSAGE IN QUEUE
	SETZ T3,		;NO PREVIOUS MESSAGE YET
DCGUD1:	LOAD T4,MSMFL,(T2)	;GET MESSAGE TYPE
	CAIN T4,CNMRFL+CNMDI	;IS IT A DI?
	JRST DCGUD2		;YES
	MOVE T3,T2		;NO, MAKE THIS MESSAGE PREVIOUS
	LOAD T2,MSLNK,(T2)	;GET ADDRESS OF NEXT MESSAGE
	JRST DCGUD1		;GO TRY THIS ONE
DCGUD2:	MOVEI T4,LLSEGQ(T1)	;GET ADDRESS OF SEGMENT QUEUE HEAD
	CALL UNQSEG		;REMOVE SEGMENT FROM QUEUE
	MOVE T1,T2		;GET ADDRESS OF OLD DI
	CALL RELRES		;GIVE BACK THE SPACE
	MOVE T1,MSGLLB		;RETRIEVE THE LL BLOCK ADDRESS

;RECEIVED DC IN NON-RUN STATE

DCABT:	JN LLSDE,(T1),[
		CALL RELLNK	;IF DISASSOCIATED
		JRST TOSMSG]	;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 NOINT IN BLKLOK
	CALL FLUSH		;GET RID OF ALL MESSAGES
	LLLOCK			;LOCK UP THE TREE
	CALL DELNOD		;FREE LL BLOCK
	LLLULK			;GIVE UP THE LOCK
	RET			;DONE
;DATA MESSAGE RECEIVED

DATMSG:	CAIE T4,5		;VALID
	CAIN T4,7		; SUBTYPE?
	JRST BADMSG		;NO, IGNORE IT
	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
	MOVE T2,MSGBLK		;GET MESSAGE ADDRESS
	CALL NSINBK		;DO BOOKKEEPING
	LOAD T2,LLSTA,(T1)	;GET STATE
	JRST @DATSTA-1(T2)	;GO DO IT

;IN CC SENT STATE

DATCCS:	STKVAR <LLBLK>		;TEMP STORAGE FOR LL BLOCK ADDRESS
	MOVEM T1,LLBLK		;SAVE IT
DATCC4:	CALL TURNON		;TRY TO SEND LS MESSAGE
	 JRST [ PUSH P,T1	;SAVE SCHEDULER TEST
	       MOVE T1,LLBLK	;RETRIEVE LL BLOCK ADDRESS
	       SETONE LLTRN,(T1)  ;STILL NEED LS
	       CALL BLKULK	;UNLOCK THE LL BLOCK
	       POP P,T1		;RETRIEVE SCHEDULER TEST
	       CALL GENWAT	;AND WAIT HERE
	       MDISMS		;UNTIL FREE SPACE IS AVAILABLE
DATCC6:	       MOVE T1,LLBLK	;GET LL BLOCK ADDRESS
	       CALL BLKLLK	;LOCK THE BLOCK
	        JRST [MDISMS	;CAN'T, WAIT
	              JRST DATCC6]  ;AND TRY TO LOCK AGAIN
	       JRST DATCC4]	;TRY TO SEND MESSAGE AGAIN
	SETZRO LLTRN,(T1)	;DON'T NEED LS ANYMORE
	MOVEI T2,LLSRUN		;NOW IN
	STOR T2,LLSTA,(T1)	; RUN STATE
	MOVEI T2,1		;SET INITIAL LS/INT
	STOR T2,LLMIC,(T1)	; REQUEST COUNT
DATCC5:	MOVE T2,LLSEGQ(T1)	;GET ADDRESS OF FIRST MESSAGE ON LINK'S QUEUE
	JUMPE T2,DATCC3		;IF NONE, ALL SET
	SETZ T3,		;NO PREVIOUS MESSAGE YET
DATCC1:	LOAD T4,MSMFL,(T2)	;GET MESSAGE TYPE
	CAIN T4,CNMRFL+CNMCF	;IS IT A CC?
	JRST DATCC2		;YES, GO REMOVE IT FROM THE QUEUE
	MOVE T3,T2		;MAKE THIS ONE PREVIOUS
	OPSTR <SKIPE T2,>,MSLNK,(T2)  ;GET ADDRESS OF NEXT
	JRST DATCC1		;GO TRY IT
	JRST DATCC3		;NO MORE TO TRY
DATCC2:	MOVEI T4,LLSEGQ(T1)	;GET ADDRESS OF LINK'S SEGMENT QUEUE
	CALL UNQSEG		;REMOVE THE CC FROM THE SENT QUEUE
	MOVE T1,T2		;GET MESSAGE ADDRESS IN NECESSARY PLACE
	CALL RELRES		;GIVE UP THE SPACE
	MOVE T1,LLBLK		;GET BACK LL BLOCK ADDRESS
DATCC3:	MOVE T2,MSGBLK		;RETRIEVE ADDRESS OF INCOMING DATA MESSAGE
				; AND PROCEED WITH LINK RUNNING
;IN RUN STATE

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

	ENDSV.

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

   REPEAT 0,<
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

	RESCD

INTLS:	CALL GETTWO		;GET ACK NUMBER
	 JRST LSIDON		;NO GOOD
	TXZE T2,ACKIND		;AN ACK?
	JRST [	MOVEI T3,MSLSI	;GET PROPER CHANNEL
		CALL ACKCHN	;DO ACK
		CALL GETTWO	;GET SEGNUM
		 JRST LSIDON	;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		;IF EXACT ONE, MOVE ON
	SKIPL T3		;NOT THE ONE, OLD OR TOO NEW?
	IFSKP.			;TOO NEW
	   LOAD T3,LLLKP,(T1)	;GET NODE'S VERSION
	   CAIE T3,.NSP31	;NSP 3.1?
	   JRST LSIDON		;NO, FORGET IT
	   SETONE LLNLS,(T1)	;SAY NEED A NAK IN LL BLOCK
	   SETZRO LLALS,(T1)	;NOT AN ACK
	ELSE.
	   SETONE LLALS,(T1)	;NEED AN ACK
	ENDIF.
	CALL ONSRVQ		;PUT LL ON "NEEDS SERVICE" QUEUE
	JRST LSIDON		;AND DONE

;HAVE A GOOD INT OR LS MESSAGE

LSINT1:	STOR T2,LLIIN,(T1)	;STORE SEG #
	MOVE T4,MSGBLK		;GET BACK MESSAGE ADDRESS
	LOAD T4,MSMFL,(T4)	;GET MESSAGE FLAGS
	CAIE T4,DATFLI+DATINT	;INT OR LS?
	JRST LSMSG		;LS
	SKIPE LLMSI(T1)		;INT, ALREADY HAVE AN INTERRUPT MESSAGE?
	 JRST LSIDON		;YES, CAN'T HAVE THAT
	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
	SETONE LLALS,(T1)	;NEED AN ACK
	SKIPN INSKED		;IN SCHEDULER?
	IFSKP.			;
	   CALL ONSRVQ		;YES, PUT LL ON "NEEDS SERVICE" QUEUE
	   RET			;DONE
	ENDIF.
	CALLRET BLKULK		;NO, UNLOCK LL AND RETURN
;HAVE A LS MESSAGE

LSMSG:	SETONE LLALS,(T1)	;NEED AN ACK
	CALL ONSRVQ		;PUT LL ON "NEEDS SERVICE" QUEUE
	GETBYM (MSGCNT,MSGBYP,LSIDON)		;GET LSFLAGS BYTE
	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
	GETBYM (MSGCNT,MSGBYP,LSIDON)		;GET NEXT
	TXNE T3,4		;DATA COUNTS?
	JRST [	OPSTR <ADD T2,>,LLMIC,(T1) ;NO. COMPUTE NEW VALUE
		TXNE T2,200	;WITHIN RANGE?
		JRST LSIDON	;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 LSIDON		;YES. LINK ERROR
	OPSTR <ADD T2,>,LLMSM,(T1) ;ADD IN THE NUMBER
	STOR T2,LLMSM,(T1)	;SAVE NEW VALUE
	TXNN T2,200		;IS THE COUNT NEGATIVE?
	JUMPN T2,[MOVEI T2,CHKSCT ;NO. HAVE SOME COUNT MORE
		PUSH P,T1	;SAVE LL BLOCK
		LOAD T1,LLFRK,(T1) ;GET FORK NUMBER
		CALL NETWKF	;WAKE UP THE PROCESS
		POP P,T1	;GET BACK LL BLOCK
		JRST .+1]	;AND PROCEED
LSIDN1:	CALL RESEND		;SEE IF CAN RESEND ANYTHING
LSIDON:	CALL CHKLLT		;CHECK FOR TTY ON THIS LL
   REPEAT 0,<
	JN LLINT,(T1),[
		CALL INTOUT	;IF INTERNAL LINK SEND ANY OUTPUT STILL LEFT
		 JFCL		;IGNORE FAILURE HERE
		JRST .+1]	;CONTINUE
   >
	SKIPN INSKED		;IN SCHEDULER?
	IFSKP.			;YES
	   MOVE T2,MSGBLK	;GET MESSAGE ADDRESS
	   SETONE MSSKD,(T2)	;SET THE RELEASE INDICATOR
	   RET			;DONE
	ENDIF.
	CALL BLKULK		;NO, FREE THE LL LOCK
	JRST TOSMSG		;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

	SWAPCD

   REPEAT 0,<
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
   >				;END REPEAT 0 AT INTSET
;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:	MOVEI T3,MSDAT		;ON THE DATA SUBCHANNEL
	LOAD T2,LLMQI,(T1)	;GET MAX QUEUE VALUE
	IFQE. LLOPI,(T1)	;Write-only?
	 JN LLFOB,(T1),RSKP	;Yes, if also SRV: then forget it
	 CLEAR T2,		;Otherwise, WO DCN: send LS so the other side
	 CALLRET SNDLS		; will send one back (set flow to zero)
	ENDIF.
	TMNE LLIMS,(T1)		;MESSAGE?
	MOVEI T2,1		;YES. ONE MESSAGE THEN
	CALLRET SNDLS		;SEND IT OFF
;COLLECTION OF ROUTINES TO GET FIELDS FROM A MESSAGE
;MOST ARE RESIDENT BECAUSE THEY ARE USED BY THE CHANNEL 7 CODE

	RESCD			;CALLED FROM SCHEDULER

;GET TWO BYTE FIELD
;CLOBBERS T3, PRESERVES T4

GETTWO:	GETBYM (MSGCNT,MSGBYP,R)		;GET A BYTE, RETURN IF NONE
	LSHC T2,-10		;SAVE LOW ORDER BYTE
	GETBYM (MSGCNT,MSGBYP,R)		;GET NEXT ONE
	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
	GETBYM (MSGCNT,MSGBYP,[SETZM T2		;GET COUNT FIELD
			       RET])		;DONE
	CAMLE T2,T4		;WITHIN RANGE?
	RET			;NO.
	MOVE W2,T2		;SAVE COUNT
	SKIPN T4,T2		;SAVE COUNT
	JRST GTASCD		;NO COUNT
GTASC1:	GETBYM (MSGCNT,MSGBYP,R)
	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

	ENDAV.			;END ACVAR
;MORE BYTE MANIPULATION ROUTINES

;SKIP AN IMAGE FIELD

SKPFLD:	GETBYM (MSGCNT,MSGBYP,R)		;GET IMAGE COUNT
	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

GETEXT:	SETZB T3,T4		;INIT ACCUMULATOR AND COUNTER
GETEX1:	GETBYM (MSGCNT,MSGBYP,R)		;GET NEXT BYTE
	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


;MAKE AN EXTENSIBLE FIELD
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T3/ THE VALUE
;RETURNS:	+1
;PRESERVES T1

MAKEXT:	MOVEI T2,177		;GET EXTENSIBLE FIELD MASK
	AND T2,T3		;GET A BYTE'S WORTH
	LSH T3,-7		;ADJUST THE REMAINING QUANTITY
	SKIPE T3		;MORE BYTES TO COME?
	TXO T2,NSPEXT		;YES, PUT IN EXTENSIBLE FLAG BIT
	CALL ONEBYT		;PUT BYTE IN MESSAGE
	JUMPN T3,MAKEXT		;IF MORE, GO DO IT
	RET			;DONE
;ROUTINE USED BY CI AND CC TO PROCESS COMMON FIELDS

	SWAPCD			;SWAPPABLE

CIPSRV:	GETBYM (MSGCNT,MSGBYP,R)		;GET SERVICES
	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
	GETBYM (MSGCNT,MSGBYP,R)		;GET LINK PRI
	MOVEM T2,MSGLKP		;SAVE IT
	CALL GETTWO		;GET SEGSIZE
	 RET			;BAD
	MOVEM T2,MSGW2		;SAVE IT
	RETSKP			;ALL GOOD
;REQUEST QUEUER ROUTINES
;SEND CONTROL MESSAGE
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ MESSAGE BLOCK
;RETURNS:	+1 ALWAYS

	RESCD

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
	TMNE LLLOC,(T1)		;LOCAL?
	 JRST CTLLCL		;YES. GO HANDLE IT
SNDSG0:	CALL NSOUBK		;DO NSP OUTPUT BOOKKEEPING
	LOAD T4,MSMFL,(T2)	;GET MESSAGE TYPE
	TRNN T4,ACKFLM		;IS IT AN ACK?
	IFSKP.
	   MOVEI T4,ACKPST	;YES, GET POSTING ROUTINE
	   CALL SNDRDY		;GET READY FOR DRVIER
	   JRST SNDMSG		;GO
	ENDIF.
	CAIE T4,CNMRFL+CNMDI	;IS IT A DI?
	IFSKP.
	   CALL ONSEGQ		;YES, PUT IT ON RESEND QUEUE
	   MOVEI T4,SEGPST	;GET POSTING ROUTINE
	   CALL SNDRDY		;GET READY FOR DRIVER
	   JRST SNDMSG		;GO
	ENDIF.
	CAIE T4,CNMRFL+CNMCF	;IS IT A CC?
	IFSKP.
	   LOAD T4,LLLKP,(T1)  ;YES, GET NSP VERSION
	   CAIN T4,.NSP31	;NSP 3.1?
	   IFSKP.
	       CALL ONSEGQ	;NO, PUT IT ON RESEND QUEUE
	       MOVEI T4,SEGPST	;GET POSTING ROUTINE
	       CALL SNDRDY	;GET READY FOR DRIVER
	       JRST SNDMSG	;GO
	   ENDIF.
	   MOVEI T4,RELRES	;YES, PHASE II - GET POSTING ROUTINE
	   CALL SNDRDY		;GET READY FOR DRVIER
	   JRST SNDMSG		;GO
	ENDIF.
	LOAD T3,MSCNT,(T2)	;GET BYTE COUNT
	LOAD T1,LLPRT,(T1)	;GET PORT NUMBER
;	HRLI T1,MSGPST		;POSTING ADDRESS
SNDSG1:	HRLI T1,RELRES		;MAKE DRIVER RELEASE THE BLOCK
SNDMSG:	STKVAR <SAVPST,SAVFF>
	MOVEM F,SAVFF		;SAVE F
	MOVE F,T2		;UNIQUE CODE FOR POST
	TMNE 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 BP TO IT
	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

	ENDSV.

;CONNECTION IS TO A TASK ON THIS NODE

CTLLCL:	SETONE MSLCL,(T2)	;REMEMBER IS LOCAL
   REPEAT 0,<			;2020 LOOPBACK
	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
   >				;END REPEAT 0
	CALL NSOUBK		;DO NSP BOOKKEEPING
	CALLRET ONMSQ		;AND GO DO IT


;GET ACS READY FOR CALL TO DRVIER
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ MESSAGE ADDRESS
;		T4/ POSTING ROUTINE ADDRESS
;RETURNS +1	T1/ POSTING ROUTINE ADDRESS ,, PORT NUMBER
;		T2/ MESSAGE ADDRESS
;		T3/ BYTE COUNT

SNDRDY:	LOAD T3,MSCNT,(T2)	;GET BYTE COUNT OF MESSAGE
	LOAD T1,LLPRT,(T1)	;GET PORT NUMBER
	HRLI T1,(T4)		;INSERT POSTING ROUTINE
	RET
;VARIOUS QUEUENING ROUTINES USED BY INT, SCHED, AND PROCESS LEVELS

;ROUTINE TO PUT A MESSGE ON NSPTSK'S QUEUE

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::	XMOVEI T2,-MSHDR(T2)	;GET POINTER TO HEADER
	MOVE T4,TODCLK		;GET TOD
	MOVEM T4,MSTIM(T2)	;PUT IT IN MESSAGE HEADER
	SKIPE T4,SMSGQ		;QUEUE NOW EMPTY?
	IFSKP.			;
	   MOVEM T2,SMSGQ	;YES, MAKE US FIRST
	   MOVEM T2,SMSGQ+1	;AND LAST
	   RET
	ENDIF.
	MOVE T4,SMSGQ+1		;NO, GET LAST MSG ON QUEUE
	MOVEM T2,MSNXT(T4)	;MAKE LAST MSG POINT AHEAD TO US
	MOVEM T4,MSPRV(T2)	;MAKE US POINT BACK TO IT
	MOVEM T2,SMSGQ+1	;MAKE QUEUE TAIL POINT TO US
	RET
;ROUTINE TO LINK A MESSAGE INTO NSSNTQ (THE TIMER) QUEUE
;
;CALL:	T2/ ADDRESS OF MESSAGE

ONTIMQ:	SAVET
	SKIPE INSKED		;IN SCHEDULER?
	JRST ONTMQ3		;YES
	SKIPN INNSPT		;IN RETRANSMISSION TIMER
	SKIPE INNSPI		; OR INACTIVITY TIMER?
	SKIPA			;YES, THEN ALREADY HAVE THE TREE LOCK
	LLLOCK			;NO, THEN USE TREE LOCK TO PREVENT RACES
ONTMQ3:	SKIPE T4,NSSNTQ		;TIMER QUEUE EMPTY?
	IFSKP.			;YES
	   MOVEM T2,NSSNTQ	;MAKE THIS MSG FIRST ON Q
	   JRST ONTMQ4		;DONE
	ENDIF.
	SETZM T3		;NO, SAY NO PREVIOUS MSG YET
ONTMQ1:	MOVE T1,MSTIM(T4)	;GET TIME STAMP OF NEXT MSG
	CAMG T1,MSTIM(T2)	;OLDER THAN US?
	JRST ONTMQ2		;YES
	SKIPE T3		;NO, ARE WE AT BEGINNING OF QUEUE?
	IFSKP.			;YES
	   MOVEM T2,NSSNTQ	;PUT US AT HEAD OF THE QUEUE
	ELSE.			;NO
	   MOVEM T2,MSNXT(T3)	;LINK US TO
	   MOVEM T3,MSPRV(T2)	; PREVIOUS ENTRY
	ENDIF.
	MOVEM T4,MSNXT(T2)	;LINK US TO
	MOVEM T2,MSPRV(T4)	; NEXT ENTRY
	JRST ONTMQ4		;DONE

ONTMQ2:	SKIPN T1,MSNXT(T4)	;ARE WE AT END OF QUEUE?
	IFSKP.			;NO
	   MOVE T3,T4		;MAKE NEXT PREVIOUS
	   MOVE T4,MSNXT(T4)	;AND GET THE NEXT
	   JRST ONTMQ1		;TRY AGAIN
	ENDIF.
	MOVEM T2,MSNXT(T4)	;YES, PUT US ON
	MOVEM T4,MSPRV(T2)	; END OF QUEUE
ONTMQ4:	SKIPE INSKED		;IN SCHEDULER?
	RET			;YES
	SKIPN INNSPT		;IN RETRANSMISSION TIMER OR
	SKIPE INNSPI		; OR INACTIVITY TIMER?
	SKIPA			;YES, DON'T GIVE UP LOCK HERE
	LLLULK			;NO, GIVE UP TREE LOCK
	RET			;DONE
;ROUTINE TO REMOVE A MESSAGE FROM NSSNTQ (THE TIMER) QUEUE
;
;CALL:	1/ ADDRESS OF MESSAGE

UNQTIM:	SAVET
	SKIPE INSKED		;IN SHCEDULER?
	JRST UNQTM2		;YES
	SKIPN INNSPT		;IN RETRANSMISSION TIMER
	SKIPE INNSPI		; OR INACTIVITY TIMER?
	SKIPA			;YES, THEN ALREADY HAVE THE TREE LOCK
	LLLOCK			;NO, THEN USE TREE LOCK TO PREVENT RACES
UNQTM2:	SKIPE T2,MSPRV(T1)	;ARE WE FIRST ON THE QUEUE?
	IFSKP.			;YES
	   SKIPE T3,MSNXT(T1)   ;ARE WE ALSO LAST ON THE QUEUE?
	   IFSKP.		;YES
	      SETZM NSSNTQ  	;RESET THE QUEUE HEADER
	   ELSE.
	      SETZM MSPRV(T3)	;NO, MAKE NEXT THE HEAD
	      SETZM MSNXT(T1)	;NO NEXT (IN CASE MESSAGE IN REQUEUED)
	      MOVEM T3,NSSNTQ	;MAKE QUEUE HEAD POINT TO US
	   ENDIF.
	   JRST UNQTM1		;DONE
	ENDIF.
	SKIPE T3,MSNXT(T1)	;NO, ARE WE LAST ON THE QUEUE?
	IFSKP.			;YES
	   SETZM MSNXT(T2)	;THEN PREVIOUS NO LONGER HAS NEXT
	   SETZM MSPRV(T1)	;WE HAVE NO MORE PREVIOUS (IN CASE OF REQUEUE)
	ELSE.
	   MOVEM T3,MSNXT(T2)	;NO, MAKE PREVIOUS POINT TO NEXT
	   MOVEM T2,MSPRV(T3)	;AND NEXT POINT TO PREVIOUS
	   SETZM MSPRV(T1)	;WE HAVE NO MORE PREVIOUS
	   SETZM MSNXT(T1)	; NOR NEXT (IN CASE OF REQUEUE)
	ENDIF.
UNQTM1:	SKIPE INSKED		;IN SCHEDULER?
	RET			;RET
	SKIPN INNSPT		;IN RETRANSMISSION TIMER OR
	SKIPE INNSPI		; OR INACTIVITY TIMER?
	SKIPA			;YES, DON'T GIVE UP LOCK HERE
	LLLULK			;NO, GIVE UP TREE LOCK
	RET			;DONE
;ROUTINE TO SEND A DATA,LS, OR INT MESSAGE
;ACCEPTS:	T1/ LL BLOCK
;		T2/ MESSAGE BLOCK

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
	TMNE LLLOC,(T1)		;LOCAL?
	 JRST SNDLCL		;YES.
LPBSEG:	CALL ONSEGQ		;PUT IT ON THE SEG QUEUE
SNDSE2:	CALL NSOUBK		;DO NSP BOOKKEEPING
	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

	ENDAS.

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

ONSEGQ:	INCR LLQOU,(T1)		;ONE MORE ON Q
	MOVE T3,TODCLK		;GET THE TIME
	MOVEM T3,MSTIM(T2)	;PUT TIME STAMP IN MESSAGE HEADER
	MOVEI T3,LLSEGQ(T1)	;GET HEADER
	LOAD T4,LLLKP,(T1)	;GET NODE'S VERSION
	CAIN T4,.NSP31		;NSP 3.1?
	JRST ONSEG0		;YES
	SKIPN (T3)		;NO, QUEUE CURRENTLY EMPTY?
	CALL ONTIMQ		;YES, TIE IN TO TIMER QUEUE
ONSEG0:	CALLRET PUTONQ		;PUT SEG ON THE Q

;LOCAL ROUTINE TO PUT MESSAGE ON INPUT QUEUE

ONMSQ:	NOSKD1			;NO SCHEDULING
	CALL ONMSGQ		;PUT MESSAGE ON THE QUEUE
	OKSKD1			;AND SCHEDULING
	RET			;AND DONE

;ENTRY USED TO RESEND A NACKED OR TIMED OUT MESSAGE

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

SNDLCL:	STKVAR <SRCLLB,DESLLB>
	MOVEM T1,SRCLLB		;SAVE THE SOURCE LL BLOCK ADDRESS
	SETONE MSLCL,(T2)	;SAY IS LOCAL
   REPEAT 0,<			;2020 LOOPBACK
	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
   >				;END REPEAT 0
	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
	MOVEM T1,DESLLB		;SAVE DESTINATION LL BLOCK ADDRESS
	MOVE T2,SNMSG		;GET MESSAGE BLOCK
	NOSKD1			;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.
	MOVE T1,SRCLLB		;RETRIEVE SOURCE LL BLOCK ADDRESS
	CALL NSOUBK		;DO NSP OUTPUT BOOKKEEPING
	MOVE T1,DESLLB		;RETRIEVE DESTINATION LL BLOCK ADDRESS
	CALL NSINBK		;DO NSP INPUT BOOKKEEPING
	CALL ONRAWQ		;GO PUT ON THE QUEUE
	OKSKD1			;ALL DONE
	JRST SNDSE1		;GO Q IT UP ON SEG Q

;ERROR ROUTINES

SNDBA1:	OKSKD1
SNDBAD:	MOVE T2,SNMSG		;GET MESSAGE ADDRESS
	CALL ONMSQ		;PUT DATA MESSAGE ON NSPTSK'S Q
	JRST SNDSE1		;AND DONE FOR NOW
;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

ACKCHN:	TMNE LLLOC,(T1)		;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
	TRZN T2,ACKBIT		;IS IT A NACK?
	IFSKP.			;YES
	   CALL ACKCHN		;DO THE ACK PROCESSING
	   LOAD T3,LLLKP,(T1)	;GET NODE'S VERSION
	   CAIE T3,.NSP31	;NSP 3.1?
	   RET			;NO
	   JRST DONACK		;YES, PHASE II LINK, SEE IF RESENDS ARE NEEDED
	ENDIF.
	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.
	PUSH P,T2		;TEMPORARILY STASH
	PUSH P,T3		; SOME ACS
	MOVE T2,TODCLK		;GET CURRENT TIME
	SUB T2,MSTIM(W1)	;CALC ROUND TRIP TIME OF MESSAGE
	MOVE T4,LLTIMO(T1)	;GET OLD TIME
	SUB T2,T4		;GET DIFFERENCE
	IDIV T2,NSLDWS		;WEIGHT THE DIFFERENCE
	ADD T2,T4		;MAKE THE NEW TIME
	CAIG T2,^D1000		;IS IT REAL SMALL?
	MOVEI T2,^D1000		;YES, IMPOSE THE MINIMUM
	MOVEM T2,LLTIMO(T1)	;SAVE THE NEW TIME OUT VALUE
	MOVEI T4,LLSEGQ(T1)	;THE Q ADDRESS
	DMOVE T2,W1		;GET ARGUMENTS IN PROPER ACS FOR CALL
	CALL UNQSEG		;REMOVE SEGEMENT
	POP P,T3		;RETRIEVE THE
	POP P,T2		; STASHED ACS
	EXCH T1,W1		;GET BACK MESSAGE ADDRESS
	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:	CALL CHKLLT		;CHECK FOR TTY ON THIS LL
   REPEAT 0,<
	JN LLINT,(T1),[
		CALL INTOUT	;IF INTERNAL LINK SEND ANY OUTPUT STILL LEFT
		 JFCL		;IGNORE FAILURE HERE
		JRST .+1]	;CONTINUE
   >
	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 [	INCR LLMSM,(T1)	;YES. ACCOUNT FOR THE MACK
		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
		JXE T3,DATEOM,DONRQ ;IS THIS THE EOM?
		INCR LLMSM,(T1)	;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.
	DECR LLMSM,(T1)		;YES. COUNT DOWN
DONRES:	PUSH P,T2		; TEMPORARILY STASH
	PUSH P,T3		; ACS
	MOVEI T4,LLSEGQ(T1)	;GET THE SEG Q HEAD
	DMOVE T2,W1		;GET ARGUMENTS IN PROPER ACS FOR CALL
	CALL UNQSEG		;REMOVE SEG FROM QUEUE
	POP P,T3		;RETRIEVE
	POP P,T2		; STASHED ACS
	MOVE T2,W1		;GET SEG
	SETZRO MSTRY,(T2)	;RESET THE TIME OUT RETRY COUNT
	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

	ENDAV.			;END ACVAR
;ROUTINE TO TAKE A SEGMENT OFF OF A SEGMENT Q
;
;ACCEPTS:	T1/ ADDRESS OF LL BLOCK
;		T2/ ADDRESS OF MESSAGE
;		T3/ ADDRESS OF PREVIOUS MESSAGE ON SEGMENT QUEUE
;		T4/ ADDRESS OF LINK'S SEGMENT QUEUE HEAD
;RETURNS:	+1

UNQSEG:	SAVET
	ACVAR <LLB>		;AC FOR LL BLOCK ADDRESS
	MOVEM T1,LLB		;SAVE IT
	DECR LLQOU,(LLB)	;ONE LESS ON SEG Q
	LOAD T1,MSLNK,(T2)	;GET ADDRESS OF NEXT SEG
	JUMPE T3,UNQSG1		;IF AT HEAD OF QUEUE, NO BACKWARD LINKING
	STOR T1,MSLNK,(T3)	;MAKE PREVIOUS POINT TO NEXT
	SKIPN T1		;IS THERE A NEXT?
	MOVEM T3,1(T4)		;NO, MAKE THIS TAIL OF QUEUE
	RET
UNQSG1:	HRRM T1,(T4)		;SET NEXT SEGMENT TO BE QUEUE HEAD
	EXCH T1,T2		;T1/ SEG TO BE ELIMINATED;  T2/ NEXT SEG
	LOAD T3,LLLKP,(LLB)	;GET NODE'S VERSION
	CAIE T3,.NSP31		;NSP 3.1?
	CALL UNQTIM		;NO, REMOVE MESSAGE FROM NSSNTQ QUEUE
	SKIPE T2		;IS THERE A NEXT?
	IFSKP.			;NO
	   SETZM (T4)		;RESET QUEUE HEADER
	   RET			;DONE
	ENDIF.
	CAIE T3,.NSP31		;NSP 3.1?
	CALL ONTIMQ		;NO, GO PUT IT ON NSSNTQ
	RET

	ENDAV.
;ROUTINE TO PUT A DATA MESSAGE ON A SEGMENT Q
;	T2/ THE MESSAGE
;	T3/ THE QUEUE ADDRESS
;PRESERVES T1,T2,T4

PUTONQ:	SAVEAC <T4>
	SKIPN T4,0(T3)		;HAVE A QUEUE?
	JRST [	MOVEM T2,0(T3)	;NO, MAKE HEAD
		MOVEM T2,1(T3)	; AND TAIL
		JRST PUTOND]	;DONE
	MOVE T4,1(T3)		;YES, GET TAIL
	STOR T2,MSLNK,(T4)	;LINK THIS IN
	MOVEM T2,1(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:	MOVE T2,LLSEGQ(T1)	;GET HEAD OF Q
RSEND1:	SKIPE T2		;ANYTHING THERE?
	IFSKP.			;NO, SHOULDN'T BE HERE
	   BUG.(CHK,NSPRSN,NSPSRV,SOFT,<NSP - NUMBER OF ENTRIES COUNT AND ACTUAL QUEUE LENGTH DON'T AGREE>,,<

Cause:

Action:

Data:

>)
	   RET			;GO AWAY
	ENDIF.
	TMNN 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
	JXE T3,DATEOM,RSEND3	;IS THIS EOM?
RSEND2:	DECR LLMSM,(T1)		;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,LLOMSG,LLOMSG
;	T1/ LL BLOCK  - MUST BE LOCKED
;RETURNS +1 ALWAYS

FLUSH::	SETZRO <LLQUN,LLQOU>,(T1) ;CLEAR COUNTS
	MOVEI T2,LLOMSG(T1)	;GET ORDERED QUEUE
	CALL PRUNE		;KILL IT
	MOVEI T2,LLMSI(T1)	;INT MESSAGES
	CALL PRUNE		;KILL THIS AS WELL
	SKIPN T2,LLSEGQ(T1)	;GET FIRST MSG ON LL'S QUEUE
	RET			;QUEUE IS EMPTY, DONE
	LOAD T3,LLLKP,(T1)	;GET NODE'S VERSION
	CAIN T3,.NSP31		;NSP 3.1?
	JRST FLUSH1		;YES, THEN NOT ON TIMER'S Q
	PUSH P,T1		;SAVE ADDRESS OF LL BLOCK
	HRRZ T1,T2		;GET ADDRESS OF MESSAGE
	CALL UNQTIM		;TAKE MSG OF TIMER'S QUEUE
	POP P,T1		;RETRIEVE ADDRESS OF LL BLOCK
FLUSH1:	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
	MOVE T1,0(T2)		;GET HEAD
	SETZM 0(T2)		;CLEAR Q HEAD
	SETZM 1(T2)		; AND TAIL
PRUNE1:	JUMPE T1,R		;IF AT THE END, DONE
	LOAD T2,MSLNK,(T1)	;GET NEXT
	PUSH P,T2		;SAVE IT
	JN MSPST,(T1),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.

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
;ROUTINE TO SEND AN ACK MESSAGE.
;	T1/ LL BLOCK
;	T2/ SEGMENT # TO ACK
;	T3/ SUBCHANNEL TO ACK
;RETURNS:	+1  FAILED
;		+2  SUCCESS
;ALL REGS PRESERVED

SNDACK:	ASUBR <LLBLK,ACKNO,ACKTYP>
NSBP09:	TMNE LLLOC,(T1)		;LOCAL?
   REPEAT 0,<			;2020 LOOPBACK
	 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
   >				;END REPEAT 0
	RETSKP			;YES, DONE
	JRST ACKRMT		;NEED TO SEND A MESSAGE

;ROUTINE TO ACK THE LS/INT CHANNEL

ACKLI:	LOAD T2,LLIIN,(T1)	;GET SEG TO ACK/NAK
	TMNN LLALS,(T1)		;NEED AN ACK?
	TXO T2,ACKBIT		;NO, TURN ON NAK BIT IN MESSAGE
	MOVEI T3,MSLSI		;THE CHANNEL I.D.
	CALL SNDACK		;SEND ACK
	 RET			;FAILED
	SETZRO <LLNLS,LLALS>,(T1)  ;DON'T NEED ACK OR NACK ANYMORE
	CALL CHKLLT		;CHECK FOR NVT LINK
	RETSKP			;OK
;SNDACK CONTINUED.....
;SEND ACK TO REMOTE NODE.

ACKRMT:	STKVAR <MSGBL>		;PLACE TO SAVE MESSAGE BLOCK
	MOVEI T3,AKLSTL-1	;GET LENGTH OF ACK LIST
ACKRM1:	SKIPE T2,ACKLST(T3)	;GET THE ENTRY
	IFSKP.			;NONE THERE
	   SOJGE T3,ACKRM1	;END OF LIST?
	   CALLRET TIMWAT	;YES, RETURN TEST ROUTINE
	ENDIF.
	JN MSACK,(T2),[SOJGE T3,ACKRM1  ;IF BUFFER IN USE, ARE THERE MORE?
		       CALLRET TIMWAT]	;NO, RETURN TEST ROUTINE
	SETONE MSACK,(T2)	;BLOCK NOW BEING USED
	MOVEM T2,MSGBL		;SAVE THE BUFFER ADDRESS
	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.
	MOVE T3,MSGBL		;RETRIEVE MESSAGE ADDRESS
	STOR T2,MSMFL,(T3)	;SAVE MESSAGE FLAGS IN MESSAGE HEADER
	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 T3,OURNUM		;GET LOCAL NUMBER
	CALL MAKEXT		;PUT IT IN MESSAGE
	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,BLKSIZ		;GET OUR DLL BLOCK SIZE
	CALL TWOBYT
	MOVE T2,SEGSZ		;OUR NSP SEGMENT 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
	MOVE T1,NODPRT		;GET PORT NUMBER
	CALL SNDSG1		;SEND NODE INIT MESSAGE
	MOVE T1,NODPRT		;GET PORT NUMBER AGAIN
	SETONE INISNT,MCBDTE(T1) ;SAY 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
;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
	MOVE T1,NODPRT		;GET PORT NUMBER AGAIN
	CALLRET SNDSG1		;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>
	TMNE LLLOC,(T1)		;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
	TMNE LLALS,(T1)		;THIS LINK NEED AN ACK?
	CALL MAKLSA		;YES, PUT IT IN
	LOAD T2,LLISN,(T1)	;GET SEG #
	AOS T2			;NEXT ONE
	ANDI T2,SEGMSK
	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)	;""
	MOVEI T3,DATFLI		;GET LS MESSAGE TYPE
	STOR T3,MSMFL,(T4)	;PUT IT IN HEADER OF MESSAGE
	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


;MAKE THE ACKNUM (PIGGYBACKED ACK) FIELD IN A LS MESSAGE
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;RETURNS:	+1
;PRESERVES T1

MAKLSA:	LOAD T2,LLIIN,(T1)	;GET LAST LS MESSAGE RECEIVED
	TXO T2,ACKIND		;PUT IN ACKNUM INDICATOR
	CALL TWOBYT		;PUT ACKNUM FIELD IN MESSAGE
	SETZRO <LLALS,LLNLS>,(T1)  ;CLEAR THE "NEED TO ACK/NACK" FLAGS
	CALL CHKLLT		;CHECK FOR NVT LINK
	RET
;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
	NOSKD1
	CAIE T3,MSDAT		;DATA
	JRST [	OPSTRM <ADDM T2,>,LLMIC,(T1) ;NO
		JRST SNDLS1]	;GO WRAP UP
	OPSTRM <ADDM T2,>,LLMSM,(T1) ;YES
SNDLS1:	CALL CHKLLT		;CHECK FOR TTY ON THIS LL
	OKSKD1
	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
;CALLED AT INT LEVEL FROM DTESRV TO GET RESIDENT FREE SPACE

;GET A BUFFER
;AACEPTS:	T1/ DTE #
;		T2/ # OF BYTES REQUIRED
;RETURNS:	+1 COULDN'T GET BLOCK
;		+2 T1/ BLOCK ADDRESS.

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 #
	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

   REPEAT 0,<
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 BLKLLK		;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

	RESCD

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.
   >				;END REPEAT 0 AT OUTSND
SUBTTL Routine Needed by TTYSRV

;GET THE NEXT SEGMENT ON THE INCOMING MESSAGE QUEUE
;ACCEPTS:	T1/ LL BLOCK
;RETURNS:	+1 - NO SEGMENT AVAILABLE
;		+2 - T2/ SEGMENT ADDRESS
;PRESERVES T1

	RESCD

TTGETS::SKIPN T2,LLOMSG(T1)	;ANY SEGMENTS?
	RET			;NO, DONE
	RETSKP


;REMOVE A SEGMENT FROM THE INCOMING MESSAGE QUEUE
;ACCEPTS:	T1/ LL BLOCK
;		T2/ SEGMENT ADDRESS
;RETURNS:	+1 ALWAYS

TTREMS::LOAD T3,MSLNK,(T2)	;GET NEXT SEGMENT ON QUEUE
	SKIPN T3		;ANY MORE?
	MOVEM T3,LLOMST(T1)	;NO, RESET THE TAIL
	MOVEM T3,LLOMSG(T1)	;MAKE NEW HEAD
	RET
SUBTTL	Scheduler Interface
;ROUTINE CALLED BY THE SCHEDULER EVERY 20 MS TO PROCESS MESSAGES
;ARRIVED FROM THE NETWORK

NSPCH7::ACVAR <W1>		;GET A WORK REG
	STKVAR <MB>		;MESSAGE ADDRESS
	SETZM RESNET		;ASSUME WE HAVE LOTS OF SPACE
	MOVEI T1,RESHLD		;GET THRESHOLD VALUE
	MOVE T2,[RS%SE0+.RESNP]	;GET DECNET POOL NUMBER
	CALL CHKRFS		;IS THIS MUCH LEFT?
	 SETOM RESNET		;NO, INDICATE WE'RE LOW ON SPACE
	MOVEI W1,15		;DO A LIMITED # PER PASS
	SKIPL LLLLCK		;LL TREE LOCK AVAILABLE
	RET			;NO
	SKIPN T1,SMSGQ		;ANY MSGS ON Q?
	JRST LLSRVR		;NO, GO SEE IF ANY LINKS NEED SERVICE
	HRRZS T1		;YES, GET FIRST MSG
NSPCH0:	MOVEM T1,MB		;SAVE MESSAGE ADDRESS
	CALL NSPMSG		;GO PROCESS THE MSG
	IFNSK.			;COULDN'T, WE'LL DO IT LATER
	   MOVE T1,MB		;RETRIEVE MESSAGE ADDRESS
	   CALL NSPNXT		;ANY MORE MSGS?
	    JRST LLSRVR		;NO
	   JRST NSPCH0		;YES
	ENDIF.
	MOVE T1,MB		;RETRIEVE MESSAGE ADDRESS
	CALL NSPREM		;REMOVE THIS MSG FROM Q
	 JRST LLSRVR		;NO MORE TO DO
	SOJGE W1,NSPCH0		;GO DO MORE
	JRST LLSRVR

	ENDSV.
	ENDAV.			;END ACVAR


;Get the next message on SMSGQ
;
;ACCEPTS:	T1/ Address of current message
;RETURNS:	+1  No more messages
;		+2  T1/ Address of next message

NSPNXT:	CHNOFF DLSCHN		;TURN OFF NET
	MOVE T1,MSNXT(T1)	;GET NEXT MSG
	CHNON DLSCHN		;TURN ON NET
	JUMPE T1,R		;RETURN NO NEXT MSG
	RETSKP			;THERE IS ANOTHER MSG
;Remove a message from SMSGQ and get the next message on the queue
;
;ACCEPTS:	T1/ Address of message to be removed
;RETURNS:	+1  Message removed, no more messages on queue
;		+2  Message removed, T1/ Address of next message

NSPREM:	ASUBR <MSG,NXT>
	CHNOFF DLSCHN		;TURN OFF NET
	SKIPN T2,MSPRV(T1)	;ARE WE FIRST ON Q?
	IFNSK.
	   SKIPN T3,MSNXT(T1)	;YES, ARE WE ALSO LAST ON Q?
	   IFNSK.
	      SETZM SMSGQ	;YES, INIT THE Q HEAD
	      SETZM SMSGQ+1	; AND THE TAIL
	      SETZM NXT		;NO NEXT MESSAGE
	      JRST NSPRE1	;DONE
	   ENDIF.
	   SETZM MSPRV(T3)	;NO, MAKE NEXT MSG THE FIRST
	   MOVEM T3,SMSGQ	;MAKE Q HEADER POINT TO US
	   MOVEM T3,NXT		;RETURN WITH NEXT
	   JRST NSPRE1
	ENDIF.
	SKIPN T3,MSNXT(T1)	;NO, WE ARE NOT FIRST.  ARE WE LAST?
	IFNSK.			;YES
	   SETZM MSNXT(T2)	;PREVIOUS NO LONGER HAS NEXT
	   MOVEM T2,SMSGQ+1	;MAKE Q TAIL POINT TO PREVIOUS
	   SETZM NXT		;NO NEXT MESSAGE
	   JRST NSPRE1		;DONE
	ENDIF.
	MOVEM T3,MSNXT(T2)	;NO, NOT FIRST OR LAST. MAKE PREVIOUS POINT AHEAD TO NEXT
	MOVEM T2,MSPRV(T3)	;MAKE NEXT POINT BACK TO PREVIOUS
	MOVEM T3,NXT		;RETURN NEXT MSG
NSPRE1:	MOVE T1,MSG		;RETRIEVE MESSAGE ADDRESS
	JE MSSKD,(T1),NSPRE2	;NEED TO RELEASE IT?
	CALL RELRES		;YES
NSPRE2:	CHNON DLSCHN		;TURN ON NET
	MOVE T1,NXT		;GET NEXT MESSAGE ON Q
	JUMPE T1,R		;RETURN NO NEXT MSG
	RETSKP			;THERE IS ANOTHER MSG

	ENDAS.
;ROUTINE TO QUEUE UP A RECEIVED MESSAGE.
;ACCEPTS:	T1/ MESSAGE BLOCK ADDRESS
;RETURNS:	+1 UNABLE TO PROCESS MESSAGE
;		+2 MESSAGE SUCCESSFULLY PROCESSED

NSPMSG::TRVAR <MSGCNT,MSGBYP,MSGSRC,MSGDST,MSGBLK,MSGLLB,<NSPDUM,11>,MSGW1>
	MOVEI T2,MSHDR(T1)	;GET TO DATA PORTION
	MOVEM T1,MSGBLK		;SAVE BLOCK ADDRESS
	HRLI T2,(<POINT 8,>)	;MAKE A BP TO IT
	MOVEM T2,MSGBYP		;SAVE BYTE POINTER
	LOAD T1,MSCNT,(T1)	;GET BYTE COUNT
	MOVEM T1,MSGCNT		;SET UP COUNT
	GETBYM (MSGCNT,MSGBYP,NSPMS4)		;GET FIRST BYTE
	TRNE T2,201		;A ROUTE HEADER?
	JRST NSPMS4		;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 NSPMS4		;NO
	CALL SKPFLD		;SKIP HOST NAME
	 JRST NSPMS4		;SOMETHING WRONG
	CALL SKPFLD		;SKIP OTHER HOST NAME
	 JRST NSPMS4		;SOMETHING WRONG
	GETBYM (MSGCNT,MSGBYP,NSPMS4)		;GET FLAGS
NSPMS1:	MOVE T1,MSGBLK		;GET MESSAGE ADDRESS
	STOR T2,MSMFL,(T1)	;SAVE MESSAGE FLAGS
	TRNE T2,CNMRFL		;IS IT A CONTROL MESSAGE?

;Control message

	JRST NSPMS4		;YES, GIVE IT TO BACKGROUND TASK

	CALL GETLLA		;( ) GET LINK NUMBERS
	 JRST NSPMS4		;BAD MESSAGE
	; ..
	; ..

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

	MOVE T1,MSGDST		;GET OUR NAME
	MOVE T2,MSGSRC		;GET ITS NAME
	LOCK LLLLCK		;GET LL TREE LOCK
	CALL LLLKUP		;(T1,T2) FIND THE LINK
	IFNSK.			;COULDN'T

;Logical link doesn't exist

	   UNLOCK LLLLCK	;GIVE UP TREE LOCK
	   JRST NSPMS4		;GIVE MSG TO BACKGROUND TASK
	ENDIF.
	TMNN LLDED,(T1)		;HAS DN20 CRASHED?
	IFSKP.

;DN20 has crashed

	   UNLOCK LLLLCK	;YES, GIVE BACK THE BIG LOCK
	   MOVE T2,MSGBLK	;GET BACK MESSAGE ADDRESS
	   SETONE MSSKD,(T2)	;TELL SCHEDULER TO TOSS THE NESSAGE
	   RETSKP		;DONE
	ENDIF.
	CALL BLKLOK		;(T1) GET LL LOCK
	IFNSK.			;COULDN'T

;Can't get interlock now, must try again later

	   UNLOCK LLLLCK	;GIVE UP TREE LOCK
	   RET
	ENDIF.
	UNLOCK LLLLCK		;GIVE UP TREE LOCK
	LOAD T2,LLSTA,(T1)	;GET STATE OF LL
	CAIE T2,LLSRUN		;RUNNING?

;Logical link not in run state

	JRST NSPMS5		;NO, GIVE MESSAGE TO BACKGROUND TASK

;Logical link is in run state

	MOVE T2,TODCLK		;YES, GET THE TIME
	ADD T2,NSINAC		;ADD INACTIVITY TIMEOUT VALUE
	MOVEM T2,LLINAC(T1)	;PUT NEW TIME IN LL BLOCK
	MOVE T2,MSGBLK		;RETRIEVE ADDRESS OF MESSAGE
	MOVE T3,MSGCNT		;GET REMAINING COUNT
	STOR T3,MSDTC,(T2)	;SAVE RESIDUAL COUNT
	MOVE T3,MSGBYP
	MOVEM T3,MSBPTR(T2)	;SAVE RESIDUAL BYTE POINTER
	MOVEM T1,MSGLLB		;SAVE LL BLOCK
	LOAD T4,MSMFL,(T2)	;GET MESSAGE FLAGS
	; ..
	; ..
	TRNN T4,ACKFLM		;AN ACK?
	IFSKP.

;Ack message

	   CALL GETTWO		;(/T2) YES, GET THE ACK NUMBER
	    JRST NSPMS5		;COULDN'T
	   CAIE T4,ACKFLM	;A DATA ACK?
	   IFSKP.		;YES
	      MOVEI T3,MSDAT	;GET ITS INDICATOR
	   ELSE.		;NO, MUST BE LS/INT ACK
	      MOVEI T3,MSLSI	;GET ITS INDICATOR
	   ENDIF.
	   CALL ACKCHN		;(T1,T2,T3) PROCESS THE ACK
	   MOVE T2,MSGBLK	;RETRIEVE MESSAGE ADDRESS
	   SETONE MSSKD,(T2)	;SET THE RELEASE INDICATOR
	   JRST NSPMS6		;DONE
	ENDIF.
	TRNN T4,DATFLI		;IS IT LS OR INT MESSAGE?
	IFSKP.

;Link service or interrupt message

	  SKIPN RESNET		;YES, LOTS OF SPACE?
	  IFSKP.
	    SETONE MSSKD,(T2)	;NO, HAVE IT TOSSED
	    MOVE T1,MSGLLB	;RETRIEVE LL BLOCK
	    JRST NSPMS6		;DONE
	  ENDIF.
	  CALL INTLS		;( ) YES, PROCESS IT
	ELSE.			;NO, MUST BE A DATA SEGMENT

;Data segment

	  CALL NSINBK		;(T1,T2) DO BOOKKEEPING
	  CALL ONRAWQ		;(T1,T2) PROCESS IT
	ENDIF.

NSPMS6:	CALL BLKULK		;(T1) UNLOCK IT
	RETSKP

;Message is for background task

NSPMS5:	CALL BLKULK		;(T1) FREE THE LL BLOCK
NSPMS4:	MOVE T2,MSGBLK		;GET MESSAGE ADDRESS
	SKIPN RESNET		;LOTS OF SPACE?
	IFSKP.
	  SETONE MSSKD,(T2)	;NO, HAVE IT TOSSED
	ELSE.
	  CALL ONMSGQ		;(T2) YES, PUT IN ON THE TASK'S Q
	ENDIF.
	RETSKP			;FINISHED WITH MSG

	ENDSV.
	ENDTV.
;PUT A DATA SEGMENT MESSAGE ON A LINK'S INCOMING QUEUE
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;		T2/ MESSAGE ADDRESS
;RETURNS:	+1

ONRAWQ:	NOSKD1			;HOLD OFF SCHEDULER
	TRVAR <MSGCNT,MSGBYP,MSGSRC,MSGDST,MSGBLK>
	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		;(MSGCNT,MSGBYP/T2) GET ACKNUM
	 JRST ONRAW1		;COULDN'T
	TRZN T2,ACKIND		;IS THIS AN ACKNUM?
	IFSKP.

;Piggy-backed Ack

;******************************************************************************
;The ACK must be processed before the RESNET check is made.  When we're low on
;space we want to process only ACKs.  When a piggy-backed ACK is found we
;process the ACK and then throw away the data segment in which it was imbedded.
;******************************************************************************

	  MOVEI T3,MSDAT	;YES, DATA MESSAGE
	  CALL ACKCHN		;(T1,T2,T3) GO HANDLE THE ACK
	  CALL GETTWO		;(MSGCNT,MSGBYP/T2) GET SEGNUM
	   JRST ONRAW1		;COULDN'T
	ENDIF.
	LOAD T3,LLDMT,(T1)	;GET NUMBER OF SEGMENTS CURRENTLY IN INCOMING Q
	AOS T3			;ADD THE ONE WE'RE LOOKING AT
	LOAD T4,LLMQI,(T1)	;GET MAXIMUM INPUT QUEUE LENGTH
	CAMG T3,T4		;WOULD THIS ONE MAKE TOO MANY?
	IFSKP.

;The link's incoming queue is full (its quota has been reached)

	  LOAD T3,LLLKP,(T1)	;YES, GET NODE'S VERSION
	  CAIE T3,.NSP31	;NSP 3.1?
	  JRST ONRAW1		;NO, DONE
	  SETONE LLFNN,(T1)	;PHASE II, SAY THIS LL NEEDS A NACK
	  SETZRO LLFNA,(T1)	;NOT AN ACK
	  CALL ONSRVQ		;(T1) PUT LL ON "NEEDS SERVICE" QUEUE
	  JRST ONRAW1		;DONE
	ENDIF.

;The link has room in its queue to accept this segment

	SKIPE RESNET		;LOTS OF SPACE?
	; ..
	; ..

;Low on free space

	JRST ONRAW1		;NO

;Lots of free space

	MOVE T3,T2		;YES, POSITION SEGMENT #
	LOAD T4,LLIDN,(T1)	;GET LAST SEG RECEIVED
	AOS T4			;MAKE NEXT EXPECTED
	ANDI T4,7777		;12 BITS ONLY (BE SURE TO CATCH WRAP AROUND)
	CAMN T3,T4		;THIS THE RIGHT ONE?
	IFSKP.

;Out-of-order segment

	  CAML T3,T4		;NO, TOO NEW?
	  IFSKP.
	    SETONE LLFNA,(T1)	;OLD, SAY THIS LL NEEDS AN ACK
	  ELSE.
	    LOAD T4,LLLKP,(T1)  ;TOO NEW, GET NODE'S VERSION
	    CAIE T4,.NSP31	;NSP 3.1?
	    JRST ONRAW1		;NO, FORGET IT
	    SETONE LLFNN,(T1)	;PHASE II, SAY LL NEEDS TO NAK
	    SETZRO LLFNA,(T1)	;NOT AN ACK
	  ENDIF.
	  CALL ONSRVQ		;(T1) PUT LL ON NEEDS SERVICE QUEUE
	  JRST ONRAW1		;DONE
	ENDIF.

;The expected segment

	STOR T3,LLIDN,(T1)	;YES, UPDATE SEGMENT NUMBER LL BLOCK
	MOVE T2,MSGBLK		;RETRIEVE MESSAGE ADDRESS
	STOR T3,MSSEG,(T2)	;SAVE SEGMENT NUMBER IN MSG HEADER
	SETONE LLFNA,(T1)	;THIS LL NEEDS AN ACK
	INCR LLDMT,(T1)		;SAY WE HAVE ANOTHER MESSAGE IN QUEUE
	LOAD T3,LLDMT,(T1)	;GET NUMBER OF SEGMENTS ON Q
	CAIN T3,1		;WAS Q PREVIOUSLY EMPTY?
	CALL DATINR		;(T1) YES, GIVE INT
	MOVEI T3,LLOMSG(T1)	;THE ORDERED MESSAGE QUEUE
	CALL PUTONQ		;(T2,T3) PUT ON NEW SEGMENT
	CALL ONSRVQ		;(T1) PUT LL ON "NEEDS SERVICE" QUEUE
	CALL CHKLLT		;(T1) CHECK FOR TTY ON THIS LL
	OKSKD1
	RET			;AND DONE

ONRAW1:	MOVE T2,MSGBLK		;GET MESSAGE ADDRESS
	SETONE MSSKD,(T2)	;TELL SCHEDULER TO RELEASE THE MESSAGE
	CALL DATINR		;(T1) REQUEST INT
	OKSKD1
	RET

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


;POSTING ADDRESS FOR ACKS
;ACCEPTS:	T1/ MESSAGE ADDRESS
;RETURNS:	+1

ACKPST::SETZM (T1)		;CLEAR
	HRL T2,T1		; OUT
	HRRI T2,1(T1)		;  THE
	BLT T2,ACKLEN+MSHDR-1(T1)  ;  BLOCK
	RET
;PROCESS "LINKS THAT NEED SERVICE" QUEUE

LLSRVR:	STKVAR <LLB>		;LL BLOCK ADDRESS
	SKIPL LLLLCK		;LL TREE LOCK AVAILABLE?
	RET			;NO
	MOVE T1,LSTLLS		;GET LAST TIME LINKS WERE SERVICED
	ADDI T1,^D200		;ADD INTERVAL
	CAMLE T1,TODCLK		;TIME TO DO IT AGAIN?
	RET			;NO, GO AWAY
	MOVE T1,TODCLK		;GET CURRENT TIME
	MOVEM T1,LSTLLS		;LINKS BEING SERVICED NOW
	SKIPN T1,LLSRVQ		;ANYTHING TO DO?
	RET			;NO, BYE
	LOCK LLLLCK		;GET LOCK ON LL TREE
LLSRV2:	MOVEM T1,LLB		;STASH LL BLOCK
	CALL BLKLOK		;LOCK THE LL
	IFNSK.			;COULDN'T
	   MOVE T1,LLB		;RETRIEVE LL BLOCK
	   JRST LLSRV3
	ENDIF.
	TMNN <LLFNN,LLFNA>,(T1)	;THIS LINK NEED A DATA ACK OR NACK?
	IFSKP.			;YES
	   CALL ACKNSP		;SEND IT
	    JRST LLSRV6		;COULDN'T
	ENDIF.
	TMNN <LLNLS,LLALS>,(T1)  ;THIS LINK NEED A LS ACK OR NACK?
	JRST LLSRV4		;NO
	CALL ACKLI		;YES, SEND IT
	IFNSK.			;COULDN'T
LLSRV6:	   MOVE T1,LLB		;RETRIEVE LL BLOCK ADDRESS
	   JRST LLSRV5		;MOVE ON
	ENDIF.
LLSRV4:	CALL UNQSRV		;REMOVE LL FROM Q
LLSRV5:	CALL BLKULK		;UNLOCK LL
LLSRV3:	LOAD T1,LLNSR,(T1)	;GET NEXT LL
	SKIPE T1		;ANY MORE?
	JRST LLSRV2		;YES
	UNLOCK LLLLCK		;GIVE UP LL TREE LOCK
	RET			;ALL DONE

	ENDSV.
;ROUTINE TO PUT AN LL BLOCK ON THE "NEEDS SERVICE" LIST
;ACCEPTS:	T1/ LL BLOCK ADDRESS
;RETURNS:	+1 ALWAYS
;PRESERVES T1,T2,T3

ONSRVQ:	NOSKED			;DON'T LET THE SCHEDULER RUN
	TMNE LLISR,(T1)		;ALREADY ON QUEUE?
	JRST ONSRV1		;YES, NOTHING TO DO
	SAVEAC <T2,T3>
	SETONE LLISR,(T1)	;NO, SAY NOW IN QUEUE
	SKIPE T2,LLSRVQ		;QUEUE CURRENTLY EMPTY?
	IFSKP.
	   MOVEM T1,LLSRVQ	;YES, MAKE QUEUE HEAD POINT TO US
	   MOVEM T1,LLSRVQ+1	;MAKE QUEUE TAIL POINT TO US
	   SETZRO <LLPSR,LLNSR>,(T1)	;CLEAR ALL POINTERS
	   JRST ONSRV1		;DONE
	ENDIF.
	MOVE T3,LLSRVQ+1	;NO, GET LAST QUEUE ENTRY
	STOR T3,LLPSR,(T1)	;MAKE IT PREVIOUS TO US
	SETZRO LLNSR,(T1)	;WE ARE AT THE END
	STOR T1,LLNSR,(T3)	;MAKE IT POINT AHEAD TO US
	MOVEM T1,LLSRVQ+1	;MAKE US TAIL OF QUEUE
ONSRV1:	OKSKED			;ALLOW SCHEDULER TO RUN AGAIN
	RET
;ROUTINE TO REMOVE AN LL FROM THE "NEEDS SERVICE" QUEUE
;ACCEPTS:	1/ LL BLOCK ADDRESS
;RETURNS:	+1 ALWAYS
;PRESRVES T1,T2,T3

UNQSRV:	NOSKED			;DON'T LET SCHEDULER RUN
	TMNN LLISR,(T1)		;NOW IN QUEUE?
	JRST UNQSR1		;NO, NOTHING TO DO
	SAVEAC <T1,T2,T3>
	SETZRO LLISR,(T1)	;YES, SAY NO LONGER IN QUEUE
	LOAD T2,LLPSR,(T1)	;GET PREVIOUS LL
	SKIPE T2		;ARE WE THE FIRST?
	IFSKP.			;YES
	   LOAD T3,LLNSR,(T1)	;GET NEXT LL
	   SKIPE T3		;ARE WE LAST?
	   IFSKP.		;YES
	      SETZM LLSRVQ	;RESET QUEUE HEAD
	      SETZM LLSRVQ+1	; AND TAIL
	      JRST UNQSR1	;DONE
	   ENDIF.
	   SETZRO LLPSR,(T3)	;NO, MAKE NEXT FIRST
	   MOVEM T3,LLSRVQ	;MAKE Q HEAD POINT TO NEXT
	   JRST UNQSR1		;DONE
	ENDIF.
	LOAD T3,LLNSR,(T1)	;GET NEXT LL
	SKIPE T3		;ARE WE LAST?
	IFSKP.			;YES
	   SETZRO LLNSR,(T2)	;MAKE PREVIOUS LAST
	   MOVEM T2,LLSRVQ+1	;MAKE Q TAIL POINT TO PREVIOUS
	   JRST UNQSR1		;DONE
	ENDIF.
	STOR T3,LLNSR,(T2)	;MAKE PREVIOUS POINT AHEAD TO NEXT
	STOR T2,LLPSR,(T3)	;MAKE NEXT POINT BACK TO PREVIOUS
UNQSR1:	OKSKED			;ALLOW SCHEDULER TO RUN AGAIN
	RET			;DONE
;ROUTINE TO SEND ANY DATA SEGMENT ACK'S NEEDED
;ACCEPTS:	T1/ ADDRESS OF LOGICAL LINK BLOCK
;RETURNS:	+1 FAILED, COULD NOT SEND THE ACK
;		+2 SUCCESS

ACKNSP:	STKVAR <SQASEG>
	LOAD T2,LLIDN,(T1)	;GET LAST SEGMENT RECEIVED
	MOVEM T2,SQASEG		;STASH SEG NUMBER
	MOVEI T3,MSDAT		;ON THE DATA CHANNEL
	TMNN LLFNA,(T1)		;NEED AN ACK?
	TXO T2,ACKBIT		;NO, TURN ON THE NACK BIT
	CALL SNDACK		;SEND IT
	 RET			;COULDN'T
	MOVE T2,SQASEG		;RETRIEVE SEG NUMBER
	STOR T2,LLLAK,(T1)	;SAY IT HAS BEEN ACKED
	SETZRO <LLFNA,LLFNN>,(T1) ;CLEAR ACK FLAGS
	RETSKP			;DONE, RETURN SUCCESS
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
	EXP NDRNM		;(16) RETURN A 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

;NOW FIX THE NODE NAME MAPPING TABLE

	MOVE T2,[MOVSO -40]	;SET UP OPERATOR
	MOVEM T2,P3		; FOR EXTEND
	MOVE Q3,OURNUM		;GET OUR NODE NUMBER
	NOINT
	LOCK NMAPLK		;LOCK THE NODE MAPPING TABLE
	SETZM NODMAP(Q3)	;NULLIFY THE CURRENT NODE NAME
	MOVE T1,OURCNT		;GET CHAR. COUNT OF NEW NAME
	MOVE T2,[440700,,OURNAM]  ;BYTE POINTER TO NEW NAME
	SETZB T3,Q2		;SINGLE WORD BYTE POINTERS
	MOVE T4,OURCNT		;GET CHAR. COUNT OF NEW NAME
	HRLI Q1,440600		;BYTE POINTER TO NEW
	HRRI Q1,NODMAP(Q3)	; NAME'S DESTINATION
	EXTEND T1,P3		;MOVE THE NEW NAME
	 JFCL
	UNLOCK NMAPLK		;UNLOCK THE NODE MAPPING TABLE
	OKINT
	RETSKP			;SUCCESS RETURN

	ENDSV.
;NDGLN - RETURN LOCAL NODE NAME

NDGLN:	UMOVE T2,2		;GET ADDRESS OF USER'S ARGUMENT BLOCK
	UMOVE T1,.NDNOD(T2)	;GET BYTE POINTER TO DEPOSIT NODE NAME
	MOVE T3,T2		;KEEP 30-BIT ADDRESS IN T3 FOR RETURNING
				; UPDATED BYTE POINTER TO USER
	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:	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
	UMOVE T2,2
	UMOVE T2,0(T2)		;GET NUMBER
	CAIL T2,1
	CAILE T2,BIGNOD		;WITHIN RANGE?
	RETBAD (NSPX25)		;NO
	MOVE T4,OURNUM		;SAVE THE CURRENT NUMBER
	MOVEM T2,OURNUM		;SET THE NEW NODE NUMBER

;NOW FIX THE NODE NAME MAPPING TABLE

	MOVE T1,T4		;RETRIEVE THE CURRENT NUMBER
	NOINT
	LOCK NMAPLK		;LOCK THE NODE MAPPING TABLE
	MOVE T3,NODMAP(T1)	;GET THE CURRENT NODE NAME
	SETZM NODMAP(T1)	;NULLIFY IT
	MOVEM T3,NODMAP(T2)	;MOVE NAME TO NEW NODE ADDRESS
	UNLOCK NMAPLK		;UNLOCK THE NODE MAPPING TABLE

;NOW FIX THE REACHABLE NODES TABLE

	LOCK NODLOK		;LOCK THE REACHABLE NODES TABLE
	MOVE T3,[POINT 2,NODTBL]  ;MAKE BYTE POINTER TO THE TABLE
	ADJBP T1,T3		;POINT TO THE CURRENT
	SETZ T4,		; AND
	DPB T4,T1		;  SAY NO LONGER REACHABLE
	ADJBP T2,T3		;POINT TO THE NEW
	MOVEI T4,2		;WE ARE PHASE II
	DPB T4,T2		;SAY THE NEW IS REACHABLE
	UNLOCK NODLOK		;UNLOCK THE REACHABLE NODES TABLE
	OKINT
	RETSKP

;GET LOCAL NODE NUMBER

NDGNM:	UMOVE T2,2
	MOVE T3,OURNUM
	UMOVEM T3,0(T2)		;STORE NUMBER
	RETSKP			;DONE
;SET LOOPBACK PORT

NDSLP:	RETBAD (NSJX04)
   REPEAT 0,<			;2020 LOOPBACK
	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
   >				;END REPEAT 0

;CLEAR LOOPBACK PORT

NDCLP:	RETBAD (NSJX04)
   REPEAT 0,<			;2020 LOOPBACK
	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
   >				;END REPEAT 0

;FIND LOOPBACK PORT

NDFLP:	RETBAD (NSJX04)
   REPEAT 0,<			;2020 LOOPBACK
	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
   >				;END REPEAT 0
; SET NETWORK TOPOLOGY INFO

NDSNT:	STKVAR <NEWTOP,NODES,TMPTOP,USRMSK>
	MOVE T1,CAPENB		;GET CURRENTLY ENABLED CAPABILITIES
	TXNN T1,SC%WHL!SC%OPR	;WHEEL, OPERATOR CAPABILITY REQUIRED
	RETBAD (CAPX1)		;WHEEL OR OPERATOR capability required
	UMOVE T2,2		;GET ADDR OF USER'S ARGUMENT BLOCK
	UMOVE T1,.NDNNO(T2)	;GET THE NUMBER OF NODES
	CAILE T1,BIGNOD		;CAN WE HANDLE THIS MANY NODES?
	RETBAD (NSPX25)		;NO, FAIL
	MOVEM T1,NODES		;SAVE THE NUMBER OF NODES BEING REPORTED
	UMOVE T1,.NDMSK(T2)	;GET USER'S ADDRESS OF TOPOLOGY MESSAGE
	MOVEM T1,USRMSK		;SAVE IT
	NOINT			;NO INTERRUPTIONS WHILE GETTING SPACE
	MOVEI T1,<BIGNOD+17>/20	;ENOUGH WORDS FOR TOPOLOGY MESSAGE
	CALL ASGDCN		;GET SWAPPABLE FREE SPACE
	 RETBAD (MONX06,<OKINT>)  ;ERROR - "NO MORE SWAPPABLE FREE SPACE"
	MOVEM T1,TMPTOP		;SAVE THE ADDRESS
	MOVEI T1,<BIGNOD+21>/22	;ENOUGH WORDS FOR TOPOLOGY BIT MASK
	CALL ASGDCN		;GET SWAPPABLE FREE SPACE
	 JRST [	MOVE T1,TMPTOP	;GET ADDR
		CALL RELDCN	;RELEASE THE SPACE
		RETBAD (MONX06,<OKINT>)]	;ERROR - NO MORE SPACE
	MOVEM T1,NEWTOP		;SAVE THE ADDR
	MOVE T3,TMPTOP		;GET DESTINATION IN CORRECT AC FOR BLT
	MOVE T1,NODES		;GET NUMBER OF NODES
	ADDI T1,17		;CALC NUMBER OF
	IDIVI T1,20		; WORDS TO BLT
	MOVE T2,USRMSK		;RETRIEVE USER'S ADDRESS
	CALL BLTUM1		;GET USER'S NEW TOPOLOGY BIT MASK
	MOVE T1,NODES		;GET NUMBER OF NODES
	ADDI T1,3		;CALC NUMBER OF
	IDIVI T1,4		; 8-BIT BYTES
	MOVE Q2,TMPTOP		;GET ADDR OF COPIED MESSAGE
	HRLZI T2,(<POINT 8,(Q2)>) ;GET A 8-BIT INDEXED BYTE POINTER
	MOVE Q3,NEWTOP		;GET ADDRESS FOR BIT MASK
	HRLZI T3,(<POINT 2,(Q3)>) ;GET A 2-BIT INDEXED BYTE POINTER
NDXLT:	ILDB T4,T2		;GET A BYTE FROM THE MESSAGE
	MOVEI Q1,4		;NUMBER OF NODES REPRESENTED IN A MESSAGE BYTE
NDXLT1:	IDPB T4,T3		;MAKE ENTRY IN BIT MASK
	SOJLE Q1,NDXLT2		;ANY MORE IN THIS BYTE?
	LSH T4,-2		;YES
	JRST NDXLT1		;CONTINUE
NDXLT2:	SOJG T1,NDXLT		;ANY MORE BYTES IN MESSAGE?
	LOCK NODLOK		;LOCK THE REACHABLE NODES TABLE

   IFN DN20SW,<			;CHECK FOR OTHER MCBS
	MOVEI T4,2		;NEXT DTE TO CHECK
NDXLT4:	SKIPL MCBDTE(T4)	;IS IT UP?
	JRST NDXLT3		;NO
	MOVE T2,NEWTOP		;MAKE BP
	HRLI T2,440200		; TO NEW TOPOLOGY

	MOVE Q2,NEWTOP		;GET ADDRESS FOR BIT MASK
	HRLZI T2,(<POINT 2,(Q2)>) ;GET A 2-BIT INDEXED BYTE POINTER
	MOVE T1,ITSNUM(T4)	;GET ITS NODE NUMBER
	ADJBP T1,T2		;POINT TO ITS ENTRY IN REACH TABLE
	MOVEI T3,3		;IT'S PHASE 3
	DPB T3,T1		;PUT IT IN
NDXLT3:	CAIGE T4,3		;CHEKCED ALL DTES YET?
	IFNSK.			;NO
	   AOS T4		;MAKE NEXT DTE
	   JRST NDXLT4		;TRY IT
	ENDIF.
   >

	MOVE Q2,NEWTOP		;GET ADDRESS FOR BIT MASK
	HRLZI T1,(<POINT 2,(Q2)>) ;GET A 2-BIT INDEXED BYTE POINTER
	MOVE T2,[POINT 2,NODTBL]  ;BYTE POINTER TO EXISTING TOPOLOGY
	MOVE T3,NODES		;NUMBER OF BYTES TO COMPARE
	SETZ T4,		;NO OFFSET DURING COMPARISON
	CALL COMPAR		;HAS TOPOLOGY CHANGED?
	 SKIPA			;YES
	JRST NDSNTR		;NO, THEN NOTHING TO DO
	MOVE T1,NEWTOP		;RETRIEVE ADDRESS OF NEW TOPOLOGY
	MOVE T2,NODES		;GET NUMBER OF NODES
	ADDI T2,21		;CALC NUMBER OF
	IDIVI T2,22		; WORDS TO SEARCH
	MOVNS T2		;MAKE
	HRLZS T2		; AOBJN WORD
NDSNTL:	MOVE T3,(T1)		;GET A WORD FROM NEW TOPOLOGY
	MOVEM T3,NODTBL(T2)	;MOVE IT TO REACHABLE NODES TABLE
	AOS T1			;INCR SOURCE POINTER
	AOBJN T2,NDSNTL		;DO THEM ALL
	CALL ADDTEL		;INFORM INTERESTED USERS OF NEW TOPOLOGY
	 JFCL			;NO SUCH RETURN
NDSNTR:	MOVE T1,TMPTOP		;GET ADDR
	CALL RELDCN		;RELEASE THE SPACE
	MOVE T1,NEWTOP		;GET ADDR
	CALL RELDCN		;RELEASE THE SPACE
	UNLOCK NODLOK		;DONE WITH THE LOCK
	OKINT			;
	RETSKP			;EVERYTHING OK

	ENDSV.
; 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 (NSPX26)		;ERROR - TABLE OF TOPOLOGY WATCHERS IS FULL
	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
;THIS ROUTINE   O N L Y   RETSKPs!!!!!!!!


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
; GET NETWORK TOPOPLOGY INFORMATION

NDGNT:	TRVAR <GNTBLK,GNTRET,GNTCNT,GNTPTR,PTRAOB>

; SET UP TO LOOP OVER EACH NODE

	SETZM GNTRET		;INIT THE "NUMBER RETURNED"
	UMOVE T4,2		;GET ADDRESS OF USER'S ARGUMENT BLOCK
	MOVEM T4,GNTBLK		;SAVE ADDRESS OF USER'S ARG BLOCK
	UMOVE T1,.NDNND(T4)	;GET NUMBER OF WORDS IN BLOCK
	ADD T1,T4		;COMPUTE LAST ADDRESS
	SOS T1			; 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
	SETZ T2,		;INIT THE "NUMBER OF NODES FOUND" COUNTER
	MOVNI T1,BIGNOD		;MAKE
	MOVSS T1		; AOBJN
	HRRI T1,1		;  WORD
	MOVE T3,[POINT 2,NODTBL]  ;BYTE POINTER TO REACH TABLE
	NOINT			;NO INTERRUPTIONS
	LOCK NMAPLK		; WHILE
	LOCK NODLOK		;  TABLES LOCKED
NDGN02:	ILDB Q2,T3		;GET INFO
	SKIPE Q2		;REACHABLE?
	AOS T2			;YES. COUNT IT
       	AOBJN T1,NDGN02		;GET NEXT NODE INFO

;end of list
	IFE. T2      		;IF NONE REACHABLE, DONE
	  UNLOCK NODLOK		;UNLOCK
	  UNLOCK NMAPLK		; TABLES
	  OKINT			;ALLOW INTERRUPTS
	  RETSKP		;DONE.
	ENDIF.

;REACHABLE NODES HAVE BEEN COUNTED

	MOVE Q2,Q1		;COPY STARTING ADDRESS OF NODE BLOCK POINTERS
	ADD Q2,T2		;COMPUTE STARTING ADDRESS OF NODE BLOCK AREA
	CAMLE Q2,GNTCNT		;ENOUGH ROOM FOR ALL THE NODE BLOCK POINTERS ?
	 JRST NDGNXX 		;NO. FAIL
	MOVX T1,.NDNBS		;GET SIZE OF A NODE BLOCK
	UMOVEM T1,.NDCNT(T4)	;STORE IN USER ARG BLOCK

;LOOP OVER EACH NODE

	MOVNI T2,BIGNOD		;MAKE
	MOVSS T2		; AOBJN
	HRRI T2,1		;  WORD (node number in LH)
	MOVE T1,[POINT 2,NODTBL]  ;BYTE POINTER TO REACH TABLE
	MOVEM T1,GNTPTR		;SAVE POINTER
NDGN10:	ILDB Q3,GNTPTR		;GET INFO
	SKIPN Q3		;REACHABLE ?
	JRST NDGN20		;NO.
	HRRZ Q3,T2		;YES. GET NODE NUMBER
	SKIPN NODMAP(Q3)	;DOES THIS NODE HAVE A NAME?
	JRST NDGN20		;NO, DON'T RETURN ANYTHING TO USER
	UMOVEM Q2,(Q1)		;STORE POINTER TO NODE BLOCK
	 ERJMP NDGNXX		;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 NDGNXX 		;NO. GO CLEAN UP AND FAIL RETURN
	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
	MOVEI T1,NODMAP(Q3)	;GET ADDRESS OF NODE NAME
	HRLI T1,440600		;MAKE A BYTE POINTER TO THE SOURCE STRING
	MOVEM T2,PTRAOB		;SAVE AOBJN WORD (NUMBER OF NODES NOT YET PROCESSED IN RH)
	MOVEI T2,40		;CONVERT SIXBIT ASCII TO 7-BIT ASCII
	MOVEI T4,6		;MAX OF 6 CHARACTERS TO BE MOVED
	CALL STONOD		;STORE NODE NAME STRING IN USER SPACE
	 JRST NDGNXX		;FAILURE.
	MOVE T2,PTRAOB		;RETRIEVE THE AOBJN WORD
	ADDI Q1,1		;INCREMENT ADDRESS OF NEXT NODE BLOCK POINTER
	HRRI Q2,1(T3)		;GET ADDRESS OF NEXT NODE BLOCK
	AOS GNTRET		;INCR THE "NUMBER RETURNED"
NDGN20:	AOBJN T2,NDGN10		;LOOP OVER EACH NODE

; HERE WHEN ALL INFO RETURNED TO USER SUCCESSFULLY
	CALL NDGNRE		;FINISH UP
	RETSKP			;DONE, RETURN SUCCESS

; HERE ON AN ERROR
NDGNXX: CALL NDGNRE		;FINISH UP
	RETBAD (ARGX04)		;RETURN "ARGUMENT BLOCK TOO SMALL"


;RETURN NUMBER OF NODES REPORTED AND CLEAN UP LOCKS
;RETURNS:	+1

NDGNRE:	MOVE T1,GNTRET		;GET NUMBER OF BLOCKS RETURNED
	MOVE T2,GNTBLK		;GET ADDR OF USER'S ARG BLOCK
	XCTU [HRLM T1,.NDNND(T2)]  ;RETURN THE INFO
	UNLOCK NODLOK 		;UNLOCK REACH TABLE
	UNLOCK NMAPLK		;UNLOCK THE MAPPING TABLE
	OKINT			;PERMIT INTERRUPTS AGAIN
	RET

	ENDTV.			;end TRVAR
; GET LINE INFORMATION INFORMATION

NDGLI:	STKVAR <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
	 ERJMPR [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
	SETZB T2,T4		;NO OFFSET, STRING ENDS WITH A NULL
	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

	ENDSV.

;STONOD - ROUTINE TO STORE NODE NAME STRING IN USER SPACE
;
;ACCEPTS IN T1/	BYTE POINTER TO SOURCE STRING
;	    T2/ OFFSET TO BE ADDED TO EACH CHARACTER
;	    T3/	BYTE POINTER TO DESTINATION IN USER SPACE
;	    T4/ MAX CHAR COUNT IF STRING DOESN'T END WITH NULL
;		CALL STONOD
;RETURNS: +1	 FAILED
;	  +2	SUCCESS

STONOD:	SAVEAC <P6>
STONO1:	ILDB P6,T1		;GET A BYTE
	JUMPE P6,STONO2		;IF NULL, ALL DONE
	SKIPE T2		;ANY OFFSET?
	ADD P6,T2		;YES
	XCTBU [IDPB P6,T3]	;STORE BYTE
	 ERJMP R		;FAILED, RETURN ERROR
	SKIPG T4		;COUNTING CHARS?
	JRST STONO1		;NO
	SOJG T4,STONO1		;YES - ANY MORE?
	SETZ P6,		;NO, MAKE A NULL
STONO2:	XCTBU [IDPB P6,T3]	;APPEND A NULL
	 ERJMP R		;FAILED, RETURN ERROR
	RETSKP			;DONE, RETURN SUCCESS
; NDVFY - VERIFY NODE NAME IS IN MONITOR'S DATABASE OF REACHABLE NODES
;NOTE:  IT MUST FIRST BE IN THE NODE NAME MAPPING TABLE
;  USES T1-T4

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

; GET NODE NAME FROM USER SPACE

	UMOVE Q1,T2		;GET ADDRESS OF USER ARGUMENT BLOCK
	MOVEM Q1,VFYARG		;SAVE IT FOR LATER
	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 IN NAME MAPPING TABLE

	HRRI T1,NDVNOD		;GET ADDRESS OF NODE NAME
	HRLI T1,(POINT 7,)	;FORM POINTER TO NODE NAME
	CALL NDVFY1		;do the work, (length is in T2 from PARNDU)

;RETURN INFO TO THE USER

       	MOVE T2,VFYARG		;RETRIEVE ADDR OF USER'S ARG BLOCK
	UMOVEM T1,.NDFLG(T2)	;RETURN THE NEWS TO THE USER
	RETSKP

	ENDSV.

;verify that the parsed node name is in the name mapping table and is reachable.
; T1 - byte pointer to parsed node name in monitor space
; T2 - length of that node name
; returns +1 always and OKINT ; flags in T1 (ND%EXM)
; uses T1-T4
; CALL NDVFY1

NDVFY1::SAVEAC (P3)
	STKVAR <VFYSTR>
	MOVEM T1,VFYSTR		;SAVE IT FOR LATER USE
	MOVE T3,T2		;GET NUMBER OF CHARS IN NAME
	MOVNI T4,40		;COMPARING 7-BIT TO SIXBIT ASCII
	MOVNI P3,BIGNOD		;MAKE
	HRLZS P3		; AOBJN
	HRRI P3,1		;  WORD
	NOINT			;NO INTERRUPTIONS
	LOCK NMAPLK		; WHILE TABLE LOCKED
NDVFY2:	MOVE T1,VFYSTR		;GET BYTE POINTER TO USER'S NAME
	HRLI T2,440600		;MAKE A BYTE POINTER
	HRRI T2,NODMAP(P3)	; TO MAPPING TABLE
	TLO T3,400000		;SPECIAL CALL TO COMPAR
	CALL COMPAR		;IS THIS IT?
	 JRST [AOBJN P3,NDVFY2	;NO, ANY MORE TO TEST?
	       UNLOCK NMAPLK	;NO, GIVE UP
	       OKINT		; THE LOCK
	       SETZ T1,		;TURN OFF THE "FOUND IT" BIT
	       RET]		;DONE

;NODE IS IN NODE NAME MAPPING TABLE, SEE IF IT IS REACHABLE.

	UNLOCK NMAPLK		;DONE WITH THE MAPPING TABLE
	LOCK NODLOK		;NOW LOCK THE REACH TABLE
	MOVE T1,[POINT 2,NODTBL]  ;MAKE BYTE POINTER TO BEGINNING OF REACH TABLE
	HRRZS P3		;GET JUST THE NODE NUMBER
	ADJBP P3,T1		;POINT TO APPROPRIATE ENTRY
	LDB T1,P3		;GET THE INFO
	SKIPN T1		;REACHABLE?
	JRST [UNLOCK NODLOK	;NO, DONE WITH
	      OKINT		; THE LOCK
	      SETZ T1,		;TURN OFF THE "FOUND IT" BIT
	      RET]        	;DONE

;NODE IS REACHABLE

	UNLOCK NODLOK		;DONE WITH
	OKINT			; THE LOCK
	MOVX T1,ND%EXM		;TURN ON THE "FOUND IT" BIT
	RET

	ENDSV.
; NDRNM - GIVEN A NODE NUMBER, RETURN THE NODE NAME

NDRNM:	UMOVE T4,.NDNOD(T2)	;GET NODE @MBER
	CAIL T4,1		;IS IT
	CAILE T4,BIGNOD		; LEGAL?
	RETBAD (NSPX25)		;NO
	NOINT			;LOCK THE
	LOCK NMAPLK		; NODE NAME MAPPING TABLE
	UMOVE T3,.NDCVR(T2)	;GET THE USER'S BP
	HRLI T2,440600		;MAKE A BP
	HRRI T2,NODMAP(T4)	; TO THE NAME
	CALL NTRNAM		;RETURN THE NODE NAME TO THE USER
	UNLOCK NMAPLK		;DONE WITH
	OKINT			; THE LOCK
	RETSKP

	TNXEND

	END