Google
 

Trailing-Edge - PDP-10 Archives - BB-M080O-SM - monitor-sources/dnadll.mac
There are 20 other files named dnadll.mac in the archive. Click here to see a list.
;------------------------- Autopatch Tape # 13 -------------------------
;------------------------- Autopatch Tape # 12 -------------------------
; UPD ID= 2261, SNARK:<6.1.MONITOR>DNADLL.MAC.90,  21-Jun-85 11:41:29 by PALMIERI
;Clear UNPTR flag in UN block NIFOPN
; UPD ID= 2241, SNARK:<6.1.MONITOR>DNADLL.MAC.89,  19-Jun-85 14:11:58 by PALMIERI
;TCO 6.1.1457  Make variable EVSDRP in STG determine if endnodes enable
;for "all routers" multicast ID.  If EVSDRP=0 then no "maybe" reachable
;is available to Router for INFO DECnet.
; UPD ID= 2213, SNARK:<6.1.MONITOR>DNADLL.MAC.88,  11-Jun-85 13:55:00 by PALMIERI
;TCO 6.1.1434 Include Ethernet source and destination address in event data for
;event 5.15.  Include TDR for event 5.14.
;TCO 6.1.1432  Fix bug in CHKADR that was incorrectly reseting AC UN.
; UPD ID= 2066, SNARK:<6.1.MONITOR>DNADLL.MAC.86,   3-Jun-85 14:31:22 by MCCOLLUM
;TCO 6.1.1406  - Update copyright notice.
; UPD ID= 2010, SNARK:<6.1.MONITOR>DNADLL.MAC.85,  24-May-85 15:11:15 by PALMIERI
;TCO 6.1.1408   Don't attempt to open an Ethernet DECnet portal if the physical
; address is not DECnet's
; UPD ID= 1874, SNARK:<6.1.MONITOR>DNADLL.MAC.84,   4-May-85 11:45:12 by MCCOLLUM
;TCO 6.1.1238 - Fix more BUG. documentation
; UPD ID= 1834, SNARK:<6.1.MONITOR>DNADLL.MAC.83,  26-Apr-85 10:03:11 by MCCOLLUM
;TCO 6.1.1238 - Fix BUG. documentation
; UPD ID= 1726, SNARK:<6.1.MONITOR>DNADLL.MAC.82,   8-Apr-85 12:48:46 by MCCOLLUM
;TCO 6.1.1238 - Fix BUG. documentation
; UPD ID= 1647, SNARK:<6.1.MONITOR>DNADLL.MAC.81,  18-Mar-85 14:54:53 by PALMIERI
;Always post buffers when DTE line comes up
; UPD ID= 1629, SNARK:<6.1.MONITOR>DNADLL.MAC.80,  13-Mar-85 14:57:51 by PALMIERI
;Don't reserve emergency buffers until Router has blessed the circuit
;Clean up for and add table of contents
; UPD ID= 1546, SNARK:<6.1.MONITOR>DNADLL.MAC.79,  20-Feb-85 14:24:50 by PALMIERI
;TCO 6.1.1215 - Make DNDINQ global for LV8CHK - Remove queue empty check at
; DNDJIF. It is now in STG at LV8CHK. Don't give DNDNNF bugchk when things
; succeed.
; UPD ID= 1525, SNARK:<6.1.MONITOR>DNADLL.MAC.78,  14-Feb-85 01:53:45 by GROSSMAN
;Remove extra line after DNDRLF BUG.
; UPD ID= 1520, SNARK:<6.1.MONITOR>DNADLL.MAC.77,  13-Feb-85 17:35:27 by PALMIERI
;Add some BUG.s
;Re-work the way emergency buffer are managed.  Reserve them here instead of
;in Router.
;Implement alternate queue block which avoids repeated PIOFF/PION when emptying
;queue to Router at LV8CHK/JIFFY time.
;Document some BUG.s
;TCO 6.1.1193 - LV8CHK now knows that DNDJIF is in XCDSEC
; UPD ID= 1485, SNARK:<6.1.MONITOR>DNADLL.MAC.76,   6-Feb-85 22:00:57 by PALMIERI
;Check for empty queue when entering DNDJIF before doing anything
; UPD ID= 1346, SNARK:<6.1.MONITOR>DNADLL.MAC.75,  16-Jan-85 11:35:33 by GLINDELL
;Remove TSTS6 tests
; UPD ID= 1327, SNARK:<6.1.MONITOR>DNADLL.MAC.74,  14-Jan-85 16:03:06 by PALMIERI
;Make attempt to set DTE line state return an error (operation failure)
; UPD ID= 1302, SNARK:<6.1.MONITOR>DNADLL.MAC.73,  10-Jan-85 16:50:29 by MOSER
;REMOVE TAB BEFORE CONTROL-L SO BUGS.MAC GENERATOR CAN RUN
; UPD ID= 1289, SNARK:<6.1.MONITOR>DNADLL.MAC.72,   8-Jan-85 18:08:51 by PALMIERI
;Add BUGCHKs if errors on Enable Multicast or Queue Message to NI fails
; UPD ID= 1286, SNARK:<6.1.MONITOR>DNADLL.MAC.71,   8-Jan-85 13:44:30 by PALMIERI
;Don't post buffers at NIIRCI unless Router is using the line
; UPD ID= 1262, SNARK:<6.1.MONITOR>DNADLL.MAC.70,   3-Jan-85 21:19:05 by PALMIERI
;Remove section 6 testing at DNDJIF
; UPD ID= 1258, SNARK:<6.1.MONITOR>DNADLL.MAC.69,   2-Jan-85 15:56:47 by PALMIERI
;Change DNDTIC TO DNDJIF
; UPD ID= 1193, SNARK:<6.1.MONITOR>DNADLL.MAC.68,  12-Dec-84 11:29:44 by PALMIERI
;Fix bit mapped counter bits to agree with network management - NLCTAB+
; UPD ID= 1173, SNARK:<6.1.MONITOR>DNADLL.MAC.67,  10-Dec-84 18:11:39 by PALMIERI
;Fix receive error event code for "frame too long"
; UPD ID= 1157, SNARK:<6.1.MONITOR>DNADLL.MAC.66,   5-Dec-84 17:27:48 by GLINDELL
;Remove unnecessary intra-section transfers
; UPD ID= 1117, SNARK:<6.1.MONITOR>DNADLL.MAC.65,  20-Nov-84 17:21:58 by PALMIERI
;Fix handling of NIA20 physical address change
; UPD ID= 1073, SNARK:<6.1.MONITOR>DNADLL.MAC.64,  14-Nov-84 13:33:59 by GLINDELL
;Fix IFIW's
; UPD ID= 1029, SNARK:<6.1.MONITOR>DNADLL.MAC.63,  12-Nov-84 14:47:21 by PALMIERI
;Initialize event communication block
; UPD ID= 1009, SNARK:<6.1.MONITOR>DNADLL.MAC.62,   8-Nov-84 14:30:52 by PALMIERI
;Fix bug at NIEVN2
; UPD ID= 989, SNARK:<6.1.MONITOR>DNADLL.MAC.61,   7-Nov-84 13:10:55 by PALMIERI
;Add support for large buffers, fix event logging
; UPD ID= 897, SNARK:<6.1.MONITOR>DNADLL.MAC.60,  18-Oct-84 13:31:25 by PALMIERI
;Fix error return to NTMAN at DNDCET+
; UPD ID= 894, SNARK:<6.1.MONITOR>DNADLL.MAC.59,  17-Oct-84 16:07:53 by PALMIERI
;Fix NMXSAL
; UPD ID= 889, SNARK:<6.1.MONITOR>DNADLL.MAC.58,  17-Oct-84 13:19:53 by PALMIERI
;Change RNMXOK to RNMXND
;Default the line state in the LINTBL
; UPD ID= 882, SNARK:<6.1.MONITOR>DNADLL.MAC.57,  15-Oct-84 16:32:41 by PALMIERI
;Replace hard coded value for RNT.NR  with sysbol now that all module are in
;sync
; UPD ID= 878, SNARK:<6.1.MONITOR>DNADLL.MAC.56,  12-Oct-84 14:10:30 by PALMIERI
;Network management SLZ fixes
; UPD ID= 861, SNARK:<6.1.MONITOR>DNADLL.MAC.55,  10-Oct-84 16:08:33 by PALMIERI
;Make dispatch table handle DMRs
;Move to extended section, add queues for UN blocks and QB blocks
; UPD ID= 836, SLICE:<6.1.MONITOR>DNADLL.MAC.48,  27-Sep-84 13:24:07 by PALMIERI
;Fix line state on close to DTE
; UPD ID= 827, SLICE:<6.1.MONITOR>DNADLL.MAC.47,  26-Sep-84 10:13:42 by PALMIERI
;Fix DNDCET I just broke
; UPD ID= 826, SLICE:<6.1.MONITOR>DNADLL.MAC.46,  25-Sep-84 17:58:37 by PALMIERI
;Make DNDCET deal with lines and circuits both
; UPD ID= 796, SNARK:<6.1.MONITOR>DNADLL.MAC.45,  12-Sep-84 12:15:24 by PALMIERI
;Add missing "RESCD" so code which must be resident is.
; UPD ID= 792, SNARK:<6.1.MONITOR>DNADLL.MAC.44,  10-Sep-84 15:05:09 by PALMIERI
;Save a permanent AC at DNDSEC that was being smashed
;Fix sense of run bit testing on Read Channel Info callback from NISRV
; UPD ID= 775, SNARK:<6.1.MONITOR>DNADLL.MAC.43,  31-Aug-84 13:46:29 by PALMIERI
;Network management fixes
; UPD ID= 718, SNARK:<6.1.MONITOR>DNADLL.MAC.42,  27-Jul-84 16:02:24 by GROSSMAN
;Use D36COM routines to play with MDPTR instead of doing it directly.
; UPD ID= 689, SNARK:<6.1.MONITOR>DNADLL.MAC.41,  16-Jul-84 17:00:01 by PALMIERI
;Set up DL for parameter functions for DTE and NI
; UPD ID= 680, SNARK:<6.1.MONITOR>DNADLL.MAC.40,  12-Jul-84 18:00:37 by HALPIN
;This time REALLY remove all references to NF.REX!!!!!!!
;
; UPD ID= 679, SNARK:<6.1.MONITOR>DNADLL.MAC.39,  12-Jul-84 17:41:36 by HALPIN
;Remove references to NF.REX Network Management Function call
;Put PABEX (Buffer EXpected) Flag in the NI Hardware Address PARAMETER
; macro.
;Fixed bugs in DNDNMF, Relating to the NFWBLK Selector (KNOWN, ADJACENT,...)
; field
;Add BEX for Ethernet address
; UPD ID= 672, SNARK:<6.1.MONITOR>DNADLL.MAC.38,   9-Jul-84 12:23:21 by PALMIERI
;Fix lost TRN in DNDINI
; UPD ID= 671, SNARK:<6.1.MONITOR>DNADLL.MAC.37,   6-Jul-84 18:07:36 by PALMIERI
;Add NTMAN interface
;Elective endnode
; UPD ID= 635, SNARK:<6.1.MONITOR>DNADLL.MAC.36,  20-Jun-84 16:21:44 by PALMIERI
;When reading NI channel list don't expect T2 to point to UN block on return
; UPD ID= 632, SNARK:<6.1.MONITOR>DNADLL.MAC.35,  18-Jun-84 18:21:17 by PALMIERI
;Check count of channels found at NIDINI
; UPD ID= 628, SNARK:<6.1.MONITOR>DNADLL.MAC.34,  18-Jun-84 13:32:35 by PALMIERI
;Check callback ID at DTIPPI
; UPD ID= 627, SNARK:<6.1.MONITOR>DNADLL.MAC.33,  18-Jun-84 09:53:52 by PALMIERI
;Fix typo at DTIPRB+1
; UPD ID= 624, SNARK:<6.1.MONITOR>DNADLL.MAC.31,  14-Jun-84 21:08:56 by PALMIERI
;Move DL BEGSTR to D36PAR for DCNSPY usage
;We no longer need to set the DECnet address for the Ethernet (SETSPD does it)
; UPD ID= 605, SNARK:<6.1.MONITOR>DNADLL.MAC.30,   6-Jun-84 14:59:09 by GLINDELL
;DF.COU changed to DF.SHC
; UPD ID= 598, SNARK:<6.1.MONITOR>DNADLL.MAC.29,   6-Jun-84 11:37:27 by PALMIERI
;NIIRCE broken by commented out instruction
; UPD ID= 595, SNARK:<6.1.MONITOR>DNADLL.MAC.28,   4-Jun-84 15:23:53 by PALMIERI
;Add in overhead when computing buffer size requiremnts for Ethernet buffers
; UPD ID= 592, SNARK:<6.1.MONITOR>DNADLL.MAC.27,   1-Jun-84 18:23:46 by PALMIERI
;Account for buffer returned on a close from DTESRV
; UPD ID= 584, SNARK:<6.1.MONITOR>DNADLL.MAC.26,  31-May-84 15:25:03 by PALMIERI
;Don't release DLB at NIFNOF: - Fix this stuff later
; UPD ID= 569, SNARK:<6.1.MONITOR>DNADLL.MAC.23,  25-May-84 16:25:07 by PALMIERI
;Remove references to %RTBSW
; UPD ID= 562, SNARK:<6.1.MONITOR>DNADLL.MAC.22,  24-May-84 15:50:32 by PALMIERI
;Check the RUN bit now that NISRV is changed
; UPD ID= 550, SNARK:<6.1.MONITOR>DNADLL.MAC.20,  23-May-84 21:38:33 by PALMIERI
;Never post more than 1 buffer to DTESRV, return buffer on close
; UPD ID= 537, SNARK:<6.1.MONITOR>DNADLL.MAC.18,  21-May-84 17:49:31 by PALMIERI
;Don't post any buffers for any error at NIIRCE (Temp till NISRV fixed)
; UPD ID= 530, SNARK:<6.1.MONITOR>DNADLL.MAC.17,  20-May-84 20:39:36 by PALMIERI
;Fix once per second code for DTE and add UNRUN check for NI
; UPD ID= 522, SNARK:<6.1.MONITOR>DNADLL.MAC.16,  14-May-84 13:59:34 by PALMIERI
;Fix NI callback dispatch table
; UPD ID= 509, SNARK:<6.1.MONITOR>DNADLL.MAC.15,   7-May-84 17:43:09 by PALMIERI
;Move circuit counters maintained by the line to DNADLL
; UPD ID= 485, SNARK:<6.1.MONITOR>DNADLL.MAC.14,  30-Apr-84 13:10:37 by PALMIERI
;Replace PION/PIOFF with SYSPIF/SYSPIN
;Interface to the new Ethernet driver (NISRV)
;Bring DNADLL up to the level descibed in the spec
; UPD ID= 407, SNARK:<6.1.MONITOR>DNADLL.MAC.11,  26-Mar-84 16:08:07 by PALMIERI
;DLUID not always set
; UPD ID= 405, SNARK:<6.1.MONITOR>DNADLL.MAC.10,  22-Mar-84 14:25:07 by PALMIERI
;Be sure UN is set up when calling PSTBUF from DNDSEC
; UPD ID= 398, SNARK:<6.1.MONITOR>DNADLL.MAC.8,  20-Mar-84 01:08:18 by GROSSMAN
;Fix typo which crashes monitor.
; UPD ID= 392, SNARK:<6.1.MONITOR>DNADLL.MAC.7,  19-Mar-84 15:54:37 by PALMIERI
;Add some small support for CIDDL and add once per second routine
; UPD ID= 375, SNARK:<6.1.MONITOR>DNADLL.MAC.5,   8-Mar-84 18:01:10 by PALMIERI
; %RTBSW is defined in D36COM, declare it external
; UPD ID= 371, SNARK:<6.1.MONITOR>DNADLL.MAC.4,   5-Mar-84 15:33:25 by GROSSMAN
;Use correct buffer size for Ethernet
; UPD ID= 358, SNARK:<6.1.MONITOR>DNADLL.MAC.3,  27-Feb-84 15:50:17 by PALMIERI
;Fix error return from DNDPRB
; UPD ID= 343, SNARK:<6.1.MONITOR>DNADLL.MAC.2,  24-Feb-84 13:22:24 by PALMIERI
;TITLE DNADLL - DLL use interface for DECnet-36  V000

;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, 1985.
;ALL RIGHTS RESERVED.

		SUBTTL Marty Palmieri	 6 March 85
		SEARCH NIPAR,D36PAR,MACSYM
	SALL

	ENTRY DNDINI

XP DNADLL,000
IFN FTOPS20,<
	SEARCH PROLOG
	TTITLE DNADLL,,< - DLL interface for DECnet-36>
	>

IFN FTOPS10,<
	SEARCH F,S
	TITLE DNADLL - DLL interface for DECnet-36
>;END OF IFN FTOPS10
	D36SYM			;SET UP D36 SPECIFIC PARAMETERS

IFN FTOPS10,<$RELOC>

	XRESCD			;RELOC TO HIGHSEG (RSCOD PSECT ON TOPS-20)
	SUBTTL	Table of Contents


;		Table of Contents for DNADLL
;
;
;			   Section			      Page
;   1. Table of Contents. . . . . . . . . . . . . . . . . . .    3
;   2. Definitions
;        2.1.   External References . . . . . . . . . . . . .    4
;        2.2.   Accumulators. . . . . . . . . . . . . . . . .    6
;        2.3.   BEGSTRs . . . . . . . . . . . . . . . . . . .    7
;        2.4.   Line tables . . . . . . . . . . . . . . . . .    8
;   3. Network management
;        3.1.   Line counter tables . . . . . . . . . . . . .    9
;        3.2.   Ethernet line counter tables. . . . . . . . .   10
;        3.3.   Line parameters (DTE) . . . . . . . . . . . .   11
;        3.4.   Line parameters (Ethernet). . . . . . . . . .   12
;        3.5.   Node parameters (Ethernet). . . . . . . . . .   12
;   4. DNDINI - Initialize Router's common DLL interface. . .   13
;   5. Ckeck entity - Build DLL database. . . . . . . . . . .   14
;   6. DNDGLB - Find a data link block. . . . . . . . . . . .   15
;   7. DNDGLT - Find a line block . . . . . . . . . . . . . .   16
;   8. DNDQUE - Enter requests on input queue . . . . . . . .   17
;   9. DNDSEC - Entry from scheduler level each second. . . .   18
;  10. DNDJIF - Entry from scheduler level to empty queues. .   19
;  11. DNDDSP - Dispatch for calls from ROUTER. . . . . . . .   20
;  12. DNDNMX - Dispatch on calls from Network Management . .   20
;  13. Network management
;       13.1.   Show known/active lines . . . . . . . . . . .   21
;       13.2.   Show active lines . . . . . . . . . . . . . .   22
;       13.3.   Show known lines. . . . . . . . . . . . . . .   22
;  14. DCIDSP - Dispatch routine for calls to CIDLL . . . . .   23
;  15. DTEDLL
;       15.1.   DTE data link layer . . . . . . . . . . . . .   24
;       15.2.   Intialize a line  . . . . . . . . . . . . . .   24
;       15.3.   Dispatch from Router or Network Management. .   25
;       15.4.   Open a port . . . . . . . . . . . . . . . . .   26
;       15.5.   Transmit a packet . . . . . . . . . . . . . .   27
;       15.6.   Close a port. . . . . . . . . . . . . . . . .   28
;       15.7.   Network management - Parameter functions. . .   29
;       15.8.   Network Management - Show/Show and zero counters  30
;       15.9.   Network management - Return list. . . . . . .   31
;       15.10.  Network management - Check entity . . . . . .   31
;       15.11.  Common call to DTESRV . . . . . . . . . . . .   31
;       15.12.  DTESRV interrupt level callbacks. . . . . . .   32
;       15.13.  Transmit complete from DTESRV . . . . . . . .   33
;       15.14.  Receive complete from DTESRV. . . . . . . . .   34
;       15.15.  Post receive buffer for DTESRV. . . . . . . .   35
;       15.16.  Line state change callback. . . . . . . . . .   36
;  16. NIDLL - Ethernet DLL interface . . . . . . . . . . . .   37
;  17. NIDLL
;       17.1.   Once per second routine . . . . . . . . . . .   38
;       17.2.   Dispatch for calls from Router or Network Management  39
;       17.3.   Open portal . . . . . . . . . . . . . . . . .   40
;       17.4.   Close an ethernet protal. . . . . . . . . . .   41
;       17.5.   Send a packet on the wire . . . . . . . . . .   42
;       17.6.   Network Management - Parameter functions. . .   43
;       17.7.   Network management - Show /Show and zero counters   44
;       17.8.   Common calls to NISRV . . . . . . . . . . . .   45
;       17.9.   Network management - Read portal counters . .   46
;       17.10.  Network management - Read channel counters. .   47
;       17.11.  Network management - Read Ethernet addreses .   48
;       17.12.  Network management - Read channel information   49
;       17.13.  Network management - Read counters interlock.   50
;       17.14.  Set the DECnet address in the channel . . . .   51
;       17.15.  Post buffers for the NIDLL. . . . . . . . . .   52
;       17.16.  Enable multicast address. . . . . . . . . . .   53
;       17.17.  Get informational portal ID . . . . . . . . .   54
;       17.18.  Close the information portal. . . . . . . . .   55
;       17.19.  Interrupt level callbacks from NISRV. . . . .   56
;       17.20.  Close complete callback . . . . . . . . . . .   57
;       17.21.  Input complete. . . . . . . . . . . . . . . .   58
;       17.22.  Transmit done . . . . . . . . . . . . . . . .   59
;       17.23.  Read portal counters complete . . . . . . . .   60
;       17.24.  Channel state change callback (line state change)   61
;       17.25.  Set channel address callback. . . . . . . . .   62
;       17.26.  Read channel counters callback. . . . . . . .   63
;       17.27.  Set channel state callback. . . . . . . . . .   64
;       17.28.  Ethernet event reporter . . . . . . . . . . .   65
;  18. Network Management Interface
;       18.1.   RTNEVT - Event Reporter . . . . . . . . . . .   66
;  19. Miscellaneous routines
;       19.1.   Get a UN block. . . . . . . . . . . . . . . .   69
;       19.2.   Get emergency buffer. . . . . . . . . . . . .   70
;       19.3.   Check Ethernet address. . . . . . . . . . . .   71
;  20. Local storage for DNADLL . . . . . . . . . . . . . . .   72
	SUBTTL Definitions -- External References

;These are the external references to the D36COM library of routines.

	EXT DNGMSG		;GET DECNET-36 MESSAGE BLOCK
	EXT DNFMSG		;FREE MESSAGE BLOCK
	EXT DNGEMS		;GET EMERGENCY MESSAGE BLOCK
	EXT DNGEBF		;Reserve emergency buffers

	EXT DNGWDS		;GET SOME WORDS
	EXT DNGWDZ		;GET SOME ZEROED WORDS
	EXT DNFWDS		;FREE SOME WORDS
	EXT DNSWDS		;SMEAR SOME WORDS

	EXT UPDTCK		; Updated DNGTIM
	EXT DNGTIM		;RETURN CURRENT UPTIME (IN MS)

	EXT NMXEVT		;NTMAN event processor
	EXT NTPARM		;Common parameter routine
	EXT NTCTRS		;Common counter routine

;These are the external references to D36COM data cells

	EXT RTRHOM		;OUR HOME AREA
	EXT RTRADR		;OUR NODE NUMBER
	EXT RTRLOO		; Low order of DECnet address (string)
	EXT MXLBSZ		;Maximum receive block size for a line
	EXT IBBLK		;DECnet-36 initialization block

;These are the external references to ROUTER

	EXT RTRPRO		;ROUTER'S PROTOCOL TYPE
	EXT RTRDLE		; Entry into ROUTER from dnadll
	EXT RTRCOP
	EXT TSTBLK
;These are some default parameters

	EXT %RTHIO		;HI PART OF THE NI ADDRESS
	EXT %RTHOM		;HOME AREA FOR THIS NODE
	EXT %RTRMA		;MULTICAST ID "ALL ROUTERS"
	EXT %RTEMA		;Multicast ID "All endnodes"
	EXT %RTBSZ
	EXT %RTEHS		;Size in bytes of Ethernet header

;These are the external references to NIDLL

	EXT DLLUNI

;These are the external references to CIDLL

	EXT CININI		;CIDLL initialization routine
	EXT CINDSP		;CIDLL dispatch routine
	EXT CINSEC		;CIDLL once a second

;Other external references

	EXT EVSDRP		;STG
	EXT RTN			;NON-SKIP RETURN
	EXT RSKP		;SKIP RETURN

;Interlock management

IFN FTOPS10,<
	EXT .CPCPN		;CURRENT CPU NUMBER
	EXT .CPSK0		;SKIP IF CURRENT CPU IS BOOT CPU
>
	SUBTTL Definitions -- Accumulators

;These are some local AC defintions for DNADLL

	DL=FREE1		;DL usually points to the data link block
	LT=FREE2 		;LT contains pointer to line table entry
	UN=MS			;UN is the NI user block

	PURGE FREE1		; Lose this symbol
	PURGE FREE2		;  and this one

;Some local symbols

	NOSET==PANST	;From BEGSTR in D36PAR
	NOCLR==PANCL
	BEX==PABEX

	DN.NDR==1B0		; Is not processed by specific DLL
	DN.NMF==1B1		; Network management function
	SUBTTL Definitions -- BEGSTRs


BEGSTR QB
	WORD NXT,		; Pointer to next request in queue
	HWORD FCN,		; Function requested
	WORD DA1,		; Function specific data
	WORD DA2,		; Additional data
	WORD DLB		; Associated data link block address
ENDSTR
	
;Line table structure

BEGSTR LT
	WORD LID		; Line ID
	FIELD FLG,2		; Flags
	  BIT DVE		; Driver believes device is present
	  BIT CAD		; Channel address is DECnet (Ethernet only)
	FIELD STA,2		; State of line
	FIELD CON,2		; Controller (normal/loopback)
	FIELD PRO,6		; Protocol type
	FIELD CTY,6		; Circuit type
	FIELD DBF,6		; Default number of buffers
	FIELD BSZ,12		; Maximum receive buffer size on this line
	HWORD BNO		; Number of buffers to post
	HWORD NBP		; Number of buffers posted
ENDSTR
	SUBTTL Definitions -- Line tables
	RESDT

;Table of maximum line configuration supported by TOPS-20

DEFINE LINCFG(TYPE,STATE,CPU,UNIT,PROT,CTYPE,NBUF),<
    EXP <FLD(1,LILXC)>!<FLD(LD.'TYPE,LIDEV)>!<FLD(CPU,LIKON)>!<FLD(UNIT,LIUNI)>
    EXP <FLD(0,LTDVE)>!<FLD(STATE,LTSTA)>!<FLD(0,LTCON)>!<FLD(^D<PROT>,LTPRO)>!<FLD(^D<CTYPE>,LTCTY)>!<FLD(^D<NBUF>,LTDBF)>!<FLD(%RTBSZ,LTBSZ)>
    EXP <FLD(0,LTBNO)>!<FLD(0,LTNBP)>
LNTBLL==<<.-LINTBL>/LT.LEN>
>

LINTBL:	LINCFG (NI,LS.ON,0,0,6,6,6)
	LINCFG (CIP,LS.ON,0,0,7,7,1)
	LINCFG (DTE,LS.OFF,0,1,8,8,1)
	LINCFG (DTE,LS.OFF,0,2,8,8,1)
	LINCFG (DTE,LS.OFF,0,3,8,8,1)
	SUBTTL  Network management -- Line counter tables

	XSWAPCD

;Circuit counters maintained by the line

CICTAB:

COUNTER (^D1000,^D32,<LOAD T1,DLBYR,(DL)>,<SETZRO DLBYR,(DL)>,,<
	Bytes received>)
COUNTER (^D1001,^D32,<LOAD T1,DLBYS,(DL)>,<SETZRO DLBYS,(DL)>,,<Bytes sent>)
COUNTER (^D1010,^D32,<LOAD T1,DLDBR,(DL)>,<SETZRO DLDBR,(DL)>,,<
	Data blocks received>)
COUNTER (^D1011,^D32,<LOAD T1,DLDBS,(DL)>,<SETZRO DLDBS,(DL)>,,<
	Data blocks sent>)
COUNTER (^D1065,^D16,<LOAD T1,DLUBU,(DL)>,<SETZRO DLUBU,(DL)>,,<
	Use buffer unavailable>)

CICTBL==.-CICTAB
	SUBTTL Network management -- Ethernet line counter tables
NLCTAB:

COUNTER (^D0,^D16,<LOAD T1,CCSLZ,(P2)>,,,<Seconds since last zeroed>)
COUNTER (^D1000,^D32,<LOAD T1,CCBYR,(P2)>,,,<Bytes received>)
COUNTER (^D1001,^D32,<LOAD T1,CCBYS,(P2)>,,,<Bytes sent>)
COUNTER (^D1002,^D32,<LOAD T1,CCMBR,(P2)>,,,<Multicast bytes received>)
COUNTER (^D1010,^D32,<LOAD T1,CCDGR,(P2)>,,,<Data blocks received>)
COUNTER (^D1011,^D32,<LOAD T1,CCDGS,(P2)>,,,<Data blocks sent>)
COUNTER (^D1012,^D32,<LOAD T1,CCMDR,(P2)>,,,<
	Multicast data blocks received>)
COUNTER (^D1013,^D32,<LOAD T1,CCDSD,(P2)>,,,<
	Data blocks sent, initially deferred>)
COUNTER (^D1014,^D32,<LOAD T1,CCDS1,(P2)>,,,<
	Data blocks sent, single collision>)
COUNTER (^D1015,^D32,<LOAD T1,CCDSM,(P2)>,,,<
	Data blocks sent multiple collisions>)
COUNTER (^D1060,^D16,<LOAD T1,CCSF,(P2)>,,<CALL [LOAD T1,CCSFM,(P2)
						 LSH T1,-4
						 RET ]>,<Send failures>)
COUNTER (^D1062,^D16,<LOAD T1,CCRF,(P2)>,,<CALL [LOAD T1,CCRFM,(P2)
						 LSH T1,-4
						 RET ]>,<Receive failures>)
COUNTER (^D1063,^D16,<LOAD T1,CCUFD,(P2)>,,,<Unrecognized frame destination>)
COUNTER (^D1064,^D16,<LOAD T1,CCDOV,(P2)>,,,<Data overrun>)
COUNTER (^D1065,^D16,<LOAD T1,CCSBU,(P2)>,,,<System buffer unavailable>)
COUNTER (^D1066,^D16,<LOAD T1,CCUBU,(P2)>,,,<User buffer unavailable>)

NLCTBL==.-NLCTAB

;Ethenet portal counters

NCCTAB:

COUNTER (^D1000,^D32,<LOAD T1,PCBYR,(P2)>,,,<Bytes received>)
COUNTER (^D1001,^D32,<LOAD T1,PCBYS,(P2)>,,,<Bytes sent>)
COUNTER (^D1010,^D32,<LOAD T1,PCDGR,(P2)>,,,<Data blocks received>)
COUNTER (^D1011,^D32,<LOAD T1,PCDGS,(P2)>,,,<Data blocks sent>)
COUNTER (^D1065,^D16,<LOAD T1,PCUBU,(P2)>,,,<Use buffer unavailable>)

NCCTBL==.-NCCTAB
	SUBTTL Network management -- Line parameters (DTE)

DLPTAB:
PARAMETER (^D0,<NOSET!NOCLR>,,,,,<LOAD T2,LTSTA,(LT)>,,<Line state>)
PARAMETER (^D1105,,^D20,^D5,^D10,<STOR T2,LTBNO,(LT)>,<LOAD T2,LTBNO,(LT)>,<
	STOR T2,LTBNO,(LT)>,<Receive buffers>)
PARAMETER(^D1110,<NOSET!NOCLR>,,,,<TRN>,<LOAD T2,LTCON,(LT)>,<TRN>,<
	Controller>)
PARAMETER(^D1112,<NOSET!NOCLR>,,,,<TRN>,<LOAD T2,LTPRO,(LT)>,<TRN>,<
	Protocol>)
PARAMETER(^D2500,<NOSET!NOCLR>,,,,<TRN>,<LOAD T2,LTBSZ,(LT)>,<TRN>,<
	Receive buffer size>)

DLPTBL==.-DLPTAB

DCPTAB:

PARAMETER (^D1112,<NOSET!NOCLR>,,,,<TRN>,<LOAD T2,LTCTY,(LT)>,<TRN>,<
	Circuit type>)

DCPTBL==.-DCPTAB
	SUBTTL Network management -- Line parameters (Ethernet)

NLPTAB:
PARAMETER (^D0,<NOSET!NOCLR>,,,,,<LOAD T2,LTSTA,(LT)>,,<Line state>)
PARAMETER (^D1105,,^D20,^D5,^D10,<STOR T2,LTBNO,(LT)>,<LOAD T2,LTBNO,(LT)>,<
	STOR T2,LTBNO,(LT)>,<Receive buffers>) ; This works for all but CI
PARAMETER (^D1110,<NOSET!NOCLR>,,,,<TRN>,<LOAD T2,LTCON,(LT)>,<TRN>,<
	Controller>)
PARAMETER (^D1112,<NOSET!NOCLR>,,,,<TRN>,<LOAD T2,LTPRO,(LT)>,<TRN>,<
	Protocol>)
PARAMETER (^D1160,<NOSET!NOCLR!BEX>,,,,<TRN>,<CALL NMFRHA>,<TRN>,<
	Hardware address>)
PARAMETER(^D2500,<NOSET!NOCLR>,,,,<TRN>,<LOAD T2,LTBSZ,(LT)>,<TRN>,<
	Receive buffer size>)

NLPTBL==.-NLPTAB

NCPTAB:

PARAMETER (^D1112,<NOSET!NOCLR>,,,,<TRN>,<LOAD T2,LTCTY,(LT)>,<TRN>,<
	Circuit type>)

NCPTBL==.-NCPTAB

	SUBTTL Network management  -- Node parameters (Ethernet)

NNPTAB:
PARAMETER (^D10,<NOSET!NOCLR!BEX>,,,,<TRN>,<CALL NMFRPA>,<TRN>,<
	Physical address>)
NNPTBL==.-NNPTAB
	XRESCD

	
	SUBTTL DNDINI - Initialize Router's common DLL interface
	
;DNDINI - Initialize common DLL interface for Router
;
; Call: 
;	with nothing
;
; Return: 
;	RET			;Only return
;
; Uses: T1-T3
;
;This routine gets called at system initialization.

	INTERNAL DNDINI

	XSWAPCD
DNDINI:	TRACE DND,<Initializing DNADLL>
	SAVEAC <P1,P2,DL>
	LOAD T1,IBRTR,+IBBLK	; Get Router type desired
	MOVEM T1,DNDRNT		; Save as Router's node type

;Get and initialize an EC (Event Communication) block

	MOVX T1,EV.GEC		;Function code "get EC block"
	CALL NMXEVT
	IFSKP.
	  MOVEM T1,DNDECP	;Save pointer
	  MOVX T2,4		;DNADLL may queue 4 event blocks
	  STOR T2,ECMAX,(T1)
	ENDIF.
	XMOVEI T1,QUEBLK	; Initialize the queues
	MOVEM T1,DNDINQ
	ADDI T1,QH.LEN
	MOVEM T1,DNDIWQ

;Now try to initialize all of the lines

	MOVNI P1,LNTBLL		; Number of lines in table
	HRLZ P1,P1
	XMOVEI P2,LINTBL
DNDIN1:	LOAD T1,LTLID,(P2)	; Line ID
	LOAD T4,LIDEV,+T1	; Get device type
	MOVE T3,MXLBSZ(T4)	; Get the maximum allowable blocksize
	OPSTR <CAML T3,>,IBBSZ,+IBBLK ; Is request for less?
	 LOAD T3,IBBSZ,+IBBLK	; Yes, then use that
	STOR T3,LTBSZ,(P2)	; Remember what we selected
	XMOVEI T2,DNDQUE	; Callback address for DLLs
	CALL @DLLINI(T4)	; (T1,T2,T3) Try to initialize
	IFSKP.
	  SETONE LTDVE,(P2)	; Indicate device exists
	ENDIF.
	ADDI P2,LT.LEN		; Step to next line
	AOBJN P1,DNDIN1		; Continue until all lines are intialized
	RET

DLLINI:	IFIW <RTN&777777>
	IFIW <DTDINI&777777>
	IFIW <RTN&777777>
	IFIW <RTN&777777>
	XCDSEC,,CININI
	IFIW <NIDINI&777777>

	XRESCD
	SUBTTL  Ckeck entity - Build DLL database

;DNDCET - Build data link blocks and circuit blocks if needed
;
; Call: 
;	T2/ NTMAN argument block
;
; Return: 
;	RET			;Only return
;
; Uses: T1-T3
;
;This routine is called by network management to cause DNADLL data link blocks
;and Router circuit blocks to be built.

	XSWAPCD

DNDCET:	SAVEAC <P1,P2,DL>
	MOVE P1,T2		; Save address of NTMAN function block
	LOAD T1,NFEID,(P1)	; Get entity ID
	TMNE LILXC,+T1		; Is it a circuit?
	IFSKP.
	  CALL DNDGLB		; (T1) No, see if we have a data link block
	   TRNA			; No, see if we should make one
	  RETSKP		; Got it, tell NTMAN o.k.
	  LOAD T1,NFEID,(P1)	; Get entity ID
	  TXO T1,LILXC		; Make this circuit entity into a line entity
	ENDIF.
	TXZ T1,LIDRP		;  and clear any multi-drop numbers
	CALL DNDGLT		; (T1) Get the line table for this line
	 RNMXER (NF.URC)
	TMNN LTDVE,(T1)		; Does the line exist?
	 RNMXER (NF.URC)	; No, then don't create data link block
	TMNE LILXC,+NF.EID(P1)	; Was the entity a line?
	 RETSKP			; Yes, return success
	MOVE P2,T1		; Keep line table address
	MOVEI T1,DL.LEN		; Length of data link block
	CALL DNGWDZ		; (T1) Allocate space
	 RNMXER (NF.RES)	;  Error to NTMAN
	MOVE DL,T1		; Hold on to this address
	LOAD T3,NFEID,(P1)	; Entity ID
	STOR T3,DLDID,(DL)	; Device ID
	STOR P2,DLLTP,(DL)	; Line table pointer
	LOAD T1,LIUNI,+T3	; Get unit number
	STOR T1,DLKNO,(DL)
	LOAD T1,LTDBF,(P2)	; Get default number of buffers
	STOR T1,LTBNO,(P2)	; Number of buffers
	MOVEI T1,DI.ICB		; Ask Router to initialize a circuit block
	MOVE T2,DL		; Get DLB address in correct place
	LOAD T4,LTBSZ,(P2)	; Tell the maximum block size for this line
	CALL RTRDLE		; (T1,T2,T3,T4) Call Router now
	SKIPE T1		; T1 contains Router callback ID if successful
	IFSKP.			;  else 0
	   MOVE T1,DL
	   CALL DNFWDS		; Return the block
	   RNMXER (NF.URC)	
	 ENDIF.
	STOR T1,DLUID,(DL)	; Save circuit block address
	ENDQUE DL,DLBQUE,DL.NXT,T2 ; Queue the data link block
	MOVX T1,2		; Get emergency buffers for this data link
	CALL DNGEBF
	 BUG.(CHK,DNDCGE,DNADLL,SOFT,<Couldn't get emergency buffer for DLL>,,<

Cause:	DNADLL requires that the memory manager save at least 2 buffers
	per link for DNADLL; one for the routing messages ROUTER keeps for
	each circuit and one to guarantee some level of route-through ability.
	DNADLL was asked to open a data link, but the memory manager could
	not guarantee the buffers.

Action:	Allocate more memory or settle for fewer circuits.

>)
	RETSKP

	XRESCD
	SUBTTL DNDGLB - Find a data link block

;DNDGLB - Search the queue for a Data Link Block
;
; Call: 
;	T1/ Line (device) ID
;
; Return: 
;	RET		;No Data Link Block for given ID
;	RETSKP		;With DL = Data Link Block
;
; Uses: T1-T2
;
;This routine is used for calls from Network Management

	XSWAPCD
DNDGLB:	SETZRO LILXC,+T1	; Clear "this is a line" indicator
	SKIPN DL,DLBQUE		;Start looking at first data link block
	 RET			;None there, just return
DNDGL1:	LOAD T2,DLDID,(DL)	;Get its' line ID
	CAMN T1,T2		;Is it the one we're looking for?
	 RETSKP			;Good return
	LOAD DL,DLNXT,(DL)	;Get the next data link block
	JUMPN DL,DNDGL1		;Go check it out
	RET			;Couldn't find it

	XRESCD
	SUBTTL DNDGLT - Find a line block

;DNDGLT - Search the line table for a specified line
;
; Call: 
;	T1/ Line (device) ID
;
; Return: 
;	RET		;No line not configuered into monitor
;	RETSKP		;With T1 pointing to entry in LINTBL
;
; Uses: T1-T2
;
;This routine is used for calls from Network Management

	XSWAPCD

DNDGLT:	MOVE T2,T1		; Copy line ID
	XMOVEI T1,LINTBL	; Point to line table
	MOVEI T4,LNTBLL		; Number of entries in table
DNDGT1:	LOAD T3,LTLID,(T1)	; Get its' line ID
	CAMN T2,T3		; Is it the one we're looking for?
	 RETSKP			; Good return - T1 contains address
	ADDI T1,LT.LEN		; Step to next entry
	SOJG T4,DNDGT1
	RET			; Couldn't find it

	XRESCD
	SUBTTL  DNDQUE - Enter requests on input queue

;DNDQUE - Queue up interrupt level requests to scheduler level
;
; Call:
;	T1 - Function to call ROUTER with (ie: DI.xxx)
;	T2 - Callback ID (Data Link Block)
;	T3 - Function specific data (Usually MB address)
;	T4 - Additional function specific data (usually status)
;
;	CALL DNDQUE
;	 only return
;
; Uses T1-T4.
;

DNDQUE:	SAVEAC <DL,P1,Q1,Q2>	; Get a spare AC
	MOVE P1,T1		; Save function for a moment
	MOVE DL,T2		; Data link block
	MOVE Q1,T3		;
	MOVE Q2,T4
	SYSPIF
	SKIPN T1,DNDQBQ		; Any free block on the QB queue?
	IFSKP.
	  MOVE T2,(T1)		; Yes, then get one from it
	  MOVEM T2,DNDQBQ
	  SOS DNDQBL		; Account for it
	ELSE.
	  MOVX T1,QB.LEN	; Get length of user NI block
	  CALL DNGWDZ		; Try to get the words
	  IFNSK.		; Couldn't
	    MOVE T1,Q1		; Get address of possible message
	    CAIE P1,DI.ODN	; Is this a function for which we
	     CAIN P1,DI.INC	;  expect a message block
	    CALL DNFMSG		; Yes, then free it
	    SYSPIN
	    RET			; No, just return
	  ENDIF.
	ENDIF.
	STOR P1,QBFCN,(T1)	; Store function
	STOR DL,QBDLB,(T1)	; Save DLB pointer
	STOR Q1,QBDA1,(T1)	; Store the data
	STOR Q2,QBDA2,(T1)
	MOVE P1,DNDINQ		; Queue to enqueue block to
	ENDQUE T1,(P1),QB.NXT,T2 ; Queue the data link block
	SYSPIN
	RET
	SUBTTL DNDSEC - Entry from scheduler level each second

	INTERNAL DNDSEC

	XRESCD
DNDSEC:	SAVEAC <DL,LT>		; Check all data link blocks
	SKIPA DL,DLBQUE
DNDSE1:	LOAD DL,DLNXT,(DL)
	JUMPE DL,CINSEC
	LOAD LT,DLLTP,(DL)	; Get line table pointer
	LOAD T1,DLDID,(DL)	; Get line ID
	LOAD T1,LIDEV,+T1	; Get device type
	MOVE T1,SECTAB(T1)	; Get dispatch address
	CALL (T1)		; Do devices once/second
	JRST DNDSE1

SECTAB:	IFIW <RTN&777777>
	IFIW <DTDSEC&777777>
	IFIW <RTN&777777>
	IFIW <RTN&777777>
	IFIW <RTN&777777>
	IFIW <NIDSEC&777777>
	IFIW <RTN&777777>
	SUBTTL DNDJIF - Entry from scheduler level to empty queues

	INTERNAL DNDJIF
	XRESCD

DNDJIF:	SAVEAC <P1,P2,DL>
	MOVE P2,DNDIWQ			; Exchange the queue pointers so we
	EXCH P2,DNDINQ			;  don't have to worry about interrupts

DNDJF1:	DEQUE P1,(P2),QB.NXT,DNDNOQ	; Get a function block from the queue
	LOAD DL,QBDLB,(P1)		; DLB pointer
	LOAD T1,QBFCN,(P1)		; Function
	LOAD T2,DLUID,(DL)		; Get DNADLL users ID
	LOAD T3,QBDA1,(P1)		; Data for function
	CAIE T1,DI.INC			; Packet received?
	IFSKP.
	  SKIPN EMBFLG			; Are we having MB resource problems?
	  IFSKP.			; Yes...
	    SETONE MBEBF,(T3)		; Indicate we are using emergency 
	  ENDIF.			;  buffers
	ENDIF.
	LOAD T4,QBDA2,(P1)		; Additional data
	CALL RTRDLE			; Call the ROUTER
	 TRN
	OPSTR <SKIPN>, DLUID,(DL)	; Do we have a circuit block?
	 STOR T1,DLUID,(DL)		; Then save expected circuit block
	MOVE T1,DNDQBL			; Get the length of the QB block queue
	CAIG T1,^D12			; Is it greater than the desired
	IFSKP.				;   maximum?
	  MOVE T1,P1			; Yes, the free the block
	  CALL DNFWDS
	ELSE.
	  SYSPIF			; No interrupts please
	  MOVE T1,DNDQBQ		; No, get the queue head
	  MOVEM T1,(P1)		 	;  and put this one at the head
	  MOVEM P1,DNDQBQ
	  AOS DNDQBL			; Add it into the count
	  SYSPIN
	ENDIF.
	JRST DNDJF1			; Get next function block on queue

DNDNOQ:	MOVEM P2,DNDIWQ			; Save pointer to new work queue
	SETZB T1,T2
	DMOVEM T1,(P2)			;  and make it look empty
	HRRM T1,2(P2)			; Preserve maximum queue length
	RET				; No more function blocks queued
	SUBTTL  DNDDSP - Dispatch for calls from ROUTER

;DNDDSP - Dispatch for calls to DNADLL from ROUTER
;
; Call: 
;	T1 - Function (DF.???)
;	T2 - DLB address
;	T3 - Function specific data
;	T4 - Additional function specific data
;
; Return: 
;	RET			;On failure (error code in T1)
;	RETSKP			;On success
;
;
	INTERNAL DNDDSP,DNDNMX

	XRESCD
DNDDSP:	SAVEAC <DL,LT>
	MOVE DL,T2
	LOAD LT,DLLTP,(DL)	; Point to line table entry
IFN FTPARANOIA,<
	CAXL T1,DF.OPN		;Range check the
	CAXLE T1,DF.MAX		; function code
	BUG.(CHK,DNDIUF,DNADLL,SOFT,<Illegal function code from DNADLL user>,,<

Cause:	DNADLL was called with a bad function by ROUTER

>,RTN)
> ;END IFN FTPARANOIA

	JRST DNDCDL		; Do the dispatch


	SUBTTL  DNDNMX - Dispatch on calls from Network Management

	XRESCD

DNDNMX:
IFN FTPARANOIA,<
	CAXL T1,NF.SET		;Range check the
	CAXLE T1,NF.CET		; function code
	BUG.(CHK,DNDINF,DNADLL,SOFT,<Illegal function code from NTMAN>,,<

Cause:	DNADLL was called with a bad function by NTMAN.

>,RTN)
> ;END IFN FTPARANOIA

	SAVEAC <P1,P2,DL,LT>	; Everyone needs these for NTPARM
	MOVE T1,DLLNXF(T1)	; Convert to internal function code
	TXZE T1,DN.NDR		; Should we process this ourselves
	 CALLRET DNDNMF		; Yes, then do not dispatch to DLL
	LOAD CX,NFETY,(T2)	; Get entity type
	CAIE CX,.NTNOD		; Is the entity node?
	IFSKP.
	  MOVEI CX,LD.NI	; Yes, then assume Ethernet (presently the
	  STOR CX,LIDEV,+CX	;  only node entity is the NI physical address)
	ELSE.			;
	  LOAD CX,NFEID,(T2)	; Get the entity ID
	ENDIF.
	TRNA
DNDCDL:	LOAD CX,DLDID,(T2)	; Get the line ID
	LOAD CX,LIDEV,+CX	; Get the device type
	CAILE CX,LD.MAX		; Legal type?
	 RET
	MOVE CX,DLLDSP(CX)	; Dispatch address
	CALLRET (CX)		; Call the DLL

DLLDSP:	IFIW <RTN&777777>
	IFIW <DTDDSP&777777>
	IFIW <RTN&777777>
	IFIW <RTN&777777>
	IFIW <DCIDSP&777777>
	IFIW <NIDDSP&777777>
	IFIW <RTN&777777>
DLLNXF:
	DN.NMF!DF.SET		;NTMAN - Set parameter
	DN.NMF!DF.CLR		;NTMAN - Clear parameter
	DN.NMF!DF.RED		;NTMAN - Read parameter
	DN.NMF!DF.SHC		;NTMAN - Show counters
	DN.NMF!DF.SZC		;NTMAN - Show and zero counters
	DN.NDR!DF.RET		;NTMAN - Return list (e.g. show known lines)
	DN.NDR!DF.A2N		;NTMAN - Map node address to name
	DN.NDR!DF.N2A		;NTMAN - Map node name to address
	DN.NDR!DF.CET		;NTMAN - Check entity
	SUBTTL Network management -- Show known/active lines

;DNDNMF  Here to process Network management requests that are not dispatched
;	 to the DLLs
;
;Call:	T1 /Function
;	T2 /NF block

	XSWAPCD

DNDNMF:	MOVE P1,T2		; Save address of NF block
	HRRZ T1,T1		; Clear any flags
	CAIN T1,DF.CET		; Requested to check entity?
	 JRST DNDCET		; Yes, then be NML's humble servant
	CAIE T1,DF.RET		; Is request for return list?
	 RNMXER (NF.MPE)	; We only do the two we just checked
	TMNN NFBFF,(P1)		; Buffer present?
	 RNMXER (NF.MPE)	;  Must have one for this stuff
	LOAD T1,NFETY,(P1)	; Get entity type
	CAIE T1,.NTLIN		; Is the entity line?
	IFSKP.
	  LOAD T1,NFBLN,(P1)	; Get the buffer length
	  CAIGE T1,^D8		; Must be long enough for all lines
	   RNMXER (NF.MPE)	; NTMAN/NML screwed up
	  LOADE T1,NFSEL,(P1)	; Get the selector type
	  CAXL T1,.NTSGN	; Range check the selection criteria
	   CAXLE T1,.NTKNO	; If not between SIGNIFICANT & KNOW
	    RNMXER (NF.MPE)	;  we don't do it
	  CALLRET <-.NTSGN>+@[
		IFIW <NMXILS&777777> ; SIGNIFICANT lines not supported
		IFIW <NMXILS&777777> ; ADJACENT lines
		IFIW <NMXILS&777777> ; LOOP line
		IFIW <NMXSAL&777777> ; ACTIVE lines
		IFIW <NMXSKL&777777>](T1) ; KNOWN lines
	ELSE.
	  RNMXER (NF.FNS)	; We don't do any others
	ENDIF.

NMXILS:	RNMXER (NF.MPE)		; NTMAN is confused
	XRESCD
	SUBTTL Network management -- Show active lines

;Call:	P1/ NF block

	SUBTTL Network management -- Show known lines

;Call:	P1/ NF block

	XSWAPCD
NMXSKL:	SKIPA T1,[-1]		; "Show known lines"
NMXSAL:	SETZ T1,		; "Show active lines"
	SAVEAC <Q1>
	STKVAR <FUNC>
	MOVEM T1,FUNC
	SETZ P2,		; Initialize the count
	LOAD T2,NFBLN,(P1)	; Get length of buffer
	LOAD T4,NFBUF,(P1)	; Get buffer address
	ADD T2,T4		; Compute end of buffer
	MOVNI T3,LNTBLL		; Number of entries in table
	HRLZ T3,T3
	XMOVEI Q1,LINTBL	; Address of table
NMXSA1:	TMNN LTDVE,(Q1)		; Does the line exist?
	 JRST NMXSA2		; No, don't include it
	LOAD T1,LTSTA,(Q1)	; Get line state
	SKIPL FUNC		; Is function "known"
	 CAIN T1,LS.ON		; No, then check for active
	TRNA			; Must be running or "known"
	 JRST NMXSA2
	LOAD T1,LTLID,(Q1)	; Get the line's ID
	CAML T4,T2		; Check to be sure we don't run off end
	 RNMXER (NF.MPE)	; NTMAN error if not enough room
	MOVEM T1,(T4)		; Save into buffer
	AOJ P2,			; Count it
	AOJ T4,			; Advance buffer
NMXSA2:	ADDI Q1,LT.LEN		; Step to next entry
	AOBJN T3,NMXSA1
	STOR P2,NFBLN,(P1)	; Tell NTMAN number written
	RETSKP

	XRESCD
	SUBTTL DCIDSP - Dispatch routine for calls to CIDLL

DCIDSP:	STKVAR <FUNC>
	MOVEM T1,FUNC
	TXZE T1,DN.NMF		; Is this from network management?
	 JRST DCIDS2		; Yes, just do the dispatch
	CAIE T1,DF.OPN		; Is this an open circuit call?
	 JRST DCIDS1		; No, not special
	MOVE T3,T2		; Callback ID goes into T3
	LOAD T2,DLDID,(T2)	; Get the line identifier for this circuit
	TRNA
DCIDS1:	LOAD T2,DLPID,(T2)	; Get the portal ID to talk to CIDLL
DCIDS2:	CALL CINDSP		; Call CIDLL
	 RET			; Pass on the error
	HRRZ T2,FUNC
	CAIE T2,DF.OPN		; Was this an open request?
	 RETSKP			; No, just return success
	STOR T1,DLPID,(DL)	; T1 should contain the Port ID
	RETSKP
	SUBTTL  DTEDLL -- DTE data link layer

	SUBTTL  DTEDLL -- Intialize a line 
;Call:
;	T1/ Line ID
;	T2/ Callback address
;	T3/ Maximum blocksize to use on this line

DTDINI:	LOAD T2,LIUNI,+T1	; Get DTE number
	MOVEI T1,DD.CKE		; Ask DTESRV to check its existance
	CALL DLLDTE
	 RET			; No such DTE
	RETSKP			; DTE exists

DTDSEC:	LOAD T1,LTNBP,(LT)	; Get number posted
	OPSTR <CAMGE T1,>,LTBNO,(LT) ; Enough posted?
	 CALL DTIPRB		; Try to post one then
	RET
	SUBTTL  DTEDLL -- Dispatch from Router or Network Management

DTDDSP:	MOVE CX,DTDDPT(T1)	; Get dispatch address
	CALLRET (CX)

DTDDPT:
	IFIW <DTDOPN&777777>	; Open a portal/circuit
	IFIW <DTDCLS&777777>	; Close a portal/circuit
	IFIW <DTDXMT&777777>	; Transmit a packet
	IFIW <DTDSET&777777>	; Set a parameter
	IFIW <DTDCLR&777777>	; Clear a parameter
	IFIW <DTDRED&777777>	; Read paramater
	IFIW <DTDSHC&777777>	; Show counters
	IFIW <DTDSZC&777777>	; Show and zero counters
	IFIW <DTDILL&777777>	; Return list
	IFIW <DTDILL&777777>	; Map Node Address to Name
	IFIW <DTDILL&777777>	; Map Node Name to Address
	IFIW <DTDILL&777777>	; Check Entity Id
	SUBTTL DTEDLL -- Open a port

;DTDOPN - Open a data link layer port
;
; Call: 
;	T1/ Function (DF.OPN)
;	DL/ Data link block address
;	LT/ Line table pointer
;
; Return: 
;	RET			;ON RESOURCE FAILURE
;	RETSKP			;On success with T1 = Data link ID
;
; Uses: T1-T3
;

DTDOPN:	LOAD LT,DLLTP,(DL)	; Get line table pointer
	TMNN LTDVE,(LT)		; Does the line exist?
	 RET
	SETONE DLLIU,(DL)	; Indicate circuit is using the line
	LOAD T1,LTNBP,(LT)	; Get number of buffers currently posted
	OPSTR <CAMGE T1,>,LTBNO,(LT) ; Do we have enough?
	IFSKP.
	  SETZ T4,		; Yes, indicate no new buffer
	ELSE.
	  LOAD T1,LTBSZ,(LT)	; User MSD size required
	  CALL DNGMSG		; Try for a message
	   RET			; Return if can't get a buffer
	  INCR LTNBP,(LT)	; Account for buffer
	  MOVE T4,T1		; Message block address
	ENDIF.
	MOVX T1,DF.OPN		; Get function
	LOAD T2,LTLID,(LT)	; Get line ID
	LOAD T2,LIUNI,+T2
	MOVE T3,DL		; Callback ID (DL block)
	CALL DLLDTE
	 TRNA
	RETSKP
	JUMPE T4,R		; If no buffer then done
	MOVE T1,T4		; Get buffer address back from DTESRV
	CALL DNFMSG		; Return memory
	DECR LTNBP,(LT)		; Buffer is no longer posted
	RET			;  and signal failure
	SUBTTL DTEDLL -- Transmit a packet

;DTDXMT - Send a packet to DTESRV
;
; Call: 
;	T3 - Message block
;	DL - Data link block address
;
; Return: 
;	RET			;On error from driver
;	RETSKP			;On success
;

DTDXMT:	LOAD T2,DLKNO,(DL)	; Get "kontroller number"
	CALL DLLDTE		;
	 RET
	RETSKP
	SUBTTL  DTEDLL -- Close a port

;DTDCLS - Close a circuit on a DTE line
;
; Call: 
;	DL - Data link block address
;
; Return: 
;	RET			;On error
;	RETSKP			;On success
;

DTDCLS:	SETZRO DLLIU,(DL)	; Clear the line in use indicator
	MOVEI T1,DF.CLS
	LOAD T2,DLKNO,(DL)	; Get DTE number
	CALL DLLDTE		; Ask DTESRV to terminate
	 RET
	MOVX T2,LS.OFF
	STOR T2,LTSTA,(LT)	; Save new line state as off
	JUMPE T1,RSKP		; If we got an MB return it
	DECR LTNBP,(LT)		; No longer posted
	CALL DNFMSG		; Return it to the free pool
	RETSKP
	SUBTTL  DTEDLL -- Network management - Parameter functions

	XSWAPCD

DTDRED:	MOVEI T3,NF.RED		; Funtion will be in T3
	CALLRET DTDCPF		; Call common parameter routine

DTDSET: MOVEI T3,NF.SET
	CALLRET DTDCPF		; Call common parameter routine

DTDCLR: MOVEI T3,NF.CLR
;	CALLRET DTDCPF		; Call common parameter routine

DTDCPF:	STKVAR <FUNC>
	MOVEM T3,FUNC		; Save funtion (read,set,clear)
	MOVE P1,T2		; Save NTMAN function block
	LOAD T1,NFETY,(P1)	; Get the entity type
	CAIE T1,.NTCKT		; Is it circuit?
	IFSKP.
	  LOAD T1,NFEID,(P1)	; Yes, get the entity ID again
	  CALL DNDGLB		; Find the data link block
	   RNMXND		; Don't know of this link-Return succes/no data
	  LOAD LT,DLLTP,(DL)	; Address of line table entry
	  XMOVEI T1,DCPTAB	; Use the circuit parameter table
	  MOVEI T2,DCPTBL	; and its length
	ELSE.
	  CAIE T1,.NTLIN	; Is entity type line?
	  IFSKP.
	    LOAD T1,NFEID,(P1)	; Get the entity ID
	    CALL DNDGLT		; Get the line table structure for this line
	     RNMXER (NF.MPE)	; We don't support this device
	    MOVE LT,T1		; Save line table entry
	    TMNN LTDVE,(T1)	; Does the line exist?
	     RNMXER (NF.URC)	; No, 
	    XMOVEI T1,DLPTAB
	    MOVEI T2,DLPTBL	;  and its length
	  ELSE.
	    RNMXER (NF.MPE)	; We don't support any others
	  ENDIF.
	ENDIF.
	MOVE T3,FUNC
	CALLRET NTPARM

	XRESCD
	SUBTTL  DTEDLL -- Network Management - Show/Show and zero counters

	XSWAPCD

DTDSHC:	SKIPA T3,[NF.COU]	;Load function code and skip
DTDSZC:	MOVX T3,NF.SZC		;Load function code
	STKVAR <FUNC>
	MOVEM T3,FUNC		;T3 will be used later
	MOVE P1,T2		;Move NF pointer to where it should be
	LOAD T1,NFETY,(P1)	;Get the entity type
	CAIE T1,.NTCKT		;Is it a circuit
	IFSKP.
	  LOAD T1,NFEID,(P1)	;Get circuit identifier
	  CALL DNDGLB		;Get the data link block block
	   RNMXND
	  XMOVEI T1,CICTAB	;Address of circuit counter table
	  MOVEI T2,CICTBL	; and its length
	ELSE.
	  CAIE T1,.NTLIN	; Is entity a line?
	  IFSKP.
	    RNMXND		; Return with no data
	  ELSE.
	    RNMXER (NF.OPF)	; We don't do any others
	  ENDIF.
	ENDIF.

;Call NTCTRS to do the real work

	MOVE T3,FUNC		;Get function to do
	CALLRET NTCTRS		;Read the counters and return
	SUBTTL  DTEDLL -- Network management - Return list

DTDRTL:

	SUBTTL  DTEDLL -- Network management - Check entity

DTDCET:	RNMXER (NF.MPE)


	SUBTTL DTEDLL -- Common call to DTESRV
	
	XRESCD
DLLDTE:	XCALLRET (MSEC1,DTEDSP)		; Call DTESRV
					; Does not return here
DTDILL:	RET
	SUBTTL DTEDLL -- DTESRV interrupt level callbacks

;DTIPPI - Interrupt from DTESRV for MCB functions
;
;
	INTERNAL DTIPPI

	XRENT DTIPPI

IFN FTPARANOIA,<
	CAXL T1,DI.ODN
	 CAXLE T1,DI.ICB
	BUG. (CHK,DTIIFK,DNADLL,SOFT,<Illegal function code from DTE kontroller>,,<
	This BUG is not documented yet.
>,RTN)
> ;END IFN FTPARANOIA

	SAVEAC <DL,LT>
	SKIPN DL,T2		;What amounts to circuit block
	BUG.(CHK,DNDCIZ,DNADLL,SOFT,<Callback ID is zero>,,<

Cause:	DTESRV has lost the callback ID for this line or never had one.

Action:	See if protocol was started when Router thought the circuit state was
	off.  Or, check DCNCID in DTESRV to see what it has for a callback ID.

>,RTN)

	LOAD LT,DLLTP,(DL)	;Get line table entry
	MOVE T1,DTIDLI(T1)
	JRST (T1)

DTIDLI:
	IFIW	<DTIILL&777777>	;Unused
	IFIW	<DTITRN&777777>	;Output done
	IFIW	<DTIRCV&777777>	;Input complete
	IFIW	<DTILSC&777777>	;Line state change
	IFIW	<DTIILL&777777>	;Initialize circuit block
	SUBTTL  DTEDLL -- Transmit complete from DTESRV

DTITRN:	STKVAR <MSG>		; Place to save message block address
	MOVEM T3,MSG
	MOVEI T1,DI.ODN		; Function is Output Done
	CALL DNDQUE		; Queue it up
	MOVE T1,MSG
	CALL DNLENG
	OPSTRM <ADDM T1,>,DLBYS,(DL) ; Update bytes sent
	INCR DLDBS,(DL)		; Another packet sent
	RET
	SUBTTL  DTEDLL -- Receive complete from DTESRV

;	T2/ Callback ID
;	T3/ MB address

DTIRCV:	STKVAR <MSG>
	MOVEM T3,MSG
	DECR LTNBP,(LT)		; Account for buffer received
	MOVEI T1,DI.INC		; Function is input complete
	CALL DNDQUE		; Queue it up
	MOVE T1,MSG
	CALL DNLENG
	OPSTRM <ADDM T1,>,DLBYR,(DL) ; Update bytes received
	INCR DLDBR,(DL)		; Another packet received
	CALL DTIPRB		; Post a buffer for DTESRV
	RET
	SUBTTL  DTEDLL -- Post receive buffer for DTESRV

;DTIPRB - DTESRV request buffer 
;
; Call: 
;	DL/ Data Link Block Address
;	LT/ Line table address
;
; Return: 
;	RET			;ALWAYS WITH T1 POINTING TO MESSAGE BLOCK
;				; OR T1 SET TO ZERO ON ALLOCATION FAILURE
;
; Uses: T1-T3

DTIPRB:	LOAD T1,LTNBP,(LT)	; Number of buffers posted
	OPSTR <CAML T1,>,LTBNO,(LT) ; Do we have enough?
	 RET			; Yes, then exit
	SAVEAC <P1>
	LOAD T1,LTBSZ,(LT)	; User MSD size required
	CALL DNGMSG		; Get the message block with T1 bytes of user
	IFSKP.			;  data area
	  SETZM EMBFLG		; Got a normal message block
	  SETZRO DLEBU,(DL)	;  and no longer using our emergency buffer
	ELSE.
	  LOAD T1,LTBSZ,(LT)	; User MSD size required
	  CALL DNDGEB		; Couldn't allocate - Try emergency buffer
	  JUMPE T1,RTN		; Just return if we're starving the DLL
	ENDIF.

	XMOVEI T2,IN.MSD(T1)	; Point to the input MSD
	STOR T2,MBFMS,(T1)	; Store in first MSD slot
	MOVE T3,T1		; Buffer address for DTESRV
	MOVE P1,T1		; Save message address around DTESRV/DTESER
	MOVEI T1,DD.PRB		; Function is post receive buffer
	LOAD T2,DLKNO,(DL)	; Get DTE number
	XCALL (MSEC1,DTEDSP)
	 TRNA
	JRST [INCR LTNBP,(LT)	; Account for buffer posted
	      RET]
	SETZRO DLEBU,(DL)	; No longer using our emergency buffer
	MOVE T1,P1		; Return message block to the free pool
	CALL DNFMSG
	SETZ T1,
	RET
	SUBTTL  DTEDLL -- Line state change callback

;	DL/ Data link block
;	T3/ New state

DTILSC:	STOR T3,LTSTA,(LT)	; Save the new state
	TMNN DLLIU,(DL)		; Is Router using this line?
	IFSKP.
	  MOVEI T1,DI.LSC	; Yes, notify ROUTER
	  CALL DNDQUE
	ENDIF.
	LOAD T1,LTSTA,(LT)	; Get state again
	CAIN T1,LS.ON		; If new state = on?
	 CALL DTIPRB		; Yes, post a buffer
DTIILL:	RET
	SUBTTL   NIDLL - Ethernet DLL interface

NIDINI:	SAVEAC <UN>
	CALL GETUNB		; Try to allocate space for a UN block
	 RET
	MOVE UN,T1
	MOVEI T1,4		; Length of buffer for channel list
	STOR T1,UNBSZ,(UN)	; Remember length for NISRV
	CALL DNGWDZ
	 CALLRET FREUNB
	STOR T1,UNBFA,(UN)
	MOVX T1,NU.RCL		; Function is "Return channel list"
	MOVE T2,UN		; Address of UN block
	CALL DLLUNI
	 BUG.(CHK,DNDRLF,DNADLL,SOFT,<Read channel list failed>,<<T1,ERRCOD>>,<

Cause:	NISRV returned an error when asked to return the channel list.

Action:	Check error code returned in T1 to see what NISRV thinks is wrong.

Data:	ERRCOD - Error code returned by NISRV

>,NIDIN1)
	LOAD T1,UNBSZ,(UN)	; Get number of channels found
	SKIPE T1		; Any found?
	 AOS (P)		; Yes, so for now, indicate success
NIDIN1:	LOAD T1,UNBFA,(UN)	; Free the buffer
	CALL DNFWDS
	CALL FREUNB		; Free the UN block
	RET
	SUBTTL  NIDLL -- Once per second routine

NIDSEC:	SAVEAC <UN>
	LOAD T1,LTSTA,(LT)	; Get line's state
	CAIE T1,LS.ON		; Is line running?
	 RET			; No, then don't attempt to post buffers
	TMNN DLLIU,(DL)		; Is DECnet using the data link?
	 RET
	LOAD UN,DLUNB,(DL)	; Get the associated UN block
	JUMPE UN,RTN		; None? 
	LOAD T1,LTNBP,(LT)	; Get number posted
	OPSTR <CAMGE T1,>,LTBNO,(LT) ; Enough posted?
	CALL NIDPB		; No, try to post enough
	RET
	SUBTTL   NIDLL -- Dispatch for calls from Router or Network Management

;Call:
;	DL/ Data link block (if not network management)
;	LT/ Line table pointer

NIDDSP:	SAVEAC <UN>
	MOVE T1,NIDDTB(T1)	; Get processor address
	CALLRET (T1)		;  and dispatch

NIDDTB:	IFIW <NIFOPN&777777>	; Open portal/circuit
	IFIW <NIFCNI&777777>	; Close portal/circuit
	IFIW <NIFXNI&777777>	; Transmit packet
	IFIW <NIFSP&777777>	; Set parameter
	IFIW <NIFCP&777777>	; Clear parameter
	IFIW <NIFRP&777777>	; Read parameter
	IFIW <NIFSHC&777777>	; Show counters
	IFIW <NIFSZC&777777>	; Show and zero counters
	IFIW <NIFILL&777777>	; Return list
	IFIW <NIFILL&777777>	; Map Node Address to Name
	IFIW <NIFILL&777777>	; Map Node Name to Address
	IFIW <NIFILL&777777>	; Check Entity Id
	SUBTTL  NIDLL -- Open portal

NIFOPN:	LOAD UN,DLUNB,(DL)	; Get UN block from previous open
	JUMPN UN,NIFOP1		; If we have one then use it
	CALL GETUNB		; Get a UN block
	 RET			; Return error
	MOVE UN,T1		; T1 contains allocated memory
	STOR UN,DLUNB,(DL)	; Remember address for later user
NIFOP1:	CALL CHKADR		; Verify that the physical address is DECnet's
	 RET			; It is not, return error
	XMOVEI T1,DNDNII	; Where DLL should call us back
	STOR T1,UNCBA,(UN)	; Give the driver tha callback address
	SETZRO UNCHN,(UN)	; For now we will use channel 0
	SETZRO UNPMS,(UN)	; We will not call at any interrupt level
	SETZRO UNPTR,(UN)	; We are not passing byte pointers
	STOR DL,UNUID,(UN)	; Associate DL block with callbacks
	MOVE T1,RTRPRO		; Router's protocol type
	STOR T1,UNPRO,(UN)
	SETONE UNPAD,(UN)	; Padding is to be done
	MOVEI T1,NU.OPN		; Function is  open a port
	MOVE T2,UN		; Address of UN block
	CALL DLLUNI		; Call the driver
	 BUG.(CHK,DNDNOF,DNADLL,SOFT,<Attempt to open an ethernet portal failed>,<<T1,ERRCOD>>,<

Cause:	NISRV returned an error when trying to open a portal.

Action:	Check error code returned in T1 to see what NISRV thinks is wrong.

Data:	ERRCOD - Error code returned by NISRV

>,NIFOF)
	LOAD T1,UNPID,(UN)	; Get portal ID
	STOR T1,DLPID,(DL)	; Save for transmits later
	TMNN UNRUN,(UN)		; Is channel running?
	IFSKP.
	  MOVEI T1,LS.ON
	ELSE.
	  MOVEI T1,LS.OFF
	ENDIF.
	STOR T1,LTSTA,(LT)	; Save state of channel

;Now enable the multi-cast address(es) we will use

	MOVE T2,DNDRNT		; Get Router's node type
	CAIE T2,RNT.NR		; Endnode?
	IFSKP.
	  MOVX T1,%RTEMA	; Yes, then multi-cast "ALL ENDNODES"
	  CALL NIFEMA
	   CALLRET NIFEMF	; Close portal if we can't enable
	  MOVX T1,%RTRMA	; Multi-cast address "ALL ROUTERS"
	  SKIPE EVSDRP
	   CALL NIFEMA		; Enable us to receive on this address
	    TRN
	ELSE.
	  MOVX T1,%RTRMA	; Multi-cast address "ALL ROUTERS"
	  CALL NIFEMA		; Enable us to receive on this address
	   CALLRET NIFEMF	; Close portal if we can't enable
	ENDIF.

;Now post some buffers for the NI driver

	CALL NIDPB		; This will post as many as we ask for
				;  or as many as it can
	SETONE DLLIU,(DL)	; Router is using the line
	LOAD T1,LTSTA,(LT)	; Return line state to Router
	RETSKP

NIFEMF:
	 BUG.(CHK,DNDEMF,DNADLL,SOFT,<Enable Ethernet multicast address failed>,<<T1,ERRCOD>>,<

Cause:	NISRV returned an error when trying to enable a multicast address.

Action:	Check the error code returned in T1 and investigate the problem in
	NISRV.

Data:	ERRCOD - Error code returned by NISRV
>)
	CALL NIFCNI		; Close the portal
	AOSA NIEMAF		;  and count enable multicast failures
NIFOF:	AOS NIOPNF		; Count open failures
	RET			;  and return error
	SUBTTL  NIDLL -- Close an ethernet protal

NIFCNI:	SETZRO DLLIU,(DL)	; Indicate Router is no longer using the line
	MOVX T1,NU.CLO		; Function is "close portal"
	LOAD T2,DLUNB,(DL)	; UN block address	 
	CALL DLLUNI
	 BUG.(CHK,DNDNCE,DNADLL,SOFT,<Error from NISRV when closing portal>,<<T1,ERRCOD>>,<

Cause:	NISRV returned an error when asked to close our portal.

Action:	Check error code returned in T1. It may be caused by DNADLL trying
	to close a portal that wasn't open or a problem in NISRV

Data:	ERRCOD - Error code returned by NISRV
>)
	RET
	SUBTTL NIDLL -- Send a packet on the wire

NIFXNI:	SAVEAC <P1,P2>
	DMOVE P1,T3		; Save these from destruction
				; P2 will have the next hop address
	CALL GETUNB
	 RET
	MOVE UN,T1
	LOAD T1,DLPID,(DL)	; Get the portal ID
	STOR T1,UNPID,(UN)	;  and put it in UN block for DLL
	SETZRO UNBSZ,(UN)	; Byte count is zero for MSD buffers
	LOAD T1,MBFMS,(P1)	; Get address of MSD string
	STOR T1,UNBFA,(UN)
	STOR MB,UNRID,(UN)	; So we can easily recover MB address
	JUMPE P2,NIFXN1		; No nexthop, must be multicast
	MOVX T1,%RTHIO		; Build nexthop ethernet address
	STOR T1,UNDAD,(UN)	; Store the destination address
	STOR P2,UNDAD,+1(UN)	;
	JRST NIFXN2
NIFXN1:	LOAD T1,MBDS1,(MB)	; Destination in MB is the multicast address
	STOR T1,UNDAD,(UN)
	SETZRO UNDAD,+1(UN)	; This is always 0 anyway
NIFXN2:
IFN FTRTST,<
	JE RMTST,(MB),NIFXN3	; Test flag on?
	MOVEI P1,TSTBLK		; Yes, then get current time


  S1XCT <CALL UPDTCK>		; Must be executed in section 1 because of 
				;  RDTIME bug

	STOR T1,TRTTD,(P1)	; Save it for later computation
	LOAD T2,TRTAF,(P1)	;  and then compute the time latency
	SUB T1,T2		;  since we entered
	STOR T1,TRTED,(P1)	;  RTRFWD
NIFXN3:  >
	MOVX T1,NU.XMT		; Function is transmit message
	MOVE T2,UN		;
	CALL DLLUNI
	 BUG.(CHK,DNDXMF,DNADLL,SOFT,<Transmit message to Ethernet failed>,<<T1,ERRCOD>>,<

Cause:	NISRV returned an error when trying to queue a message for transmit.

Action:	Check error code returned in T1 and investigate problem in NISRV.

Data:	ERRCOD - Error code returned by NISRV

>,FREUNB)

	CALL FREUNB		;  and return the UN block
	RETSKP
	SUBTTL  NIDLL --  Network Management - Parameter functions

	XSWAPCD

NIFSP:	MOVEI T3,NF.SET		; Set parameter
	CALLRET NIFCPR		; Call our common setup for parameters

NIFCP:	MOVEI T3,NF.CLR		; Clear parameter
	CALLRET NIFCPR		; Call our common setup for parameters

NIFRP:	MOVEI T3,NF.RED		; Read parameter
;	CALLRET NIFCPR		; Call our common setup for parameters

NIFCPR:	STKVAR <FUNC>
	MOVEM T3,FUNC
	MOVE P1,T2		; NTPARM wants function block here
	LOAD T1,NFETY,(P1)	; Get the entity type
	CAIE T1,.NTLIN		; Is it a line?
	IFSKP.
	  LOAD T1,NFEID,(P1)	; Get the entity ID
	  CALL DNDGLT		; Get the line table structure for this line
	   RNMXER (NF.MPE)	; We don't support this device
	  MOVE LT,T1		; Save line table entry
	  TMNN LTDVE,(T1)	; Does the line exist?
	   RNMXER (NF.URC)	; No, 
	  XMOVEI T1,NLPTAB	; Address of line parameter table
	  MOVEI T2,NLPTBL	;  and its length
	ELSE.
	  CAIE T1,.NTCKT	; Is it circuit?
	  IFSKP.
	    LOAD T1,NFEID,(P1)	; Get the entity ID
	    CALL DNDGLB		; Get the correct data link block
	     RNMXND		; Return success but no data
	    LOAD LT,DLLTP,(DL)	; Get line table pointer
	    XMOVEI T1,NCPTAB	; Address of circuit parameter table
	    MOVEI T2,NCPTBL	;  And its length
	  ELSE.
	    XMOVEI T1,NNPTAB	; Use Node parameter table
	    MOVEI T2,NNPTBL	;
	  ENDIF.
	ENDIF.			; Function is in T3
	MOVE T3,FUNC		; Recover requested function
	CALLRET NTPARM		; Call the common parameter processer
				; T1/ table
				; T2/ table's length
				; T3/ function
	XRESCD
	SUBTTL  NIDLL -- Network management - Show /Show and zero counters

	XSWAPCD

NIFSHC:	SKIPA T3,[NF.COU]	; Show counters
NIFSZC:	MOVEI T3,NF.SZC		; Show and zero counters
	STKVAR <FUNC,BUFADR>
	MOVEM T3,FUNC		; T3 will be used later
	CALL NIDLKW		; Get the interlock (wait if have too)
	MOVE P1,T2		; Save the NF block pointer
	LOAD T1,NFBLN,(P1)	; Get length of buffer
	AOJ T1,			; Plus one more for flags
	CALL DNGWDS		; Get a buffer of at least that size for NISRV
	 RNMXER (<NF.OPF>,<SETOM NIDLOK>)
	MOVEM T1,BUFADR		; Buffer address
	LOAD T1,NFETY,(P1)	; Get the entity type
	CAIE T1,.NTCKT		; Is it a circuit?
	IFSKP.
	  LOAD T1,NFEID,(P1)	; Get circuit identifier
	  CALL DNDGLB		; Get the data link block block
	  IFNSK.
	    MOVE T1,BUFADR	; Failed so free up the buffer we have
	    CALL DNFWDS
	    RNMXER (<NF.URC>,<SETOM NIDLOK>)
	  ENDIF.
	  MOVE T1,FUNC		; Recover function
	  MOVE T2,BUFADR	;  Buffer address
	  AOJ T2,		; Step over flags
	  LOAD T3,NFBLN,(P1)	;   and length
	  CALL NIFRPC		; Read the portal counters
	  IFNSK.
	    MOVE T1,BUFADR
	    CALL DNFWDS
	    RNMXER (<NF.OPF>,<SETOM NIDLOK>)
	  ENDIF.
	ELSE.
	  CAIE T1,.NTLIN	; Is entity a line?
	  IFSKP.
	    LOAD T1,NFEID,(P1)	; Get entity ID
	    TXZ T1,LIDRP	;  and clear any multi-drop numbers
	    CALL DNDGLT		; (T1) Get the line table for this line
	     RNMXER (NF.URC)
	    TMNN LTDVE,(T1)	; Does the line exist?
	     RNMXER (NF.URC)	; No, then no counters
	    MOVE T1,FUNC	; Get function (read or read/clear)
	    MOVE T2,BUFADR	;  Buffer address
	    AOJ T2,		; Step over flags
	    LOAD T3,NFBLN,(P1)	;   and length
	    CALL NIFRCC		; Read channel counters
	    IFNSK.
	      MOVE T1,BUFADR	; Error, free the buffer
	      CALL DNFWDS
	      RNMXER (<NF.OPF>,<SETOM NIDLOK>)
	    ENDIF.
	  ELSE.
	    MOVE T1,BUFADR	; Don't need this buffer any more
	    CALL DNFWDS
	    RNMXER (<NF.MPE>,<SETOM NIDLOK>)
	  ENDIF.
	ENDIF.
	MOVEI T1,NISCHK		; Scheduler test routine (uses only 18 bits)
	MDISMS			; Dismiss this process until NISRV returns data
	SETOM NIDLOK		; Free the lock
	LOAD T1,NFETY,(P1)	; Get the entity type again ...
	CAIE T1,.NTCKT		; Is it a circuit?
	IFSKP.
	  XMOVEI T1,NCCTAB	; Address of circuit (portal) counter table
	  MOVEI T2,NCCTBL	; and its length
	ELSE.
	  XMOVEI T1,NLCTAB	; Address of line (channel) counter table
	  MOVEI T2,NLCTBL	;  and its length
	ENDIF.
	MOVE P2,BUFADR		; NTCTRS needs the buffer address
	SKIPE (P2)		; Any errors from NISRV?
	 JRST NIFSCE		; Yes..
	MOVE T3,FUNC
	AOJ P2,			; Step over flags
	CALL NTCTRS		; Now copy the data to NTMAN's buffer
	 JRST NIFSCE		; Did not successfully copy data
	MOVE T1,BUFADR		; Data copied, free the buffer
	CALL DNFWDS
	RETSKP

NIFSCE: MOVE T1,BUFADR		; Free the buffer
	CALL DNFWDS
	RNMXER (NF.OPF)		;  and return operation failure

	ENDSV.	

	XRESCD
	SUBTTL  NIDLL --  Calls for illegal functions

NIFILL:	RET			; We don't support the function
	SUBTTL  NIDLL --  Network management - Read portal counters

;Call:
;	T1/ Function (read/read and zero)
;	T2/ Buffer for counter data
;	T3/ Buffer length
;	DL/ Data link block

	XSWAPCD

NIFRPC:	STKVAR <FUNC,BUFADR,BUFLEN>
	MOVEM T1,FUNC
	MOVEM T2,BUFADR
	MOVEM T3,BUFLEN
	CALL GETUNB		; Get a UN block
	 RET
	MOVE UN,T1
	LOAD T1,DLPID,(DL)	; Get the portal ID
	STOR T1,UNPID,(UN)
	STOR T1,UNSPI,(UN)	; Portal to read buffers for
	MOVE T1,BUFADR		; Get address of buffer for NISRV
	STOR T1,UNBFA,(UN)
	MOVE T1,BUFLEN		;  and its length
	STOR T1,UNBSZ,(UN)
	MOVE T1,FUNC
	CAIE T1,NF.SZC		; Is function show and zero? 
	IFSKP.
	  SETONE UNZRO,(UN)	; Yes, set the to be zeroed flag
	ENDIF. 
	SETZM RCCFLG		; Clear read/clear complete flag
	MOVX T1,NU.RPC		; Function is read portal counters
	MOVE T2,UN
	CALL DLLUNI
	 CALLRET NMXERR		; Failed with error in T1
	CALLRET NMXGUD		; Success - counters loaded into users buffer

	ENDSV.
	XRESCD
	SUBTTL  NIDLL --  Network management - Read channel counters

;Call:
;	T1/ Function to perform
;	T2/ Counter buffer address
;	T3/ Counter buffer length

	XSWAPCD

NIFRCC:	STKVAR <FUNC,BUFADR,BUFLEN>
	MOVEM T1,FUNC
	MOVEM T2,BUFADR
	MOVEM T3,BUFLEN
	CALL GETUNB		; Get a UN block
	 RET
	MOVE UN,T1
	CALL NIFOIP		; Get the info portal ID
	 RET			; Can't get it
	STOR T1,UNPID,(UN)
	LOAD T1,NFETY,(P1)	; Get line ID
	LOAD T1,LIUNI,+T1	; Get unit number
	STOR T1,UNCHN,(UN)
	MOVE T1,BUFADR		; Get users buffer address
	STOR T1,UNBFA,(UN)
	MOVE T1,BUFLEN		;  and length of buffer
	STOR T1,UNBSZ,(UN)
	MOVE T1,FUNC
	CAIE T1,NF.SZC		; Is function show and zero? 
	IFSKP.
	  SETONE UNZRO,(UN)	; Yes, set the to be zeroed flag
	ENDIF. 
	SETZM RCCFLG		; Clear read/clear complete flag
	MOVX T1,NU.RCC		; Function is read channel counters
	MOVE T2,UN
	CALL DLLUNI
	 CALLRET NMXERR		; Failed with error in T1
	CALLRET NMXGUD		; Success - Wait for counters to be loaded
	ENDSV.			;  into data buffer
	XRESCD
	SUBTTL  NIDLL --  Network management - Read Ethernet addreses

;NMFRHA  - Read hardware address

	XSWAPCD

NMFRHA:	JSP T1,NIFRCI		; Read the address from the driver
	LOAD T1,UNHAD,(UN)	; Get hi-order of address
	LOAD T2,UNHAD,+1(UN)	;  and lo-order
	LOAD T3,NFBUF,(P1)	; Get the buffer address
	MOVEM T1,(T3)		;  and store the hardware address in it
	MOVEM T2,1(T3)
	RET

;Read current physical address

NMFRPA:	JSP T1,NIFRCI		; Read the physical address from the driver
	LOAD T1,UNCAR,(UN)	; Get hi-order of address
	LOAD T2,UNCAR,+1(UN)	;  and lo-order
	LOAD T3,NFBUF,(P1)	; Get the buffer address
	MOVEM T1,(T3)		;  and store the physical address in it
	MOVEM T2,1(T3)
	RET

	XRESCD
	SUBTTL  NIDLL --  Network management - Read channel information

;Call:
;	P1/ NF argument block
	XSWAPCD

NIFRCI:	STKVAR <RETADR>
	MOVEM T1,RETADR
	CALL GETUNB		; Get a UN block
	 RET
	MOVE UN,T1
	LOAD T1,NFETY,(P1)	; Get entity type
	CAIE T1,.NTNOD		; Is it node?
	IFSKP.
	  SETZ T1,		; Use channel 0
	ELSE.
	  LOAD T1,NFEID,(P1)	; Get entity ID
	  LOAD T1,LIUNI,+T1	; Get unit number
	ENDIF.
	STOR T1,UNCHN,(UN)
	MOVX T1,NU.RCI		; Function is read channel information
	MOVE T2,UN
	CALL DLLUNI		; Call NISRV
	 CALLRET NMXERR		;  Error - T1 contains reason (???) NTMAN?
	MOVE T1,RETADR
	CALL (T1)		; Let caller copy the data he wants
	CALL FREUNB
	MOVX T1,NF.FCS		; Indicate success
				; Can't use NMXGUD here - Must be non-skip
	RET			; Success - Parameter loaded into users buffer

	XRESCD
	SUBTTL  NIDLL --  Network management - Read counters interlock

;NIDLKW - Interlock routine for process level callers
;
; Call:
;	T1/ Address of processor to call with the interlock
;
; Return:
;	RET
;
; Uses: T1
;
;This version of the interlock will spin on NIDLOK until it is freed.
;This is to be called only from process level, thus it will only spin
;if another process has the interlock.
;
;Note that NIDLOK must be uncached if this is a multiprocessor system.

NIDLKW:
IFN FTOPS10,<
	AOSE NIDLOK		; Test and set the interlock
	JRST NIDLKW		; Its locked, spin until its freed
	APRID NIDLKO		; Set the owner of the interlocK
>;END IFN FTOPS10		; Can only be competing with another
				; processor on TOPS10
IFN FTOPS20,<
        AOSN NIDLOK		; Test and set the interlock
	 JRST NIDLKF		; Its free, continue processing
	XMOVEI T1,NIDLST	; No, set up scheduler test
	MDISMS			; Wait for competing process to finish
	JRST NIDLKW		; Ok, lets try again

	RESCD
NIDLST:	SKIPL NIDLOK		; Is read counters lock free yet?
	 RET			; No, sleep on
	RETSKP			; Yes, wake up fork
	XRESCD

NIDLKF:
>  ;End FTOPS20
	RET

	RESCD
NISCHK:	SKIPL RCCFLG		; Has data been returned yet?
	 RET			; No, sleep on
	RETSKP			; Yes, wake up fork
	XRESCD

NMXERR:	 BUG.(CHK,DNDNNF,DNADLL,SOFT,<Network management failed>,<<T1,ERRCOD>>,<

Cause:	NISRV returned an error when asked to read network management 
	parameters or counters.

Action:	Check error code returned in T1 to see what NISRV thinks is wrong.

Data:	ERRCOD - Error code returned by NISRV
>)
	TRNA
NMXGUD:	AOS (P)			; Make a skip return
	SAVEAC <T1>		; Preserve error code if any
	CALL FREUNB
	RET
	SUBTTL  NIDLL -- Set the DECnet address in the channel
REPEAT 0,<

;Call with:
;	UN/ UN block
;	DL/ DL block

NIFSCA:	SETZRO UNCHN,(UN)	; Channel zero
	MOVE T1,%RTHIO		; DECnet address (high order)
	STOR T1,UNDAD,(UN)
	MOVE T1,RTRLOO		;  low order
	STOR T1,UNDAD,+1(UN)
	MOVX T1,NU.SCA	
	MOVE T2,UN
	CALL DLLUNI
	 RET
	RETSKP
>
	SUBTTL  NIDLL -- Post buffers for the NIDLL

;Call:
;	DL/ Data link block
;	UN/ UN block

NIDPB:	SAVEAC <MB>
	DO.
	  LOAD T1,LTNBP,(LT)		; Get number posted
	  OPSTR <CAML T1,>,LTBNO,(LT)	; Enough posted?
	   RET
	  LOAD T1,LTBSZ,(LT)		; Get the size to post for this link
	  ADDI T1,%RTEHS		; Add overhead for Ethernet header
	  MOVE MB,T1			; Save size around call to DNGMSG
	  CALL DNGMSG			; Request a message block
	  IFSKP.
	    SETZM EMBFLG
	    SETZRO DLEBU,(DL)		; No, longer using emergency buffer
	  ELSE.
	    MOVE T1,MB			; Recover size and try for an emergency
	    CALL DNDGEB			;  buffer
	    JUMPE T1,RTN		; If zero we are starving the driver
	  ENDIF.
	  MOVE MB,T1
	  STOR T1,UNRID,(UN)		; Store the MB as request ID
	  XMOVEI T1,+UD.MSD(MB)		; Get address of MSD
	  CALL DNF2WG##			; Fetch a two word global byte pointer
	  OPSTR <DMOVEM T1,>,UNBFA,(UN)	; Store buffer address
	  MOVEI T2,UNA.EV
	  STOR T2,UNADS,(UN)		; We are using EXEC virtual memory
	  LOAD T1,MDALL,+UD.MSD(MB)	; Get allocated length
	  STOR T1,UNBSZ,(UN)		; So the port knows what it can swallow
	  MOVEI T1,NU.RCV		; Function is post receive buffer
	  MOVE T2,UN
	  CALL DLLUNI			; Attempt to post the buffer
	   JRST [ SETZRO DLEBU,(DL)	; No longer using our emergency buffer
		  MOVE T1,MB		; Get message block address
	          CALL DNFMSG		; Free message block we couldn't post
		  AOS NPBERR		; Count failures
	          RET]			;  and return
	  INCR LTNBP,(LT)		; Account for buffer posted
	  LOOP.				; Loop back
	ENDDO.
	SUBTTL  NIDLL -- Enable multicast address

;Call:	T1/ Address to enable
;	UN/ UN block to use

NIFEMA:	STOR T1,UNDAD,(UN)	; Save the address for the port
	SETZRO UNDAD,+1(UN)	; Node address field is zero
	SETZRO UNRSP,(UN)	; No callback is desired
	MOVX T1,NU.EMA		; Enable this address
	MOVE T2,UN
	CALL DLLUNI
	 RET
	RETSKP
	SUBTTL  NIDLL -- Get informational portal ID
;Call:
;	With nothing
;
;Uses:	T1-T4

	XSWAPCD

NIFOIP:	SKIPE T1,INFPID		; Do we have one already?
	 RETSKP			; Return it in T1
	SAVEAC <UN>
	CALL GETUNB
	 RET
	MOVE UN,T1
	SETO T1,		; Get a -1
	STOR T1,UNPRO,(UN)	; Indicate we want an information portal
	XMOVEI T1,DNDNII	; Get callback routine address
	STOR T1,UNCBA,(UN)	; Save it
	MOVX T1,NU.OPN		; Open the portal
	MOVE T2,UN		; Get UN block addr into T2
	CALL DLLUNI
	 RET			;  Sigh...
	LOAD T1,UNPID,(UN)	; Get informational portal ID
	MOVEM T1,INFPID		; Save for posterity
	CALL FREUNB
	MOVE T1,INFPID		; Return portal ID to caller
	RETSKP			; Return PID in T1

	XRESCD
	SUBTTL  NIDLL -- Close the information portal

;Call:

NIFCIP:	SKIPN INFPID		; Is there an information portal open?
	 RET			; No
	SAVEAC <UN>
	CALL GETUNB		; Yes, get a UN block
	MOVE UN,T1
	MOVE T2,T1
	MOVE T1,INFPID		; Get the portal ID for NISRV
	STOR T1,UNPID,(T2)
	MOVX T1,NU.CLO		; Function is "close portal"
	CALL DLLUNI
	 TRNA
	SETZM INFPID		; No longer have a portal open
	CALL FREUNB
	RET
	SUBTTL  NIDLL --  Interrupt level callbacks from NISRV
;DNDNII - Interrupt from the NI data link layer
;
; Call: 
;	T1 - Function
;	T2 - User block
;
; Return: 
;	RET			;Only return
;
; Uses: T1-T3
;
DNDNII:
IFN FTPARANOIA,<
	CAXL T1,NU.OPN
	 CAXLE T1,NU.MAX
	BUG. (CHK,DNDIKF,DNADLL,SOFT,<Illegal function code from DLL kontroller>,,<

Cause:	NISRV called back with a function code that was not recognized as 
	valid by DNADLL.

Action:	Check to see if there is a version skew between DNADLL and NISRV.
>,RTN)
> ;END IFN FTPARANOIA

	SAVEAC <DL,LT,UN,P1,MB>
	MOVE UN,T2		; UN block address
	LOAD DL,UNUID,(UN)	; From that get the data link block
	LOAD LT,DLLTP,(DL)	; Point to line table entry
	MOVE T1,NIIDLI(T1)
	JRST (T1)		; Dispatch to correct routine

NIIDLI:	IFIW	<NIIILL&777777>	; Unused
	IFIW	<NIIILL&777777>	; Unused as a callback
	IFIW	<NIICLS&777777>	; Close a Portal Callback
	IFIW	<NIIRCV&777777>	; Datagram Received Callback
	IFIW	<NIITRN&777777>	; Datagram Sent Callback
	IFIW	<NIIILL&777777>	; Enable Multicast Callback
	IFIW	<NIIILL&777777>	; Disable multicast callback
	IFIW	<NIIRPC&777777>	; Read portal counters callback
	IFIW	<NIIRCI&777777>	; Channel state change callback (Chan info)
	IFIW	<NIIILL&777777>	; Unused as a callback (RPL)
	IFIW	<NIIILL&777777>	; Unused as a callback (RCL)
	IFIW	<NIIILL&777777>	; Unused as a callback (RPI)
	IFIW	<NIISCA&777777>	; Set channel address callback
	IFIW	<NIIRCC&777777>	; Read channel counters callback
	IFIW	<NIIILL&777777>	; Unused as a callback

NMXILL:
NIIILL:	RET
	SUBTTL  NIDLL -- Close complete callback

NIICLS:	RET
	SUBTTL  NIDLL -- Input complete
;Call
;	UN/ UN block returned by NISRV
;

NIIRCV:	DECR LTNBP,(LT)			; Another buffer used up
	LOAD MB,UNRID,(UN)		; Set up MB
	SKIPE T3			; Any errors?
	 JRST NIIRCE			; Yes, log event and return message
	LOAD T1,UNSAD,(UN)		; Get the high order source address
	STOR T1,MBSR1,(MB)		; Put it into the MB
	SETZ T1,
	LOAD T2,UNSAD,+1(UN)		; Get the low order (node address) in
	LSHC T1,^D8			;  string format.  Shift nn-2 into T1
	LSH T2,-^D20			; Right justify the area+2
	IOR T1,T2			;  and include the number
	STOR T1,MBSRC,(MB)		; Stuff it into the MB
	OPSTR <DMOVE T1,>,UNBFA,(UN)	; Fetch two word global byte pointer
	XMOVEI T3,+UD.MSD(MB)		; Get address of MSD
	CALL DNSBP##			; Store the byte pointer into the MSD
	LOAD T1,UNBSZ,(UN)		; Get the length received
	STOR T1,MDBYT,+UD.MSD(MB)	; Save as bytes written
	MOVEI T1,DI.INC			; Function is input complete
	MOVE T2,DL
	MOVE T3,MB			; 
	LOAD T4,UNDAD,(UN)		; So Router knows destination multi-
					;  cast if running as endnode
	CALL DNDQUE			; Queue up the buffer for jiffy level
	CALL NIDPB			; Post another buffer if possible
	RET

NIIRCE:	CAIE T3,UNLER%			; Length error?
	IFSKP.
	  MOVEI T1,DE%RCF		; Yes, say receive failed
	  CALL NIEVNT			; See if we need to log an event
	ENDIF.
	CAIE T3,UNRAB%			; Buffer being returned because port is
	 CALL NIDPB			; shutting down? No, post another
	SKIPE T1,MB			; Get message block address
	 CALLRET DNFMSG			;  and return to free list
	RET
	SUBTTL  NIDLL -- Transmit done

NIITRN:	SKIPN T3			; Any errors?
	IFSKP.
	  MOVEI T1,DE%XMF		; Transmit failed
	  CALL NIEVNT			; See if we need to log an event
	ENDIF.
	MOVE T2,DL			; T2 = data link block address
	LOAD T3,UNRID,(UN)		; Address of message block
	MOVEI T1,DI.ODN			; Function is Output Done
	CALL DNDQUE			; Queue it up
	RET
	SUBTTL  NIDLL -- Read portal counters complete

NIIRPC:	SETOM RCCFLG		; Read counters is complete
	LOAD T1,UNBFA,(T2)	; Get buffer address
	MOVEM T3,-1(T1)		; Store flags ahead of data
	RET
	SUBTTL  NIDLL -- Channel state change callback (line state change)

;Call:
;	UN/ UN block
;	DL/ DL block
;	LT/ Line table pointer

NIIRCI:	MOVEI T3,LS.OFF		; Assume state is off
	TMNE UNRUN,(UN)		; Is new state "running"?
	 MOVEI T3,LS.ON		; Yes, change to on state
	LOAD T1,LTSTA,(LT)	; Get current state
	CAIN T1,(T3)		; Any change?
	 RET			; No, then done
	STOR T3,LTSTA,(LT)	; Save new state
	TMNN DLLIU,(DL)		; Is Router using this line?
	IFSKP.
	  CAIN T3,LS.ON	 	; Yes, is new state "running"?
	   CALL NIDPB		; Yes, try to post buffers	  
	  MOVEI T1,DI.LSC	; Notify ROUTER for either state
	  MOVE T2,DL		; T2 must contain the DL block address
	  CALL DNDQUE
	ENDIF.
	TMNN UNRUN,(UN)		; Is new state "running"?
	 CALL NIFCIP		; No, close the information portal
	RET
	SUBTTL  NIDLL -- Set channel address callback

;Call:
;	DL/ Data link block (if any)
;	LT/ Line table pointer
;	UN/ UN block address


NIISCA:	LOAD T3,UNCAR,(UN)	; Get hi-order of new address
	LOAD T4,UNCAR,+1(UN)	; Get low order address
	DMOVEM T3,DCNNIA	; Save address
	JUMPE DL,R		; If no data link block then don't check for
				;  DECnet address
	TMNN DLLIU,(DL)		; Is Router using this data link?
	 RET			; No, not to worry then
	CAMN T3,[%RTHIO]	; YES, is the address still DECnet's?
	 CAME T4,RTRLOO		; Is it our local address?
	IFSKP.
	  TMNE LTCAD,(LT)	; Was it DECnet before?
	   RET			; Yes, then done
	  SETONE LTCAD,(LT)	; Indicate channel address is DECnet	  
	  MOVX T3,LS.ON		; Signal a line state change to on
	  MOVE T2,DL
	  MOVX T1,DI.LSC
	  CALL DNDQUE		; Notify Router
	ELSE.
	  TMNN LTCAD,(LT)	; Was it DECnet before?
	   RET			; No, then done
	  SETZRO LTCAD,(LT)	; Channel address is not DECnet's
	  MOVEI T1,DI.LSC	; Yes, notify ROUTER
	  MOVE T2,DL		; T2 must contain the DL block address
	  MOVX T3,LS.OFF	; Report new line state is off
	  CALL DNDQUE
	ENDIF.
	RET
	SUBTTL  NIDLL -- Read channel counters callback

NIIRCC:	SETOM RCCFLG		; Read couters is complete
	LOAD T1,UNBFA,(T2)	; Get buffer address
	MOVEM T3,-1(T1)		; Store flags ahead of data
	RET
	SUBTTL  NIDLL -- Set channel state callback

NIISCC:	RET
	SUBTTL  NIDLL -- Ethernet event reporter

;Call:
;	T1/ Type
;	T3/ Reason
;	DL/ data link block
;

NIEVNT:	STKVAR <EVNTYP>
	MOVEM T1,EVNTYP
	MOVNI T2,NIETBL		; Length of event table
	HRLZ T2,T2
NIEVN1:	HLRZ T1,NIEVTB(T2)	; Get reason code
	CAIN T1,(T3)		; Is this the one?
	 JRST NIEVN2		; Yes, try to log the event
	AOBJN T2,NIEVN1		; No, try next
	RET
NIEVN2:	MOVE T1,EVNTYP		; Get type
	HRRZ T3,NIEVTB(T2)	; Get event reason
	LOAD T2,DLDID,(DL)	; Get entity ID
	CALLRET RTNEVT

;Data link layer events

DE%XMF==^D14		; Transmit failed
DE%RCF==^D15		; Receive failed

NIEVTB:	XWD UNEXC%,^D0		; Excessive collisions
	XWD UNCCF%,^D1		; Carrier check failed
	XWD UNSHT%,^D3		; Short circuit
	XWD UNOPN%,^D4		; Open circuit
	XWD UNLER%,^D5		; Length error (frame too long)
	XWD UNRFD%,^D6		; Remote failure to defer
NIETBL=.-NIEVTB
	SUBTTL Network Management Interface -- RTNEVT - Event Reporter

;RTNEVT - Report Router event
;
; Call:
;	T1/ Event type
;	T2/ Entity ID (we know the entity type from DNETAB)
;	T3/ Event specific word (REASON, STATUS, etc.)
;
; Return:
;	RET			;ALWAYS
;
; Uses: T1-T4
;
;This calls something which will call network management to log this event
;which has taken place.  This routine is called by the EVENT macro.

	 EVTMLN==^D30		;Maximum length of event parameter data (bytes)

RTNEVT:	SAVEAC <P1,P2>
	DMOVE P1,T1
	MOVEM T3,DNDEVW		; Save the event argument

;Check if event should be thrown away

	MOVX T1,.NCDLL		; DNADLL event class
	STOR T1,FACCL,+T2
	STOR P1,FACTY,+T2	;  and event type to T2
	MOVX T1,EV.FIL		; Function code "filter event"
	CALL NMXEVT
	  RET			;   -throw it away
	SKIPN DNDECP		; Verify that EC pointer is non-zero
	  RET			;   -was zero, must have failed to initialize
; Continued...
;Ok, to log an event

	MOVX T1,NE.LEN+<<EVTMLN+3>/4> ;Get enough for arg block and
				; Maximum amount of event parameter data
	CALL DNGWDZ		;Get the words
	 BUG.(INF,DNDCGV,DNADLL,SOFT,<Couldn't get memory for event arg block>,,<

Cause:	DECnet has used all of its available memory and could not give us any.

Action:	Try to determine who is using all the memory and why.  Setting FTDEBUG
	to non-zero will give more information about who is using each block
	of memory.

>,RTN)
	STOR P1,NECTY,(T1)	; Put the event type in the arg block
	STOR P2,NEEID,(T1)	; Put entity-id in event block
	MOVE P1,T1		; Save the pointer to the block
	MOVE T1,DNDECP		; Get EC pointer
	STOR T1,NEECP,(P1)	;  and store it in NE block
	MOVX T1,.NTLIN		; Get our entity type
	STOR T1,NEETP,(P1)
	MOVX T1,.NCDLL		; The event class is data link
	STOR T1,NECCL,(P1)	; Put in ne arg block
	XMOVEI T1,NE.LEN(P1)	; Make a fullword pointer to data
	STOR T1,NEDAT,(P1)	; Store pointer to it in arg block
	MOVE P2,[POINT 8,NE.LEN(P1)] ; Make up byte pointer to parameter data
	SETZ T4,		; Intialize count of bytes written
	CALL DNDRFR		; Write parameter strings into the data area
	LOAD T1,NECTY,(P1)	; Get event type
	CAIE T1,DE%RCF		; Was this a receive failure?
	IFSKP.
	  CALL DNDWEH		; Yes, put Ethernet addresses in event data
	ELSE.
	  CALL DNDDIS		; No, then insert the TDR (distance)
	ENDIF.
	STOR T4,NEDLN,(P1)	; Save count of bytes actually written
	MOVX T1,EV.LOG		; Function code is "log an event"
	MOVE T2,P1		;  NE pointer in T2
	CALL NMXEVT		; Call the event processor
	 TRN
	RET			; Return, NTMAN will deallocate NE block
	SUBTTL Network Management Interface -- RTNEVT - Event data routines

DNDRFR:	MOVEI T1,^D16		; Parameter number - Failure reason
	MOVEI T2,2		; Get number of bytes
	CALL PUTNBT		; Insert the bytes swapped
	MOVEI T1,201		; Coded, single field, length 1 byte
	CALL PUTBYT		; Stuff it
	MOVE T1,DNDEVW		; Get the reason
	CALLRET PUTBYT		; Insert it and return

;Writes Ethernet addresses into event data

DNDWEH:	MOVEI T1,^D18		; Parameter number - Ethernet header
	MOVEI T2,2		; Get number of bytes
	CALL PUTNBT		; Insert the bytes swapped
	MOVEI T1,302		; Coded multiple with 2 fields
	CALL PUTBYT
	LOAD T1,UNDAD,(UN)	; Get 6 char destination address
	LOAD T2,UNDAD,+1(UN)
	DMOVEM T1,ETHADR	;  and save it for event data
	CALL PUTEA		; Put in destination address
	LOAD T1,UNSAD,(UN)	; Get 6 char source address
	LOAD T2,UNSAD,+1(UN)
	DMOVEM T1,ETHADR	;  and save it for event data
	CALLRET PUTEA		; Put in source address

;Writes the distance (TDR) data into the event

DNDDIS:	MOVEI T1,^D17		; Parameter number - Distance
	MOVEI T2,2		; Get number of bytes
	CALL PUTNBT		; Insert the bytes swapped
	MOVEI T1,002		; Data type - decimal unsigned, two bytes
	CALL PUTBYT
	MOVEI T2,2		; Number of bytes to transfer
	LOAD T1,UNTDR,(UN)	; Get Time Domain Reflectometry value
	CALLRET PUTNBT		; Put data into event buffer
	SUBTTL Network Management Interface -- RTNEVT - Event data routines

;Writes a 6 character hex address into the event data

PUTEA:	MOVEI T1,040		; Not coded, hex image
	CALL PUTBYT		; Install data type
	MOVEI T1,6		; Length of data is always 6 bytes
	CALL PUTBYT		; Install length of data
	MOVX T2,6		; We always want six bytes
	MOVE T3,[POINT 8,ETHADR] ; Point to address for event data
	CALLRET PUTNBY		; Put them in the NE block

;Put n (in T2) bytes in the string pointed to by pointer in T3.
;It also updates T4, which is the count of bytes put in so far.

PUTNBY:	JUMPE T2,RTN		; Return if no more bytes left
	ILDB T1,T3		; Get a byte of event data
	IDPB T1,P2		; Store the byte
	ADDI T4,1		; Update the global count
	SOJA T2,PUTNBY		; See if we have to put in more

;Put n (in T2) bytes of the number in T1.

PUTNBT:	JUMPE T2,RTN		; Return if nothing left
	IDPB T1,P2		; Put the byte in the message
	LSH T1,-^D8		; Shift over to the next byte
	ADDI T4,1		; Update the count
	SOJA T2,PUTNBT		; Do the rest

;Put one byte (in T1) into the data string for network management

PUTBYT:	IDPB T1,P2		; Install the byte
	AOJA T4,RTN		; Increment the number of bytes
	SUBTTL  Miscellaneous routines -- Get a UN block

;GETUNB  - Get a UN block

GETUNB:	SYSPIF			; No interrupts please
	SKIPN T1,DNDUNQ		; Any free blocks on the queue?
	IFSKP.
	  MOVE T2,(T1)		; Yes, take the first one
	  MOVEM T2,DNDUNQ
	  SOS DNDUQL		;  and account for it
	ELSE.
	  SYSPIN
	  MOVX T1,UN.LEN	; Get length of user NI block
	  CALL DNGWDZ		; Try to get the words
	   RET			; Can't, return error
	ENDIF.
	SYSPIN
	RETSKP			; Return address in T1

;Free a UN block.
;This means put it on the queue of free UN blocks or return it to the
; the free pool if the queue is at the desired maximum.

;Call:
;	UN/ UN block address

FREUNB:	MOVE T1,DNDUQL		; Get the length of the UN block queue
	CAIG T1,6		; Is it greater than the desired maximum?
	IFSKP.
	  MOVE T1,UN		; Yes, the free the block
	  CALL DNFWDS
	ELSE.
	  SYSPIF
	  MOVE T1,DNDUNQ	; No, get the queue head
	  MOVEM T1,(UN)	 	;  and put this one at the head
	  MOVEM UN,DNDUNQ
	  AOS DNDUQL		; Add it into the count
	  SYSPIN
	ENDIF.
	RET
	SUBTTL	Miscellaneous routines -- Get emergency buffer


; Here when we couldn't get a buffer from the memory manager.
; Use the per-circuit emergency buffer, in case it's a
; important control message.  Otherwise, return a zero in T1 for the DLL.

DNDGEB:	TMNE DLEBU,(DL)		; Already using emergency buffer?
	 JRST DNDGE1		; Yes, can't have another now
	CALL DNGEMS		; Get one of the emergency message blocks
	 JRST DNDGE1		; Couldn't get one
	SETOM EMBFLG		; Set emergency buffer flag
	SETONE DLEBU,(DL)	; Indicate we took an emergency buffer
	RET
DNDGE1:	SETZ T1,		; No buffer available
	RET
	SUBTTL	Miscellaneous routines -- Check Ethernet address

;Call:
;	UN/ UN block we can use
;Return:
;	+1 If address is not DECnet's
;	+2 If address is DECnets's

CHKADR:	SKIPE DCNNIA		; Do we already have the address?
	IFSKP.			; No, get it
	  SETZ T1,		; Use channel 0
	  STOR T1,UNCHN,(UN)
	  MOVX T1,NU.RCI	; Function is read channel information
	  MOVE T2,UN
	  CALL DLLUNI		; Call NISRV
	   RET
	  LOAD T1,UNCAR,(UN)	; Get hi-order of address
	  LOAD T2,UNCAR,+1(UN)	;  and lo-order
	  DMOVEM T1,DCNNIA	;  and save it
	ELSE.
	  DMOVE T1,DCNNIA	; Get the current address
	ENDIF.
	CAMN T1,[%RTHIO]	;  and see if it is DECnet's
	CAME T2,RTRLOO
	IFSKP.
	  SETONE LTCAD,(LT)	; Indicate channel address is DECnet	  
	  RETSKP
	ELSE.
	  SETZRO LTCAD,(LT)	; Channel address is not DECnet's
	  RET			; No, then non-skip
	ENDIF.
	SUBTTL	Local storage for DNADLL

	RESDT

DNDINQ::XCDSEC,,QUEBLK		; Queue pointer - interrupt callback functions
DNDIWQ:	XCDSEC,,QUEBLK+3	; Queue pointer - working queue
QUEBLK:	BLOCK 2*QH.LEN		; Space for callback functions & working queue
DLBQUE:	BLOCK QH.LEN		; Queue of data link blocks
DNDUNQ:	BLOCK 1			; Queue of free UN blocks
DNDUQL:	BLOCK 1			; Length of UN block queue
DNDQBQ:	BLOCK 1			; Queue of free function blocks
DNDQBL:	BLOCK 1			; Length of QB queue
DNDRNT:	BLOCK 1			; Router's node type
EMBFLG:	EXP 0			; Flag someone is using emergency buffer
RCCFLG:	EXP -1			; Read couter complete flag for NIDLL
NIDLOK:	EXP -1			; Interlock so only one counter reader
DNDEVW:	BLOCK 1			; Event reason
ETHADR:	BLOCK 2			; Ethernet address for event data
DNDECP:	EXP 0			; Event communication pointer
INFPID:	EXP 0			; Informational portal ID
DCNNIA: BLOCK 2			; DECnet Ethernet address
NIEMAF:	BLOCK 1			; Count of enable multicast failures
NIOPNF:	BLOCK 1			; Count of open failures
NPBERR:	BLOCK 1			; Count of failures posting buffer to NISRV
	XRESCD
	END