Google
 

Trailing-Edge - PDP-10 Archives - decnet_mcb_cusps_703a - 10,7/703mon/ntman.mac
There are 26 other files named ntman.mac in the archive. Click here to see a list.
;TITLE NTMAN - Network Management Interface for DECnet-36


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

  	SUBTTL	Jim Halpin, Gunnar Lindell, & Tarl Neustaedter

	SEARCH D36PAR,MACSYM
	SALL

IFN FTOPS20,<
	SEARCH PROLOG
	TTITLE NTMAN,,< - Network Management interface for DECnet-36>
	>

IFN FTOPS10,<
	SEARCH F,S
	TITLE NTMAN - Network Management interface for DECnet-36
.CPYRT<1976,1986>
	$RELOC
>;END IFN FTOPS10

	D36SYM			;SET UP D36 SPECIFIC PARAMETERS

;Declare all global entry points to NTMAN
	ENTRY NTMAN		;TO FORCE LINK TO LOAD WITH REST OF DECNET

	INTERN .NTMAN		; = NTMAN. JSYS/UUO entry point
	INTERN NMXEVT		;Event logger
	INTERN PRSCOU		;Hook for NSP event "Database reused"

IFN FTOPS20 <
	INTERN EVRKIL		;Kill the event reader
	INTERN NMLEVT		;Check if event reader should get PSI
>

	SUBTTL	Table of Contents


;		Table of Contents for NTMAN
;
;
;			   Section			      Page
;   1. Table of Contents. . . . . . . . . . . . . . . . . . .    2
;   2. Data structures
;        2.1.   Value definitions . . . . . . . . . . . . . .    3
;        2.2.   BEGSTR NT . . . . . . . . . . . . . . . . . .    4
;        2.3.   Byte pointers into NSP node block . . . . . .    5
;        2.4.   Parameter and counter definitions . . . . . .    6
;        2.5.   Event and logging definitions . . . . . . . .   12
;   3. NTMAN
;        3.1.   Entry . . . . . . . . . . . . . . . . . . . .   13
;        3.2.   Get pertinent data from user's data block . .   14
;        3.3.   Dispatch to functions . . . . . . . . . . . .   15
;   4. Functions
;        4.1.   .NTMAP - Map node name/number . . . . . . . .   16
;        4.2.   .NTREX - Return local node number . . . . . .   17
;        4.3.   .NTSET,.NTCLR - Parse and process a parameter   18
;        4.4.   .NTZRO,.NTSZC - Zero counters . . . . . . . .   19
;        4.5.   .NTSHO
;             4.5.1.     Select parameters to return. . . . .   20
;             4.5.2.     Return parameters to user. . . . . .   21
;        4.6.   .NTRET
;             4.6.1.     List node names. . . . . . . . . . .   22
;             4.6.2.     List circuit and line names. . . . .   23
;   5. Entities
;        5.1.   Convert entity names to entity ids. . . . . .   24
;        5.2.   Circuit ID to name conversion . . . . . . . .   25
;        5.3.   Convert name to Circuit-ID. . . . . . . . . .   26
;   6. Layers
;        6.1.   Main interface to layer levels. . . . . . . .   27
;        6.2.   Read/set NSP node blocks. . . . . . . . . . .   28
;        6.3.   Read/set RTR circuit blocks . . . . . . . . .   29
;        6.4.   Read/set node state . . . . . . . . . . . . .   30
;        6.5.   Read/set executor node information. . . . . .   31
;        6.6.   Read/set RTR node information . . . . . . . .   32
;        6.7.   Find circuit which points to a node . . . . .   33
;        6.8.   Set/clear node names. . . . . . . . . . . . .   34
;        6.9.   Create/Destroy loopback nodes . . . . . . . .   35
;        6.10.  Call the data link layer. . . . . . . . . . .   36
;   7. Events
;        7.1.   Interface layer / NMX (NMXEVT). . . . . . . .   37
;        7.2.   NMXEVT
;             7.2.1.     EVGEC (Get EC block) . . . . . . . .   38
;             7.2.2.     EVREC (Release Ec block) . . . . . .   39
;             7.2.3.     EVFIL (Filter an event). . . . . . .   40
;             7.2.4.     EVLOG (Log an event) . . . . . . . .   41
;             7.2.5.     EVSIG (Log a signal) . . . . . . . .   45
;        7.3.   .NTTEV function (Test event logger) . . . . .   46
;        7.4.   .NTSLM function (Set global logging mask) . .   47
;        7.5.   .NTPSI function (Set event PSI channel) . . .   48
;        7.6.   .NTEVQ function (Pass queued event to user) .   49
;   8. User strings
;        8.1.   Write parameter with nice . . . . . . . . . .   51
;        8.2.   Write coded data. . . . . . . . . . . . . . .   52
;        8.3.   Write ascii image data. . . . . . . . . . . .   53
;        8.4.   Write numeric data. . . . . . . . . . . . . .   54
;        8.5.   Read a number from user . . . . . . . . . . .   55
;        8.6.   Read and write milliseconds . . . . . . . . .   56
;        8.7.   Copy STRINGID from user to exec . . . . . . .   57
;        8.8.   Copy STRINGID from exec to user . . . . . . .   58
;        8.9.   Get and put user byte routines. . . . . . . .   59
;        8.10.  Get and put single bytes into data strings. .   60
;   9. Miscellaneous
;        9.1.   Error returns . . . . . . . . . . . . . . . .   61
;        9.2.   Name/number conversion. . . . . . . . . . . .   62
;  10. Data base
;       10.1.   Find an NSP node block. . . . . . . . . . . .   63
;       10.2.   Find an existing NSP node block . . . . . . .   64
	SUBTTL Data structures -- Value definitions

;AC definitions
	TM=FREE0		;A WORK AC. PRESERVED
	NT=FREE1		;POINTS TO THE TABLE FORMAT BLOCK



;Network management non-error code
	XP NESUC%,1

;Function codes
	.NTSLM==-4		;Set global logging mask (TOPS-20 only)
	.NTPSI==-3		;SET PSI MASK (TOPS20 ONLY)
	.NTMAP==-2		;Map Node name/Node number
	.NTREX==-1		;Return local node ID
	.NTSET==0		;SET PARAMETER
	.NTCLR==1		;CLEAR PARAMETER
	.NTZRO==2		;ZERO COUNTERS
	.NTSHO==3		;SHOW SELECTED ITEMS
	.NTSZC==4		;SHOW AND ZERO COUNTERS
	.NTRET==5		;RETURN LIST OF ITEMS
 	.NTEVQ==6		;REMOVE AN ITEM FROM THE EVENT QUEUE

 	.NTSUM==0		;SUMMARY		;(FOR .NTSHO)
	.NTSTA==1		;STATUS
	.NTCHA==2		;CHARACTERISTICS
 	.NTCOU==3		;COUNTERS
				;Skip 4 to avoid possible confusion with EVENTS
	.NTCST==5		;CIRCUIT STATE
;Offsets to important locations in block
	.NTQUA==5		;BYTE POINTER TO FUNCTION QUALIFER
	.NTSEL==4		;SELECTION CRITERIA FOR FUNCTION
	.NTQUA==5		;QUALIFIER
	.NTBPT==6		;BYTE POINTER TO DATA STRING
	.NTBYT==7		;BYTE COUNT FOR DATA STRING
	.NTERR==10		;RETURN CODE, OR ERROR CODE

;Some Maximum Length Constants
	MXNNLN==6		;Maximum Node Name Length
	MXHILN==6		;Maximum Hexidecimal Image string Length

;Constants for Memory allocations
	FHIBLK==4		;Hexidecimal Image buffer
	COUBLK==^D100		;Counter Block, should have plenty of
				;extra room, just incase some wierd layer
				;invents some newer counters.
	CIRBLK==^D100		;For RETURN LIST OF ENTITY IDS function
	LPNBLK==^D32		;For return list of LOOP Nodes
	NDBLEN==^D1024		;For return of Home Area Nodes

;Some constants for NICE Data Type Fields
	NT.CNM==200		;Coded Non-Multiple (OR'ed into byte length)
	NT.CM1==301		;Coded Multiple, 1 fields long
	NT.CM2==302		;Coded multiple, 2 fields long
	NT.CM3==303		;Coded multiple, 3 fields long
	NT.DU1==1		;Decimal, Unsigned, 1 byte long
	NT.DU2==2		;Decimal, Unsigned, 2 bytes long
	NT.AI==100		;ASCII Image field
	NT.HI==40		;HEXIDECIMAL Image field

;Needed Parameter Numbers
	NODSTA==0		;Node State Parameter number value

;MACRO TO GIVE AN ERROR RETURN. THIS IS USED SIMPLY TO HIGHLIGHT THE FACT
;OF AN ERROR RETURN, AND DOES NOT PRECLUDE OTHER WAYS OF REACHING THE ROUTINES
;WHICH SET AN ERROR CODE. A JSP IS USED TO FACILITATE DEBUGGING.

DEFINE XERRRET(ROUTINE),<XJSP (CX,XCDSEC,ROUTINE)>	; Jump to error routine
							; in Extended Section

DEFINE ERRRET(ROUTINE),<JSP CX,ROUTINE>


	XSWAPCD			;Most of NTMAN is swappable ($HIGH on TOPS-10)

EXTERN DNGWDZ,DNGWZP,DNGWDS,DNFWDS,NMXTIM,NMXPRV		;D36COM
EXTERN IBBLK,D36IFG
EXTERN TIMBAS,DNGTIM						;D36COM
EXTERN RTRMXN
EXTERN RTN,RSKP,CHKBPT,KONNAM
IFN FTOPS10,<EXTERN GETWRD,GETWR1,PSIDVT>

;NMX Standard Interface Routines
EXTERN SCLNMX			;Session Control Layer
EXTERN ECLNMX			;End Communication Layer
EXTERN RTRNMX			;Routing layer
EXTERN DNDNMX			;Data Link Layer
	SUBTTL Data structures -- BEGSTR NT

;Table to find and validate a call parameter or counter.
BEGSTR NT
	FIELD TYP,4		;DATA TYPE (ASCII, HEX,...)
	 XP NT.FC,1		;CODED FORMAT
	 XP NT.FCM,2		;CODED MULTIPLE (THIS MEANS SPECIAL CASING)
	 XP NT.FAI,3		;ASCII IMAGE (8-BIT)
	 XP NT.FDU,4		;DECIMAL, UNSIGNED. CANNOT BE ZERO.
	 XP NT.FDS,5		;DECIMAL, SIGNED
	 XP NT.FH,6		;HEX INTEGER.
	 XP NT.FHI,7		;HEX, IMAGE.
	 XP NT.FOC,^D8		;OCTAL.
				;ABOVE ARE DATA TYPES AS DESCRIBED IN NM SPEC
				; V3.0 PAGE 162.
				;BELOW ARE DATA TYPES USED INTERNALLY ONLY TO
				; THIS MODULE.
				; THESE SHOULD BE SHIFTED DOWN IF NM SPECIFIES
				; MORE DATA TYPES
	 XP NT.FDM,^D9		;INTERNAL DATA TYPE ONLY. DECIMAL,MILLISECONDS.
				; THIS GETS OUTPUT AS NT.FDU (SEE NMXWNM)
	 XP NT.FVN,^D10		;INTERNAL DATA TYPE ONLY. VERSION NUMBER.
				; THIS GETS OUTPUT AS NT.FCM (DU-1,DU-1,DU-1)
	 XP NT.FNE,^D11		;INTERNAL DATA TYPE ONLY. NODE ENTITY ID.
				; THIS GETS OUTPUT AS NT.FCM (DU-2,AI-6)
	 XP NT.FNN,^D12		;INTERNAL DATA TYPE ONLY. ASCII NODE NAME
				; THIS GET OUTPUT AS NT.FAI (AI-6)
	 XP NT.FCN,^D13		;INTERNAL DATA TYPE ONLY. ASCII CIRCUIT NAME
				; THIS GET OUTPUT AS NT.FAI (AI-16)
	FIELD LEN,5		;LENGTH
	FIELD ROU,6		;INDEX TO ROUTINE TO CALL
	FIELD DEV,6		;DEVICE APPLICABILITY
	 BIT D.R		;DMR-11
	 BIT D.N		;Ethernet (KLNI)
	 BIT D.C		;Computer Interconnect (KLPI)
	 BIT D.P		;DDP
	 BIT D.K		;KDP
	 BIT D.D		;DTE-20 (UGH)
	FIELD QUA,15		;Qualifier Parameter Number

NXTWRD				;FORCE NEXT WORD ALIGNMENT.
	FIELD APL,4		;APPLICABILITY RESTRICTIONS
	 BIT A.E		;EXECUTOR
	 BIT A.L		;LOOP NODES.
	 BIT A.R		;REMOTE NODES.
	 BIT A.H		;HOME AREA NODES ONLY.
	FIELD INF,6		;INFORMATION TYPE
	 BIT I.C		;CHARACTERISTICS (LISTED IN SPEC AS 'C')
	 BIT I.S		;STATUS (LISTED IN SPEC AS 'S')
	 BIT I.%		;SUMMARY (LISTED IN SPEC AS '*')
	 BIT I.K		;Circuit State.
	 BIT I.Q		;This parameter is Qualified
	 BIT I.N		;NONE. NOOP BIT, NOT NECESSARY
	FIELD SET,2		;SETTABILITY RESTRICTIONS
	 XP NTS.,0		;0 MEANS READ AND WRITE
	 XP NTS.R,1		;READ ONLY PARAMETER.
	 XP NTS.W,2		;WRITE ONLY PARAMETER.
	FIELD BUF,1		;Buffer Field
	 XP NTB.,0		;Parameter Value fits into a Word
	 XP NTB.B,1		;Parameter value too big, go allocate a buffer
	FIELD BSZ,10		;Buffer size needed (if needed)
	FIELD SEQ,13		;SEQUENCE OR TYPE OF FIELD
ENDSTR
IFN <NT.LST-2>,<PRINTX ?LENGTH OF BEGSTR NT IS WRONG> ;TABLE LOGIC KNOWS LENGTH

;Bit positions for fields - will need for building tables.
TYP$==POS(NTTYP)
SEQ$==POS(NTSEQ)
SET$==POS(NTSET)
LEN$==POS(NTLEN)
ROU$==POS(NTROU)
QUA$==POS(NTQUA)
BSZ$==POS(NTBSZ)
BUF$==POS(NTBUF)

	SUBTTL -- NMX dispatch table. Routines are indexes into this table.

NMXDSP:

PHASE	0			;Make labels be relative offsets.
NMXMIN:!			;Lowest offset for NMXDSP
SCL:!	XCDSEC,,SCLNMX		;Session Control Layer
ECL:!	XCDSEC,,ECLNMX		;End Communication Layer
RTL:!	XCDSEC,,RTRNMX		;Routing Layer
DLL:!	XCDSEC,,DNDNMX		;Data Link Layer
NMXMAX:!			;Maximum value plus one
IFGE <NMXMAX-<1_WID(NTROU)>>,<PRINTX ?Too many Layer servers for width of NTROU>
DEPHASE
	SUBTTL Data structures -- Parameter and counter definitions
DEFINE	NODE$P,<

N(0	,C,1	,S%,ERH	,R,,RTL)                ;State.
N(10	,HI,6	,S,E	,R,,DLL,,B,4)		;Physical Address
repeat 0,<
IFN FTOPS10,<
N(100	,AI,31	,C%,E	,,NMI,0)		;Identification
>; End IFN FTOPS10
> ;end repeat 0
N(500	,NN,6	,N,R	,W,,SCL)                ;Name of node (set only)
N(501	,CN,16	,C%,L	,,,SCL)       	        ;Circuit
N(502	,DU,2	,N,E	,W,,SCL)		;Address (set only)
N(510	,DM,2	,C,E	,,,SCL)	                ;Incoming timer
N(511	,DM,2	,C,E	,,,SCL)                 ;Outgoing timer
N(600	,DU,2	,S%,ER	,R,,ECL)                ;Active links.
N(601	,DM,2	,S%,R	,R,,ECL)	        ;Delay
N(700	,VN,3	,C,E	,R,,ECL)                ;NSP version
N(710	,DU,2	,C,E	,,,ECL)			;Maximum Links
N(720	,DU,1	,C,E	,,,ECL)                 ;Delay factor.
N(721	,DU,1	,C,E	,,,ECL)                 ;Delay weight.
N(722	,DU,2	,C,E	,,,ECL)                 ;Inactivity timer.
N(723	,DU,2	,C,E	,,,ECL)                 ;Retransmit factor.
N(810	,C,1	,S,RH	,R,,RTL)		;Type
N(820	,DU,2	,S,RH	,R,,RTL)                ;Cost
N(821	,DU,1	,S,RH	,R,,RTL)                ;Hops
N(822	,CN,16	,S%,R	,R,,RTL)		;circuit
N(830	,NE,2	,S%,R	,R,,RTL)		;Next Node
N(900	,VN,3	,C,E	,R,,RTL)                ;Routing version
N(901	,C,1	,C,E	,R,,RTL)                ;Type
N(910	,DU,2	,C,E	,,,RTL)                 ;Routing timer.
N(912	,DU,2	,C,E	,,,RTL)			;Broadcast Routing Timer
N(920	,DU,2	,C,E	,,,RTL)			;Maximum address.
N(921	,DU,2	,C,E	,,,RTL)			;Maximum Circuits.
N(922	,DU,2	,C,E	,,,RTL)                 ;Maximum cost.
N(923	,DU,1	,C,E	,,,RTL)                 ;Maximum hops.
N(924	,DU,1	,C,E	,,,RTL)                 ;Maximum visits.
N(926	,DU,2	,C,E	,,,RTL)			;Maximum Broadcast Non-Routers
N(927	,DU,2	,C,E	,,,RTL)			;Maximum Broadcast Routers
N(930	,DU,2	,C,E	,,,RTL)			;Maximum Buffers
N(931	,DU,2	,C,E	,R,,RTL)                ;Buffer size.
N(932	,DU,2	,C,E	,,,RTL)			;Segment Buffer Size
>

DEFINE	LINE$P,<

N(0	,C,1	,S%,	,,,DLL)			;State
N(1105	,DU,2	,C,	,R,,DLL)		;Receive Buffers
N(1110	,C,1	,C,	,R,,DLL)		;Controller
REPEAT 0,<
N(1111	,C,1	,C,	,R,,DLL)              ;Duplex
> ;END REPEAT 0
N(1112	,C,1	,C,	,R,,DLL)		;Protocol
N(1160	,HI,6	,C,	,R,N,DLL,,B,4)		;Hardware Address
N(2500	,DU,2	,C,	,R,,DLL)		;Receive block size
>

DEFINE	CIRC$P,<

N(0	,C,1	,K,	,,,RTL)			;State.
N(400	,NN,6	,S%,	,R,,SCL)		;Loopback Name
N(800	,NE,2	,%,	,R,,RTL,,B,1023)	;Adjacent node
N(801	,NE,2	,S,	,R,N,RTL)		;Designated Router
N(810	,DU,2	,SQ,	,R,,RTL,800)		;Block size
N(900	,DU,1	,C,	,,,RTL)			;Cost.
N(901	,DU,1	,C,	,,N,RTL)		;Maximum Routers
N(902	,DU,1	,C,	,,N,RTL)		;Router Priority
N(906	,DU,2	,C,	,,,RTL)			;Hello timer
N(1112	,C,1	,C,	,,,DLL)			;Circuit Type
N(907	,DU,2	,CQ,	,,,RTL,800)		;Listen timer
>




DEFINE XPAND(.RES,.PFX,.CHA),<
.RES=0
IFB <.CHA>,<.RES=-1>
IRPC .CHA,<IFNB <.CHA>,<.RES=.RES!.PFX'.CHA>>
>

DEFINE .M(MASK),<1_WID(MASK)>

;Macro to create primary table entry
DEFINE 	NTENT(.APL,.INF,.SET,.BFF,.SIZ,.SEQ),<
IFB <.SIZ>,<BSZ==0>
IFNB <.SIZ>,<BSZ==^D'.SIZ>
IFGE <^D'.SEQ-.M(NTSEQ)>,<PRINTX ?Parameter .SEQ will not fit in NTSEQ>
XPAND(APL,NTA.,.APL)
XPAND(INF,NTI.,.INF)
<APL&NTAPL>!
<INF&NTINF>!
<<NTS.'.SET>B<SET$>&NTSET>!
<<NTB.'.BFF>B<BUF$>&NTBUF>!
<<BSZ>B<BSZ$>&NTBSZ>!
<<^D'.SEQ>B<SEQ$>&NTSEQ>
>

;Define rightmost positions of fields, for ddt
NTNMSK==:<1B<POS(NTAPL)>!1B<POS(NTINF)>!1B<POS(NTSET)>!1B<POS(NTBUF)>!1B<POS(NTBSZ)>!1B<POS(NTSEQ)>>
NSSMSK==:<1B<POS(NTTYP)>!1B<POS(NTLEN)>!1B<POS(NTROU)>!1B<POS(NTDEV)>!1B<POS(NTQUA)>>
;Example - NTN$3M NODEP+3$10r$o/   100.,10.,4.,0.,0.
;displays fields NTAPL, NTINF, NTSET, NTSEQ .

;Macro to define secondary entry (Format)
DEFINE STENT(.TYP,.LEN,.ROU,.DEV,.QUA),<
XPAND(DEV,NTD.,.DEV)
IFB <.QUA>,<QUA==0>
IFNB <.QUA>,<QUA==^D'.QUA>
IFGE <.ROU-NMXMAX>,<PRINTX ?Routine .ROU out of range>
IFGE <^D'.LEN-.M(NTLEN)>,<PRINTX ?Parameter .LEN will not fit in NTLEN>
<<NT.F'.TYP>B<TYP$>&NTTYP>!
<<^D'.LEN>B<LEN$>&NTLEN>!
<<.ROU>B<ROU$>&NTROU>!
<DEV&NTDEV>!
<<QUA>B<QUA$>&NTQUA>
>

;Define all the REAL stuff now.

DEFINE N(.SEQ,.TYP,.LEN,.INF,.APP,.SET,.DEV,.ROU,.QUA,.BFF,.SIZ),<
	STENT(.TYP,.LEN,.ROU,.DEV,.QUA)
	NTENT(.APP,.INF,.SET,.BFF,.SIZ,.SEQ)
>


DEFINE MAKTAB(.LAB,.STF),<
XLIST
.LAB: .STF
.LAB'L==:.-.LAB
LIST
>

MAKTAB(NODEP,NODE$P)
MAKTAB(LINEP,LINE$P)
MAKTAB(CIRCP,CIRC$P)


;Pointers to parameter data base.
PRMP: 	XWD <-NODEPL/NT.LST>,NODEP	;NODE PARAMETERS
	XWD <-LINEPL/NT.LST>,LINEP	;LINE PARAMETERS
	Z				;LOGGING PARAMETERS
	XWD <-CIRCPL/NT.LST>,CIRCP	;CIRCUIT PARAMETERS
	Z				;MODULE - WE DON'T HAVE ANY
	Z				;EVENTS - CAN'T SET ANYTHING.

	SUBTTL Data structures -- Event and logging definitions

	RESVR

;Event queue variables
NMXEVQ:	BLOCK QH.LEN		;Event queue header 
NMXELO:	BLOCK 1			;Event queue contains a lost event

;Signal queue variables
NMXSIQ:	BLOCK QH.LEN		;Signal queue header

;Macros to define global filter table

	DEFINE $SFIL <>			;"Start filter table"

	DEFINE $FIL(A,B) <		;"Filter table entry"
		XWD A,B
		REPEAT <B+1-A>,<XWD 37777,-1>
	>

	DEFINE $NOFIL(A,B) <		;;"Off filter table entry"
		XWD A,B
		REPEAT <B+1-A>,<EXP 0>
	>

	DEFINE $EFIL <EXP -1>		;"End filter table"

;Now generate filter table
	RESDT			;Initialized data

NMXFIL:	$SFIL
	  $FIL(2,6)		;Event classes 2 through 6 known by monitor
	  $NOFIL(^D96,^D96)	;LCG specific events - turned off
IFN FTDEBUG <
	  $FIL(^D480,^D480)	;Accept event class 480 while debugging
>
	$EFIL

;Note: add more $FIL entries to declare more monitor event classes.
;The table will expand to
;
;	NMXFIL:	2,,6
;		REPEAT 5,< 37777,,777777>	;All 32 event types within
;		-1				; a class in BLISS bit meaning
; -1 is an end flag

	SWAPCD

	SUBTTL NTMAN -- Entry

;Called from DISP2A in UUOCON
;Call
;	M[T6]/ UUO itself (Used for storing values in the AC later)
;	T1/ Contents of the AC at UUO time
;	P/ Pointer to a stack in the current section
;Return
;	RET	error, .NTERR and AC contain error code
;	SKPRET	success. AC unchanged


.NTMAN: 
NTMAN: 
IFN FTOPS20,<
	MCENT			;ENTER MONITOR CONTEXT
	UMOVE T1,1		;GET ADDRESS OF BLOCK
>
	SKIPL D36IFG		;Is DECNET initialized?
IFN FTOPS20,<
	ITERR (NTMX3)		; -no, return error code
>
IFN FTOPS10,<
	RET		; Just give error return
> ;end ifn ftops10
;** Note **
; If you change this TRVAR, you need to change the TRVAR in routine GENE32
; in LLINKS as well.
	TRVAR <<NMXVAR,NX.LST>,<NFWBLK,NF.LST>>	;SET UP TRVAR
;** End note **
	SETZM NMXVAR		;CLEAN FIRST WORD OF BLOCK
	HRRI T2,1+NMXVAR	;GET POINTER TO SECOND WORD IN BLOCK
	HRLI T2,NMXVAR		;POINT AT START OF BLOCK
	BLT T2,NX.LST-1+NMXVAR	;CLEAN UNTIL END OF BLOCK
	STOR T1,NXADR,+NMXVAR	;SAVE ADDRESS OF ARGUMENT BLOCK
	SETZM NFWBLK		;CLEAN FIRST WORD OF BLOCK
	HRRI T2,1+NFWBLK	;GET POINTER TO SECOND WORD IN BLOCK
	HRLI T2,NFWBLK		;POINT AT START OF BLOCK
	BLT T2,NF.LST-1+NFWBLK	;CLEAN UNTIL END OF BLOCK
IFN FTOPS10,STOR T6,NXUUO,+NMXVAR ;** TOPS10 CALLS US WITH M/ UUO EXECUTED
	XCALL (XCDSEC,NMXPRV)	;MAKE SURE WE ARE PRIVED.
  IFN FTOPS10,<			;Tops-10 wants error in NTMAN argument block
	IFNSK.
	 XERRRET NTEPRV		;NOPE, GIVE THE NO PRIVS RETURN
	ENDIF.
  >
  IFN FTOPS20,<			;While Tops-20 generates CAPX1 error
	 ITERR (CAPX1)
  >
	CALL GETBLK		;GET STUFF FROM USER PARAMETER BLOCK
	 ERRRET NTERXI		;DIDN'T MAKE IT. SOMETHING WRONG.
IFN FTXMON,<
	XCALL (XCDSEC,NMXDIS)	;DISPATCH TO ROUTINES (IN NTMAN)
>
IFE FTXMON,<
	DNCALL (NMXDIS)
>
	 ERRRET NTERXI		;ERROR EXIT OF SOME KIND. CHECK.
  IFN FTDEBUG <
	TMNE NXERR,+NMXVAR	;MAKE SURE NO ERROR CODE HAS MADE IT'S WAY HERE
	 BUG.(CHK,NTMSRF,NTMAN,SOFT,<Skipness of return fouled up>,,<

Cause:	There is an error code stored in field NXERR after a return from 
	NTMAN with a skip return.

Action:	Put a non-skip return in the routine giving the error call.
>,RTN)
  >
	LOAD T2,NXADR,+NMXVAR	;GET ADDRESS OF USER'S ARGUMENT BLOCK
	MOVX T1,NESUC%		;ERROR CODE INDICATING SUCCESS.
	UMOVEM T1,.NTERR(T2)	;PUT IN ERROR CODE SPOT OF ARGUMENT BLOCK
	UMOVE T3,.NTBYT(T2)	;GET ORIGINAL NUMBER OF BYTES HE ALLOWED US
	LOAD T1,NXDAT,+BP.BYT+NMXVAR ;GET NUMBER OF BYTES LEFT IN STRING
	SUB T3,T1		;GET NUMBER OF BYTES WE ACTUALLY DEPOSITED
	TMNE NXWUS,+NMXVAR	;DID WE WRITE TO THE USER'S STRING?
	 UMOVEM T3,.NTBYT(T2)	;TELL USER HOW MANY BYTES WE GAVE HIM
IFN FTOPS20,MRETNG		;MAKE THE UUO DO A GOOD RETURN
IFN FTOPS10,RETSKP

NTERXI:
	OPSTR <SKIPL T1,>,NXERR,+NMXVAR
	BUG.(CHK,NTMNEC,NTMAN,SOFT,<No error code with error return>,,<

Cause:	A routine has returned non-skip, but has not given
	an error code by calling NTExxx. A return to the top level found 
	field NXERR zero.

Action:	Determine which routine is failing, and make the error return
	give an error code.
>)
IFN FTOPS10,<
	LOAD T6,NXUUO,+NMXVAR	;GET UUO BACK - NEED FOR STOTAC
	MCALL (RG,MCSEC0,STOTAC##) ;PUT ERROR CODE IN AC
	LOAD T1,NXERR,+NMXVAR	;GET ERROR CODE
	CAXN T1,NEADC%		;WAS THIS AN ADDRESS CHECK?
	RET			;YES, DON'T DO FURTHER DAMAGE.
> ;END IFN FTOPS10
	LOAD T2,NXADR,+NMXVAR	;GET ADDRESS OF USER BLOCK
	UMOVEM T1,.NTERR(T2)	;NOPE, SAFE TO GIVE HIM ERROR CODE
	SETZ T1,		;0 BYTES
	UMOVEM T1,.NTBYT(T2)	;TELL NML THAT WE DIDN'T GIVE HIM ANYTHING.
IFN FTOPS20,ITERR (NTMX1)	;GENERIC NETWORK MANAGEMENT ERROR
IFN FTOPS10,RET			;RETURN NON-SKIP, INDICATING UUO FAILED
	SUBTTL NTMAN -- Get pertinent data from user's data block

;Called from NMXDIS

;GETBLK - Copy pertinent fields from user's argument block to NX block
;;Call
;	NX/ Pointer to NX block
;Returns
;	Non skip on failure - Address check
;	Skip return on success
GETBLK:
	SAVEAC P1		;SO WE CAN HOLD SOME STUFF
	LOAD T6,NXADR,+NMXVAR	;GETWRD UNDERSTANDS T6 AS ADDRESS.
	MCALL (RG,MSEC1,GETWRD)	;GET FIRST WORD OF BLOCK
	IFNSK.
	 XERRRET NTEADC		;NO GO. CAN'T HAPPEN
	ENDIF.
	CAIGE T1,.NTERR		;MAKE SURE BLOCK INCLUDES .NTERR
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
	MCALL (RG,MSEC1,GETWR1)	;GET NEXT WORD IN BLOCK
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
	CAXL T1,.NTNOD		;RANGE CHECK THE ENTITY TYPE
	CAXLE T1,.NTARE
	IFNSK.
	 XERRRET NTEINI		;NOPE, ADDRESS CHECK.
	ENDIF.
	STOR T1,NXENT,+NMXVAR	;SAVE AS ENTITY TYPE
	MCALL (RG,MSEC1,GETWR1)	;GET BYTE POINTER TO ENTITY ID
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
	MOVE P1,T6		;SAVE POINTER TO ARG BLOCK FOR A WHILE
	MOVX T2,^D16		;THIS COULD BE AS MUCH AS 16 BYTES
	MCALL (RG,MSEC1,CHKBPT##) ;ASK IF THIS IS A GOOD BYTE POINTER
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
	MOVE T6,P1		;GET BACK POINTER TO OUR ARGUMENT LIST
	STOR T1,NXEID,+BP.BPT+NMXVAR ;SAVE RESOLVED BYTE POINTER
	MOVX T1,^D16		;MAXIMUM LENGTH FOR AN ENTITY ID
	STOR T1,NXEID,+BP.BYT+NMXVAR ;SAVE
	MCALL (RG,MSEC1,GETWR1)	;GET FUNCTION TO BE PERFORMED
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
IFN FTDEBUG <
	CAXL T1,.NTTEV
>
IFE FTDEBUG <
	CAXL T1,.NTSLM		;RANGE CHECK FUNCTION
>
	CAXLE T1,.NTEVQ
	IFNSK.
	 XERRRET NTEUFO		;BAD FUNCTION
	ENDIF.
	STOR T1,NXFNC,+NMXVAR	;SAVE AWAY.
	MCALL (RG,MSEC1,GETWR1)	;GET SELECTION CRITERIA
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
	STOR T1,NXSEL,+NMXVAR	;STASH AWAY
	MCALL (RG,MSEC1,GETWR1)	;GET FUNCTION QUALIFIER
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
				;I DON'T KNOW WHAT TO DO WITH THIS. TOSS.
	MCALL (RG,MSEC1,GETWR1)	;GET BYTE POINTER TO THE USER BUFFER
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
	MOVE P1,T1		;HANG ON TO BYTE POINTER FOR A WHILE
	MCALL (RG,MSEC1,GETWR1)	;GET BYTE COUNT OF STRING
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
	STOR T1,NXDAT,+BP.BYT+NMXVAR ;SAVE BYTE COUNT
	UMOVEM T1,(T6)		;TRY TO MOVE IT BACK. (MAKE SURE WRITABLE)
IFN FTOPS10,ERJMP NTEADC 	;DIDN'T WORK, MUST BE A HIGH SEGMENT.
	MOVE T2,T1		;NUMBER OF BYTES WE WANT TO CHECK
	MOVE T1,P1		;BYTE POINTER WE ARE GOING TO ASK ABOUT
	MOVE P1,T6		;SAVE OUR ARGUMENT LIST POINTER
	MCALL (RG,MSEC1,CHKBPT##) ;ASK IF THIS BYTE POINTER IS ANY GOOD
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
	STOR T1,NXDAT,+BP.BPT+NMXVAR ;SAVE FOR GETBYT
	MOVE T6,P1		;GET BACK POINTER TO THE USER ARG BLOCK
	MCALL (RG,MSEC1,GETWR1)	;MAKE SURE .NTERR IS IN CORE
	IFNSK.
	 XERRRET NTEADC		;NOPE, ADDRESS CHECK.
	ENDIF.
	UMOVEM T1,(T6)		;TRY TO PUT IT BACK.
IFN FTOPS10,ERJMP NTEADC	;DIDN'T WORK, MUST BE FIRST WORD IN HISEG
	RETSKP			;RETURN SUCCESS TO CALLER
IFN FTOPS20,<
;GETWRD & GETWR1 - Get a word from user space
;Call
;	T6/ address desired
;Return
;	+2 always

GETWR1:	AOJ T6,			;POINT TO NEXT WORD
GETWRD:	UMOVE T1,(T6)		;GET WORD
	RETSKP			;AND RETURN



> ;END IFN FTOPS20
	SUBTTL NTMAN -- Dispatch to functions

	XSWAPCD			;Section 6 Swapable Code

NMXDIS:
	LOAD P1,NXENT,+NMXVAR	;GET ENTITY TYPE
	LOAD T1,NXFNC,+NMXVAR	;GET FUNCTION CODE
IFE FTDEBUG <
	MOVE T2,<-.NTSLM>+[	;GET FLAG BITS FOR THIS FUNCTION
>
IFN FTDEBUG <
	MOVE T2,<-.NTTEV>+[	;GET FLAG BITS FOR THIS FUNCTION
		NX%ECV			;.NTTEV (check entity)
>
		NX%WRM			;.NTSLM (TOPS-20 only)
		NX%WRM			;.NTPSI (TOPS-20 ONLY)
		NX%WUS			;.NTMAP
		NX%WUS			;.NTREX
		NX%WRM!NX%ECV		;.NTSET
		NX%WRM!NX%ZMC!NX%ECV	;.NTCLR
		NX%WRM!NX%ZMC!NX%ECV	;.NTZRO
		NX%WUS!NX%ECV		;.NTSHO
		NX%WUS!NX%ZMC!NX%WRM!NX%ECV;.NTSZC
		NX%WUS			;.NTRET
		NX%WUS](T1)		;.NTDQE
	STOR T2,NXFLG,+NMXVAR	;SAVE FLAGS WE JUST GOT
	TXNN T2,NX%ECV		;SHOULD WE PARSE THE ENTITY?
	JRST NMXDI2		;NO, SKIP OVER
	CALL ENTCVT		;CONVERT THE ENTITY TO AN ID
	 RET			;error...
	LOAD T1,NXFNC,+NMXVAR	;GET FUNCTION CODE BACK AGAIN.
NMXDI2:
IFN FTDEBUG <
	CAXL T1,.NTTEV
>
IFE FTDEBUG <
	CAXL T1,.NTSLM		;RANGE CHECK FUNCTION
>
	CAXLE T1,.NTEVQ		; CODE.
	BUG.(CHK,NTMFUR,NTMAN,SOFT,<Function code out of range>,,<

Cause:	While dispatching by function code, the function code is found 
	to be out of range. Since the function code the user supplies is 
	checked in GETBLK, this means that field NXFNC has been trashed 
	in the meantime.
>,NTEMPE)
	CAXL P1,.NTNOD		;RANGE CHECK ENTITY
	CAXLE P1,.NTARE		;  TYPE.
	BUG.(CHK,NTMEOR,NTMAN,SOFT,<Entity type out of range>,,<

Cause:	While double checking the entity ID before dispatching
	on it, the value was found to be illegal. Since the
	value the user supplies is checked at GETBLK, this means that
	field NXENT has been trashed.
>,NTEMPE)
IFN FTDEBUG <
	CALLRET @.+1-.NTTEV(T1)	;DISPATCH TO APPROPRIATE ROUTINE.
>
IFE FTDEBUG <
	CALLRET @.+1-.NTSLM(T1)	;DISPATCH TO APPROPRIATE ROUTINE.
>
IFN FTDEBUG <
	  IFIW <NTTEV&777777>	;.NTTEV - Test function
>
	  IFIW <NTSLM&777777>	;.NTSLM - Set global logging mask
	  IFIW <NTPSI&777777>	;.NTPSI - SET EVENT INTERRUPT (TOPS-20 ONLY)
	  IFIW <NODMAP&777777>	;.NTMAP - MAP NODE NUMBERS AND NAMES
	  IFIW <NODLOC&777777>	;.NTREX - RETURN ENTITY ID FOR EXECUTOR
	  IFIW <PRSPRM&777777>	;.NTSET - SET A PARAMETER
	  IFIW <PRSPRM&777777>	;.NTCLR - CLEAR A PARAMETER
	  IFIW <PRSCOU&777777>	;.NTZRO - ZERO COUNTERS
	  IFIW <SELITM&777777>	;.NTSHO - SHOW PARAMETERS/COUNTERS
	  IFIW <PRSCOU&777777>	;.NTSZC - SHOW AND ZERO COUNTERS
	  IFIW @<-.NTNOD>+[	;.NTRET - LIST ENTITIES
		IFIW <NMXLND&777777> ;  .NTNOD - NODE
		IFIW <NMXLCK&777777> ;  .NTLIN - LINE
		IFIW <NTEURC&777777> ;  .NTLOG - DOESN'T EXIST
		IFIW <NMXLCK&777777> ;  .NTCKT - CIRCUIT
		IFIW <NTEURC&777777> ;  .NTMOD - Doesn't exist
		IFIW <NTEURC&777777>](P1) ;  .NTARE - Doesn't exist
	  IFIW <NTEVQ&777777>	;.NTEVQ - PASS A QUEUED EVENT TO USER
	SUBTTL Functions -- .NTMAP - Map node name/number

;Called from NMXDIS

;Extract parameter from input string, if a number return node name,
;	if a name, return node number (Address, or ID).
;Call
;	NC/ Pointer to block of data copied from user.

NODMAP:
	SAVEAC P1		;NEED ACS FOR BYTE ROUTINES
	CALL GET2BT		;GET NODE NUMBER
	 RET
	STOR T1,NXNUM,+NMXVAR	;STORE ENTITY ID (MAYBE)
	CALL GETSTR		;COPY SOME BYTES
	 RET
	JE NXVAL,+NMXVAR,NODMA2	;IF NO NAME, HE GAVE US AN ADDR
	CALL NMXN2A		;CONVERT NAME IN NXVAL TO NUMBER
	 RET			;Error return
	STOR T1,NXNUM,+NMXVAR	;STORE THE NODE ADDRESS AWAY.

NODMA2:
	JE NXNUM,+NMXVAR,NTEPAM	;IF NO NODE ADDRESS YET, ILLEGAL.
	LOAD T1,NXADR,+NMXVAR	;GET USER'S ARG BLOCK ADDRESS
S1XCT <
	UMOVE T1,.NTBPT(T1)	;GET BYTE POINTER AGAIN
	STOR T1,NXDAT,+BP.BPT+NMXVAR ;RESET EVERYTHING AGAIN
	LOAD T1,NXADR,+NMXVAR	;ARG BLOCK ADDRESS AGAIN
	ADDI T1,.NTBYT		;POINT TO BYTE COUNT
	UMOVE T1,(T1)		;GET BYTE COUNT FOR DATA STRING
	>
	STOR T1,NXDAT,+BP.BYT+NMXVAR ;STASH AWAY FOR PUTBYT
	LOAD T1,NXNUM,+NMXVAR	;GET NODE ADDRESS BACK
	CALL NMXA2N		;CONVERT NODE ADDRESS TO NODE NAME
	IFNSK.
	 LOAD T1,NXERR,+NMXVAR	;Get the error code (If any.)
	 CAXE T1,NF.URC		;Unrecognized Component?
	  RET			;No, it is a real error, report it
	 SETZRO NXVAL,+NMXVAR	;Otherwise, return #, without a name.
	 SETZRO NXERR,+NMXVAR	;Get rid of the error code
	ENDIF.
NODMA3:	LOAD T1,NXNUM,+NMXVAR	;GET NODE NUMBER
	CALL PUT2BT		;PUT INTO DATA STRING
	 RET			;error...
	XMOVEI P1,NX.VAL+NMXVAR	;POINTER TO STRINGID CONTAINING NODE NAME
	CALLRET PUTSTR		;COPY STRING FROM NXVAL TO USER DATA STRING
	SUBTTL Functions -- .NTREX - Return local node number

;Called from NMXDIS

NODLOC:
	CALL LOCNID		;Get the Local Node Id
	 RET
	CALL PUT2BT		;SEND TWO BYTES INTO THE OUTPUT STRING.
	 RET			;error
	SETZ T1,		;NO NODE NAME (DON'T BOTHER)
	CALLRET PUTBYT		;STORE AWAY IN USER STRING

;	Get the Local Node Id
;
;Return
;	 RET			;Error return from ROUTER
;	RETSKP			;Local Node ID (Address) in T1
;
LOCNID:	

	LOAD T1,IBADR,+IBBLK	;Get our node address
	RETSKP			;Success....


LOCARE:	LOAD T1,IBADR,+IBBLK	;Get our node address
	ASH T1,-<^D10>		;Get just the area number
	RETSKP

	SUBTTL Functions -- .NTSET,.NTCLR - Parse and process a parameter

;Called from NMXDIS

;PRSPRM - Parse a parameter from the data string, and process
;CALL
;	T1/ Function (From NXFNC)
;RETURN
;	Non skip, on error, with code stored in NXERR
;	Skip, no error, parameter has been processed
PRSPRM:
	SAVEAC NT
	MOVE NT,PRMP(P1)	;GET AOBJN POINTER TO NMXTAB
	LOAD T1,NXENT,+NMXVAR	;Get the entity type
	STOR T1,NFETY,+NFWBLK	;Store it in the Argument Block
	MOVE T3,T1		;Put Entity type into T3 for upcoming dispatch
	LOAD T1,NXNUM,+NMXVAR	;Get the Converted Entity Id
	STOR T1,NFEID,+NFWBLK	;And put it into the NFW Arg Block.
	JE NXDAT,+BP.BYT+NMXVAR,TABCLR ;IF NO PARAMETER, TRY CLEAR ALL
	CALL GET2BT		;GET DATA-ID FIELD.
	 RET			;error
	STOR T1,NFPRM,+NFWBLK	;STORE SEQUENCE NUMBER

;Now search for sequence number in NMXTAB table.
TABSRC:	JUMPGE NT,NTEUPT	;IF END OF TABLE, NO SUCH PARAMETER
	LOAD T2,NTSEQ,(NT)	;GET AN ENTRY OUT OF THE TABLE.
	CAME T1,T2		;IS THIS THE ENTRY WE ARE LOOKING FOR ?
	JRST [ADD NT,[1,,NT.LST] ;INCREMENT POINTER, DECREMENT COUNT
		JRST TABSRC]	;AND TRY AGAIN
;NT now points to table entry describing this parameter or counter.
	LOAD T1,NTSET,(NT)	;GET SETTABILITY RESTRICTIONS
	CAXN T1,NTS.R		;IS IT READ ONLY?
	 ERRRET NTEOPF		;YEP - HE CAN'T BE WRITING THIS ONE
	LOAD T1,NXENT,+NMXVAR	;GET TYPE OF ENTITY
	CAXE T1,.NTNOD		;IS IT A NODE?
	JRST TABSR1		;NO, APPLICABILITY DOESN'T APPLY
	LOAD T2,NXNTY,+NMXVAR	;GET TYPE OF NODE
	MOVE T2,[NTA.E		;BIT INIDICATING EXECUTOR
		 NTA.R		;    REMOTE
		 NTA.L]-1(T2)	;    LOOPBACK
	TDNN T2,NT.APL(NT)	;DOES THIS PARAMETER APPLY TO THIS NODE TYPE?
	ERRRET NTEPNA		;NO, PARAMETER NOT APPLICABLE
	JRST TABSR2		;Skip over Line/Circuit Check

TABSR1:	TXNN T1,<.NTLIN&.NTCKT>	;Is it a LINE or a CIRCUIT?
	 JRST TABSR2		;No, don't bother checking Line type
	LOAD T2,NXLTY,+NMXVAR	;Get the Line type
	MOVE T2,[NTD.D		;Bit indicating DTE
		 NTD.K		; KDP
		 NTD.P		; DDP
		 NTD.C		; CI
		 NTD.N		; NI
		 NTD.R]-1(T2)	; DMR
	TDNN T2,NT.DEV(NT)	;Does this Parameter apply to this Line Type?
	ERRRET NTEPNA		;Parameter Not Applicable

TABSR2:	JN NXZMC,+NMXVAR,TABSR3	;IF ZEROING MONITOR CORE, DON'T GET VALUES
	LOAD T1,NTTYP,(NT)	;FIND OUT WHAT KIND OF DATA WE ARE READING
	CAXL T1,NT.FC		;IS IT LESSER THAN SIMPLE CODED?
	CAXLE T1,NT.FCN		;OR GREATER THAN CIRCUIT NAME
TABSRE:	BUG.(CHK,NTMBFP,NTMAN,SOFT,<Bad format type encountered>,,<

Cause:	In the process of reading a value from the user string,
	descriptor tables have returned an invalid format for this
	item. The AC "NT" points to the descriptor for this item, and
	field NTSEQ tells which item is being referred to.

Action:	Fix the entry for this item to contain a valid format type.
>,NTEMPE)
	CALL <-NT.FC>+@[	;DISPATCH ACCORDING TO FORMAT TYPE
		IFIW <NMXRNC&777777> ;ORDINARY CODED.
		IFIW <TABSRE&777777> ;CODED MULTIPLE. ILLEGAL
		IFIW <TABSRE&777777> ;ASCII IMAGE. ILLEGAL
		IFIW <NMXRNU&777777> ;DECIMAL UNSIGNED.
		IFIW <NMXRNS&777777> ;DECIMAL SIGNED.
		IFIW <NMXRNU&777777> ;HEX INTEGER.
		IFIW <NMXRHI&777777> ;HEX IMAGE. STRING ID.
		IFIW <NMXRNU&777777> ;OCTAL - READ AS DECIMAL UNSIGNED
		IFIW <NMXRNM&777777> ;MILLISECONDS (REALLY DECIMAL UNSIGNED)
		IFIW <TABSRE&777777> ;VERSION NUMBER. ILLEGAL, READ-ONLY
		IFIW <TABSRE&777777> ;NODE ENTITY ID. ILLEGAL, READ-ONLY
		IFIW <NMXRNN&777777> ;NODE NAME (IN ASCII IMAGE FORMAT)
		IFIW <NMXRCN&777777>](T1) ;CIRCUIT NAME. (IN ASCII IMAGE FORMAT)
	 RET			;PROPAGATE ERROR
	MOVX T1,NF.SET		;Get the SET PARAMETER function code
	SKIPA			;Skip
TABSR3:	MOVX T1,NF.CLR		;Get the CLEAR PARAMETER function code
	XMOVEI T2,NFWBLK	;Put address of the Arg Block in T2
	LOAD T3,NTROU,(NT)	;GET ROUTINE FOR THIS PARAMETER
	CALL NMXLAY		;HAVE THE LAYER DO THE REST.
	 JRST NTEERR		;Go report the error
	JE NFBFF,+NFWBLK,RSKP	;If no buffer,we are finished
	LOAD T1,NFBUF,+NFWBLK	;Get the buffer address
	CALL DNFWDS		;Deallocate it
	SETZRO NFBUF,+NFWBLK	;Get rid of the address
	SETZRO NFBFF,+NFWBLK	;and the flag
	RETSKP			;FINISHED

;Logic for CLEAR ALL command

TABCLR: TMNN NXZMC,+NMXVAR	;ARE WE DOING A CLEAR?
	ERRRET NTEPAM		;NOPE, PARAMETER MISSING
TABCL1:	JUMPGE NT,RSKP		;DONE WHEN POSITIVE
	LOAD T1,NTSET,(NT)	;GET SETTABILITY RESTRICTIONS
	CAXE T1,NTS.		;ARE THERE ARE RESTRICTIONS?
	JRST TABCL5		;YES, IGNORE THIS PARAMETER
	LOAD T1,NXENT,+NMXVAR	;GET ENTITY TYPE
	CAXE T1,.NTNOD		;IS IT NODE?
	JRST TABCL2		;NOPE, APPLICABILITY DOESN'T APPLY
	LOAD T1,NXNTY,+NMXVAR	;GET TYPE OF NODE
	MOVE T1,[NTA.E
		NTA.R
		NTA.L]-1(T1)	;GET BITS REPRESENTING APPLICABILITY
	TDNN T1,NT.APL(NT)	;DOES THIS APPLY TO THIS NODE?
	JRST TABCL5		;NOPE, BYPASS IT

TABCL2:	TXNN T1,<.NTLIN&.NTCKT>	;Is it a LINE or a CIRCUIT?
	 JRST TABCL3		;No, don't bother checking Line type
	LOAD T2,NXLTY,+NMXVAR	;Get the Line type
	MOVE T2,[NTD.D		;Bit indicating DTE
		 NTD.K		; KDP
		 NTD.P		; DDP
		 NTD.C		; CI
		 NTD.N		; NI
		 NTD.R]-1(T2)	; DMR
	TDNN T2,NT.DEV(NT)	;Does this Parameter apply to this Line Type?
	JRST TABCL5		;NOPE, BYPASS IT

TABCL3:	CALL TABSR3		;Go CLEAR this parameter
	 RET			;Error
TABCL5:	ADD NT,[1,,NT.LST]	;INCREMENT POINTER, DECREMENT COUNT
	JRST TABCL1		;AND DO THE NEXT PARAMETER

	SUBTTL Counter Functions
;PRSCOU - Counter Functions Routine.
;	All three JSYS Counter Functions dispatch to here. The
;	NFWBLK Block is set up, a memory block is allocated,
;	and the NMX function code is stored in T1.
;	We then dispatch off of the Entity Type field to the
;	routines which call the layers.

;Note: this routine is also called from LLINKS. NSP needs a little
; help to generate the NICE message of the NSP node counters on a
; "database reused" event.
;
;LLINKS sets up a NMXVAR and NFWBLK TRVAR's, so it mimics the higher
; layers of NTMAN.

PRSCOU:
	LOAD T1,NXENT,+NMXVAR	;Get the Entity Type
	STOR T1,NFETY,+NFWBLK	;Put entity Type into NFWBLK
	LOAD T1,NXNUM,+NMXVAR	;Get the Entity ID (Already converted)
	STOR T1,NFEID,+NFWBLK	;Copy it into NFWBLK
	MOVX T1,COUBLK		;Get the size of a counter block
	STOR T1,NFBLN,+NFWBLK	;Copy it into NFWBLK
	CALL DNGWDS		;Get buffer of that length
	 ERRRET NTERES		;Resource Error
	STOR T1,NFBUF,+NFWBLK	;Put Buffer Address into NFWBLK
	SETONE NFBFF,+NFWBLK	;Flag that we sre sending a buffer to the layer
	LOAD T2,NXFNC,+NMXVAR	;Get the JSYS function code
IFE FTDEBUG <
	MOVE T1,<-.NTSLM>+[	;GET FLAG BITS FOR THIS FUNCTION
>
IFN FTDEBUG <
	MOVE T1,<-.NTTEV>+[	;GET FLAG BITS FOR THIS FUNCTION
		NF.ILG			;.NTTEV (check entity)
>
		NF.ILG			;.NTSLM (TOPS-20 only)
		NF.ILG			;.NTPSI (TOPS-20 ONLY)
		NF.ILG			;.NTMAP
		NF.ILG			;.NTREX
		NF.ILG			;.NTSET
		NF.ILG			;.NTCLR
		NF.SZC			;.NTZRO
		NF.COU			;.NTSHO
		NF.SZC			;.NTSZC
		NF.ILG			;.NTRET
		NF.ILG](T2)		;.NTDQE
	SKIPGE T1		;Skip if Function code is alright
	JRST [	LOAD T1,NFBUF,+NFWBLK	;Put the buffer address back into T1
		CALL DNFWDS		;Return the block
		SETZRO NFBUF,+NFWBLK	;Get rid of the address
		SETZRO NFBFF,+NFWBLK	;and the flag
		BUG.(CHK,NTMICF,NTMAN,SOFT,<Non-counter function in PRSCOU>,,<

Cause:	There is an illegal function in the PRSCOU routine. NXFNC 
	is wrong.
	>,NTEMPE)]

	LOAD T2,NXENT,+NMXVAR	;Get the Entity Type so we can dispatch
	CALL <-.NTNOD>+@[	;Dispatch according to Entity Type
		IFIW <PRSNDC&777777> ;Node Counters
		IFIW <PRSLNC&777777> ;Line Counters
		IFIW <NTEUFO&777777> ;Logging Counters (There are none!)
		IFIW <PRSCKC&777777> ;Circuit Counters
		IFIW <NTEUFO&777777> ;Module Counters (None)
		IFIW <NTEUFO&777777>](T2) ;Area Counters (None)

	 RET			;Error has been reported and buffer deallocated
	LOAD T1,NFBUF,+NFWBLK	;Get the Counter Block Address
	CALL DNFWDS		;Return the block
	SETZRO NFBUF,+NFWBLK	;Get rid of the address
	SETZRO NFBFF,+NFWBLK	;and the flag
	RETSKP			;return success

	SUBTTL PRSNDC - Process Node counters
;Show Node counters (and maybe Zero)
;Call
;	T1/	Function Code (NF.COU or NF.SZC)
;	NFWBLK is all set up for call to ECLNMX and RTRNMX
;Return
;	 RET	on error, error code in T1
;	RETSKP, via PRSCBK on success
PRSNDC:
	SAVEAC <P1>		;Will store Function code here
	MOVE P1,T1		; so we have it for RTRNMX call
	XMOVEI T2,NFWBLK	;And NF Block address in T2
	CALL ECLNMX		;Call the End Communication Layer
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 SETONE NXNIL,+NMXVAR	;Indicate no info returned, but no error
	ENDIF.
	LOAD T1,NFBUF,+NFWBLK	;Get the Counter Block Address
	LOAD T2,NFBLN,+NFWBLK	;and the # of words written	
	CALL PRSCBK		;Go parse the counter block
	 RET
	SETZRO NXNIL,+NMXVAR	;Make sure the No Information bit is clear
	CALL LOCNID		;Get the Local node number
	 RET
	LOAD T2,NFEID,+NFWBLK	;Get the Node Number back
	CAME T1,T2		;Is it our node number
	 RETSKP			;No, Return. ROUTER has EXECUTOR COUNTERS only
	MOVX T1,COUBLK		;We have to reset the Buffer Length because
	STOR T1,NFBLN,+NFWBLK	; ECLNMX returned bytes written there.
	MOVE T1,P1		;Put function code in T1
	XMOVEI T2,NFWBLK	;And NF Block address in T2
	CALL RTRNMX		;Call the End Communication Layer
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 SETONE NXNIL,+NMXVAR	;Indicate no info returned, but no error
	ENDIF.
	LOAD T1,NFBUF,+NFWBLK	;Get the Counter Block Address
	LOAD T2,NFBLN,+NFWBLK	;and the # of words written	
	CALLRET PRSCBK		;Go parse the counter block

	SUBTTL PRSCKC - Process Circuit counters
;Show Circuit counters (and maybe Zero)
;Call
;	T1/	Function Code (NF.COU or NF.SZC)
;	NFWBLK is all set up for call to RTRNMX and DNDNMX
;Return
;	 RET	on error, error code in T1
;	RETSKP, via PRSCBK on success
PRSCKC:
	SAVEAC <P1>		;Will store Function code here
	MOVE P1,T1		; so we have it for DNDNMX call
	XMOVEI T2,NFWBLK	;And NF Block address in T2
	CALL RTRNMX		;Call the End Communication Layer
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 SETONE NXNIL,+NMXVAR	;Indicate no info returned, but no error
	ENDIF.
	LOAD T1,NFBUF,+NFWBLK	;Get the Counter Block Address
	LOAD T2,NFBLN,+NFWBLK	;and the # of words written	
	CALL PRSCBK		;Go parse the counter block
	 RET
	SETZRO NXNIL,+NMXVAR	;Make sure the No Information bit is clear
	MOVX T1,COUBLK		;We have to reset the Buffer Length because
	STOR T1,NFBLN,+NFWBLK	; ECLNMX returned bytes written there.
	MOVE T1,P1		;Put function code in T1
	XMOVEI T2,NFWBLK	;And NF Block address in T2
	CALL DNDNMX		;Call the End Communication Layer
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 SETONE NXNIL,+NMXVAR	;Indicate no info returned, but no error
	ENDIF.
	LOAD T1,NFBUF,+NFWBLK	;Get the Counter Block Address
	LOAD T2,NFBLN,+NFWBLK	;and the # of words written	
	CALLRET PRSCBK		;Go parse the counter block

	SUBTTL PRSLNC - Process Line Counters
;Show (and maybe Zero) Line counters
;Call
;	T1/	Function Code
;	NFWBLK is all set up for call to DNDNMX
;Return
;	 RET			on error
;	RETSKP			on success

PRSLNC:
	XMOVEI T2,NFWBLK	;And NF Block address in T2
	CALL DNDNMX		;Call the Data Link Layer
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 SETONE NXNIL,+NMXVAR	;Indicate no info returned, but no error
	ENDIF.
	LOAD T1,NFBUF,+NFWBLK	;Get the Counter Block Address
	LOAD T2,NFBLN,+NFWBLK	;and the # of words written	
	CALLRET PRSCBK		;Go parse the counter block

	SUBTTL Parse Counter block and build NICE response
;PRSCBK - Parse the counter block passed back from a DECnet layer
;
;Call
;	T1/	Counter Block Address
;	T2/	Number of words written in block
;Return
;	RET			;If error
;	RETSKP			;If counter block handled OK
;

PRSCBK:
	JN NXNIL,+NMXVAR,RSKP	;If Layer didn't know about him, ignore it.
	JE NXWUS,+NMXVAR,RSKP	;IF NOT WRITING TO THE USER, RETURN
	SAVEAC <P1,P2>		;P1<=Block Addr., P2<= # of words
	MOVE P1,T1
	MOVE P2,T2
COULOP:	LOAD T1,KBWID,(P1)	;GET COUNTER SIZE
	CAXN T1,40		;IS IT SIZE 32.
	 MOVX T1,30		;NICE WANTS IT TO GET A 30 (octal)
	ASH T1,^D10		;SHIFT IT INTO WIDTH FIELD OF HEADER FIELD
	TXO T1,1_^D15		;TURN ON BIT INDICATING A COUNTER HEADER
	TMNE KBBMF,(P1)		;Check for a Bit Mask Field, skip if none
	 TXO T1,1_^D12		;set "Bit Mask" bit 
	LOAD T2,KBTYP,(P1)	;GET SEQUENCE NUMBER OF PARAMETER OR COUNTER
	IOR T1,T2		;OR INTO HEADER DUO-BYTE
	CALL PUT2BT		;PUT 2 BYTES OF HEADER INTO USER DATA STRING
	 RET			;error...
	TMNE KBBMF,(P1)		;Skip over code that puts in Bit mask, if none
	IFNSK.
	 LOAD T1,KBMSK,(P1)	;Get the Bit mask from the Counter Block
	 CALL PUT2BT		;Put 2 bytes of bit mask into user data string
	  RET			;error...
	ENDIF.
NOBITM: LOAD T1,KBWID,(P1)	;Get the counter width
	MOVX T2,1		;we are going to calculate overflow value in T2
	LSH T2,(T1)		;Shift over counter width times, decrement
	SUBI T2,1		; to get Max Counter value, and complement
	SETCA T2,T2		; it to get the bits that should not be set.
	LOAD T1,KBVAL,(P1)	;Now get the 36-bit counter value returned
	TDNE T1,T2		;Skip if we do not have a counter overflow.
	IFNSK.
	 SETCA T2,T2		;Set the mask back to the Max Counter value
	 STOR T2,KBVAL,(P1)	;Put max value into counter block
				;Now go and store the counter value
	ENDIF.
STORCV:	LOAD T2,KBWID,(P1)	;GET NUMBER OF BYTES FOR COUNTER AGAIN
	LOAD T1,KBVAL,(P1)	;GET VALUE TO RETURN
	ASH T2,-3		;Right justify width
	CAXL T2,1		;MUST BE AT LEAST ONE BYTE
	CAXLE T2,4		;MAY BE AT MOST 4 BYTES
COULNE:	BUG.(CHK,NTMBCL,NTMAN,SOFT,<Bad counter byte length>,,<

Cause:	While generating output for a numeric field, there has been a 
	request to generate an illegal number of bytes.
>,NTEMPE)
	CALL <-1>+@[IFIW <PUTBYT&777777> ;PUT A SINGLE BYTE
		IFIW <PUT2BT&777777> ;PUT A DUO BYTE
		IFIW <COULNE&777777> ;DO THREE BYTES. ILLEGAL
		IFIW <PUT4BT&777777>](T2) ;4 BYTES.
	 RET			;error...
	JE KBBMF,(P1),ADDTWO	;Skip over code for Bit Masks
	SKIPA T1,[3]		;Three words if Bit Mask was included
ADDTWO:	MOVX T1,2		;Only two words if no bit mask
	ADD P1,T1		;Move the address pointer down the block
	SUB P2,T1		;decrement the count of words in buffer
	JUMPG P2,COULOP		;do more counters if any left
	SKIPE P2		;Count is zero, OK
	BUG.(CHK,NTMCBL,NTMAN,SOFT,<Bad Counter Block length>,,<

Cause:	A DECnet Layer has returned an invalid length for a
	Counter Block.
>,NTEMPE)

	RETSKP

	SUBTTL Functions -- .NTSHO -- Select parameters to return
;SELITM - Select items from list of parameters for an entity, and
;	write their values to the user string
;Call
;	P1/ Type of entity
;Return
;	RET			;on error, NXERR contains code
;	RETSKP			;success, all info for this entity in string
;

SELITM:
	SAVEAC <P1,P2,P3,NT>	;GET SOME WORK REGISTERS
	LOAD T1,NXSEL,+NMXVAR	;GET SELECTION CRITERIA
	CAXL T1,.NTSUM		;RANGE CHECK SELECTION CRITERIA
	CAXLE T1,.NTCST		;CIRCUIT STATE IS HIGHEST.
	BUG.(CHK,NTMSOR,NTMAN,SOFT,<Selection criteria is out of range>,,<

Cause:	The criteria is out of range for selecting items to return (for .NTSHO) 
	dependent on the selection criteria.

Action:	Fix the check in GETBLK or find out who is trashing field NXSEL
>,NTEUFO)
	CAXN T1,.NTCOU		;IS THIS SHOW COUNTERS?
	 JRST PRSCOU		;Yes, jump to Counter Processing Routine
	MOVE NT,PRMP(P1)	;NOPE, GET POINTER TO PARAMETERS
	MOVE P1,<-.NTSUM>+[NTI.% ;SUMMARY BIT
		NTI.S		;STATUS BIT
		NTI.C		;CHARACTERISTICS BIT
		NTI.N		;NOOP (COUNTERS NOT HANDLED HERE)
		NTI.N		;NOOP (EVENTS NOT HANDLED HERE)
		NTI.K](T1)	;CIRCUIT STATE BIT
	LOAD T1,NXNTY,+NMXVAR	;GET NODE TYPE (REMOTE, EXECUTOR...)
	CAXL T1,0		;RANGE CHECK NODE TYPE (LOWEST IS NONE)
	CAXLE T1,NX.LPN		;LOOPBACK IS HIGHEST YET.
	BUG.(CHK,NTMNTR,NTMAN,SOFT,<Node type is out of range>,,<

Cause:	It is necessary to know the node type (executor,remote, or loop) 
	to select entries to return (for function .NTSHO). Other entities  
	(circuit, lines) should have this field zero. This field is set by  
	ENTCVT.
>,NTEMPE)
	MOVE P2,[NTAPL		;NO NODE TYPE, DO THEM ALL
		NTA.E		;BIT INDICATING APPLIES TO EXECUTOR NODE
		NTA.R		;APPLIES TO REMOTE NODES
		NTA.L](T1)	;APPLIES TO LOOPBACK NODES

	LOAD T1,NXLTY,+NMXVAR	;GET LINE TYPE (CI, NI, DTE,...)
	CAXL T1,0		;RANGE CHECK LINE TYPE (LOWEST IS NONE)
	CAXLE T1,NX.DMR		;DMR IS HIGHEST.
	BUG.(CHK,NTMLTR,NTMAN,SOFT,<Line type is out of range>,,<

Cause:	To determine entries to return (for function .NTSHO),
	it is necessary to know the Line type (CI,NI,DTE,...). 
	Other entities (Nodes,Modules) should have this field
	zero. This field is set by ENTCVT.
>,NTEMPE)
	MOVE P3,[NTDEV		;NO LINE TYPE, DO THEM ALL
		NTD.D		;APPLIES TO DTE'S
		NTD.K		;APPLIES TO KDP'S
		NTD.P		;DDP'S
		NTD.C		;CI'S
		NTD.N		;NI'S
		NTD.R](T1)	;DMR'S

SELIT4:	JUMPGE NT,RSKP		;WHEN DONE, RETURN SUCCESS
	LOAD T2,NXENT,+NMXVAR	;Get the Entity Type
	CAXE T2,.NTNOD		;Is it a NODE Entity?
	IFSKP.
	 CALL LOCARE		;Yes, go get Home Area number
	  JRST NTEERR
	 LOAD T2,NXNUM,+NMXVAR	;Get the Node address from the user
	 TXZ T2,RN%NOD		;Get just the AREA Number
	 LSH T2,-^D10		; Right justify
	 CAMN T1,T2		;Is the requested node in the Home Area?
	 IFSKP.			;No, Check if parameter is for Home Area only
	  MOVX T1,NTA.H		;Put Home Area Only flag into T1
	  TDNE T1,NT.APL(NT)	;Check Parameter applicabilty
	   JRST SELIT6
	 ENDIF.
	ENDIF.
	TDNE P1,NT.INF(NT)	;DOES THIS MATCH OUR SELECTION CRITERIA?
	TDNN P2,NT.APL(NT)	;AND DOES THIS APPLY TO US?
	SKIPA			;NOPE. SKIP OVER IT
	TDNN P3,NT.DEV(NT)	;Does it apply to this device?
	JRST SELIT6		;NOPE. SKIP OVER IT
	MOVX T1,NTI.Q		;Get the 'Qualified Parameter' bit flag
	TDNE T1,NT.INF(NT)	;Skip if this parameter is not qualified
	IFSKP.
	 CALL SHOPRM		;Go SHOW QUALIFIED PARAMETER
	  RET			;Error return...
	ELSE.
	 CALL SHOQUP		;YEP. DO THIS PARAMETER
	  RET			;error, punt...
	ENDIF.
SELIT6:	ADD NT,[1,,NT.LST]	;POINT TO NEXT ITEM ON LIST
	JRST SELIT4		;GO TRY FOR THIS NEW ITEM
	SUBTTL Functions -- Get the Qualifier values, for a Qualified Parameter
;SHOQUP - Show qualified Parameter.

SHOQUP:	SAVEAC <P1,P2,P3,P4,NT>
	LOAD T1,NXENT,+NMXVAR	;Get the Entity Type Back
	MOVE P1,NT		;Save the Qualified Parameter table entry
	MOVE NT,PRMP(T1)	;Get the pointer to top of the parameter table
	LOAD T1,NTQUA,(P1)	;Get the Qualifier Parameter Number

SHOQU1:	JUMPGE NT,NTEMPE	;If we hit the end of table, we have an error
	LOAD T2,NTSEQ,(NT)	;Get a Sequence number
	CAME T1,T2		;Is it our Qualifier????
	IFNSK.
	 ADD NT,[1,,NT.LST] 	;NO! Get next entry in table
	 JRST SHOQU1		;And loop until we find it....
	ENDIF.
	MOVE T1,NT		;Get the Table Entry address for the Qualifier
	CALL SETNFB		;Set up the NF Block
	 RET			;error
	MOVX T1,NF.RED		;Set up READ function code
	XMOVEI T2,NFWBLK	;And the argument block goes into T2
	LOAD T3,NTROU,(NT)	;GET ROUTINE FOR THIS PARAMETER
	CALL NMXLAY		;CALL LAYER-LEVEL ROUTINE TO DO PARAMETER
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 SETONE NXNIL,+NMXVAR	;Indicate no info returned, but no error
	ENDIF.
	JE NFBFF,+NFWBLK,ONEQUA	;Jump if only One qualifier, (i.e no buffer)
	LOAD P2,NFBUF,+NFWBLK	;Get the buffer address back into P2
	MOVE P4,P2		;Keep the head of the buffer address in P4
	LOAD P3,NFBLN,+NFWBLK	;And the number of words written...
	JUMPE P3,SHOQU3		;Jump if no values returned
	SETZRO NFBFF,+NFWBLK	;indicate no buffer present.
SHOQU2:	MOVE T1,(P2)		;Get the first Qualifier value
	STOR T1,NFBUF,+NFWBLK	;Put the value into the Buffer/value field
	CALL NMXWTY		;Write qualifier value to user buffer
	IFNSK.
	 MOVE T1,P4		;Get the buffer address back into T1
	 CALL DNFWDS		;And return buffer
	 RET
	ENDIF.
	EXCH NT,P1		;Get the Qualified parameter table entry
	MOVE T1,NT		;Put the Parameter Table Entry address into T1
	CALL SETNFB		;Set up the Interface Block
	IFNSK.
	 MOVE T1,P4		;Get the buffer address back into T1
	 CALL DNFWDS		;Deallocate it.
	 RET			;error return, buffer has been deallocated
	ENDIF.
	MOVE T1,(P2)		;Get the first Qualifier value again
	STOR T1,NFQUA,+NFWBLK	;Store it in the Qualifier Field
	SETONE NFQUF,+NFWBLK	;Flag we are sending a qualifier
	MOVX T1,NF.RED		;Set up READ function code
	XMOVEI T2,NFWBLK	;And the argument block goes into T2
	LOAD T3,NTROU,(NT)	;GET ROUTINE FOR THIS PARAMETER
	CALL NMXLAY		;CALL LAYER-LEVEL ROUTINE TO DO PARAMETER
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	 IFNSK.
	  STOR P4,NFBUF,+NFWBLK	;Put buffer back in NFWBLK
	  SETONE NFBFF,+NFWBLK	;NTEERR will deallocate buffer for us
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 ENDIF.
	 SETONE NXNIL,+NMXVAR	;Indicate no info returned, but no error
	ENDIF.
	CALL NMXWTY		;WRITE STRING OUT TO USER IN APPROPRIATE FORMAT
	IFNSK.
	 MOVE T1,P4		;Get the buffer address back into T1
	 CALL DNFWDS		;Deallocate it.
	 RET			;error return, buffer has been deallocated
	ENDIF.
	EXCH NT,P1		;Get the Qualifier parameter table entry
	AOJ P2,			;Increment the buffer pointer
	SOJG P3,SHOQU2		;Jump if more qualifiers
SHOQU3:	MOVE T1,P4		;Get the buffer address back
	CALL DNFWDS		;Deallocate the buffer
	RETSKP

ONEQUA: JN NXNIL,+NMXVAR,RSKP	;Return if layer didn't know about Qualifier
	CALL NMXWTY		;Write qualifier value to user string
	 RET			;Error return...
	EXCH NT,P1		;Get the Qualified Parameter table entry
	LOAD P1,NFBUF,+NFWBLK	;Save the Qualifier value
	MOVE T1,NT		;Now put it into T1
	CALL SETNFB		;Set up the NFWBLK
	 RET
	STOR P1,NFQUA,+NFWBLK	;Store it in the Qualifier Field
	SETONE NFQUF,+NFWBLK	;Flag we are sending a qualifier
	JRST SHOPR1		;And jump into SHOPRM

	SUBTTL Functions -- .NTSHO -- Return parameters to user
;SHOPRM - Process a parameter, and put into user data string

SHOPRM:	SAVEAC <P1,P2,NT,TM>	;SAVE A BUNCH OF ACS (TRASHED IN CM HANDLING)
	MOVE T1,NT		;Put the Parameter Table Entry address into T1
	CALL SETNFB		;Set up the Interface Block
	 RET
SHOPR1:	MOVX T1,NF.RED		;Set up READ function code
	XMOVEI T2,NFWBLK	;And the argument block goes into T2
	LOAD T3,NTROU,(NT)	;GET ROUTINE FOR THIS PARAMETER
	CALL NMXLAY		;CALL LAYER-LEVEL ROUTINE TO DO PARAMETER
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 SETONE NXNIL,+NMXVAR	;Indicate no info returned, but no error
	ENDIF.
	CALL NMXWTY		;WRITE STRING OUT TO USER IN APPROPRIATE FORMAT
	 RET			; error return
	JE NFBFF,+NFWBLK,RSKP	;If no buffer,we are finished
	LOAD T1,NFBUF,+NFWBLK	;Get the buffer address
	CALL DNFWDS		;Deallocate it
	SETZRO NFBUF,+NFWBLK	;Get rid of the address
	SETZRO NFBFF,+NFWBLK	;and the flag
	RETSKP			;FINISHED

;Setup NMX Interface Block
;Call:
;	T1/	Address of a Parameter Table Entry
;Return
;	
;	RET	error return
;	RETSKP	NFWBLK/ All set up for a call to a DECnet Layer
;
SETNFB:	SAVEAC <NT>		;Preserve NT
	MOVE NT,T1		;Put parameter table entry address here
	SETZM NFWBLK		;CLEAN FIRST WORD OF BLOCK
	HRRI T2,1+NFWBLK	;GET POINTER TO SECOND WORD IN BLOCK
	HRLI T2,NFWBLK		;POINT AT START OF BLOCK
	BLT T2,NF.LST-1+NFWBLK	;CLEAN UNTIL END OF BLOCK
	LOAD T1,NXNUM,+NMXVAR	;Get the converted Entity Id
	STOR T1,NFEID,+NFWBLK	;Put it int the argument block
	LOAD T1,NTSEQ,(NT)	;Get the parameter type (number) from the table
	STOR T1,NFPRM,+NFWBLK	;and into the argument block
	LOAD T1,NXENT,+NMXVAR	;We need the Entity type
	STOR T1,NFETY,+NFWBLK	;save it...
	JE NTBUF,(NT),SETNF1	;Does this Parameter require a buffer
	LOAD T1,NTBSZ,(NT)	;Yes, get the size needed from table
	STOR T1,NFBLN,+NFWBLK	;Put it into the argument block
	CALL DNGWDS		;Go allocate the block
	 ERRRET NTERES		;No memory available, resource error
	STOR T1,NFBUF,+NFWBLK	;Put the buffer addr into the arg block
	SETONE NFBFF,+NFWBLK	;And tell Layer to expect a buffer
	RETSKP

SETNF1:	SETZRO NFBFF,+NFWBLK	;No buffer in this case.
	SETZRO NFBUF,+NFWBLK	;Get rid of the buffer address
	RETSKP

	SUBTTL Functions -- .NTRET -- List node names
;NMXLND - List a series of node names. Function .NTRET
;Call
;	NMXVAR/ NX block
;Return
;	RET		;On error, error code loaded into NXERR,+NMXVAR
;	RETSKP		;Success, with user's data string containing list

NMXLND:
	SAVEAC <P1,P2,NT>	;I NEED A LOT OF ACS
	MOVX T1,.NTNOD		;Get the NODE ENTITY TYPE code
	STOR T1,NFETY,+NFWBLK	;Put it into the Arg Block
	SETZ NT,		;FLAG NOTHING SPECIAL YET
	LOAD P1,NXSEL,+NMXVAR	;FIND OUT WHAT KIND OF LIST HE WANTS
	STOR P1,NFSEL,+NFWBLK	;Put it into the NF Block
	CAXL P1,.NTSGN		;Range Check the Selection Criteria
	CAXLE P1,.NTKNO		;If not between SIGNIFICANT & KNOW
	 JRST NTEUFO		; it is an error
	JRST <-.NTSGN>+@[
		IFIW <NTEUFO&777777> ;SIGNIFICANT nodes not supported
		IFIW <NMXLAD&777777> ;ADJACENT nodes
		IFIW <NMXLLN&777777> ;LOOP Nodes
		IFIW <NMXLAC&777777> ;ACTIVE Nodes
		IFIW <NMXLNA&777777>](P1) ;KNOWN Nodes


NMXLNA:	CALL GETEBY		;Get the Area Number user wants
	 RET			;Error return
	STOR T1,NFEID,+NFWBLK	;Put it into the Argument Block
	MOVE NT,T1		;And save it in a register for now
	CALL LOCARE		;Get the local Node Id
	 RET			;Error Return
	CAME T1,NT		;Does user want the Home Area????
	 JRST NMXLFA		;No, go ask Session Control
	MOVX T1,NDBLEN		;Length of a Node Bffer
	CALL DNGWZP		;Get a Zeroed Buffer (Low Priority)
	 JRST NTERES		;Resource Error
	STOR T1,NFBUF,+NFWBLK	;Put it into the arg block
	SETONE NFBFF,+NFWBLK	;Tell the layers we are giving them a buffer
	MOVX T1,NDBLEN		;Get the buffer length
	STOR T1,NFBLN,+NFWBLK	;So the layer knows how long it is.
	MOVX T1,NF.RET		;Get the function code
	XMOVEI T2,NFWBLK	;and the Arg Block address
	CALL SCLNMX		;Ask Session Control for KNOWN NODES
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;and go report the error
	 JRST NMXLA2		;Return OK, No Data....
	ENDIF.
	MOVX T1,NF.RET		;Get the function code
	XMOVEI T2,NFWBLK	;and the Arg Block address
	CALL RTRNMX		;Ask Routing Layer for KNOWN NODES
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;and go report the error
	 JRST NMXLA2		;Return OK, No Data....
	ENDIF.

	LOAD P2,NFBUF,+NFWBLK	;Get the buffer address into P2
	ADDI P2,1		;START AT NODE NUMBER 1
NMXLN2:	LOAD T1,NFBUF,+NFWBLK	;Get Buffer address
	ADDI T1,<NDBLEN-1>	;Find the end of the buffer
	CAMLE P2,T1		;HAVE WE PASSED THE MAXIMUM NODE NUMBER?
	IFNSK.
	 LOAD T1,NFBUF,+NFWBLK	;Get the Counter Block
	 CALL DNFWDS		;Free up memory
	 SETZRO NFBUF,+NFWBLK	;Get rid of the address
	 SETZRO NFBFF,+NFWBLK	;and the flag
	 JRST RSKP		;Yes, we are all done
	ENDIF.
	MOVE T1,(P2)		;Get the contents of this cell
	SKIPN T1		;Are the contents zero???
	 AOJA P2,NMXLN2		;If so increment index, and loop
	CALL PUT2BT		;PUT NODE NUMBER IN DATA STRING
	 RET
	SETZ T1,		;NO NAME FOLLOWING, SO A ZERO STRINGID HEAD
	CALL PUTBYT		;PUT BYTE IN DATA STRING
	 RET
	AOJA P2,NMXLN2		;GO DO ANOTHER NODE

;Ask Session Control for KNOWN NODES in a Specific area, other than
;the Home area.
NMXLFA:
	LOAD T1,NXDAT,+BP.BPT+NMXVAR ;Get the Byte pointer to the user buffer
	STOR T1,NFBPT,+NFWBLK	;Put it into the Arg block
	LOAD T1,NXDAT,+BP.BYT+NMXVAR ;Get the number of bytes in the user buf.
	STOR T1,NFBLN,+NFWBLK	;Send it to Session control
	SETONE NFUBF,+NFWBLK	;Flag it is a user buffer
	MOVX T1,NF.RET		;Get the function code
	XMOVEI T2,NFWBLK	;and the Arg Block address
	CALL SCLNMX		;Ask Session Control for Known Nodes
	 JRST NTEERR		;Report error and deallocate buffer
	SETZRO NFUBF,+NFWBLK	;Get rid of the User buffer flag
	LOAD T1,NFBPT,+NFWBLK	;Get the byte pointer back
	STOR T1,NXDAT,+BP.BPT+NMXVAR ;Put it back where NTMAN expects it
	LOAD T1,NFBLN,+NFWBLK	;And the updated count
	STOR T1,NXDAT,+BP.BYT+NMXVAR ;And save it again
	RETSKP			;return success
;Ask Session Control for LOOP NODES

NMXLLN:	MOVX T1,LPNBLK		;Get the size of a LOOP NODE Block
	STOR T1,NFBLN,+NFWBLK	;Copy it into NFWBLK
	CALL DNGWDS		;Get buffer of that length
	 ERRRET NTERES		;Resource Error
	STOR T1,NFBUF,+NFWBLK	;Put Buffer Address into NFWBLK
	SETONE NFBFF,+NFWBLK	;Flag that we sre sending a buffer to the layer
	MOVX T1,.NTNOD		;Get the NODE ENTITY TYPE code
	STOR T1,NFETY,+NFWBLK	;Put it into the Arg Block
	MOVX T1,NF.RET		;Get the function code
	XMOVEI T2,NFWBLK	;and the Arg Block address
	CALL SCLNMX		;Ask Session Control for LOOP NODES
	 JRST NTEERR		;Report error and Deallocate buffer
	LOAD NT,NFBUF,+NFWBLK	;Get the Buffer address back
	LOAD P2,NFBLN,+NFWBLK	;Get the number of words written into buffer
	JUMPE P2,NMXLN6		;Jump if no Loop nodes returned...
NMXLN5:	MOVE T1,(NT)		;Get the name 
	CALL NMXS2A		;Convert Node name to ASCII and save in NMXVAR
	SETZ T1,		;NO NUMBER
	CALL PUT2BT		;PUT TWO BYTES IN STREAM INDICATING NO NUMBER
	 RET
	XMOVEI P1,NX.VAL+NMXVAR	;POINT TO THE WHERE THE NODE STRING IS
	CALL PUTSTR		;COPY THE STRING TO THE USER
	 RET
	SOSLE P2		;Decrement count of Circuits and skip if done
	 AOJA NT,NMXLN5		;Increment Buffer pointer and do next Node
NMXLN6:	LOAD T1,NFBUF,+NFWBLK	;Get the Buffer Address
	CALL DNFWDS		;Return the block
	SETZRO NFBUF,+NFWBLK	;Get rid of the address
	SETZRO NFBFF,+NFWBLK	;and the flag
	RETSKP			;return success

;Ask Routing Layer for ACTIVE or ADJACENT NODES.

NMXLAD:
NMXLAC:	SAVEAC <P1,P2>
	MOVX T1,NDBLEN		;Length of a Node Bffer
	CALL DNGWZP		;Get a Zeroed Buffer (Low Priority)
	 JRST NTERES		;Resource Error
	STOR T1,NFBUF,+NFWBLK	;Put it into the arg block
	SETONE NFBFF,+NFWBLK	;Tell the layers we are giving them a buffer
	MOVX T1,NDBLEN		;Get the buffer length
	STOR T1,NFBLN,+NFWBLK	;So the layer knows how long it is.
	MOVX T1,NF.RET		;Get the function code
	XMOVEI T2,NFWBLK	;and the Arg Block address
	CALL RTRNMX		;Ask Session Control for Known Nodes
	IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;and go report the error
	 JRST NMXLA2		;Return OK, No Data....
	ENDIF.
	LOAD P1,NFBUF,+NFWBLK	;Get the buffer address 
	LOAD P2,NFBLN,+NFWBLK	;And the number of node numbers written
	JUMPE P2,NMXLA2		;Jump if the count is zero
NMXLA1:	MOVE T1,(P1)		;Get a node number
	CALL PUT2BT
	 RET
	SETZ T1,
	CALL PUTBYT
	 RET
	AOJ P1,
	SOJG P2,NMXLA1
NMXLA2:	LOAD T1,NFBUF,+NFWBLK	;Get the Counter Block
	CALL DNFWDS		;Free up memory
	SETZRO NFBUF,+NFWBLK	;Get rid of the address
	SETZRO NFBFF,+NFWBLK	;and the flag
	RETSKP			;return success

	SUBTTL Functions -- .NTRET -- List circuit and line names
;NMXLCK - Return a list of line/circuit names
;Call
;	NMXVAR/ NX block
;	P1/ Entity Type (LINE or CIRCUIT)
;Return
;	RET			;ON ERROR, NXERR,+NMXVAR CONTAINING ERROR CODE
;	RETSKP			;WITH LIST OF NAMES IN USER DATA STRING

NMXLCK:
	SAVEAC	<P1,P2,NT>
	STOR P1,NFETY,+NFWBLK	;Put entity Type into NFWBLK
	LOAD T1,NXSEL,+NMXVAR	;Get the Selector
	STOR T1,NFSEL,+NFWBLK	;Copy it into NFWBLK
	MOVX T1,CIRBLK		;Get the size of a return-circuits block
	STOR T1,NFBLN,+NFWBLK ;Copy it into NFWBLK
	CALL DNGWDS	;Get buffer of that length
	 ERRRET NTERES	;Resource Error
	STOR T1,NFBUF,+NFWBLK ;Put Buffer Address into NFWBLK
	SETONE NFBFF,+NFWBLK ;Flag that we sre sending a buffer to the layer
	MOVX T1,NF.RET		;Set up the function code
	XMOVEI T2,NFWBLK	;Get the buffer address into T2
	CAXE P1,.NTLIN		;Is the Entity Type a LINE??
	IFSKP.
	CALL DNDNMX		;Go ask DNADLL for the circuit ids
	 IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 JRST NMXLC5		;No data returned, but no error...
	 ENDIF.
	ELSE.
	CALL RTRNMX		;Go ask Router for the circuit ids
	 IFNSK.
	 SKIPE T1		;Is there 'error' return zero??
	  JRST NTEERR		;No. Report error and deallo buffer if there
	 JRST NMXLC5		;No data returned, but no error...
	 ENDIF.
	ENDIF.
	LOAD NT,NFBUF,+NFWBLK	;Get back the buffer address
	LOAD P2,NFBLN,+NFWBLK	;and the number of words returned
	JUMPLE P2,NMXLC5	;If none (or less than none), do nothing.
NMXLC4:	MOVE T1,(NT)		;Get the Circuit Id
	MOVE T2,[POINT 8,NX.VAL+NMXVAR] ;DATA STORAGE AREA
	CALL NMXC2N		;CONVERT CIRCUIT-ID TO NAME
	 JRST NTEMPE		;ERROR!
	XMOVEI P1,NX.VAL+NMXVAR	;POINT TO THE CIRCUIT NAME STRINGID
	CALL PUTSTR		;PUT THIS STRING IN THE USER'S BUFFER
	 RET			;error
	SOSLE P2		;Decrement count of Circuits and skip if done
	AOJA NT,NMXLC4		;Increment Buffer pointer and do next circuit
NMXLC5:	LOAD T1,NFBUF,+NFWBLK	;Get the Buffer Address
	CALL DNFWDS		;Return the block
	SETZRO NFBUF,+NFWBLK	;Get rid of the address
	SETZRO NFBFF,+NFWBLK	;and the flag
	RETSKP			;return success

	SUBTTL Entities -- Convert entity names to entity ids

;Called from NMXDIS

ENTCVT:	SETZRO NXNTY,+NMXVAR	;NO NODE AS OF YET
	SETZRO NXLTY,+NMXVAR	;NO LINE AS OF YET
	CALLRET @.+1-.NTNOD(P1)
	  IFIW <NODCVT&777777>	;CONVERT NODE TYPE
	  IFIW <LINCVT&777777>	;LINE TYPE
	  IFIW <NTEURC&777777>	;LOGGING. PUNT, WE DON'T DO THESE
	  IFIW <CIRCVT&777777>	;SAME AS LINE
	  IFIW <NTEURC&777777>	;MODULE - ILLEGAL
	  IFIW <NTEURC&777777>	;ILLEGAL.


;Called from ENTCVT

NODCVT:
	SAVEAC <P1>		;NEED FOR TEMP BYTE STORAGE
	CALL GETEBY		;GET ENTITY STRING BYTE
	 RET
	MOVE P1,T1		;SAVE THE BYTE FOR A WHILE
	CALL GETEBY		;GET ANOTHER BYTE
	 RET
	ASH T1,^D8		;SHIFT HIGH-ORDER BYTE OVER
	IOR P1,T1		;INCLUDE LOW ORDER BYTE
	JUMPN P1,NODCVX		;IF WE HAVE AN ADDRESS, WE ARE OK
	CALL GETSTI		;NO ADDRESS, I MUST HAVE A NAME
	 RET
	CALL NMXN2A		;CONVERT THE NAME TO AN ADDRESS.
	 JRST NODCV2		;NO SUCH NAME, MUST BE LOOPBACK
	MOVE P1,T1		;Need the address in P1 now.
	JRST NODCV0

NODCVX:	MOVE T1,P1		;Get the node number back
	ASH T1,-<^D10>		;Get just the AREA Number
	JUMPN T1,NODCV0		;Jump if AREA is non-zero
	CALL LOCARE		;Get the Local Area Number
	 RET
	ASH T1,^D10		;Shift it over to the right position
	IOR P1,T1		;And or it into the node number
NODCV0:	STOR P1,NXNUM,+NMXVAR	;SAVE IN ARGUMENT BLOCK
	CALL LOCNID		;Get our Node address, returned in T1
	 RET			;Error, give up...
	LOAD T2,NXNUM,+NMXVAR	;Get back the address we are working on
	CAME T2,T1		;IS THIS US?
	 JRST NODCV1		;NOPE
	MOVX T1,NX.EXN		;THIS IS THE EXECUTOR NODE
	STOR T1,NXNTY,+NMXVAR	;DECLARE TYPE OF NODE
	RETSKP			;WE'RE DONE, RETURN
NODCV1:	MOVX T1,NX.REN		;THIS IS A REMOTE NODE
	STOR T1,NXNTY,+NMXVAR	;DECLARE THAT THIS IS A NODE, AND WHAT TYPE
	RETSKP

;Come here only for loop nodes after a fail return from NMXN2A.  The latter
; routine will have written an error code into NXERR that needs to be cleared.
NODCV2:	SETZRO NXERR,+NMXVAR	;Clear error code from NMXN2A
	LOAD T2,NXFNC,+NMXVAR	;GET THE FUNCTION CODE WE ARE TO DO
	CAXE T2,.NTSET		;Is this a set?
	IFNSK.
	 MOVX T1,.NTNOD		;Get the Node Entity type code
	 STOR T1,NFETY,+NFWBLK	;Put it into the Arg block
	 MOVX T1,NF.CKL		;Check Loopback Node function
	 XMOVEI T2,NFWBLK	;Get the Argument Block
	 CALL SCLNMX		;Go ask Session Control if Loopback Node Exists
	  JRST NTEERR		;No it doesn't, go handle error
	ENDIF.
	LOAD T1,NFEID,+NFWBLK	;Get the Node Name back from the Block
	STOR T1,NXNUM,+NMXVAR	;SAVE THE NODNAME IN NXNUM
	MOVX T1,NX.LPN		;THIS IS A LOOPBACK NODE
	STOR T1,NXNTY,+NMXVAR	;SAVE THE NODE TYPE
	RETSKP

;Called from ENTCVT

LINCVT:
	CALL GETSTI		;COPY MULTIPLE BYTES (INTERNAL LIMIT 16)
	 RET			;error...
	MOVE T1,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO LINE NAME WE COPIED
	CALL NMXN2C		;CONVERT NAME TO LINE-ID
	 RET			; error, pass the code back
	SETONE LILXC,+T1	;Flag that it is a Line Id (not circuit)
	STOR T1,NXNUM,+NMXVAR	;SAVE AWAY LINE ID
	LOAD T2,LIDEV,+T1	;Get the Device Type Back
	STOR T2,NXLTY,+NMXVAR	;AND INTO THE NMX BLOCK
	STOR T1,NFEID,+NFWBLK	;Put the Line Id into argument block
	LOAD T1,NXENT,+NMXVAR	;Get the entity type
	STOR T1,NFETY,+NFWBLK	;Store it in Arg block
	MOVX T1,NF.CET		;Check Entity Function code into T1
	XMOVEI T2,NFWBLK	;And the Argument Block address into T2
	CALL DNDNMX		;Have the Data Link Layer Verify Line Id
	 JRST NTEERR		;Save the error code
	RETSKP			;Return success if not

;Called from ENTCVT

CIRCVT:
	CALL GETSTI		;COPY MULTIPLE BYTES (INTERNAL LIMIT 16)
	 RET			;error...
	MOVE T1,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO LINE NAME WE COPIED
	CALL NMXN2C		;CONVERT NAME TO LINE-ID
	 RET			; error, pass the code back
	SETZRO LILXC,+T1	;Flag that it is a Circuit Id (not Line)
	STOR T1,NXNUM,+NMXVAR	;SAVE AWAY LINE ID
	LOAD T2,LIDEV,+T1	;Get the Device Type Back
	STOR T2,NXLTY,+NMXVAR	;AND INTO THE NMX BLOCK
	STOR T1,NFEID,+NFWBLK	;Put the Line Id into argument block
	LOAD T1,NXENT,+NMXVAR	;Get the entity type
	STOR T1,NFETY,+NFWBLK	;Store it in Arg block
	MOVX T1,NF.CET		;Check Entity Function code into T1
	XMOVEI T2,NFWBLK	;And the Argument Block address into T2
	CALL DNDNMX		;Have the Data Link Layer Verify Line Id
	 JRST NTEERR		;Save the error code
	RETSKP			;Return Success

	SUBTTL Entities -- Circuit ID to name conversion
;NMXC2N - Convert circuit ID to name
;Call
;	T1/ Circuit ID
;	T2/ Local byte pointer to use in returning bytes
;	Area must be large enough to receive 16 bytes.
;Return
;	+1/ No such circuit ID
;	+2/ Data area has stringid for circuit name
;

NMXC2N:: 
	SAVEAC <P1,P2>		;SOME SCRATCH ACS
	DMOVE P1,T1		;SAVE BOTH ARGUMENTS FOR THIS CALL
	SETZ T6,		;NUMBER OF BYTES DEPOSITED
	IDPB T6,P2		;FIRST BYTE IS COUNT OF BYTES FOLLOWING
	MOVE T5,P2		;SAVE BYTE POINTER TO COUNT BYTE
	LOAD T1,LIDEV,+P1	;GET THE TYPE OF DEVICE
	CAXLE T1,LD.MAX		;IN RANGE OF DEVICES WE KNOW?
	 BUG.(CHK,NTMKOR,NTMAN,SOFT,<Controller out of range in Circuit-id>,,<

Cause:	The controller field in a line-id is out of range. The value
	LD.MAX defines the number of controllers known by D36PAR, and
	thus by NTMAN. The most likely cause of this bug is a trashed
	AC.
				Note:	
	
	A controller is any device driver to which a router will interface.
	It is currently used to define the name of a Circuit/Line,
	under the assumption that each Kontroller will control only
	a single line type.

>,RTN)
;WE KNOW THAT ALL DEVICE NAMES ARE AT MOST 4 BYTES LONG, AND THUS FIT IN A WORD
	HRLI T2,(POINT 7,)	;WE STORE THE DATA IN 7 BIT BYTES INTERNALLY
	HRRI T2,KONNAM(T1)	;GET POINTER TO DEVICE NAME
NMXC20:	ILDB T1,T2		;GET A BYTE FROM THE DEVICE NAME
	JUMPE T1,NMXC21		;END OF STRING, FALL THROUGH
	IDPB T1,P2		;SAVE IT IN OUR DESTINATION DATA STRING
	AOJA T6,NMXC20		;INCREMENT NUMBER OF BYTES DEPOSITED
NMXC21:	MOVEI T1,"-"		;SEPERATOR
	IDPB T1,P2		;STORE IT
	AOJ T6,			;COUNT UP CHARACTER
	LOAD T1,LIKON,+P1	;GET THE KONTROLLER NUMBER
	PUSHJ P,NMXC28		;OUTPUT NUMBER IN DECIMAL
IFN FTOPS10,<
	LOAD T1,LIDEV,+P1	;GET THE DEVICE TYPE
	CAXN T1,LD.ETH		;IS IT AN ETHERNET?
	JRST NMXC22		;YES, WE ARE DONE
>; END IFN FTOPS10
	MOVEI T1,"-"
	IDPB T1,P2		;STORE THE SEPARATOR
	AOJ T6,			;INCREMENT NUMBER OF BYTES
	LOAD T1,LIUNI,+P1	;GET THE UNIT NUMBER
	PUSHJ P,NMXC28		;OUTPUT THE NUMBER IN DECIMAL
	JN LILXC,+P1,NMXC22	;Jump if we are not dealing with a CIRCUIT
	LOAD T1,LIDEV,+P1	;GET THE DEVICE TYPE
	CAXE T1,LD.CIP		;IS IT A CI?
	JRST NMXC22		;NO, WE ARE DONE
	MOVEI T1,"."		;OUTPUT SEPERATOR
	IDPB T1,P2		;STORE IT
	AOJ T6,			;AND INCREMENT COUNT
	LOAD T1,LIDRP,+P1	;GET THE DROP NUMBER (PORT ON THE CI)
	PUSHJ P,NMXC28		;AND OUTPUT IT IN DECIMAL
NMXC22:	CAIL T6,^D16		;DID WE DO THIS IN 16 BYTES?
	BUG.(HLT,NTMCNO,NTMAN,SOFT,<Circuit name overrun>,,<

Cause:	More than 16 bytes of data have been returned into a 16 byte field.
	The data beyond the buffer has been trashed.

Action:	Examine the algorithm above to determine why more bytes than 
	expected were returned.  Fix the above code to check for overrun 
	while it is producing the bytes, so that this halt does not occur.
>)
	DPB T6,T5		;STORE NUMBER OF BYTES WE GAVE
	RETSKP

NMXC28:	IDIVI T1,^D10		;SEPERATE INTO DIGITS
	JUMPE T1,NMXC29		;COMPLETED THE SEPARATION, START OUTPUTTING.
	PUSH P,T2		;SAVE DIGIT ON STACK
	PUSHJ P,NMXC28		;RECURSE
	POP P,T2		;GET BACK DIGIT
NMXC29:	ADDI T2,"0"		;MAKE IT INTO AN ASCII DIGIT
	IDPB T2,P2		;DEPOSIT INTO STRING
	AOJ T6,			;INCREMENT NUMBER OF BYTES GIVEN
	RET			;RETURN
	SUBTTL Entities -- Convert name to Circuit-ID.
;NMXN2C - Convert a string to line id
;Call
;	T1/ Byte pointer to name
;Return
;	+1, No such circuit
;	+2, t1/ Circuit ID

NMXN2C:
	SAVEAC <P1,P2>		;WORK REGISTERS
	MOVE P1,T1		;SAVE BYTE POINTER TO NAME
	MOVE T6,[POINT 7,T2]	;BYTE POINTER TO COPY NAME
	MOVEI T5,5		;MAX OF 5 BYTES (ONE WORD)
	ILDB T4,P1		;GET NUMBER OF BYTES IN THIS STRINGID
	SETZB T2,P2		;CLEAR OUT DESTINATION, AND CIRCUIT ID
NMXN20:	SOJL T4,NTEINI		;TERMINATED TOO SOON. INVALID
	ILDB T1,P1		;GET A BYTE
	CAIL T1,140		;IS IT LOWER CASE?
	SUBI T1,40		;YES, MAKE IT UPPER CASE
	CAIN T1,"-"		;DID IT INCLUDE THE DASH?
	 JRST NMXN21		;YES, STOP HERE.
	IDPB T1,T6		;SAVE IN COPYING STRING
	SOJG T5,NMXN20		;GET ANOTHER BYTE
	ERRRET NTEINI		;ILLEGAL NAME, GIVE UNRECOGNIZED COMPONENT
NMXN21:	MOVEI T1,LD.MAX		;MAXIMUM KONTROLLER DEVICE NUMBER
NMXN22:	CAMN T2,KONNAM(T1)	;IS THIS THE CONTROLLER WE CARE ABOUT?
	 JRST NMXN23		;YES, EXIT
	SOJGE T1,NMXN22		;TRY FOR NEXT KONTROLLER DEVICE NUMBER
	ERRRET NTEINI		;ILLEGAL NAME
NMXN23:	STOR T1,LIDEV,+P2	;STORE IN CIRCUIT ID WE ARE BUILDING
	CALL NMXN28		;GET A NUMBER FROM THE STRING
	STOR T1,LIKON,+P2	;STORE AS KONTROLLER NUMBER IN CIRCUIT ID
	CALL NMXN28		;GET THE NEXT NUMBER FROM THE STRING
	STOR T1,LIUNI,+P2	;SAVE UNIT NUMBER
	CALL NMXN28		;GET NEXT NUMBER (IF ANY)
	STOR T1,LIDRP,+P2	;SAVE AS DROP NUMBER (PORT ON CI)
	MOVE T1,P2		;GET THE CIRCUIT ID WE JUST BUILT
	RETSKP			;RETURN SUCCESS.

NMXN28:	SETZ T1,		;CLEAR DESTINATION NUMBER
NMXN29:	SOJL T4,RTN		;NO MORE BYTES, RETURN
	ILDB T2,P1		;GET NEXT DIGIT
	CAIL T2,"0"		;RANGE
	CAILE T2,"9"		; CHECK
	RET			;NOT A DIGIT
	SUBI T2,"0"		;CONVERT TO NUMBER
	IMULI T1,^D10		;SHIFT ORIGINAL NUMBER
	ADD T1,T2		;ADD IN CURRENT DIGIT
	JRST NMXN29		;AND GET ANOTHER DIGIT

	SUBTTL Layers -- Main interface to layer levels
;NMXLAY - Call layer-level routine, to get/set value.
;CALL
;	T1/ NMX Function Code
;	T2/ NFWBLK - NMX Interface argument block
;	T3/ Routine Index value from Parameter Table Entry (NTROU)
;	NMXVAR/ NX block
;	NT/ Pointer to STENT part of NT block
;Return
;	RET			;on error, NXERR has code
;	RETSKP			;
;				
NMXLAY:
	SETZRO NXNIL,+NMXVAR	;CLEAR THE "I DIDN'T DO ANYTHING" FLAG
	CAXGE T3,NMXMAX		;RANGE CHECK
	CAXGE T3,NMXMIN
	BUG.(CHK,NTMDVI,NTMAN,SOFT,<NMXDSP value illegal>,,<

Cause:	There will be a call to a "layer" to obtain or set a value for
	an item. The routine value in the descriptor block pointed
	to by NT is illegal.

Action:	Examine the data structure pointed to by NT. In all probability
	this is caused by a trashed NT, since the descriptor block
	generation macros are supposed to range check this value.

Note:	A "layer" is any routine described at NMXDSP.
>,NTEMPE)
	CALLRET @NMXDSP(T3)	;CALL LAYER-LEVEL ROUTINE

	SUBTTL Events -- Interface layer / NMX (NMXEVT)

;NMXEVT is the interface routine between a layer and the event logger.
;
;Context: interrupt or scheduler level
	XRESCD
;
;Arguments:
;	T1/ function code
;	T2/ function dependent argument
;
;Returns (depends on function):
;	+1 indicates that the function could not be successfully completed
;	+2 success

	XRESCD
NMXEVT:

;Verify the function code
	CAIL T1,EV.GEC		;Function code within range?
	CAILE T1,EV.SIG
	BUG.(CHK,NTMEFO,NTMAN,SOFT,<Event function out of range>,,<

Cause:	The event function supplied by a DECnet layer to NMXEVT was
	out of range.

Action:	Make callers of NMXEVT supply the correct function code
>,RTN)

;Dispatch to appropriate routine
	CALLRET	<-EV.GEC>+@[	;Dispatch according to function code
		IFIW <EVGEC&777777> ;Get EC block
		IFIW <EVREC&777777> ;Release EC block
		IFIW <EVFIL&777777> ;Filter an event
		IFIW <EVLOG&777777> ;Log an event
		IFIW <EVSIG&777777>](T1) ;Log a signal

	SUBTTL Events -- NMXEVT -- EVGEC (Get EC block)

;EVGEC allocates an EC block
;
;Input: none
;Return: +1 if no memory, no EC block allocated
;	 +2 with T1/ address of EC block

;Resident...

EVGEC:	MOVX T1,EC.LEN		;Length of EC block
	CALLRET DNGWDZ		;Get chunk of zero words and propagate return
				; from memory allocator

	SUBTTL Events -- NMXEVT -- EVREC (Release Ec block)

;EVREC releases an EC block
;
;Input: T2/ address of EC block
;Returns: +2 always

;Resident...

EVREC:

;Unless ECCNT is non-zero (i.e. there is a NE block on queue pointing back
; to this EC block) it is OK to release the memory. In the case of ECCNT
; non-zero, the ECDEL bit is set to indicate to NTEVQ that the EC block
; should be deallocated when ECCNT goes to zero.
	MOVE T1,T2			;T1 := ^EC
	OPSTR <SKIPG>,ECCNT,(T1)	;ECCNT greater than zero?
	IFSKP.				; -yes
	 SETONE ECDEL,(T1)		;  Set ECDEL flag
	ELSE.				; -no, all OK
	 CALL DNFWDS			;  Deallocate memory
	ENDIF.
	RETSKP

	SUBTTL Events -- NMXEVT -- EVFIL (Filter an event)

;EVFIL filters an event
;
;Input: T2/ event code in the following format:
;		FIELD CCL,13	Event class
;		FIELD CTY,5	Event type
;		FILLER 18
;
;Returns: +1	Event should be thrown away
;	  +2	Event should be logged

;Resident...

EVFIL:	SAVEAC <P1>
	MOVE P1,T2		;P1 := event class and type
	LOAD T1,FACCL,+P1	;Get event class
	CALL NTFFIL		;Find filter
	 RET			; -not there, throw away event
	LOAD T2,FACTY,+P1	;Get event type
	MOVX T3,1		;Load a 1 into test word
	LSH T3,(T2)		; and shift into position
	TDNN T3,NMXFIL(T1)	;Is bit set in filter mask?
	 RET			; -no, throw away
	RETSKP			;-yes, keep event

;NTFFIL - find index of event class in filter table (NMXFIL)
;
;Call with: T1/ event class
;Returns:   +1/ did not find event class in table
;	    +2/ T1/ index of filter in table
;
NTFFIL:	;Ac usage: T1/ event class, T2/ moving index
	SETZ T2,		;Start at index 0 in table
	DO.			;Loop over all event classes
	  SKIPGE NMXFIL(T2)	;  At end of list?
	  RET			;   -yes, return 'not found'
	  HLRZ T3,NMXFIL(T2)	;  Get low bound
	  HRRZ T4,NMXFIL(T2)	;   and high bound
	  CAML T1,T3		;  Is event class in interval?
	  CAMLE T1,T4
	  IFNSK.		;    -no, step to next event class interval
	    SUB T4,T3		;     Find out # of entries to step over
	    ADDI T4,2		;     Dont forget the interval word
	    ADD T2,T4		;     Add to current index
	    LOOP.		;      and loop back
	  ELSE.			;    -yes, in interval
	    MOVE T4,T1		;     Calculate matching index
	    SUB T4,T3
	    AOJ T4,
	    ADD T4,T2
	    MOVE T1,T4		;     and put it in T1
	    EXIT.		;     Exit DO loop to exit routine
	  ENDIF.
	ENDDO.
	RETSKP			;   Return 'found'

	SUBTTL Events -- NMXEVT -- EVLOG (Log an event)

;EVLOG logs an event
;
;Input:	T2/ NE block
;	Note: The NE block must contain a valid pointer to the EC block
;
;Returns: +2 always

;Resident...

EVLOG:	SAVEAC <P1,P2>		;Ac usage: P1/ NE block, P2/ EC block
	MOVE P1,T2		;P1 := ^NE
	LOAD P2,NEECP,(P1)	;P2 := ^EC
	CALL DNGTIM		;Get system time
	STOR T1,NETIM,(P1)	;Store for future conversion to julian time
	D36OFF			;Turn off interrupts
	CALL EVLOG1		;Call coroutine that does the work
	IFNSK.			; No-skip means event lost; deallocate it
	  D36ON			; First turn on interrupts
	  MOVE T1,P1		; Get ^NE
	  CALL EVRNE		; Call EVRNE to release NE block
	  RETSKP		; Always success return
	ENDIF.
	D36ON			;Skip means NE block now on queue
	MCALL (RG,MSEC1,PSIDVT)	;Give a PSI if someone wiating
	RETSKP
;EVLOG1 - EVLOG worker routine
;
;Called with D36OFF
;
;Input:
; P1/ ^NE block
; P2/ ^EC block
;
;Output:
; +1 lost event, deallocate it
; +2 do not deallocate event
;
;Local AC use:
; T4/ count of entries on queue

EVLOG1:

; if ECLOS gtr 0 then lose_event
	JN ECLOS,(P2),EVLOGL	;If ECLOS non-zero, lose this one too

; if NMXECN = NMXELN then lose_event
	LOAD T4,QHCNT,+NMXEVQ	;Get current # of entries in queue
	CAIL T4,NMXELN		;Compare with max length of queue
	JRST EVLOGL		;Lose event

; if ECCNT geq ECMAX
	LOAD T1,ECCNT,(P2)
	OPSTR <CAMGE T1,>,ECMAX,(P2)
	IFSKP.			; ... then
	  SKIPE NMXELO		;  if NMXELO = true
	  JRST EVLOGL		;    then lose event
	  CALL EVLOGM		;    else lose event and make lost event
	ELSE.			; ... else
	  CAIE T4,<NMXELN-1>	;   if queue length = queue max - 1
	  IFSKP.		;    then
	    SKIPE NMXELO	;      and NMXELO is false
	    ANSKP.
	      CALL EVLOGM	;      lose event and make lost
	  ENDIF.
	ENDIF.
;Queue NE block
	ENDQUE P1,NMXEVQ,NE.NXT,T1
;Increment ECCNT
	INCR ECCNT,(P2)
;Return with queued block
	RETSKP
;EVLOG support routines
;

;Resident...

;EVLOGL - called to lose event and return
EVLOGL:	INCR ECLOS,(P2)		;Increment # of lost events
	RET			;No-skip to deallocate NE block

;EVLOGM - called to remake event to "lost event"
; The event will then be queued as an "ordinary event"
EVLOGM:	INCR ECLOS,(P2)		;Increment # of lost events
	SETZRO NECCL,(P1)	;Event class := 0
	SETZRO NECTY,(P1)	;Event type := 0
	SETONE NEETP,(P1)	;Entity type := no entity
	SETZRO NEDLN,(P1)	;Data length := 0
	SETOM NMXELO		;And now is NMXELO true
	RET
;EVRNE - release NE block. Called on "lost event" or when event is copied
; to user (NTEVQ).
;
; T1/ ^NE block

;Resident...

EVRNE:	LOAD T2,NECBK,(T1)	;Get callback address
	SKIPN T2		;Was one supplied?
	IFNSK.			; -no, use default
	  CALLRET DNFWDS	;  DECnet deallocator
	ELSE.
	  CALL (T2)		; -yes, call users routine
	   JFCL			;  Ignore no-skip
	ENDIF.
	RET			;Return

	SUBTTL Events -- NMXEVT -- EVSIG (Log a signal)

;EVSIG signals an event
;
;Input: T2/ NE block
;
;Returns: +2 always

;Resident...

EVSIG:	SAVEAC <P1,P2>		;Ac usage: P1/ NE block, P2/ EC block
	MOVE P1,T2		;P1 := ^NE
	LOAD P2,NEECP,(P1)	;P2 := ^EC
	CALL DNGTIM		;Get system time
	STOR T1,NETIM,(P1)	;Store for future conversion to julian time
;Turn off interrupts
	D36OFF
;Verify that there is room in the signal queue
	LOAD T1,QHCNT,+NMXSIQ	;Get current count
	CAIL T1,NMXSLN		; and compare with max allowed
	BUG.(INF,NTMSQF,NTMAN,SOFT,<Signal queue full>,,<

Cause:	The signal queue was full when a new signal was logged.
	This might be caused by a malfunctioning NMLT20 that does not
	read the signals from the signal queue, or it may be caused by
	a DECnet device driver going bad.  A signal is used to tell
	NMLT20 that a device needs attention/reload.

Action:	Restart NMLT20, or turn off malfunctioning DECnet device.
	If necessary, reload any devices by hand
>,EVSIG2)

;If no BUGCHK, come here and insert event into signal queue
	ENDQUE P1,NMXSIQ,NE.NXT,T1
EVSIG1:	D36ON			;Turn on interrupts
	MCALL (RG,MSEC1,PSIDVT)	;Give a PSI if someone waiting
	RETSKP

EVSIG2:	D36ON			;Turn on interrupts
	MOVE T1,P1		;Get pointer to NE block
	CALL EVRNE		;Release NE block
	RETSKP

;End of resident code
	XSWAPCD

IFN FTDEBUG <
	SUBTTL Events -- .NTTEV function (Test event logger)

;Called from NMXDIS

;The .NTTEV function tests the event logger and uses the ET structure

NTTEV:	SAVEAC <P1,P2,MB,MS>

; P1/ ^NE block, P2/ ^EC block, MS/ ^ET block, MB/ count of events to do

;Get ET block
	MOVX T1,ET.LEN
	CALL DNGWDZ
	ERRRET NTERES
	MOVE MS,T1

;Copy from user argument block to our ET block
;
;T1/ ^user argument
;T2/ rolling index
	UMOVE T1,1
	UMOVE T1,.NTSEL(T1)
	SETZ T2,
	DO.
	  CAIL T2,ET.LEN	;Through copying?
	  EXIT.			; -yes,exit
	  MOVE T3,T1
	  ADD T3,T2
	  UMOVE T4,(T3)		;Get user word
	  ERJMP [	MOVE T1,MS 	;On illegal read, return MS block
			CALL DNFWDS
			ERRRET NTEADC 	;Give "address check"
		]
	  MOVE T3,MS
	  ADD T3,T2
	  MOVEM T4,(T3)		;Store in ET block
	  AOJ T2,
	  LOOP.
	ENDDO.
	LOAD MB,ETCNT,(MS)	;Get count of events to do

;Get EC block
	MOVX T1,EV.GEC		;Get EC block
	CALL NMXEVT
	IFNSK.
	  MOVE T1,MS
	  CALL DNFWDS
	  ERRRET NTERES
	ENDIF.
	MOVE P2,T1
	MOVX T1,2		;Allow 2 events on queue
	STOR T1,ECMAX,(P2)

;Get NE block
NEGET:	MOVX T1,NE.LEN
	ADDI T1,<44/4>		;Add data string
	CALL DNGWDZ
	IFNSK.
	  MOVX T1,EV.REC	;Release EC block
	  MOVE T2,P2
	  CALL NMXEVT
	   JFCL
	  MOVE T1,MS
	  CALL DNFWDS
	  ERRRET NTERES
	ENDIF.
	MOVE P1,T1		;P1 := ^NE

;At this point all blocks are allocated, and the user arguments have been
; copied to our ET block

;Copy data to NE block
	STOR P2,NEECP,(P1)	;Store EC pointer
	LOAD T1,ETCCL,(MS)	;Get event class
	STOR T1,NECCL,(P1)
	LOAD T1,ETCTY,(MS)	;Get event type
	STOR T1,NECTY,(P1)
	LOAD T1,NXENT,+NMXVAR	;Get entity type
	STOR T1,NEETP,(P1)
	LOAD T1,NXNUM,+NMXVAR	;Get entity ID
	STOR T1,NEEID,(P1)
	LOAD T1,ETDLN,(MS)	;Get data length
	STOR T1,NEDLN,(P1)
	XMOVEI T1,NE.DAT(P1)	;Get address of data string
	AOJ T1,
	STOR T1,NEDAT,(P1)
;Copy the string also
	LOAD T1,ETDLN,(MS)	;Get string length
	MOVSI T2,(POINT 8,0)	;Byte pointer
	TDO T2,[1B12]		;Make it global...
	XMOVEI T3,ET.DAT(MS)	;Get source address
	DMOVE T4,T1		;Duplicate T1-T2
	LOAD T6,NEDAT,(P1)	;Get destination address
	EXTEND T1,[MOVSLJ]	;"Move string left justified"
	 JFCL			;Ignore error

;Now log or signal the event
	MOVX T1,EV.SIG		;Assume signal
	OPSTR <SKIPE>,ETSIG,(MS)
	IFSKP.			;No, it was "ordinary" event
	  SETZ T2,		;Clear word to receive argument
	  LOAD T1,NECCL,(P1)	;Get event class
	  STOR T1,FACCL,+T2
	  LOAD T1,NECTY,(P1)	;Get event type
	  STOR T1,FACTY,+T2
	  MOVX T1,EV.FIL	;Filter the event
	  CALL NMXEVT
	  IFNSK.		;Throw away this event
	    MOVE T1,P1
	    CALL DNFWDS		;Release NE block
	  ELSE.
	    MOVX T1,EV.LOG	;Log event
	    MOVE T2,P1
	    CALL NMXEVT
	     JFCL
	  ENDIF.
	ELSE.
	  MOVE T2,P1
	  CALL NMXEVT
	   JFCL
	ENDIF.

;Check count
	SOJG MB,NEGET		;More to do?

;No, deallocate EC and ET blocks
	MOVX T1,EV.REC
	MOVE T2,P2
	CALL NMXEVT
	 JFCL

;And ET block too
	MOVE T1,MS
	CALL DNFWDS
	
;Everything done, return success
	RETSKP

>

	SUBTTL Events -- .NTSLM function (Set global logging mask)

;Called from NMXDIS

;The .NTSLM function sets/changes the global logging masks in NTMAN.
;The event class to set is in word .NTSEL, and the new filter in word .NTQUA.

NTSLM:	SAVEAC <P1>
	UMOVE P1,1		;P1 := user ^argblk
	UMOVE T1,.NTSEL(P1)	;Get event class
	CALL NTFFIL		;Find the filter
	ERRRET NTEPNA		;Say 'parameter not applicable'
;Index of matching entry is now in T1
	UMOVE T2,.NTQUA(P1)	;Get event filter
	TXZ T2,17B3		;Clear bits 0-3 (BLISS bits 33-36)
	MOVEM T2,NMXFIL(T1)	;Store new filter
	RETSKP			;Give success return
	SUBTTL Events -- .NTPSI function (Set event PSI channel)

;Called from NMXDIS

;The .NTPSI sets the PSI channel for "events available" interrupts. TOPS-10
; uses another mechanism to set event interrupts, so the following routine is
; Tops-20 only.
;
; The PSI channel is in word .NTSEL

NTPSI:

IFN FTOPS10,<ERRRET NTEUFO>	;NOT IN TOPS10

IFN FTOPS20,<
       	SKIPN T1,EVRFRK		;SOMEONE ALREADY DOING THIS?
	IFSKP.
	   HRRZS T1		;YES, GET HIS ID
	   CAME T1,FORKX	;IS HE RESETTING?
 	   S1XCT <ITERR (NTMX2)>;Return "Event facility already in use"
	ENDIF.
	LOAD T1,NXSEL,+NMXVAR	;Get users PSI channel from .NTSEL
	CAME T1,[-1]		;DOES HE STILL WANT TO BE NOTIFIED?
	IFSKP.
	   SETZM EVRFRK		;NO, NO MORE EVENT READER
	ELSE.
	   CAIL T1,0		;YES, CHECK FOR
	   CAILE T1,^D36	; LEGAL PSI CHANNEL
	   ERRRET NTEMPE	;  -not legal, give 'management program error'
	   AOS T1		;FIX IT FOR INTERNAL USE
	   HRLM T1,EVRFRK	;SET IT UP
	   MOVE T1,FORKX	;GET USER
	   HRRM T1,EVRFRK	;SET IT UP
	   SKIPE NMXEVQ		;IS THERE ANYTHING IN THE QUEUE ?
	   CALL NMLEVT		;YES. GIVE INTERRUPT.
	ENDIF.
	RETSKP


;KILL THE EVENT READER (CALLED FROM .RESET AND KSELF)
;RETURNS:	+1

;Resident ? (To be checked in future/GL)
	XRESCD

	XRENT EVRKIL
	HRRZ T1,EVRFRK		;GET THE EVENT LOGGER
	CAMN T1,FORKX		;IS IT US?
	SETZM EVRFRK		;YES, NO MORE EVENT READER
	RET			;NO, NOTHING TO DO

;GIVE THE EVENT READER A PSI
;CALLED FROM LV8CHK

;This must be resident

	XRESCD
NMLEVT:	SETZM NMLPSI		;CLEAR THE FLAG
	HLRZ T1,EVRFRK		;GET PSI CHANNEL
	JUMPE T1,RTN		;IF THERE IS ONE.
	SOS T1			;THERE IS. MAKE IT REAL.
	HRRZ T2,EVRFRK		;GET EVENT READER FORK
	XCALLRET (MSEC1,PSIRQ)	;LET HIM KNOW

;ASSERT EVENT PSI FOR SCHEDULER TO CATCH
;MAY BE CALLED AT ANY LEVEL.
;CALL PSIDVT
;RETURNS +1 ALWAYS
	XRESCD			;MUST BE RESIDENT

PSIDVT:	SETOM NMLPSI  		;SET FLAG FOR SCHEDULER.
	RET

;No more resident code
	XSWAPCD


>;END IFN FTOPS20

	SUBTTL Events -- .NTEVQ function (Pass queued event to user)

;Called from NMXDIS

;Writes next event to user buffer. If there are no events on queue,
; a zero length is indicated to the user.

;Must be resident since D36OFF is done
	XRESCD

NTEVQ:	SAVEAC <P1,P2>		;Ac usage: P2/ ^NE block

;Turn off interrupts and call routine to get next event.
	D36OFF
	CALL NTEVQN		;Pull next event off queues
	IFNSK.			;No-skip indicates no event on queue
	  D36ON			;  Turn on interrupts
	  RETSKP		;  Do success return, higher layer will write
	ENDIF.			;   0 into the "number of bytes returned" field
	D36ON			;Turn on interrupts on success return
	JRST NTEVQ1		;Proceed in swappable code

	XSWAPCD
;Come here with T1/ ^NE block
NTEVQ1:	MOVE P2,T1		;P2 := ^NE

;Now "build" a NQ block in the users buffer, i.e.
;	B:2	event class and type
;	3*B:2	julian day, second and millisecond
;	B:2	entity type
;	B:n	entity ID
;	B:m	m bytes of event data

;Event class and type
	LOAD T1,NECCL,(P2)	;Get event class
	ASH T1,6		;Shift over to make room for type
	OPSTR <IOR T1,>,NECTY,(P2) ;Or in event type
	CALL PUT2BT		;Put to user
	 RET			;error...

;Julian day, second and millisecond
	LOAD T1,NETIM,(P2)	;Get system time stored
	STKVAR <SEC,MSC>	;Two local variables
	CALL NMXTIM		;Convert to julian time
	MOVEM T2,SEC		;Save julian seconds
	MOVEM T3,MSC		;Save julian milliseconds
	CALL PUT2BT		;Put julian 1/2day to user
	 RET			;error...
	MOVE T1,SEC
	CALL PUT2BT		;Put julian seconds to user
	 RET			;error...
	MOVE T1,MSC
	CALL PUT2BT		;Put julian milliseconds to user
	 RET			;error...

;Now put entity type and entity ID
	LOADE T1,NEETP,(P2)	;Get entity type
	CALL PUTBYT		;Put to user
	 RET			;error...

	LOADE T1,NEETP,(P2)	;Get entity type again
	CAXE T1,.NTNOD		;Is it node?
	IFSKP.			; -yes
	  LOAD T1,NEEID,(P2)	; Get entity ID (node number)
	  CALL PUT2BT		; Put # in user buffer
	   RET			;error...
	  SETZ T1,		; Zero length node name
	  CALL PUTBYT		; Put length byte to user
	   RET			;error...
	ELSE.			; -no, not node entity
	  CAXE T1,.NTCKT	;   Is it circuit
	  CAXN T1,.NTLIN	;   or a line?
	  IFNSK.		;     -yes, it was
	    LOAD T1,NEEID,(P2)	;      Get entity ID
	    MOVE T2,[POINT 8,NX.VAL+NMXVAR] ;Where to store circuit/line string
	    CALL NMXC2N	;      Convert id to a name
	     JRST NTEMPE	;      Error!
	    XMOVEI P1,NX.VAL+NMXVAR ;  Load pointer to string containing name
	    CALL PUTSTR	;      Copy string to user space
	     RET		;error...
	  ELSE.			;     -not circuit or line ID
	    AOJ T1,		;      Maybe 'NO ENTITY' (elevenish -1)
	    TRNE T1,<<377_8>+377> ;    Is it?
	      BUG.(CHK,NTMORE,NTMAN,SOFT,<Unrecognized entity type>,,<

Cause:	An event was received from a DECnet layer, and the entity type
	is not legal.

Action:	Find the routine that logged the event, and change it to
	a legal entity type.
>,NTEMPE)
	  ENDIF.
	ENDIF.

;Now copy data string to user buffer
	SAVEAC <MB>
	LOAD NT,NEDLN,(P2)	;Count in NT
	LOAD MB,NEDAT,(P2)	;Address of string to MB
	MOVE P1,[POINT 8,(MB)]	;Do it this way to get intersection copy
	DO.
	  SOSGE NT		;Any more bytes?
	    EXIT.		;  -no
	  ILDB T1,P1		;Get next byte
	  CALL PUTBYT		; and give it to user
	   RET			;error...
	  LOOP.
	ENDDO.
	
;Now the NE block has been copied to the user buffer, deallocate the NE block
; and then return successfully
	MOVE T1,P2		;EVRNE wants pointer in T1
	CALL EVRNE
	RETSKP
;NTEVQN - extract next event from queue
;
;Called with D36OFF, so must be resident
	XRESCD
;
;Returns: +1 	No events on queue
;	  +2	T1/ ^NE block

NTEVQN:	SAVEAC <P1,P2>		;P1/ ^NE block, P2/ ^EC block

;Try dequeue an event from the signal queue
	DEQUE T1,NMXSIQ,NE.NXT,NTEVQM ;Dequeue into T1
	RETSKP			;Success, return

;NTEVQM - try to extract event from the event queue
NTEVQM:	DEQUE P1,NMXEVQ,NE.NXT,RTN ;Just return if nothing available

;Come here with P1/ ^NE block
	LOAD P2,NEECP,(P1)	;P2 := ^EC

;Is this an events lost?
	LOAD T1,NECCL,(P1)	;Get event class
	LOAD T2,NECTY,(P1)	; and event type
	SKIPN T1		;Is event class = 0
	SKIPE T2		; and event type = 0
	SKIPA			; -no, skip next instruction
	SETZM NMXELO		; -yes, flag no "events lost" on queue any more
;Decrement ECCNT by one; and if it went to zero there may be things to do
	DECR ECCNT,(P2)
	OPSTR <SKIPE>,ECCNT,(P2) ;Did it go to zero?
	IFSKP.			; -yes
	  ;Code may go here to generated "events were lost event"
	  ;
	  SETZRO ECLOS,(P2)	;No more lost events now
	  ;If ECDEL is set, then deallocate the EC block
	  OPSTR <SKIPN>,ECDEL,(P2) ;Set?
	  IFSKP.		;    -yes
	    MOVE T2,P2
	    CALL EVREC
	     JFCL
	  ENDIF.
	ENDIF.
;Put NE address in T1, and return skip to indicate that there was an event
	MOVE T1,P1
	RETSKP

;End of resident code
	XSWAPCD

	SUBTTL User strings -- Write parameter with nice
;NMXWTY - Write a parameter to the user data string, including NICE
;	headers such as DATA ID and DATA TYPE
;Call
;	NT/ Pointer to STENT part of NT block
;	NXVAL,+NMXVAR/ Value obtained from NMXLAY
;	
;Return
;	RET			;On error, NXERR has error code
;	RETSKP			;when done, maybe with stuff in user string
;

NMXWTY:
	JN NXNIL,+NMXVAR,RSKP	;If Layer didn't know about him, ignore it.
	JE NXWUS,+NMXVAR,RSKP	;IF NOT WRITING TO THE USER, RETURN
	SETZ T1,		;START OFF WITH A CLEAN HEADER DUO-BYTE
	LOAD T2,NTSEQ,(NT)	;GET SEQUENCE NUMBER OF PARAMETER
	IOR T1,T2		;OR INTO HEADER DUO-BYTE
	CALL PUT2BT		;PUT 2 BYTES OF HEADER INTO USER DATA STRING
	 RET			;error...
NMXWT3:	LOAD T1,NTTYP,(NT)	;GET DATA TYPE OF THIS PARAMETER
	CAXL T1,NT.FC		;IS IT LESSER THAN SIMPLE CODED?
	CAXLE T1,NT.FCN		;OR GREATER THAN ASCII CIRCUIT NAME?
	BUG.(CHK,NTMFOR,NTMAN,SOFT,<Format out of range>,,<

Cause:	While formatting output for a show, the format block for
	this item has been found to have an illegal format type.
>,NTEMPE)
	CALLRET @.+1-NT.FC(T1)
	  IFIW <NMXWCD&777777>	;ORDINARY CODED. HANDLE AS INTEGER
	  IFIW <RSKP&777777>	;CODED MULTIPLE IS HANDLED AT ANOTHER LEVEL
	  IFIW <RSKP&777777>	;ASCII IMAGE. HANDLED AT ANOTHER LEVEL
	  IFIW <NMXWNU&777777>	;DECIMAL UNSIGNED
	  IFIW <NMXWNU&777777>	;DECIMAL SIGNED.
	  IFIW <NMXWNU&777777>	;HEXADECIMAL INTEGER.
	  IFIW <NMXWHI&777777>	;HEX IMAGE. BYTE STRING
	  IFIW <NMXWNU&777777>	;OCTAL
	  IFIW <NMXWNM&777777>	;MILLISECONDS
	  IFIW <NMXWVN&777777>	;VERSION NUMBER
	  IFIW <NMXWNE&777777>	;NODE ENTITY ID
	  IFIW <NMXWNN&777777>	;NODE NAME
	  IFIW <NMXWCN&777777>	;WRITE CIRCUIT NAME

	SUBTTL User strings -- Write coded data
;NMXWCD - Write coded info to user data string
;Call
;	NT/ Pointer to format block
;Return
;	RET			;Error, code is in NXERR
;	RETSKP			;data type byte and data are in user string
;

NMXWCD:
	SAVEAC <P1,P2>		;GET SOME WORK AREA
	LOAD T1,NTLEN,(NT)	;GET SIZE OF FIELD
	CAIE T1,1		;WE ONLY HAVE SINGLE BYTE CODEDS. (**HACK**)
	 BUG.(CHK,NTMBCF,NTMAN,SOFT,<Bad coded field on output>,,<

Cause:	Output for a SHOW is being formatted, and there has been a request
	to generate a CODED field of more than one byte. This can't be 
	done.

Action:	Look at the descriptor block pointed to by NT. Check to see if
	this item is supposed to be a multiple byte coded. If not, fix
	the item's entry. If it is correct, you are going to have to write
	the code to handle multiple byte codeds.
>,NTEMPE)
	TXO T1,NT.CNM		;INDICATE CODED NON MULTIPLE (PP 148 OF NM)
	CALL PUTBYT		;DEPOSIT DATA TYPE BYTE IN USER STRING
	 RET			;error
	LOAD T1,NFBUF,+NFWBLK	;GET THE CODED VALUE TO OUTPUT
	CALLRET PUTBYT		;PUT THE BYTE IN THE OUTPUT STRING, AND RETURN



	SUBTTL User strings -- Write ascii image data
;NMXWNN - Write ASCII image Node Name data to user data string
;Call
;	NT/ Pointer to format block
;	NF.BUF contains sixbit node name
;Return
;	RET			;Error, code is in NXERR
;	RETSKP			;Data type byte and data are in user string

NMXWNN:
	SAVEAC <P1,P2>
	MOVX T1,NT.AI		;Non-coded, ASCII image data
	CALL PUTBYT		;Store data type byte
	 RET			; -error
	MOVE P1,[POINT 6,NF.BUF+NFWBLK]	;Byte pointer to stringid with value

;Make a first pass over sixbit string since we need the count first
	MOVE T1,P1		;Get byte pointer
	MOVEI T2,6		;Max 6 chars in a node name
	DO.			;LOOP
	  ILDB T3,T1		;  Get next byte
	  SKIPE T3		;  Empty?
	  SOJG T2,TOP.		;   or out of bytes?
	ENDDO.			;    - yes, come here with T1 = remaining bytes
	MOVEI T1,6		;Get max # of bytes again
	SUB T1,T2		; and get # of bytes to write
	MOVE P2,T1		;Remember # of bytes to write
	CALL PUTBYT		;Output that
	 RET			; -error
	DO.			;LOOP again
	  SOSGE P2		;  Any more bytes to do?
	  EXIT.			;  -no, all done
	  ILDB T1,P1		;  Get byte
	  ADDI T1,^O40		;  and make ASCII
	  CALL PUTBYT		;  Dump it to user
	   RET			;   -error
	  LOOP.			;  And go back
	ENDDO.
	RETSKP

NMXWCN:
	SAVEAC <P1,P2>		;GET SOME WORK AREA
	LOAD T1,NFBUF,+NFWBLK	;Get the returned Circuit/Line Id word
	MOVE T2,[POINT 8,NX.VAL+NMXVAR] ;A temporary place to write CN
	CALL NMXC2N		;Convert Circuit Id to Name
	 JRST NTEMPE		;Weird error!!!!!!!!!!!!!
	MOVX T1,NT.AI		;NON-CODED, ASCII IMAGE DATA
	CALL PUTBYT		;STORE DATA TYPE BYTE
	 RET			;error
	MOVE P1,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO STRINGID WITH VALUE
	ILDB T1,P1		;GET FIRST BYTE, WHICH IS SIZE
	MOVE P2,T1		;COPY SIZE, TO COUNT DOWN BYTES
NMXWC2:	CALL PUTBYT		;PUT IT IN USER DATA STRING
	 RET
	ILDB T1,P1		;GET NEXT BYTE
	SOJGE P2,NMXWC2		;DECREMENT COUNT, IF ANY BYTES LEFT, DO THEM
	RETSKP			;DO A GOOD RETURN
	

	SUBTTL User strings -- Write hexidecimal image data
;NMXWHI - Write HEXIDECIMAL image data to user data string
;Call
;	NT/ Pointer to format block
;	NFWBLK/ Argument Block returned from Layer
;		NFBPT/ Byte pointer to start of Hexidecimal number
;		NFBYT/ number of bytes in number
;Return
;	RET			;Error, code is in NXERR
;	RETSKP			;data type byte and data are in user string

NMXWHI:
	SAVEAC <P1,P2,P3>	;GET HOME WORK AREA
	MOVX T1,NT.HI		;NON-CODED, HEXIDECIMAL IMAGE DATA
	CALL PUTBYT		;STORE DATA TYPE BYTE
	 RET			;Error return
	LOAD P3,NFBUF,+NFWBLK	;Get the buffer address into P1
	MOVE P1,[POINT 8,(P3)]	;Point at the buffer.
	MOVEI P2,6		;Get the number of bytes in the number
	MOVE T1,P2		;copy size and...
NMXWH2:	CALL PUTBYT		;PUT IT IN USER DATA STRING
	 RET
	ILDB T1,P1		;GET NEXT BYTE
	SOJGE P2,NMXWH2		;DECREMENT COUNT, IF ANY BYTES LEFT, DO THEM
	RETSKP			;DO A GOOD RETURN

	SUBTTL User strings -- Write numeric data
;NMXWNU - Write a numeric value to the user data string
;CALL
;	NMXVAR/ NX block
;	NT/ Pointer to STENT part of NT block
;	NFBUF,+NFWBLK/ Integer to deposit
;RETURN
;	RET			;On error, NXERR contains code
;	RETSKP			;Integer has been placed in data string
;

NMXWNU:	LOAD T2,NTLEN,(NT)	;GET LENGTH IN BYTES OF THIS NUMBER
	LOAD T1,NTTYP,(NT)	;GET FORMAT OF THIS NUMBER
	CAXL T1,NT.FDU		;MAKE SURE THIS IS IN NUMERIC RANGE
	CAXLE T1,NT.FOC		;BETWEEN DECIMAL UNSIGNED AND OCTAL.
	BUG.(CHK,NTMINT,NTMAN,SOFT,<Invalid numeric type>,,<

Cause:	When generating output for a numeric field, something other than 
	Decimal, Hexadecimal or Octal was requested.
>,NTEMPE)
	MOVE T1,<-NT.FDU>+[	;GET NICE TYPE.
		0_3		;DECIMAL UNSIGNED IS FORMAT 0
		1_3		;DECIMAL SIGNED IS FORMAT 1
		2_3		;HEXADECIMAL NUMBER IS FORMAT 2
		-1		;HEX IMAGE DOESN'T COME HERE.
		3_3](T1)	;OCTAL NUMBER IS FORMAT 3
	IOR T1,T2		;OR IN SIZE OF FIELD
	CALL PUTBYT		;PUT THIS BYTE IN USER DATA AS DATA TYPE
	 RET
NMXWCO:	LOAD T2,NTLEN,(NT)	;GET NUMBER OF BYTES FOR COUNTER AGAIN
	LOAD T1,NFBUF,+NFWBLK	;GET VALUE TO RETURN
	CAXL T2,1		;MUST BE AT LEAST ONE BYTE
	CAXLE T2,4		;MAY BE AT MOST 4 BYTES
NMXWCE:	BUG.(CHK,NTMBDL,NTMAN,SOFT,<Bad multiple byte length>,,<

Cause:	While generating output for a numeric field, there has been
	a request to generate an illegal number of bytes.
>,NTEMPE)
	CALLRET @.(T2)
	  IFIW <PUTBYT&777777>	;PUT A SINGLE BYTE
	  IFIW <PUT2BT&777777>	;PUT A DUO BYTE
	  IFIW <NMXWCE&777777>	;DO THREE BYTES. ILLEGAL
	  IFIW <PUT4BT&777777>	;4 BYTES.

	SUBTTL Write out NSP or Routing Version numbers
;NMXWVN - Write out NSP or Routing Version numbers
;
NMXWVN:
	SAVEAC <P1>		;We are going to put the Version # word here
	MOVX T1,NT.CM3		;Going to build a CM-3 Data Type Field
	CALL PUTBYT		;Put it into the string
	 RET			;Error
	MOVX T1,NT.DU1		;Now we are building a DU-1 header
	CALL PUTBYT		;Put it into the string
	 RET
	LOAD P1,NFBUF,+NFWBLK	;Get the value from the Argument Block
	LOAD T1,VNVER,+P1	;Get the Version number
	CALL PUTBYT
	 RET
	MOVX T1,NT.DU1		;Now we are building a DU-1 header
	CALL PUTBYT		;Put it into the string
	 RET
	LOAD T1,VNECO,+P1	;Get the ECO number
	CALL PUTBYT
	 RET
	MOVX T1,NT.DU1		;Now we are building a DU-1 header
	CALL PUTBYT		;Put it into the string
	 RET
	LOAD T1,VNUCO,+P1	;And finally the User ECO number
	CALLRET PUTBYT		;Write out that byte and we are done

	SUBTTL Write out Node Entity Id 
;NMXWNE - We come here to write out the value of parameters which are
;	  Node Ids, such as ADJACENT NODE, DESIGNATED ROUTER, ect...
;	  We have already received the Node Address part of the parameter
;	  from the Routing Layer.  Before we write out anything to the
;	  user buffer, we will check to see if there is enough room in the
;	  buffer for the entire node entity (assuming a six character name).
;	  If not we give up right away, subtract two from the byte count,
;	  because the parameter nmuber has already been stored, and report
;	  a resource error. Then, we will try to get a Node Name from Session
;	  Control.  We will then write out a Coded Multiple entry,
;	  depending on what we have.

NMXWNE:	SAVEAC <P1,P2>		;
	JE NFBFF,+NFWBLK,ONENDE	;If no buffer, Write one Node Entity
	LOAD P2,NFBLN,+NFWBLK	;Get the number of entity Ids in buffer
	JUMPE P2,RSKP		;If none, then return skip
	LOAD P1,NFBUF,+NFWBLK	;Get the buffer address
NMXWN1:	MOVE T1,(P1)		;Put the Node Number into P1
	CALL WRTNDE		;Write out the Node Id to user buffer
	 RET			;Error return
	AOJ P1,			;Update the buffer pointer
	SOSG P2			;Skip if more node numbers in buffer
	RETSKP
	LOAD T1,NTSEQ,(NT)	;Get the Parameter Number again
	CALL PUT2BT		;Need to put it into user buffer for each
	 RET			;entry
	JRST NMXWN1		;Loop until done.

ONENDE:	LOAD T1,NFBUF,+NFWBLK	;Get the node number into T1
	CALL WRTNDE		;Write out the Node Id to user buffer
	 RET			;Error return
	RETSKP

;
;	Write Out a Node Entity Id to the user Buffer
;CALL
;	T1/	Node Number
;
;
WRTNDE:	SAVEAC <P1,P2>		;
	MOVE P1,T1		;Get the Node Address
	CALL GETNDN		;Try to get Node Name from SCLINK
	 JRST NONAME		;No name mapped in SCLINK
	CALL NMXS2A		;Convert SIXBIT name to ASCII, store it
	MOVX T1,NT.CM2		;Get the CM-2 header
	CALL PUTBYT
	 RET
	MOVX T1,NT.DU2		;Get the DU-2 Header byte
	CALL PUTBYT		;
	 RET
	MOVE T1,P1		;Get the Node address back
	CALL PUT2BT		;Put it into the User string
	 RET
	MOVX T1,NT.AI		;Get the AI-6 header byte
	CALL PUTBYT		;
	 RET
	XMOVEI P1,NX.VAL+NMXVAR	;Get address of ASCII Image string
	CALL PUTSTR		;Write it to the user buffer
	 RET
	RETSKP

NONAME:	MOVX T1,NT.CM1		;Get the CM-1 header
	CALL PUTBYT
	 RET
	MOVX T1,NT.DU2		;Get the DU-2 Header byte
	CALL PUTBYT		;
	 RET
	MOVE T1,P1		;Get the Node address back
	CALL PUT2BT		;Put it into the User string
	 RET
	RETSKP



GETNDN:	TRVAR <<NFNBLK,NF.LST>>	;Need a brand new Argument Block here
	SETZM NFNBLK		;CLEAN FIRST WORD OF BLOCK
	HRRI T2,1+NFNBLK	;GET POINTER TO SECOND WORD IN BLOCK
	HRLI T2,NFNBLK		;POINT AT START OF BLOCK
	BLT T2,NF.LST-1+NFNBLK	;CLEAN UNTIL END OF BLOCK
	STOR T1,NFEID,+NFNBLK	;Store the node number back into the block
	MOVX T1,.NTNOD		;We need the Entity Type (Node)
	STOR T1,NFETY,+NFNBLK	;Store the Entity Type
	MOVX T1,NF.A2N		;Function code into T1
	XMOVEI T2,NFNBLK	;Argument Block
	CALL SCLNMX		;Map Node address into Node Name
	 RET
	LOAD T1,NFBUF,+NFNBLK	;Get the node name into T1
	RETSKP

	SUBTTL User strings -- Read a number from user
;NMXRNU - Read an integer from data string, and put into NXVAL
;

NMXRNU:
	LOAD T1,NTLEN,(NT)	;GET SIZE OF FIELD
	CALL NMXRBY		;READ BYTES
	 RET			;error
	JUMPE T1,NTEIPV		;ILLEGAL TO SET QUANTITY TO ZERO
	STOR T1,NFBUF,+NFWBLK	;SAVE VALUE IN NF BLOCK
	SETZRO NFBFF,+NFWBLK	;And Flag that there is no buffer
	RETSKP			;RETURN SUCCESS

NMXRNC:	LOAD T1,NTLEN,(NT)	;GET SIZE OF CODED FIELD
	CALL NMXRBY		;READ BYTES
	 RET			;Error
	STOR T1,NFBUF,+NFWBLK	;SAVE VALUE IN NF BLOCK
	SETZRO NFBFF,+NFWBLK	;And Flag that there is no buffer
	RETSKP

NMXRCN:
	CALL GETSTR		;Go read the string into Monitor Core
	 RET			;error
	MOVE T1,[POINT 8,NX.VAL+NMXVAR] ;Pointer to beginging of circuit name
	CALL NMXN2C		;Convert Name to Line ID
	 RET			;error
	STOR T1,NFBUF,+NFWBLK	;Put Line ID into the NF Block
	SETZRO NFBFF,+NFWBLK	;No buffer being used
	RETSKP

NMXRNN:	CALL GETSTR		;Go read the string into Monitor Core
	 RET			;error
	SETZ T1			;Start off with a clear Node Name
	MOVE T4,[POINT 6,NF.BUF+NFWBLK]	;Destination Byte Pointer for SIXBIT name
	MOVE T3,[POINT 8,NX.VAL+NMXVAR]	;Pointer to String Containing name
	ILDB T2,T3		;Get Number of bytes in Node Name
	JUMPLE T2,NTEIPV	;No Name, return error...
	CAXLE T2,MXNNLN		;Make sure name is not longer than six
	 JRST NTEIPV		;Error...
NMXRN2:	ILDB T5,T3		;GET A BYTE FROM THE NODE NAME STRINGID
	CAIL T5,^O140		;IS IT LOWER CASE
	SUBI T5,^O40		;MAKE IT UPPER CASE
	SUBI T5,^O40		;MAKE IT SIXBIT
	IDPB T5,T4		;STORE IT IN THE SIXBIT NODE NAME
	SOJG T2,NMXRN2		;LOOP UNTIL ENTIRE NAME COPIED.
	SETZRO NFBFF,+NFWBLK	;Make sure Layer knows that is no buffer
	RETSKP
NMXRHI:
	SAVEAC <P1>
	MOVX T1,FHIBLK		;Get the size of the Buffer we need
	STOR T1,NFBLN,+NFWBLK	;Put it into the argument block
	CALL DNGWDS		;Go allocate the block
	 ERRRET NTERES		;No memory available, resource error
	MOVE P1,T1		;Put buffer address into P1
	STOR T1,NFBUF,+NFWBLK 	;Put the buffer addr into the arg block
	SETONE NFBFF,+NFWBLK 	;And tell Layer to expect a buffer

	CALL GETSTR		;Go read the string into Monitor Core
	 RET			;error
	MOVE T1,[POINT 8,NX.VAL+NMXVAR] ;Pointer to beginging of Hex String
	MOVE T2,[POINT 8,(P1)]	;Pointer to Buffer to go to DECnet Layer
	STOR T2,NFBPT,+NFWBLK	;Save Virgin Pointer for the DECnet Layer
	ILDB T3,T1		;Get the Length of the string
	JUMPLE T3,NTEIPV	;Negative or zero, Invalid Parameter Value
	CAXLE T3,MXHILN		;And it must be less than or equal to 6
	 JRST NTEIPV		;error
	STOR T3,NFBYT,+NFWBLK	;Send the number of bytes to the DECnet Layer
NMXRH1:	ILDB T4,T1		;Get a byte from user
	IDPB T4,T2		;Put it into Buffer
	SOJG T3,NMXRH1		;Loop until entire string is copied
	RETSKP

;	I have commented out this routine (except for RETSKP) because
;	there are currently NO Decimal Signed Parameters maintained
;	by DECnet Layers in the Monitor.
;
NMXRNS:
;	LOAD T1,NTLEN,(NT)	;GET SIZE OF FIELD
;	CALL NMXRBY		;READ THE BYTES
;	 RET			;Error
;	JUMPE T1,NTEIPV		;ZERO IS AN ILLEGAL NUMBER
;	LOAD T2,NTLEN,(NT)	;GET SIZE AGAIN
;	IMULI T2,^D8		;CONVERT TO NUMBER OF BITS
;	SETO T3,		;POSSIBLE SIGN EXTENSION
;	ASH T3,(T2)		;SHIFT TO BECOME ONLY THE SIGN BITS
;	TDNE T3,T1		;IS THE SIGN BIT ON?
;	 IOR T1,T3		;YES, TURN ON ALL THE SIGN BITS
;	STOR T1,NFBUF,+NFWBLK	;SAVE VALUE IN NF BLOCK
;	SETZRO NFBFF,+NFWBLK	;And Flag that there is no buffer
	RETSKP


NMXRBY:	CAXL T1,1		;RANGE CHECK NUMBER OF BYTES TO READ
	CAXLE T1,4		;TO ENSURE ONLY 1,2, AND 4
NMXRBE:	BUG.(CHK,NTMILN,NTMAN,SOFT,<Illegal number size>,,<

Cause:	When going to read a numeric value from the user's string, 
	the format descriptor block for this item has specified an illegal
	number of bytes to read.
>,NTEMPE)
	CALLRET @.(T1)		;DISPATCH
	IFIW <GETBYT&777777>	;GET A SINGLE BYTE
	IFIW <GET2BT&777777>	;GET 2 BYTES OF INTEGER
	IFIW <NMXRBE&777777>	;
	IFIW <GET4BT&777777>	;GET 4 BYTES
	SUBTTL User strings -- Read and write milliseconds
;NMXWNM - Write milliseconds
;Call
;	NMXVAR/ NX block
;	NT/ Pointer to NT begstr
;Return
;	see NMXWNU

NMXWNM:	LOAD T1,NFBUF,+NFWBLK	;GET VALUE WE ARE GOING TO WRITE OUT
	IDIVI T1,TIMBAS		;CONVERT TO SECONDS
	STOR T1,NFBUF,+NFWBLK	;PUT BACK WHERE IT CAME FROM
	LOAD T1,NTLEN,(NT)	;GET THE LENGTH WE ARE GOING TO STORE
;	IOR T1,0_3		;NICE CODE INDICATING DECIMAL UNSIGNED
	CALL PUTBYT		;PUT THE NICE HEADER IN
	 RET			;error...
	JRST NMXWCO		;AND JOIN COMMON CODE

;NMXRNM - Read seconds, store milliseconds
;Call
;	NMXVAR/ NX block
;	NT/ Pointer to NT begstr

NMXRNM:	CALL NMXRNU		;READ THE NUMBER AS DECIMAL UNSIGNED
	 RET			;error...
	MOVX T1,TIMBAS		;CONVERSION FACTOR
	OPSTRM <IMULB T1,>,NFBUF,+NFWBLK ;CONVERT TO MILLISECONDS
	RETSKP			;AND RETURN SUCCESSFULLY



	SUBTTL User strings -- Copy STRINGID from user to exec

;GETSTR - Copy a number of bytes (String) to a place in monitor core.
;Call
;	NMXVAR/ NX block
;Return
;	Non-skip on address check, error already in NXERR
;	Skip if successfull, string starting at NXVAL

GETSTR:	XMOVEI T1,NX.DAT+NMXVAR	;GET POINTER TO DATA BP BLOCK
	JRST GETST0		;JUMP INTO MAIN CODE
GETSTI:	XMOVEI T1,NX.EID+NMXVAR	;GET POINTER TO ENITITY ID BP BLOCK
GETST0:	SAVEAC <P1,P2,NT>	;SAVE SOME DATA ACS
	MOVE P2,T1		;SAVE POINTER
	MOVE P1,[POINT 8,NX.VAL+NMXVAR] ;PUT STRING IN VALUE PART OF NX
	MOVE T2,P2		;GET POINTER TO BP BLOCK
	CALL DNGUBT		;GET A SINGLE BYTE
	 RET			;error...
	IDPB T1,P1		;PUT BYTE AWAY IN DESTINATION STRING
	CAXLE T1,^D32		;WILL THIS STRING FIT IN NXVAL?
	ERRRET NTEPVL		;NOPE. PARAMETER TOO LONG
	MOVE NT,T1		;SAVE NUMBER OF BYTES TO DO
GETST1:	SOJL NT,RSKP		;AT END, RETURN SUCCESS
	MOVE T2,P2		;GET POINTER TO BP BLOCK
	CALL DNGUBT		;GET A BYTE
	 RET			;error...
	IDPB T1,P1		;PUT BYTE AWAY.
	JRST GETST1		;DO ANOTHER BYTE
	SUBTTL User strings -- Copy STRINGID from exec to user
;PUTSTR - Copy string from exec space to user data string
;Call
;	P1/ Full word pointer to stringid in exec space
;Return
;	RET on address check
;	RETSKP with string in user address space

PUTSTR:	SAVEAC <NT,P2>		;SAVE AN AC FOR BYTE COUNT
	MOVX P2,<POINT 8,(P1)>	;MAKE AN 8-BIT BYTEPOINTER TO STRING
	ILDB T1,P2		;GET BYTE COUNT (FIRST BYTE)
	MOVE NT,T1		;SAVE BYTE COUNT FOR LATER
	CALL PUTBYT		;PUT BYTE IN USER'S OUTPUT STRING
	 RET			;error...
PUTST1:	SOJL NT,RSKP		;RETURN WHEN DONE
	ILDB T1,P2		;GET ANOTHER BYTE
	CALL PUTBYT		;PUT IN USER DATA STRING
	 RET			;error...
	JRST PUTST1		;DO ANOTHER BYTE
	SUBTTL User strings -- Get and put user byte routines.
;CALL
;	T1/ integer to deposit
;RETURN
;	RET on error, code in NXERR
;	RETSKP with number deposited/loaded from/to T1

PUTBYT: XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE
	JRST DNPUBT		;PUT THE BYTE IN THE STREAM.

PUT4BT: SAVEAC <P1,P2>		;P1 IS OUR DATA, P2 IS THE NUMBER OF BYTES
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE.
	MOVX P2,4		;DO 4 BYTES
	JRST PUTMBT		;PUT MULTIPLE BYTES
PUT2BT: SAVEAC <P1,P2>		;P1 IS DATA, P2 IS COUNT OF BYTES
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE.
	MOVX P2,2		;WE ARE DOING 2 BYTES
;;	JRST PUTMBT		;PUT MULTIPLE BYTES
PUTMBT:
	MOVE P1,T1		;SAVE ORIGINAL BYTES
PUTMB1:	LDB T1,[POINT 8,P1,35]	;GET BOTTOM BYTE
	CALL DNPUBT		;STORE IT IN USER'S DATA STRING
	 RET			;error...
	SOJLE P2,RSKP		;IF DONE, RETURN SUCCESS.
	ASH P1,-10		;DROP (INTO BIT BUCKET) THE BYTE WE JUST PUT
	JRST PUTMB1		;AND PUT ANOTHER BYTE IN USER'S STRING

GETEBY: 
	XMOVEI T2,NX.EID+NMXVAR	;POINTER TO BP FOR ENTITY ID
	CALLRET DNGUBT		;AND GET A BYTE FROM IT.
GETBYT: 
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE
	CALLRET DNGUBT		;AND GO GET THE BYTE
GET2BT: 
	SAVEAC P1		;WE ARE GOING TO ACCUMULATE BYTES HERE
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE.
	CALL DNGUBT		;GET A BYTE OUT OF STREAM
	 RET			;error...
	MOVE P1,T1		;SAVE WHILE WE GET HIGH ORDER BYTE
	CALL DNGUBT		;GET SECOND BYTE
	 RET			;error...
	ASH T1,8		;SINCE THIS IS HIGH ORDER, MAKE ROOM FOR LOW
	IOR T1,P1		;OR IT IN, MAKING A 2-BYTE AC
	RETSKP			;RETURN WITH 2 BYTES IN T1
GET4BT: 
	SAVEAC P1		;THIS IS WHERE WE ACCUMULATE INCOMING BYTES
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE.
	CALL DNGUBT		;GET A BYTE OUT OF USER STREAM
	 RET			;error...
	MOVE P1,T1		;COPY BYTE INTO SAFE AC
	ROT P1,-10		;NEXT BYTE IS HIGHER ORDER THAN THIS
	CALL DNGUBT		;GET BYTE NUMBER 2
	 RET			;error...
	IOR P1,T1		;ACCUMULATE THIS BYTE IN
	ROT P1,-10		;LET NEXT BYTE COME IN ABOVE THIS ONE
	CALL DNGUBT		;GET BYTE NUMBER 3
	 RET			;error...
	IOR P1,T1		;ACCUMULATE IT IN
	ROT P1,-10		;NEXT BYTE IS THE HIGHEST ORDER BYTE
	CALL DNGUBT		;GET THE LAST (4TH) BYTE
	 RET			;error...
	IOR T1,P1		;INCLUDE STUFF WE HAVE BEEN ACCUMULATING
	ROT T1,30		;ROTATE SO WE HAVE A REAL NUMBER
	RETSKP			;RETURN WITH THE ENTIRE NUMBER IN T1
	SUBTTL User strings -- Get and put single bytes into data strings.
;Call
;	T1/ Byte to be put, or byte returned.
;	T2/ Pointer to BP block
;Return
;	RET	on error, error code in NXERR
;	RETSKP	T1 deposited/loaded
;
;Note - These assume the caller has verified the byte pointer by calling
;CHKIND, to avoid the possibility of an indirect loop, and to insure that
;the destination byte stream is in core.
;For reasons of efficiency, T2 is guaranteed to be preserved.


DNPUBT: 
	OPSTRM <SOS T3,>,BPBYT,(T2) ;DECREMENT COUNT OF AVAILABLE BYTES
	JUMPL T3,NTERES		;PARAMETERS TOO LONG
	TMNE NXMCX,+NMXVAR	;Writing to monitor context?
	IFSKP.			; -no
	  S1XCT <XCTBU [IDPB T1,(T2)]> ;deposit the byte in user context
	ELSE.			; -yes,
	 IDPB T1,(T2)		;  just a single deposit
	ENDIF.

	RETSKP

DNGUBT: 
	OPSTRM <SOS T3,>,BPBYT,(T2) ;DECREMENT COUNT OF BYTES PERMITTED
	JUMPL T3,NTEPAM		;PARAMETER MISSING
S1XCT <
	XCTBU [ILDB T1,(T2)]	;DO THE ILDB
	>
	RETSKP			;GOT THE BYTE IN T1 - RETURN SUCCESS


	SUBTTL Miscellaneous -- Error returns
;;Error returns. Put error code in AC and .NTERR in user's block,
;and return non-skip.

DEFINE NMXERR(CODE),<
	MOVX T1,^D'CODE		;ERROR CODE
	JRST NTEERR		;AND DO ERROR
>

NTEUFO:	NMXERR(-1)		;UNRECOGNIZED FUNCTION OR OPTION
NTEIMF:	NMXERR(-2)		;INVALID MESSAGE FORMAT
NTEPRV:	NMXERR(-3)		;PRIVILEGE VIOLATION.
NTEMPE:	NMXERR(-5)		;MANAGEMENT PROGRAM ERROR
NTEUPT:	NMXERR(-6)		;UNRECOGNIZED PARAMETER TYPE
NTEURC:	NMXERR(-8)		;UNRECOGNIZED COMPONENT
NTEINI:	NMXERR(-9)		;INVALID IDENTIFICATION
;	NELCE%==-10		;LINE COMMUNICATION ERROR
;	NECWS%==-11		;COMPONENT IN WRONG STATE
NTERES:	NMXERR(-15)		;RESOURCE ERROR
NTEIPV:	NMXERR(-16)		;INVALID PARAMETER VALUE
NTENRM:	NMXERR(-20)		;NO ROOM (OR SLOT ALREADY TAKEN)
NTEPNA:	NMXERR(-22)		;PARAMETER NOT APPLICABLE
NTEPVL:	NMXERR(-23)		;PARAMETER VALUE TOO LONG
NTEOPF:	NMXERR(-25)		;OPERATION FAILURE
NTEFNS:	NMXERR(-26)		;FUNCTION NOT SUPPORTED
NTEIPG:	NMXERR(-27)		;INVALID PARAMETER GROUPING
NTEPAM:	NMXERR(-29)		;PARAMETER MISSING
NTEADC:	NMXERR(-47)		;ADDRESS CHECK

NTEERR:	STOR T1,NXERR,+NMXVAR	;Save the error code the Layer sent back
	JE NFBFF,+NFWBLK,RTN	;If no buffer, return now
	LOAD T1,NFBUF,+NFWBLK	;Get the Counter Block
	CALL DNFWDS		;Free up memory
	SETZRO NFBUF,+NFWBLK	;Get rid of the address
	SETZRO NFBFF,+NFWBLK	;and the flag
	RET			;Return non-skip

	SUBTTL Miscellaneous -- Name/number conversion.
;NMXA2N - Address to name conversion
;Call
;	T1/ Node address
;Return
;	RET			;No such node, illegal, ect.
;	RETSKP, name in NXVAL	;on success

NMXA2N:	SETZRO NFBUF,+NFWBLK	;SCLINK doesn't like anything in here....
	STOR T1,NFEID,+NFWBLK	;Store the Node Address in the Argument block
	MOVX T1,.NTNOD		;NODE ENTITY TYPE
	STOR T1,NFETY,+NFWBLK	;Put it into the block
	MOVX T1,NF.A2N		;Function code into T1
	XMOVEI T2,NFWBLK	;Argument Block address
	CALL SCLNMX		;CONVERT NODE ADDRESS TO NODE NAME
	IFNSK.
	 SKIPE T1		;Is it a zero error code?
	  JRST NTEERR		;No, It is a real error then...
	 SETZRO NXVAL,+NMXVAR	;SET BYTE COUNT AND NODE NAME TO 0
 	 RETSKP			;And do an error return
	ENDIF.
	LOAD T1,NFBUF,+NFWBLK	;Get the SIXBIT Node Name
	CALL NMXS2A		;Convert name and store it in NMXVAR block
	RETSKP			;RETURN SUCCESS

;Convert SIXBIT Node Name to ASCII Node Name and save in NMXVAR Block
;Call
;	T1/	SIXBIT Node Name
;Return
;	RET always, ASCII Node Name stored in NXVAL,+NMXVAR

NMXS2A:	SETZ T2,		;START OFF WITH ZERO BYTES RETURNED
	MOVE T3,[POINT 6,T1]	;POINTER TO THE NODE NAME RETURNED
	MOVEI T4,6		;MAXIMUM NUMBER OF CHARACTERS TO CHECK
NMXS21:	SOSL T4
	IFNSK.
	 ILDB T5,T3		;GET A BYTE FROM THE NAME
	 JUMPE T5,NMXS22	;IF ZERO BYTE, END OF NAME
	 AOJA T2,NMXS21		;ELSE KEEP COUNTING.
	ENDIF.
NMXS22:	MOVE T4,[POINT 6,T1]	;BYTE POINTER TO THE NODE NAME
	MOVE T3,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO WHERE WE WANT NAME
	IDPB T2,T3		;START OFF STRINGID WITH NUMBER OF CHARACTERS
NMXS23:	ILDB T5,T4		;GET A BYTE FROM THE NAME
	ADDI T5,^O40		;MAKE IT ASCII
	IDPB T5,T3		;STORE IT IN NMXVAR IN STRINGID FORMAT
	SOJG T2,NMXS23		;AND CONTINUE COPYING UNTIL DONE.
	RET

;NMXN2A - Name to address conversion
;Call
;	NXVAL+NMXVAR/ Stringid for node name. Max 6 chars.
;Return
;	RET			;Unknown name. NTEURC.
;	RETSKP			;T1 contains node address.

NMXN2A:	SETZ T1,		;START OFF WITH A CLEAN NODE NAME
	MOVE T6,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO STRINGID WITH NAME
	MOVE T5,[POINT 6,NF.EID+NFWBLK]	;BYTE POINTER TO CREATE SIXBIT NAME
	ILDB T4,T6		;GET COUNT OF BYTES
	JUMPE T4,RTN		;IF NOTHING, ERROR
NMXN2B:	ILDB T3,T6		;GET A BYTE FROM THE NODE NAME
	CAIL T3,^O140		;IS IT LOWER CASE
	SUBI T3,^O40		;MAKE IT UPPER CASE
	SUBI T3,^O40		;MAKE IT SIXBIT
	IDPB T3,T5		;STORE IT IN THE NODE NAME
	SOJG T4,NMXN2B		;AND LOOP UNTIL BYTES EXHAUSTED.

	MOVX T1,.NTNOD		;NODE ENTITY TYPE
	STOR T1,NFETY,+NFWBLK	;Send it to Session Control Layer
	MOVX T1,NF.N2A		;Get the Function Code
	XMOVEI T2,NFWBLK	;And the address of the Argument Block
	CALL SCLNMX		;CONVERT NODE NAME TO NODE ADDRESS
	 JRST NTEERR		;SESSION CONTROL CAN'T FIND THE NAME. ERROR.
	LOAD T1,NFBUF,+NFWBLK	;Put the address into T1
	RETSKP			;SUCCESS. T1 CONTAINS NODE ADDRESS.



	XLIST
	LIT
	LIST
IFN FTOPS10, .XCMSY
IFN FTOPS20, TNXEND
IFN FTOPS10,<
	RESDT
NTMLOW::!
	XRESCD
>; END IFN FTOPS10
	END