Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_3_19910112 - mit/monitor/mnetdv.mac
There are 10 other files named mnetdv.mac in the archive. Click here to see a list.
;[MIT-XX]PS:<MONITOR.ISIMAC>MNETDV.MAC.5501, 28-Feb-83 17:08:55, Edit by BERLIN
;3032 Ignore value of DBUGSW; always bring up net
;<5.ISI.MONITOR>MNETDV.MAC.5500	18-Jan-83 09:48:50	Edit by JGOLDBERGER
;#550 Ignore domains in GTHST%
;<5.ISI.MONITOR>MNETDV.MAC.5350	 6-Jan-83 18:22:43	Edit by CLYNN
;#535 Update from CLynn
;<134>MNETDV.MAC;7    13-DEC-82 14:13:38    EDIT BY TAFT
; MNETGO set SF%NVT flag in FACTSW to permit TVT listener to be started.
;<134>MNETDV.MAC;6    13-DEC-82 10:02:42    EDIT BY TAFT
; Put definition and all uses of FIXLDR inside IFN MAXLDR-.NBHHL conditional.
;<134>MNETDV.MAC;5    11-DEC-82 14:27:42    EDIT BY TAFT
; Fix use of incorrect AC at SETDF5.
; Eliminate use of STS (=AC0 !) in HSTLUK -- does this work in Tops20??
;<134>MNETDV.MAC;4    10-DEC-82 15:11:02    EDIT BY TAFT
; Insert GHOSTN routine to simulate the HOSTN GETAB table (taken from old NETWRK.MAC).
; Also add GTBIRD to simulate a subset of the NETRDY table.
;<134>MNETDV.MAC;3     9-DEC-82 14:50:41    EDIT BY TAFT
; Insert missing setup instructions in monitor fork initialization.
;<134>MNETDV.MAC;2     7-DEC-82 17:51:44    EDIT BY TAFT
; For Tenex, SITE-ADDRESS.TXT file has to be on <SYSTEM>, not SYSTEM:.
; Add interface type ALTO.
;[BBNF]<TAPPAN.NEW>MNETDV.MAC.61, 29-Jul-82 17:20:36, Edit by: TAPPAN
; Fix GTHHNI (using name table index rather than status table)
;[BBNF]<TAPPAN.NEW>MNETDV.MAC.60, 27-Jul-82 16:42:30, Edit by: TAPPAN
; Get rid of old version of HSTINI
;[BBNF]<TAPPAN.NEW>MNETDV.MAC.49,  3-Jun-82 11:51:39, Edit by TAPPAN
; modify LCLHST to allow an address of 0 as a synonym
; for the local host (returns primary address in T1)
;<TAPPAN.NEW>MNETDV.MAC.4, 27-Mar-82 16:04:34, Edit by TAPPAN
; Remove NTSNDX BUGCHK since it can happen legitimately
; if an interface is down
;<TAPPAN.NEW>MNETDV.MAC.2, 27-Mar-82 15:40:27, Edit by TAPPAN
; Create seperate Multinet fork for maintaining hardware.
; initialize all protocals from MNTINI
;<TAPPAN.4>MNETDV.MAC.17,  3-Mar-82 18:07:17, Edit by TAPPAN
; FIx NETNCT (and therefore the routines that call it)
; to work even if the referenced interface is down.
;<TAPPAN.4>MNETDV.MAC.14,  1-Mar-82 13:42:12, Edit by TAPPAN
; Add PACKET-SIZE:<bytes> keyword to address file
; Have NTSNDI call "output allowed" routine before
; sending a packet, so interfaces can refuse packets if they wish
;<TAPPAN.4>MNETDV.MAC.3, 18-Feb-82 18:51:47, Edit by TAPPAN
; Changes for class C addresses:
; remove some unused routines for handling internet packets
; make FNDNCT,NETCHK take a host number instead of a net number
; remove HNFNCT,HNETCK
; JSYS's now accept either a network number (8-24 bits) or a 32 bit
; host number
;<TAPPAN.4>MNETDV.MAC.2, 29-Oct-81 09:15:08, Edit by TAPPAN
; Allow address file to leave off an interface number
; for <device>#0
;<TAPPAN.4>MNETDV.MAC.2, 27-Aug-81 17:20:48, Edit by TAPPAN
; 102: Change ADRINI for new format address files
;<MULTINET-MONITOR>MNETDV.MAC.121, 26-Jun-81 18:54:37, Edit by TAPPAN
; Have FNDNCT check network number against MAXNET

	SEARCH PROLOG,MONSYM,MACSYM,IMPPAR,INPAR,MNTPAR
	TTITLE MNETDV
;;; Routines for driving Multinet
;;;
	ASCIZ	/
	MNETDV
	COPYRIGHT (C) 1980,1981,1982,1983 BOLT BERANEK and NEWMAN INC.
	/

;;; Routines in this module
;;;
;;; MNTINI - System startup routine for multinet *
;;; MNTCHK - Hardware maintainance routine
;;; NTHSND - Send a high priority packet on a network *
;;; NTLSND - Send a low priority packet on a network *
;;; NULHDR - Null header producing routine*
;;; NTSNDI - Send an internet packet*
;;; .SAVP1 - Routine to automaticly save P1*
;;; FNDNCT - Find an NCT for a given net number *
;;; HSTHSH - Find index of a host number in host tables *
;;; NETCHK - check if interface on a net is up *
;;; NETCMP - Check if a host is on a given interface *
;;; LCLNET - Check if a host is on the same net as us.*
;;; LCLHST - CHeck if an address is one of ours *
;;; MNTHLT - Shut down all networks prior to going down *
;;; MNTSET - Set status of a network*
;;; ADRINI - Initialize the interface address'*
;;; HSTINI - Initialize the host tables *

ND CHAOS,0
	SWAPCD

;;; MNTINI - Called at system startup, initializes tables and
;;; storage needed by Multinet
MNTINI::SE1CAL			; Call section 1
	ACVAR <IDX>		; temp register

	SETZM DEFADR		; Clear default address field
	SETZM NETSUP		; Networks not yet up

	MOVX T1,CR%CAP		; Create a Job 0 fork, with capabilities
	CFORK
	 MNTBUG(HLT,MNTCCF,<CAN'T CREATE MULTINET FORK>)
	MOVEI T2,MNETGO
	MSFRK			; Start fork in monitor
	MOVE IDX,INIPTL		; Protocal handler table
	JUMPE IDX,R		; None
	MOVNS IDX		; Make into
	MOVSS IDX		; An
	HRRI IDX,1		; AOBJN pointer
	CALL @INIPTL(IDX)	; Initialize one
	AOBJN IDX,.-1		; loop
	RET			; Done
	ENDAV.

;;; Here in fork context to initialize the rest of multinet
MNETGO:	SE1ENT			; Run in section one
IFKA <	MOVSI T1,UMODF		; (So MENTR will set up the PC)
	MOVEM T1,FPC>
	MCENTR			; And in monitor space
	MOVEI T1,.FHSLF		; Give us some priority
	MOVEI T2,1		;  by running in queue 0
	SPRIW
IFKA <	 ERJMP .+1>

	MOVEI T1,101		;KLUDGE TO GET HIGH PRIORITY
	MOVEM T1,JOBBIT
	CALL SETSPQ

	MOVE T1,FORKX		; Remember FORKX
	MOVEM T1,MNTFRK		; ...

	MOVE T1,[XWD ITFPC,MNTUXI]
	MOVEM T1,MONBK		; Trap any interrupts
	MOVE T1,CHNSON		; Trap all these channels
	MOVEM T1,MONCHN

IFNKA	<
	MOVEI T1,BMNTLK		; Beginning of pages needed to lock down
	SETSEC T1,MNTSEC	; In proper section
	MOVEI T2,EMNTLK		; End of area to lock
	SETSEC T2,MNTSEC	; Same section
	CALL LKSTOR		; Lock storage
>				; End IFNKA
	MOVSI T1,-%NETS		; Get number of networks we handle
	SKIPA P1,NCTVT		; Link together all the physical NCT's
MNTIN0:	LOAD P1,NTLNK,(P1)	; get next on list
	MOVE T2,NCTVT+1(T1)	; Get next pointer
	STOR T2,NTLNK,(P1)	; Link it to this one
	SETZM NTPHY(P1)		; Not virtual
	AOBJN T1,MNTIN0		; Loop through all
	SETZRO NTLNK,(P1)	; Clear last pointer (End of list)

	CALL HSTINI		;GET THE SYSTEM TO KNOW NAMES OF SITES
	 MNTBUG(INF,NOHSTN,<HSTINI FAILED TO FIND HOST NAME FILE>)
	CALL ADRINI		; Init addresses
	 MNTBUG(INF,NOADDR,<ADRINI failed to find address file>)

	CALL NETHSI		; Initialize the network hash table

;3032	MOVE T1,DBUGSW		; Get system switch
;3032	CAIG T1,1		; System normal?
	 SKIPN DEFADR		; Did addresses initialize properly?
	  CAIA
	   CALL	MNETON		; Yes, Yes, start things up
IFKA <	MOVX T1,SF%NVT		; Enable TVT listener to be started
	IORM T1,FACTSW>

	JRST MNETLP		; Go to main fork loop

;;;
;;; MNETON - Turn networks on if NETSUP has been off
;;;; Called by CALL MNETON$X
;;; returns +1 always
MNETON::
MNTINA:	SKIPA P1,NCTVT		; Point to vector table
MNTIN2:	  LOAD P1,NTLNK,(P1)	; get next in list
	JUMPE P1,MNTINY		; Return when done
	SETOM NETON(P1)		; Turn it on
	MNTCALL NTPINI		; Do protocal specific initialization
	SKIPN NTPHY(P1)		; If not physical
	IFSKP.
	 SETOM NTRDY(P1)	; don't init hardware, but do bring it up
	ELSE.
	 MNTCALL NTHINI		; Initialize network device
	 SETZM NTDCLK(P1)	; Init "down timeout" clock
	 SETZM NTPRIO(P1)	; Clear priority cell
	 MNTCALL NTRSRT		; get it going
	ENDIF.
	JRST MNTIN2		; and loop

MNTINY:	SETOM	NETSUP		; Flag networks on
	RET

;;; Unexpected interrupt trap
MNTUXI:	MNTBUG(CHK,MNTUX0,<NET HARDWARE FORK - UNEXPECTED INTERRUPT>)
	SE1ENT			; Make sure in section one
	MCENTR
	JRST MNETLP		; Recover processing

	RESCD
;;; Keep this resident for better response
;;; Main Multinet fork loop
MNETLP:	SETZM MNTFLG		; Clear flag
	MOVEI T1,^D60000	; Default time to run next
	MOVEM T1,MNTTIM		; save
	CALL MNTCHK		; Check on the interfaces

	MOVE T1,MNTTIM		; set as next time to run
	CALL SETBKT		; Convert to BLOCKT arg
	HRRI T1,MNTBPT		; Schedular test routine
	MDISMS			; Sleep awhile
	JRST MNETLP		; loop

;;; Scheduler test
MNTBPT:	SKIPE MNTFLG		; Any reason to run?
	 JRST 1(T4)		; yes
	JRST BLOCKT		; Check for time expired

;;;
;;; MNTWAK -- Wake up multinet fork
;;; If caller is not the multinet fork does an
;;; immediate wakeup. Otherwise sets a wakeup
;;; "fairly soon" (under the assumption that
;;; nothing is critical enough to take over the whole machine)
;;;
MNTWAK::
	MOVE T1,FORKX		; Get running fork
	CAME T1,MNTFRK		; already running?
	 JRST MNTWK1		; No
	MOVEI T1,^D1000		; wake in one second
	CAMG T1,MNTTIM		; Anyone asking for sooner?
	 MOVEM T1,MNTTIM	; no, use this
	CAIA
MNTWK1:	AOS MNTFLG		; Signal an immediate wakeup
	RET			; done
;;;
;;; MNTCHK - routine for keeping things going on all nets
;;;
MNTCHK:	SKIPA P1,NCTVT		; Point to the vector table
MNTCH0:	LOAD P1,NTLNK,(P1)	; Get next in list
	JUMPE P1,R		; Return if done

	CALL CHKHDW		; Check out the interface

	SKIPE NTSTCH(P1)	; Change of state?
	 CALL LOGSTC		; Yes, print it out
	SKIPN NTPHY(P1)		; If virtual
	 SKIPN NETON(P1)	; or network off
	  JRST MNTCH0		; Loop

	MOVE T1,SCTLW		; System shutdown?
	TXNN T1,<1B3>
	 JRST MNTCH0		; No, continue
	MNTCALL NTHKIL		; Drop ready line
	JRST MNTCH0		; and loop through the rest
	SWAPCD
;;; Log network change of state to CTY
;;; P1 -- NCT for the network
;;;
LOGSTC:	SETZM NTSTCH(P1)	; Clear flag
	SKIPG NTLADR(P1)	; Any address?
	 RET			; No, ignore it

;;; Now isolate the bytes of the net number
	MOVE T1,NTNET(P1)	; Get number
	SETZ T4,		; init count (N-1)
LOGST1:	LSHC T1,-^D8		; shift off a byte
	PUSH P,T2		; save
	SKIPE T1		; Done?
	 AOJA T4,LOGST1		; No, count up another

	HRROI T1,[ASCIZ /
[Network /]
	PSOUT

;;; Write all the bytes of the net number
	MOVX T1,.PRIOU		; Primary output
LOGST2:	SETZ T2,
	POP P,T3		; get a byte
	LSHC T2,^D8		; Justify it correctly
	MOVX T3,^D10		; output in decimal
	NOUT			; ...
	 NOP			; Shouldn't fail
	MOVEI T2,"."		; seperator
	SKIPE T4		; If any left
	 BOUT			; write it
	SOJGE T4,LOGST2		; Loop through them all
	HRROI T1,[ASCIZ / on/]
	SKIPN NETON(P1)
	 HRROI T1,[ASCIZ / off/]
	PSOUT
	HRROI T1,[ASCIZ /, Output /]
	PSOUT
	HRROI T1,[ASCIZ /on/]
	SKIPN NTORDY(P1)
	 HRROI T1,[ASCIZ /off/]
	PSOUT
	MOVEI T1," "
	PBOUT
	CALL LGTAD		; REPORT TIME OF THIS CHANGE
	SKIPGE T2,T1		; IF TIME KNOWN
	 JRST LOGSTX		; NOT KNOWN.
	MOVEI T1,.PRIOU		; STILL ON CTY
	SETZ T3,
	ODTIM
LOGSTX:	TMSG <]
>
	SKIPN NTORDY(P1)	; Did the hardware come up?
	 CALLRET INTDWN		; No, signal it's down
	CALLRET	INTUP		; Signal that it's available for use
	RESCD
;;;
;;; CHKHDW -- Check, and maintain, the status of an interface
;;;
;;; This routine assumes the following usage for some flags in the NCT
;;;
;;; NTERRF --	-1 if an error occured "recently"
;;; NETON --	<0 if the interface should be up, 0 if it should be down
;;; NTRDY --	<0 if interface is up, 0 if interface is down, 
;;;		>0 if interface is on the way down
;;;		Protocal, or hardware specific "take down" routines
;;;		can use bits in the right half as flags. Basicly
;;;		The right half is set to 777777 when the down cycle
;;;		starts, and is changed (set to 0) only when the
;;;		interface is completely down.
;;; NTDCLK --	Timeout clock, used to timeout various events
;;;		(error condition, going down, etc.)
;;;
CHKHDW:	SKIPE NTPHY(P1)		; Is this a physical NCT?
	 JRST CHKINU		; No, don't check any hardware
	SKIPL NTRDY(P1)		; Should it be ok?
	 JRST CHKIND		; Down cycle
	AOSN NTERRF(P1)		; Did an error occur recently?
	 JRST CHKINE		; Yes
	MNTCALL NTSCHK		; Check the current status
	 JRST CHKINE		; Not good
	SKIPN NTDCLK(P1)	; Was it down previously?
	 JRST CHKINU		; No
	SETZM NTDCLK(P1)	; It's up now
	CALL LGTAD		; get time of day
	MOVEM T1,NTXUPT(P1)	; Save as when it came up

;;; Signal the virtual NCT's that it's come up
	XMOVEI T1,[SKIPG NTLADR(P1)	; If no address associated
		    RET			; do nothing
		   MNTCALL NTPINI	; Do protocal specific initialization
		   CALLRET INTUP]	; and mark it up

	CALL VNCTFN		; Do the function

;;; At this point the interface is apparently functional
CHKINU:	SKIPN NETON(P1)		; Should it be functional?
	 JRST CHKINN		; No, take it down
;;; Interface is, and should be, up
	SKIPE NTPHY(P1)
	 RET			; Nothing more if only a virtual interface
	SKIPE T1,NTTOUT(P1)	; Get current output timeout
	 CAMLE T1,TODCLK	; Timed out?
	  JRST CHKINA		; No
	MNTBUG(INF,NTOHNG,<Network output hung>,<P1,D>)
	MNTCALL NTRSRT	; If timeout, reset net
CHKINA:	MNTCALL NTISRT		; Make sure input
CHKINB:	MNTCALL NTOSRT		; And output are going
	RET			; and return

;;; Here if interface is dead, or has a transient error
CHKINE:	SKIPE T1,NTDCLK(P1)	; Was it down last time?
	 JRST CHKIE1		; Yes, check how long
	MNTCALL NTPERR		; Do protocal dependent error recovery
	MOVE T1,TODCLK		; Get time now
	MOVEM T1,NTDCLK(P1)	; Save as when went off
CHKIE1:	SUB T1,TODCLK		; Subtract current time
	MOVNS T1		; (Current time is larger)
	CAIG T1,^D10000		; Down for 10 seconds (arbitrary)?
	 JRST CHKINU		; No, may still be ok
;;; Interface has been down for too long, kill it.
CHKINN:
;;; Must take this one down and all its
;;; "virtual" interfaces
	XMOVEI T1,[ HRRZI T1,-1		; Function to perform
		   MOVEM T1,NTRDY(P1)   ; signal going down
		   CALL LGTAD		; Get current time
		   MOVEM T1,NTXDNT(P1)	; save as when it when off
		   SETZM NTDCLK(P1)	; clear clock
		   SKIPL NTLADR(P1)	;if an address associated with it
		    CALL INTDWN		; Take that one down
		   RET]
	CALL VNCTFN		; Do it

;;; Here if an interface is down or on it's way down
CHKIND:	SKIPE NTRDY(P1)		; Already down?
	IFSKP.	
	 SKIPN NETON(P1)	; Should it be up?
	 IFSKP.			; Yes
	  SKIPN T1,NTPHY(P1)	; Virtual?
	  IFSKP.
	   SKIPGE NTRDY(T1)	; Is real one usable?
	    SKIPL NTORDY(T1)	; ?
	    IFSKP.
	     SETOM NTRDY(P1)	; Mark this one ready
	     SETOM NTORDY(P1)	;...
	    ENDIF.
	  ELSE.			; Physical
	   MNTCALL NTRSRT	; Try to restart it
	  ENDIF.		; end of SKIPN NTPHY
	 ENDIF.			; end of SKIPN NETON
	 RET			; Return now
	ENDIF.			; End of SKIPE NTRDY

	CALL MNTWAK		; We need to come back fairly soon.
	SKIPN NTORDY(P1)	; Still doing protocal specific stuff?
	 JRST CHKID1		; No

	MNTCALL NTPKIL		; Do protocal specific kill action
	 JRST CHKINA		; Not done yet, keep I/O going for now.

	AOS NTSTCH(P1)		; Note the change of state
 	SETZM NTORDY(P1)	; Output not allowed any more

	SKIPE NTPHY(P1)		; If only a virtual interface
	IFSKP.
	 SETZM NTRDY(P1)	; Done now
	 RET
	ENDIF.

	MOVE T1,TODCLK		; Get now
	MOVEM T1,NTDCLK(P1)	; set it
CHKID1:	MOVE T1,NTDCLK(P1)	; Get timeout value
	SUB T1,TODCLK		; Subtract from current time
	MOVNS T1		; ...
	CAIL T1,^D30000		; Been waiting too long?
	 JRST CHKID3		; Yes, give up

	SKIPN NTOB(P1)		; Stuff going out?
	 SKIPE NTIOBO(P1)
	  JRST CHKINB		; Output must go on

	SKIPN NTHOBO(P1)	; Other queues
	 SKIPE NTLOBO(P1)	; ...
	  JRST CHKINB		; keep it moving

;;; Here when ready to kill the thing
CHKID3:	MNTCALL NTHKIL		; Kill the hardware
	SETZM NTRDY(P1)		; All down
        AOS NTSTCH(P1)		; Log the change of state
	CALLRET MNTCLQ		; Clear anything still on the queues

;;;
;;; VNCTFN -- perform a function on an NCT and all the associated
;;; virtual NCT's.
;;;	T1 -- pointer to function to call
;;;	P1 -- Physical NCT
;;;
;;;	Returns +2 if any of the function calls did
;;;
VNCTFN::
	STKVAR	<OLDP1,SKPFLG,FUNC>
	SETZM SKPFLG		; Nothing skipped
	MOVEM P1,OLDP1		; save NCT
	MOVEM T1,FUNC		; Save function
	JRST VNCTF1		; skip checks first time thorough

VNCTF0:	LOAD P1,NTLNK,(P1)	; get linked (first vitual)
	JUMPE P1,VNCTFX		; no more
	SKIPN NTPHY(P1)		; virtual?
	 JRST VNCTFX		; No, done with these
VNCTF1:	CALL @FUNC		; perform the function
	 CAIA			; returned +1
	  SETOM SKPFLG		; something skipped
	JRST VNCTF0		; loop

VNCTFX:	MOVE P1,OLDP1		; retore NCT
	SKIPN SKPFLG		; something skipped?
	 RET			; no
	RETSKP			; yes, follow suite

	SWAPCD
;;;
;;; MNTCLQ -- Clear an interfaces buffer queues.
;;; Called with P1 -- NCT (must be a "real" NCT)
;;;
;;; The interface should be turned off at this point or
;;; I/O page failures may result
;;;
;;; Buffer address considerations -- Internet packets
;;; on the input or output q's do NOT point to
;;; MAXLDR before the buffer, instead they point
;;; MAXLDR-<local header size>.
;;; this means that the address, and count, must be
;;; corrected before the packet can be released.
;;;
MNTCLQ:	SKIPN NTRDY(P1)		; Must be turned off
	SKIPE NTORDY(P1)	; Output disallowed.
	 RET			; Bad, don't try it

	MNTCALL	NTIDUN		; Simulate end of input

	SETZ T2,
	EXCH T2,NTOB(P1)	; get output
	CALL MNTCLB		; return it

	PIOFF
	SETZM NTIOBI(P1)	; Clear internet Q
	SETZ T2,
	EXCH T2,NTIOBO(P1)	; get tail
	PION
	CALL INTFBF		; Flush an internet buffer chain

	PIOFF
	SETZM NTHOBI(P1)	; High priority Q
	SETZ T2,
	EXCH T2,NTHOBO(P1)	; get tail
	PION
	MNTCALL NTRBUF		; FLush local chain

	PIOFF
	SETZM NTLOBI(P1)	; Low priority Q
	SETZ T2,
	EXCH T2,NTLOBO(P1)	; get tail
	PION
	MNTCALL NTRBUF		; FLush it
	RET			; and return

;;;
;;; MNTCLB -- Release a buffer that may be internet or local
;;; T2 -- buffer
MNTCLB:	JUMPLE T2,R		; No buffer
	HLRZ CX,T2		; Get section number
	CAIE CX,INTSEC		; Internet?
	 JRST MNTCLL		; Non-Internet
	CALLRET	INTFB1		; Internet, correct header and return

MNTCLL:	MNTCALL NTRBUF		; release it
	RET			; and return
	RESCD
;;; Functions shared by several interface/protocal drivers.
;;; These will change considerably (as will much else)
;;; when a general "network buffer" pool
;;; is developed.

;;; 
;;; INTBCK -- Check if an internet buffer
;;; Called T1 -- buffer address
;;; Returns +2 if in internet space
INTBCK::
	CAML T1,[XWD INTSEC,INTFRE]
	 CAMLE T1,[XWD INTSEC,INTFRE+INTFSZ-1]
	  RET
	   RETSKP

;;;
;;; INTEIN -- End of input with an Internet buffer
;;;
INTEIN::
	SETZ T1,
	EXCH T1,NTIB(P1)	; get the buffer (and clear)
	SETZRO NBQUE,(T1)	; make sure it's not linked
	PIOFF			; Keep machine
	MOVE T2,INTIBI		; Get input list
	JUMPN T2,INTEI0		; Something there
	MOVEM T1,INTIBO		; else set head of list
	CAIA			; skip
INTEI0:	 STOR T1,NBQUE,(T2)	; Put on Q
	MOVEM T1,INTIBI		; and set new tail
	PION
	AOS INTFLG		; signal gateway
	MNTCALL NTISRT		; Keep input moving if needed
	RET

;;;
;;; INTFBF -- Flush a buffer (chain)
;;;	Called with	T2/	First buffer
;;;			P1/	NCT pointer
INTFBF::
	JUMPE	T2,R		; Nothing there

INTFB0:
	CAML T2,[XWD INTSEC,INTFRE] ; Valid buffer?
	 CAMLE T2,[XWD INTSEC,INTFRE+INTFSZ-1]
	  MNTBUG(HLT,INTRBB,<Releasing bad Internet buffer>)
	LOAD T1,NBQUE,(T2)	; get next buffer in list
	PUSH P,T1		; Save
	SETZRO NBQUE,(T2)	; zero queue pointer
	CALL INTFB1		; release it
	POP P,T1		; restore next
	JUMPE T1,R		; end of list
	MOVE T2,T1		; Get this
	SETSEC T2,INTSEC
	JRST INTFB0		; Loop

;;; Here to do the actual release
;;; T2/ Buffer pointer
;;; Clobbers T3 and T1 (indirectly)
INTFB1:
IFNKA <	MOVN T3,NTHDRL(P1)	; Size of local leader
	CALL FIXLDR>		; Correct Local leader to MAXLDR
IFKA <IFN MAXLDR-.NBHHL,<
	MOVN T3,NTHDRL(P1)	; Size of local leader
	CALL FIXLDR		; Correct Local leader to MAXLDR
>>
	MOVE T1,T2		; Copy for indexing
	PIOFF
	EXCH T2,INTNFB		; Put on free list
	STOR T2,NBQUE,(T1)	; Hang old list off of this new head
	PION
	AOS INTFLG		; Get Internet gateway to notice it
	RET
;;;
;;; INTODN -- Output done
;;;
INTODN::
	SETZM NTTOUT(P1)	; Clear the timeout
	SETZ T2,
	EXCH T2,NTOB(P1)	; Get output buffer (and clear)
	SETZRO NBQUE,(T2)	; clear any garbage link
	CALLRET INTFB1		; Join above


;;;
;;; FIXLDR -- Correct the leader size for the real network
;;; Called	T2 -- Buffer pointer, MAXLDR above packet
;;; 		|T3| -- Size of local leader (including link word)
;;;	T3 is positive to correct, negative to uncorrect
;;;
FIXLDR::
	PUSH P,T1		; Save a scratch
	SKIPL T3		; Decrementing size?
	 SKIPA T1,[-MAXLDR]	; Yes, get appropriate modifier
	  MOVEI T1,MAXLDR	; No, incrementing
	ADD T3,T1		; Amount and direction to correct
	LOAD T1,NBBSZ,(T2)	; Get current packet size
	ADD T1,T3		; Correct size
	SUB T2,T3		; and pointer
	STOR T1,NBBSZ,(T2)	; Update size
	POP P,T1		; Restore
	RET			; And return
;;; Routines for outputing packets to a network

;;; NTHSND - Put packet on High priority Q
;;; Called
;;;	T2/	packet pointer
;;;	returns +2 if packet succesfully queued
NTHSND::
	SAVP1
	CALL FNDNCT
	 RET			; Not available (currently?)
	MOVEI T1,NTHOBO		; High priority Q
	JRST NTQPKT		; And queue it

;;; NTLSND - Put packet on low priority Q
;;;
NTLSND::
	SAVP1
	CALL FNDNCT
	 RET			; Not available
	MOVEI T1,NTLOBO		; low priority Q

;;; NTQPKT - PUT PACKET ON FIFO Q
;;; Reached with T1 Queue head offset
;;; T2 - Pointer to packet
;;; P1 - Pointer to NCT for the interface
;;;
NTQPKT:	SKIPE NTPHY(P1)		; Virtual?
	 MOVE P1,NTPHY(P1)	; yes, get the physical one
	SKIPN NTORDY(P1)	; Output allowed?
	 RET			; No, fail
	TRNN T2,-1		; Is the address good?
	 MNTBUG(HLT,BADBUF,<Null buffer address>)
	HRRZS 0(T2)		; Make sure succesor chain is NIL
	ADD T1,P1		; Offset to the proper Q
	PIOFF			; INSURE INTERGRETY OF QUEUES
	SKIPE T3,1(T1)		; Q empty?
	 JRST NTQPK2		; No, put on tail
	MOVEM T2,0(T1)		; Yes, set head pointer
	SKIPA			; Don't chain, no predecessor
NTQPK2:	STOR T2,NBQUE,(T3)	; Chain from predecessor to new guy
	MOVEM T2,1(T1)		; This is new tail of Q
	PION			; ALLOW  INTERRUPTS AGAIN
	MNTCALL NTOSRT		; Start output if needed
	RETSKP			; And return succesfully
;;; NTSNDI -- Default routine for EnQuing an internet packet
;;; Called with
;;;	T1/	Local host
;;;	T2/	Packet pointer
;;;	P1/	NCT
;;; Returns +2 if packet queued succesfully, else 
;;; +1 with T1 holding an ICMP error code
NTSNDI::
	MNTCALL NTOTOK		; Can this packet be sent?
	 RET			; No, T1 has reason
	MNTCALL NTLLDR		; Make a local header
	MOVEI T1,NTIOBO		; Point to right Q
	CALL NTQPKT		; And Q the packet
	 CAIA			; Failed
	  RETSKP		; Success
	MOVX T1,<ICM%SQ>	; Back off a minute, interface unusable
	RET			; return
	
;;; .SAVP1 - The function for automaticly saving and restoreing the P1 AC
;;;	Called via JSP CX,.SAVP1 (the SAVP1 MACRO)
.SAVP1::PUSH P,P1		; Save it on stack
	CALL 0(CX)		; Call the routine
	 SKIPA			; +1 return
	AOS -1(P)		; Add to return PC
	POP P,P1		; Restore old one
	RET			; And return
;;; FNDNCT - Given a host number in T1 returns 
;;; +2 with a pointer to the NCT for an interface on that net
;;; in P1 if we have one, else +1
;;;
FNDNCT::
	SAVET			; Save temps
	NETNUM T2,T1		; Get the network number
FNDNC0:	CALL NETHSH		; Look it up in the tables
	  RET			; No, knowledge of that net
	SKIPL P1,NETGWY(T2)	; Get the interface
	 RET			; Not directly connected
	RETSKP			; And skip return

;;;
;;; NETNCT -- Given either a net number, or a host number
;;; in T1, finds the NCT, returns as FNDNCT
;;; Note that it doesn't have the restriction (that FNDNCT has)
;;; that the network be up, but is slower
;;;
NETNCT::	
	SAVET			; Save temps
	TXNN T1,-1B11		; Host address?
	 JRST NETNC0		; No
	NETNUM T1,T1		; Get the network number
NETNC0:	XMOVEI P1,NCTVT		; point to the table
NETNCL:	LOAD P1,NTLNK,(P1)	; get net in the chain
	JUMPE P1,R		; no more
	CAMN T1,NTNET(P1)	; Same network?
	 RETSKP			; yes, success
	JRST NETNCL		; else loop
;;; HSTHSH - Given a host number in T1 finds entry for that
;;; number in host tables
;;; Does skip return if found
;;; is table index, or -1 if no more room in tables
;;;
HSTHSH::
	MOVE T2,T1		;DO A HASH
	IDIVI T2,NHOSTS		;GET INITIAL GUESS, DIV BY PRIME
	EXCH T2,T3		;2/ FIRST GUESS
	IDIVI T3,NHOSTS		;DIV BY PRIME AGAIN
	CAIN T4,0		;GET INCREMENT
	 MOVEI T4,1
	MOVEI T3,NHOSTS		;COUNTER FOR GUESSES
	SETSEC T2,MNTSEC	; Look in the right section
HSTHLP:	SKIPG HOSTNN(T2)	;NO HOST THERE?
	 RET			;NO, 2/ WHERE TO PUT IT
	CAMN T1,HOSTNN(T2)	;MATCH?
	 RETSKP
	ADDI T2,(T4)		;STEP BY INCREMENT
	CAML T2,[XWD MNTSEC,NHOSTS]	; Check for overflow
	 SUBI T2,NHOSTS		; Wrap around if needed
	SOJG T3,HSTHLP		;COUNT DOWN GUESSES
	SETO T2,		;-1 TABLE FULL
	RET			; Return error
	SWAPCD
;;; NETCHK - Check if our interface on a given net is up
;;; Called with	T1 - Host number
;;;	Returns+1 if interface is down
;;;	+2	if it is up
NETCHK::
	SAVP1			; Save P1 AC
	CALL	FNDNCT		; Find the NCT (Or not up)
	 TRNA			; No such Net
	SKIPL	NTRDY(P1)	; Network up?
	 RET			; No
	RETSKP			; Yes, return good


;;; NETCMP - Check if a host is on a given interface
;;; Called with:
;;;	T1 - Host number
;;;	P1 - Pointer to NCT
;;;	Returns +1 if host is not on that interface, +2 if it is
NETCMP::
	SAVET			; Save temps
	NETNUM T1,T1		; Get the net number
	MOVE T2,NTNET(P1)	; And that of this NCT
	CAME T2,T1		; Same?
	 RET			; No
	RETSKP			; Yes
 
;;; LCLNET -- Check if a host address is on a net we're connected 
;;; to
;;; Called T1/	Host address
;;; returns +1 if we have an intersecting network
;;; (Note that this doesn't mean that the interface is currently usable)
LCLNET::
	SAVET			; Save temps
	NETNUM T1,T1		; Get the net number
	XMOVEI T3,NCTVT		; Point to the interface table
LCLNT0:	LOAD T3,NTLNK,(T3)	; get the next in the list
	JUMPE T3,R		; end of the list
	CAMN T1,NTNET(T3)	; On this network?
	 RETSKP			; yes, return success
	JRST LCLNT0		; loop through all

;;; LCLHST - Check if a given address is one of ours
;;; Called with T1 - 32 bit address
;;; Returns +1 if it is not ours, +2 if it is
LCLHST::
	JUMPN T1,LCLHS1		; Address of 0 always succeeds
	MOVE T1,DEFADR		; Return our default address
	RETSKP			; and success

LCLHS1:	SAVP1			; Save P1
	PUSH P,T1		; Save address
	SKIPA P1,NCTVT		; check out the NCTs
LCLHS0:	 LOAD P1,NTLNK,(P1)	; get the next
	JUMPE P1,LCLHS9		;no match if none
	MOVE T1,0(P)		; get address back
	ANDCM T1,NTNLHM(P1)	; mask off any logical host bits
	CAME T1,NTLADR(P1)	; same address?
	 JRST LCLHS0		; no, try the next

	AOS -1(P)		; success! skip
LCLHS9:	POP P,T1		; restore
	RET			; and back

;;;
;;; MNTHLT - Tell all networks we are going away
;;; Called at system shutdown time
MNTHLT::SAVP1			; Save register
	MOVX T1,<377777777777>	; +infinity
	MOVEM T1,PINGTM		; turn off pinging
	CALL MNTWAK		; wake up the hardware fork
	SKIPA P1,NCTVT		; Get pointer to tables
MNTHL0:	  LOAD P1,NTLNK,(P1)	; Get link
	JUMPE P1,R		; If done
	SETZM NETON(P1)		; Turn it off
	JRST MNTHL0		; Loop through all

;;; MNTSET - Set a network status
;;; Accepts T1 - Network number, or host address
;;;	    T2 - value
;;; Possible values are: <0 = on
;;;			  0 = off
;;;			>0 = request cycle
MNTSET::SAVP1
	CALL NETNCT		; Find the NCT
	 RET			; If none
	MOVEM T2,NETON(P1)	; Set function
	CALL MNTWAK		; Wake up the hardware fork
	RETSKP			; Success return
;;; PERROR - Print out the erring line in the file
;;;
;;; Called P1 - JFN
;;; P2 - Byte index of BOL

PERROR:	MOVE T1,P1
	RFPTR			; Read where we are
	 TRN
	MOVE T3,T2		; Save it in T3
	MOVE T2,P2		; Get BOL pointer
	SFPTR			; set back to beginning of line
	 TRN
PERLP:	MOVE T1,P1
	RFPTR			; Read where we are
	 TRN
	CAMN T2,T3		; Are we where error occured?
	 CALL PMARK		; Yes, Mark it
	CALL GCH1		; Get a character
	 MOVEI T2,.CHLFD	; Fake EOL if done
	CAIN T2,.CHLFD		; End of line?
	 JRST PERLPX		; Yes, exit
	MOVE T1,T2		; Get caharacter
	PBOUT			; Type it out
	JRST PERLP		; And loop

;;; PMARK, Mark where error occured
;;;
PMARK:	PUSH P,T1		; Save AC1
	MOVEI	T1,"^"		; A convenient character
	PBOUT			; Write it out
	POP P,T1		; And restore it
	RET			; And back to caller

;;; PERLPX - Done with error line
PERLPX:	HRROI T1,[ASCIZ /
/]
	PSOUT			; Write a carridge return
	RET			; Return when done


;;; GBOL - Get Set pointer to the beginning of a line
;;; Returns +1 if EOF hit
;;; else +2 with T1 - JFN
;;;		 P2 - Byte number of beginning of line
;;;	
GBOL:	MOVE T1,P1		; Get JFN
	CALL GCH		; Get a character
	 RET
	CAIN T2,.CHLFD		; Line feed?
	 JRST GBOL		; Yes, blank line
	BKJFN			; Backup over that character
	 MOVE T1,P1		; Restore JFN
	RFPTR			; get pointer
	 NOP
	MOVE P2,T2		; Save it
	RETSKP			; And return with it


;;; GCH - read the next non-comment, non-blank character
;;; returns +2 if character (character in T2)
;;; +1 if EOF
GCH:	MOVE T1,P1		; Get JFN
GCH2:	CALL GCH1		; Get a byte
	 RET			; EOF
	CAIN T2,";"		; Comment, 
	 JRST GCHSMC		; ignore it
	CAIE T2,.CHTAB		; TAB?
	CAIN T2," "		; or SPACE?
	 JRST GCH2		; Skip it
	RETSKP			; Else return with character

GCH1:	CALL GBIN		; BIN a byte
	 RET			; EOF
	CAIE T2,.CHCRT		; Ignore 
	CAIN T2,.CHFFD		; and form-feed
	 JRST GCH1		; ..
	RETSKP			; return with character

GCHSMC:	CALL GBIN		; Get a byte
	 RET			; EOF
	CAIN T2,.CHLFD		; Until end of line
	 RETSKP			; when we return
	JRST GCHSMC		; Else lop

GBIN:	BIN			; get a char
IFNKA <	ERJMP R>		; If end of file return +1
	JUMPN T2,RSKP		; If good
IFKA <				; Tenex end-of-file check
	GTSTS			; get file's status
	TXNE T2,1B8		; at end of file?
	  RET			; yes, return +1
>
	JRST GBIN		; flush NULLS


;;; GTFIL - Get a JFN for a file, and setup 
;;; ACs, used in HSTINI and ADRINI, 
;;; called with T2 pointing to file name
;;; returns +2 if successful with AC's setup
;;; P1 - Contains JFN
GTFIL:	MOVX T1,<GJ%OLD+GJ%SHT>	; Olf file, short
	GTJFN			; GEt JFN
	 RET			;; Can't file not found
	MOVE P1,T1		;Save JFN in P1
	MOVX T2,7B5+OF%RD	; Open for reading
	OPENF			; ..
	 JRST [	MOVE T1,P1	; If fails, get JFN back
		RLJFN		; Release it
		 NOP
		RET]
	RETSKP			; Succesful return

;;; ADRINI - Reads in the file SYSTEM:SITE-ADDRESS.TXT and 
;;; initializes the interface tables from it
;;; Called from HSTINI at system startup, does skip return if
;;; successful
;;; AC usage
;;;	P1 - JFN of input file
;;;	P2 - Local address once read
;;;	P3 - NCT associated with that address, if any
;;;
ADRINI::
	SE1CAL			; ENTER SECTION 1
	SAVEPQ			; Save registers clobbered
	STKVAR <NONUM,<BUFFER,10>,LSTPHY,LSTNCT>
IFNKA <	HRROI T2,[ASCIZ /SYSTEM:SITE-ADDRESS.TXT/]>
IFKA <	HRROI T2,[ASCIZ /<SYSTEM>SITE-ADDRESS.TXT/]>
	CALL GTFIL		; Get the file
	 RET
	SETZM LSTPHY		; We haven't seen any NCT's yet
;;; 102: Clear NLHOST slots
	SETZ T1,		; clear an index
ADRIN1:	SKIPN NLHOST(T1)	; slot used?
	 JRST ADRIN2		; no, done with table
	SETOM NLHOST(T1)	; empty that slot
	AOJA T1,ADRIN1		; and loop

;;; Release all virtual NCT's
ADRIN2:
IFNKA <	MOVE P3,NCTVT		; Get the start of the list
ADRIN3:	SETOM NTLADR(P3)	; No local address set
	SKIPN NTPHY(P3)		; physical?
	 JRST ADRIN4		; yes, try next
	HRRZ T1,P3		; Get the addess
	LOAD P3,NTLNK,(P3)	; walk down chain one
	CALL RELRES		; release the storage	
	CAIA
ADRIN4:	LOAD P3,NTLNK,(P3)	; Get the next
ADRIN5:	JUMPN P3,ADRIN3		; join above
> ;end ifnka
	
ADRLP0:	CALL GBOL		; Start off a line
	 JRST ADRDUN		; Done with file
	MOVE T1,P1		; Get JFN
;;; 102: beginning of change
;;; Now read in the interface type
	MOVE T3,[POINT 7,BUFFER] ; point to temp buffer
ADGINM: CALL GCH
	 JRST ADREOF		; enf of file
	CAIN T2,"#"		; end of name?
	 JRST [	SETZM NONUM	; flag that there is a number
		JRST ADGINX]	; and leave loop
	CAIN T2,.CHLFD		; end of line?
	 JRST ADIERR		; error
	CAIN T2,","		; or field delimiter?
	 JRST [	SETOM NONUM	; flag that number is 0
		JRST ADGINX]	; and join below
	IDPB T2,T3		; save character in string
	JRST ADGINM		; and loop

;;; Here if error in interface descriptor
ADIERR:	HRROI T1,[ASCIZ /Error in interface descriptor/]
	JRST ADRERR		; goto error printer
	
ADGINX:	SETZ T2,		; put a null
	IDPB T2,T3		; at end
	MOVEI T1,INTNAM		; point to type table
	MOVE T2,[POINT 7,0]	; make a pointer
	ADDI T2,BUFFER		;  to the string buffer
	TBLUK			; and look it up
	TXNE T2,TL%NOM!TL%AMB	; match?
	 JRST ADIERR		; error
	HRRZ T4,(T1)		; get entry
	SETZ P3,		; assume no NCT
	MOVE T1,P1		; GET JFN
	SKIPE NONUM		; is there a number?
	 JRST [	SETZ T2,	; no, use 0
		JRST ADGIN2]	; and skip reading it
	MOVEI T3,^D10		; read in decimal
	NIN
	 JRST ADIERR		; error
ADGIN2:	BKJFN			; Backup over terminator
	 NOP			; Shouldn't fail
	CAIN T4,NT.NIN		; No particular interface?
	 JRST ADGNUM		; right, No NCT associated with it
IFKA <	JRST ADFNCT>		; Skip virtual NCT stuff if Tenex
IFNKA <	CAIE T4,NT.LNK		; Linked? (virtual?)
	 JRST ADFNCT		; No, find the right physical one	 
	SKIPN P3,LSTPHY		; Any physical NCT already?
	 JRST [ HRROI T1,[ASCIZ /Virtual NCT before physical/]
		JRST ADRERR]
	SKIPE LSTNCT		; Any other virtual ones?
	 JRST ADMAKV		; yes
	SETOM NTLADR(P3)	; Clear local address field of old
	MOVEM P3,LSTNCT		; This was also the last
	CALL MKVNCT		; Make aand link a virtual NCT
ADMAKV:	CALL MKVNCT		; Create a virtual copy
	MOVE P3,T1		; Get the NCT
	JRST ADGNUM		; join below
> ; end ifnka

ADFNCT:
;;; Find the NCT for the interface
	XMOVEI P3,NCTVT		; point to vector table
ADFINT:	MOVE P3,(P3)		; get next in list
	JUMPE P3,ADIERR		; error if no more
	LOAD T1,NTDEV,(P3)	; get interface type
	CAIE T1,(T4)		; Same as we're looking for?
	 JRST ADFINT		; No, try next
	SOJGE T2,ADFINT		; Try another if not right number
	SETZM NTPHY(P3)		; Not a shared interface.
	MOVEM P3,LSTPHY		; Save as the last physical NCT we inited
	SETZM LSTNCT		; No virtual ones yet
;;; Read in the address on that interface
ADGNUM:	CALL NXTFLD		; read to the next field
	CALL ADG4DB		; Get 4 decimal bytes
	MOVEM T1,P2		; save address
	CALL HSTHSH		; Hash it into table
	 JUMPL T2,NETFUL	; No room for number
	MOVEM P2,HOSTNN(T2)	; Put number in table
	MOVX CX,HS%UP!HS%SLF!HS%VAL	; It is me , and valid status
	IORM CX,HSTSTS(T2)	; Mark it so
	SETZ T2,		; clear an index
ADGNM1:	SKIPLE NLHOST(T2)	; anything in this slot?
	 AOJA T2,ADGNM1		; No, try next
	SKIPL NLHOST(T2)	; empty?
	 JRST NETFUL		; No, table overflow.
	MOVEM P2,NLHOST(T2)	; save number
	JUMPE P3,ADGNM2		; Skip next if no NCT associated with number
	MOVEM P2,NTLADR(P3)	; Set local address
	NETNUM T1,P2		; Get the network number
	MOVEM T1,NTNET(P3)	; Set it in NCT
ADGNM2:	MOVE T1,P1		; get JFN back
	BKJFN			; Back over last terminator
	 NOP
ADRLP3:	CALL GCH		; Read it in
	 JRST ADREOF		; Eof error
	CAIN T2,.CHLFD		; Was it a linefeed?
	 JRST ADRLP0		; Yes, loop

;;; Must be a comma, means a type name
	MOVE T3,[POINT 7,BUFFER] ; point to buffer
;;; Here to read in a modifier
ADGTYP:	CALL GCH		; Get first char of keyword
	 JRST ADREOF		; Error
	CAIE T2,","		; end of field?
	 CAIN T2,.CHLFD		; line feed?
	  JRST ADGTYX		; got full field
	CAIN T2,":"		; Value?
	 JRST ADGTYX		; yes
	IDPB T2,T3		; else save in string
	JRST ADGTYP		; and loop

ADGTYX:	SETZ T2,		; put a null
	IDPB T2,T3		; at end of string
	MOVEI T1,TYPNAM		; point to type table
	MOVE T2,[POINT 7,0]	; and to string
	ADDI T2,BUFFER		;  in the buffer
	TBLUK			; and look it up in table
	TXNE T2,TL%NOM!TL%AMB	; good name?
	 JRST [ HRROI T1,[asciz /Bad network type descriptor/]
		JRST ADRERR]	; no
	MOVE T1,(T1)		; get routine address
	CALL (T1)		; go to it
	MOVE T1,P1		; Get JFN
	BKJFN			; Back up
	 NOP			; shouldn't fail
	JRST ADRLP3		; and loop	

;;; Here on DEFAULT keyword
ADDFLT:	MOVE T1,P2		; get the address
	MOVEM T1,DEFAD0		; remember as backup default
	CALL SETDFA		; set new default address
	RET

;
; SETDFA - set default network address
; Called T1 - address (or 0 to choose new default)
;
SETDFA::
	SAVEAC <T1,T2,T3>
	JUMPN T1,SETDF5		; address specified
;
; First try to use backup default
;
	MOVE T1,DEFAD0		; get the address
	CALL NETCHK		; that interface working?
	 CAIA			; no
	  JRST SETDF5		; yes

	SAVP1			; save NCT AC
	SKIPA P1,NCTVT		; get first entry
SETDF0:	  LOAD P1,NTLNK,(P1)	; get next in the chain
	JUMPE P1,R		; no interfaces up, give up ??

	MOVE T1,NTLADR(P1)	; get this interface address
IFNKA <	CALL NETCHK>		; up?
IFKA <	SKIPN NTORDY(P1)>	; usable?
	 JRST SETDF0		; no, try the next

SETDF5:	MOVEM T1,DEFADR		; remember the address
	
	NETNUM T2,T1		; Get the network number
	MOVEM T2,DEFNET		; Save as default network number

	MOVE T3,T1		; Get number
	ANDX T3,-1B27		; mask off network number (Class C)
	CAIG T2,177777		; Class B or A?
	 ANDX T3,-1B19		; Mask for class B
	CAIG T2,377		; Class A?
	 ANDX T3,-1B11		; yes, mask appropriately
	MOVEM T3,NETFLD		; Set as default network field

;;; Kludge up the 8 bit host address
; this should be removed soon
	MOVE T2,T1		; get number again
	ROTC T2,-6		; Save IMP number
	LSH T2,-^D10		; Flush middle bits
	ROTC T2,6		; Combine Host and IMP
	ANDI T2,377		; Round to 8 bits
	MOVEM T2,NOHOST		; Save in proper cell

	RET			; and return

;;; Here on NCP keyword
ADNCP:	MOVEI T1,NT.NCP		; get NCP network type
	STOR T1,NTTYP,(P3)	; save in NCT
	MOVE T1,NTNET(P3)	; Get the network number
	CAILE T1,^D255		; Valid type A address?
	 JFCL			; error ***
;;; once host tables are right, find hosts for this net and set in NCP tables
	RET			; and done

;;; Here on CHAOS keyword
ADCHAO:
IFE CHAOS,<
	HRROI T1,[ASCIZ /% CHAOS ignored since Chaos is not in the system./]
	JRST ADRERR
> ; End of IFE CHAOS
IFG CHAOS,<
	MOVE T1,P2		; get address
	ANDI T1,177777		; make 16 bits
	MOVEM T1,MYCHAD		; set as local chaosnet address
	JUMPE P3,R		; if No NCT associated with it, return
	MOVEI T1,NT.CHA		; else set it
	STOR T1,NTTYP,(P3)	; to chaos protocal
	RET			; and return
> ; End of IFG CHAOS

;;; Here on ETHERNET keyword
ADETHR:	MOVEI T1,NT.ETH		; Ethernet
	STOR T1,NTTYP,(P3)	; set it
	RET			; and return

;;; Here on MLC keyword
ADMLC:	RET			; Temporarily NULL

;;; Here on PACKET-SIZE keyword, next parameter is the maximum packet
;;; size for this interface in decimal bytes

ADPSIZ:	MOVE T1,P1		; Get JFN
	MOVEI T3,^D10		; decimal
	NIN
	 JRST [	HRROI T1,[ASCIZ /Invalid PACKET-SIZE /]
		JRST ADRERR]	; error
	MOVEM T2,NTPSIZ(P3)	; save the size
	RET			; and return


;;; Here on LOGICAL-HOST-MASK keyword, next parameter is the 32-bit mask
;;; for this interface in decimal bytes

ADLHM:	HRROI T4,[ASCIZ / Invalid LOGICAL-HOST-MASK value field/]
	CALL ADG4DB		; Read 4 decimal bytes
				; Goes ADRERR on error
	MOVEM T1,NTNLHM(P3)	; Save the mask
	RET			; and return
; ADG4DB - Read in 4 decimal bytes
;	T4/	String pointer to error message
;	P1/	JFN
; Returns+1	Success, T1 has address
; ADRERR	Error detected

ADG4DB:	PUSH P,BHC		; Save a blank
	MOVEI Q1,4		; There are 4 fields to an address
ADG4D2:	MOVE T1,P1		; Get JFN back
	MOVX T3,^D10		; Again decimal
	NIN
	  JRST [SUB P,BHC+2	; Pop address & return
		MOVE T1,T4	; Error message
		JRST ADRERR]	; Error exit
	IORM T2,0(P)		; Merge in latest part
	SOJLE Q1,ADG4D8		; All parts read?
	MOVE T2,0(P)		; No, get so far
	LSH T2,^D8		; Shift over one byte
	MOVEM T2,0(P)		; Store back
	JRST ADG4D2		; Loop through all 4 fields

ADG4D8:	POP P,T1		; Get full address
	RET


;;; The following set the appropriate protocal vectors

;;; Here on 1822 keyword
AD1822:	XMOVEI T1,NCPVEC	; Protocal vector
	TRNE T1,-1		; Have 1822 in configuration?
	  JRST ADPVEC		; Yes, join below
	HRROI T1,[ASCIZ /1822 is not in the system configuration, ignored/]
	JRST ADRERR

;;; Here on NETWORK-FE keyword
ADNFE:	XMOVEI T1,NFEVEC	; NFE protocal vector
	TRNE T1,-1		; Have NFE in configuration?
	  JRST ADPVEC		; Yes, join above
	HRROI T1,[ASCIZ /NFE is not in the system configuration, ignored/]
	JRST ADRERR

ADPVEC:	MOVEM T1,NTPVEC(P3)	; set it
	RET

;;; Error handler routine
NETFUL:	POP P,T4		; Clean stack
	MNTBUG(HLT,NORMIA,<No room in host tables for local address>)
	HRROI T1,[ASCIZ /No room in host tables for local address/]

ADRERR:	PSOUT			; Write error string
	HRROI T1,[ASCIZ / In ADDRESS file
/]
	PSOUT
	CALL PERROR		; Print offending line
	JRST ADRLP0		; And loop

ADREOF: HRROI T1,[ASCIZ /Premature EOF in ADDRESS file/]
	PSOUT
	CALL PERROR		; Print bad line

ADRDUN:	CLOSF			; Close the JFN
	 NOP			; Don't worry if fails
	MOVE P2,NLHOST+0	; Get default default network
	SKIPN DEFADR		; was default address set?
	 CALL ADDFLT		; No, use this one	 
	CALL NETHSI		; Initialize the hash table
	RETSKP			; And return succesfully

;;; Here to skip to the next field of keyword
NXTFLD:	CALL GCH		; Get character
	 RET			; Return now if EOF
	CAIE B,","		; comma?
	 CAIN B,.CHLFD		; EOL?
	  RET			; yes, return now
	JRST NXTFLD		; else read more

 IFNKA	<
;;;
;;; MKVNCT -- Create a virtual NCT
;;; Called P1 -- Physical NCT
;;; LSTNCT -- The last NCT on this subchain
;;;
MKVNCT:	MOVE T1,[XWD .RESP3,VNCTSZ]	; Priority,, Size of buffer
	MOVX T2,.RESGP		; From general pool
	CALL ASGRES		; Assign it
	 JRST [ POP P,0(P)	; Flush return address
		HRROI T1,[ASCIZ /No storage for virtual NCT/]
		JRST ADRERR]
	MOVEM P3,NTPHY(T1)	; This is the physical one
	LOAD T2,NTTYP,(P3)	; same network type
	STOR T2,NTTYP,(T1)	; ..
	LOAD T2,NTDEV,(P3)	; Same device (sort of)
	STOR T2,NTDEV,(T1)	; ..
	MOVE T2,NTPVEC(P3)	; Same protocal vector
	MOVEM T2,NTPVEC(T1)	; ...
	MOVE T3,LSTNCT		; Get the last
	LOAD T2,NTLNK,(T3)	; Get it's link
	STOR T1,NTLNK,(T3)	; Link this one
	STOR T2,NTLNK,(T1)	; into chain
	RET
> ;end ifnka

;;; Tables for address file keywords

;;; Start a table definition
DEFINE TABLE(NAME)<
NAME:  XWD ..'NAME,..'NAME
..TABLE==0		; Init count
>
DEFINE TABEND(NAME)
< ..'NAME==..TABLE>

DEFINE KEY(NAME,DATA)
< XWD [ASCIZ /NAME/],DATA
  ..TABLE==..TABLE+1		; Increment the count of entries
>

;;; Table of interface type names
TABLE(INTNAM)
KEY ALTO,NT.ALT
KEY AN20,NT.ANX
KEY IMP10,NT.BBN
KEY LINK,NT.LNK
KEY NETWORK-DTE,NT.NFE
KEY NONE,NT.NIN
TABEND(INTNAM)

;;; Take of modifiers
TABLE(TYPNAM)
KEY 1822,AD1822			; 1822 type network
KEY CHAOS,ADCHAO		; Network uses CHAOSNet protocal
KEY DEFAULT,ADDFLT		; This is the 'primary' address for host
KEY ETHERNET,ADETHR		; 10 MB Ethernet
KEY LOGICAL-HOST-MASK,ADLHM	; set logical host mask
KEY MLC,ADMLC			; network is a PTIP (speaks MLC protocal)
KEY NCP,ADNCP			; network uses Arpanet NCP protocal
KEY NETWORK-FE,ADNFE		; Network front end
KEY PACKET-SIZE,ADPSIZ		; Maximum packet size allowed
TABEND(TYPNAM)

;;; 102: end of change

	ENDSV.
;;; .CVHST - The CVHST JSYS, moved here from MNETWK since not ARPANET Dependent
;;; Convert host number to string

.CVHST::MCENT
	SETOB P1,P2		;NO NAME YET
	MOVE T1,T2		;GET HOST NUMBER IN RIGHT PLACE
	CALL GTHNTS		;CONVERT NUMBER TO STRING
	JUMPL P1,[EMRETN(CVHST1)] ;STRING NOT FOUND
	LOAD P4,HSTNMP,(P1)	;GET THE NAME POINTER
	SETSEC P4,MNTSEC	; Into proper section
	ADDI P4,HSTNAM		;POINT TO NAME
	MOVE P3,[<POINT 7,0>!1B12]	; Extended pointer word
	UMOVE T1,1		; Get desination
	CALL GTHSOU		; Write string to user space
	UMOVEM T1,1		; Write updated pointer to user space
	JRST SKMRTN


;;; .GTHST - The GTHST% JSYS, Get information on a Host or
;;; Network, Moved here from MNETWK because expansion
;;; allows it to be general over all Interfaces rather than
;;; just the ARPANET
;;; Called as in JSYS documentation
;;;
;;; The following register conventions are used in it
;;;
;;; P1 - Index into Name tables
;;; P2 - Index into Hash tables
;;; P3,P4 - Byte pointers (extended or otherwise)
;;; P5,P6 - Scratch

.GTHST::MCENT			; Establsh MONITOR context
	SKIPL T1		;CHECK RANGE OF FUNCTION CODE
	 CAIL T1,GTHMAX
	  RETERR (ARGX02)	;BAD FUNCTION CODE
	SETOB P1,P2		;NO NUMBER NOR NAME
	XCT GTHDSP(T1)		;DO THE FUNCTION

GTHSXX:	MOVX T4,HS%NCK		;SET THE NICKNAME FLAG
	SKIPL P1		;NO NAME
	SKIPL HOSTN(P1)		;DID WE HAVE ONE?
	 SKIPA T4,HSTSTS(P2)	;NO
	IOR T4,HSTSTS(P2)	;RETURN STATUS
	UMOVEM T4,4
	MOVE T3,HOSTNN(P2)	;RETURN HOST NUMBER
	UMOVEM T3,3
	JRST SKMRTN		;SKIP RETURN

GTHDSP:	JRST GTHSIZ		;(00)GET NAME TABLE SIZE
	JRST GTHIDX		;(01)INDEX INTO NAME SPACE
	JRST GTHNUM		;(02)CONVERT NUMBER TO STRING
	JRST GTHSTR		;(03)CONVERT STRING TO NUMBER
	JRST GTHHNN		;(04)STATUS BY NUMBER
	JRST GTHHNI		;(05)STATUS BY INDEX
	JRST GTHNHN		;(06)Get local number on a network
	JRST GTHNST		;(07)Get status table of a network
GTHMAX==.-GTHDSP		;NUMBER OF FUNCTIONS

GTHSIZ:	HRLZ T2,MHOSTS		;-LENGTH,,1ST INDEX
	UMOVEM T2,2		;RETURN TO USER
	MOVSI T3,-NHOSTS	;NUMBER OF HOST SLOTS
	UMOVEM T3,3		;RETURN TO USER
	MOVE T4,DEFADR		; Get default address
	UMOVEM T4,4		;RETURN TO USER
	JRST SKMRTN		;DONE

GTHIDX:	MOVN T1,MHOSTS		;GET NUMBER OF HOST NAMES IN USE
	HRRZ P1,T3		;CHECK RANGE OF HOST NAME INDEX
	CAML P1,T1
	 RETERR (GTJIX1)	;BAD INDEX TO HOSTN
	SETSEC P1,MNTSEC	; In the right section
	LOAD P2,HSTIDX,(P1)	;GET INDEX INTO HOSTNN
	SETSEC P2,MNTSEC	; And in the proper section
	JRST GTHTUS		;WRITE THE STRING

GTHNUM:	MOVE T1,T3		;GET HOST NUMBER
	CALL GTHNTS		;CONVERT NUMBER TO STRING
	JUMPL P1,[RETERR(GTHSX3)]	 ;NO STRING FOR THAT NUMBER

;;; Write host string to user space
GTHTUS:	LOAD P4,HSTNMP,(P1)	;GET THE NAME POINTER
IFNKA	<
	SETSEC P4,MNTSEC	; Into proper section
	ADDI P4,HSTNAM		;POINT TO NAME
	MOVE P3,[<POINT 7,0>!1B12]>	; Extended pointer word
IFKA	<
	MOVEI P3,HSTNAM(P4)	; 10x, Use normal pointer
	HRLI P3,(<POINT 7,0>)>
	UMOVE T1,2		; Get dest
	CALL GTHSOU		;WRITE STRING
	UMOVEM T1,2		; Update user's pointer
	JRST GTHSXX		;EXIT

GTHNTS:	CALL CVNHST		;MAKE IT NEW FORMAT
	CALL HSTHSH		;GET ITS INDEX
	 RET			;NOT THERE
	MOVE P2,T2		; Save index
	SKIPG P1,HOSTPN(T2)	; has it a name?
	 SETO P1,		; no
	RET

IFKA <
;;; Convert host number in AC1 to new format

CVNHST::CAMN T1,[-1]		;IF -1 USE LOCAL HOST NUMBER
	 MOVE T1,DEFADR		; Default local host
	AND T1,[HSTMSK]		;CUT DOWN TO SIZE
	TLNE T1,37700
	 RET
	ANDI T1,377
	TRZE T1,100		;SET THE HOST BITS
	 TRO T1,200000
	TRZE T1,200
	 TRO T1,400000
	IOR T1,NETFLD		;Add default network number
	RET
> ; End of IFKA

GTHSTR:	CALL GTHSTN		;CONVERT STRING TO NUMBER	
	SKIPL T2		;VAILD STRING FOUND?
	 RETERR(GTHSX5)		; no, return error
	MOVE P1,T2		; Save
	SETSEC P1,MNTSEC	; in the right section
	MOVE T1,T4		;GET INDEX TO HOSTNN
	CALL CVNHST		; Convert number to 32 bits if necessary
	CALL HSTHSH		; Look it up in tables
	 RETERR(GTHSX2)		; Not there
	MOVE P2,T2		; Save that index
	JRST GTHSXX		;EXIT

;;; Convert host string to a number
;;; returns T4/ Number
;;;	    T2/ >0 not found
;;;		<0 RH index to HOSTN
GTHSTN:	STKVAR <<GTHSBF,10>>
	MOVEI P3,GTHSBF		; Point to buffer
	HRLI P3,(<POINT 7,0>)	; ....
	CALL GTHSIN		;GET STRING FROM USER
	MOVEI T1,GTHSBF		;MAKE BYTE POINTER
	HRLI T1,(<POINT 7,0>)
	CALLRET HSTLUK		;LOOKUP NAME

GTHHNI:	HRRZ T1,T3		;GET INDEX
	CAIL T1,NHOSTS		; Compare to table size
	 RETERR (GTJIX1)	; Bad index
	SETSEC T1,MNTSEC	; Put in proper section

	SKIPA T1,HOSTNN(T1)	; Get number
GTHHNN:	  MOVE T1,T3		;GET HOST NUMBER
	CALL GTHNTS		;CONVERT NUMBER TO INDEX
	JUMPL P2,[RETERR (GTHSX1)] ;UNKNOWN HOST
	JRST GTHSXX		;EXIT

;;; Move string from user space 
GTHSIN:	UMOVE T1,2		; GET POINTER
	MOVE T4,[XCTBU [ILDB T2,T1]]
	TLNN T1,777777		; IF JFN DO THE JSYS
	 MOVE T4,[BIN]
	TLC T1,777777		; CHECK FOR LH -1
	TLCN T1,777777
	 HRLI T1,(<POINT 7,0>)	; USE STANDARD POINTER
	MOVEI P5,MAXLC		; UP TO 39 CHARS
GTHSIL:	XCT T4			; DO RIGHT OPERATION
	SOSG P5			; Decrement counter
	 MOVEI T2,0		; AFTER MAXLC CHARS FORCE NULL
	CAIL T2,140		; LOWER CASE?
	 TRZ T2,40		; YES, RAISE
	CAIE T2,"."		;#550 For now ignore domains
	 CAIG T2,40		; END ON SPACE OR LESS
	  MOVEI T2,0		; terminating with null
	IDPB T2,P3		; Stick it in destination string
	JUMPG T2,GTHSIL		; loop if more to it
	CAME T4,[BIN]		; DON'T BACKUP A TTY
	BKJFN			; backup to before termination
	 NOP			; (shouldn't fail)
	UMOVEM T1,2		; restore updated pointer
	RET			; and return

;;; Write string to user space
;;; Called with T1 - Dest in user space
;;; Returns +1 T1 updated pointer
GTHSOU:	MOVE T4,[XCTBU [IDPB T2,T1]]
	TLNN T1,777777		; IF JFN DO THE JSYS
	 MOVE T4,[BOUT]
	TLC T1,777777		; CHECK FOR LH -1
	TLCN T1,777777
	 HRLI T1,(<POINT 7,0>)	; USE STANDARD POINTER
GTHSOL:	ILDB T2,P3		; Get next byte
	JUMPE T2,GTHSOX		; If a null
	XCT T4			; DO RIGHT OPERATION
	JRST GTHSOL		; Loop
GTHSOX:	CAMN T4,[BOUT]		; Don't backup a JFN
	 RET			; Return now if a JFN
	XCT T4			; Stick on NULL
	BKJFN			; Backup destination
	 NOP			; ...
	RET			; and return


;;; New functions

;;; Get hostnumber on a network
;;; Accepts T2 - Network number, or host number on the net
;;; Returns +1 if no interface on that network
;;; +2 if we have one, T2 - Hostnumber
GTHNHN:	MOVE T1,T2		; Get number
	CALL NETNCT		; Look for an NCT for that net
	 RETERR (GTHSX5)	; Return error if none
	MOVE T1,NTLADR(P1)	; Get our number there
	UMOVEM T1,T2		; Restore it to user
	JRST SKMRTN		; And do a skip return

;;; Get status of a network
;;; Accepts T2 - Network number or host number on the net
;;;	    T3 - Pointer to where to store data
;;;	    T4 - -Number of words,,offset of first
;;; Returns +1 if no such network or invalid offset
;;;	    +2 if good arguments with data in table
;;;
GTHNST:	MOVE T1,T2		; Get number
	CALL NETNCT		; Look it up
	 RETERR(GTHSX5)		; Bad number
	HLRE T1,T4		; Get number wanted
	MOVMS T1		; Magnitude
	ADDI T1,(T4)		; Add in first
	CAILE T1,NTXUPT-NTRDY+1	; Size of area
	 RETERR(GTJIX1)		; Bad
	XMOVEI P1,NTRDY(P1)	; Point to start of area
	ADDI P1,(T4)		; Add in offset of fist word
	XCTU [HRR T4,T3]	; Setup an AOBJN destination pointer
GTHNS0:	MOVE T1,0(P1)		; get a word
	UMOVEM T1,0(T4)		; Store it
	AOS P1			; Increment source pointer
	AOBJN T4,GTHNS0		; And loop through all desired
	JRST SKMRTN		; And do a skip return
IFKA <			; In MNETWK on TOPS-20
HSTLUK::SAVEPQ				;GET SOME ROOM
	MOVE UNIT,T1			;SAVE POINTER
	MOVEI T3,10
	NIN				;TRY TO GET A NUMBER
	 JRST HSTLKI			;TRY A NAME
	MOVE UNIT,T1			;SAVE UPDATED POINTER
	MOVE T1,T2
	CALL CVNHST
	MOVE T4,T1			;RETURN HOST NUMBER
	MOVE T1,UNIT			;AND UPDATED POINTER
	SETZ T2,			;HOST NUMBER FOUND
	RET

HSTLKI:	HRLZ T2,MHOSTS			;SCAN THE TABLE
IFNKA <	PUTSEC STS,MNTSEC>		; In this section
IFKA <	SETZ T4,>
HSTLK0:	MOVE T1,UNIT			;DO NAME POINTER
IFNKA	<
	LOAD T4,HSTNMP,(STS)
	ADD T4,[XWD MNTSEC,HSTNAM]	; Point to the table
	MOVE T3,[<POINT 7,0>!1B12]	; Make extended pointer
>
IFKA	<
	LOAD T3,HSTNMP,(T4)
	ADD T3,[POINT 7,HSTNAM]
>
HSTCMP:	ILDB IOS,T1			;COMPARE A STRING
	ILDB HN,T3
	SKIPN IOS
	 JUMPE HN,[
		IFNKA <
		   LOAD T4,HSTIDX,(STS)
		   SETSEC T4,MNTSEC>
		IFKA <LOAD T4,HSTIDX,(T4)>
		   MOVE T4,HOSTNN(T4)
		IFNKA <HRR T2,STS>		; Save index
		IFKA <HRR T2,T4>		; Save index
		   RET]
	CAIN IOS,(HN)
	 JRST HSTCMP
IFNKA <	AOS STS>				; Point to next slot in table
IFKA <	AOS T4>
	AOBJN T2,HSTLK0			;STEP TO NEXT HOST
	SETZ T4,			;NO HOST FOUND
	RET
;ROUTINE TO PRODUCE THE OLD HOSTN TABLE

GHOSTN::HRRZ T4,HOSTN(T2)		;GET INDEX
	MOVE T1,HOSTNN(T4)		;GET THE HOST NUMBER
	CALL CVOHST			;CONVERT TO OLD FORMAT
	MOVE T3,HSTSTS(T4)		;GET HOST STATUS
	ANDI T3,777000			;GET THE RIGHT BITS
	IORI T1,(T3)			;BUILD LH
	MOVSI T1,(T1)
	SKIPGE HOSTN(T2)		;NICKNAME?
	 TXO T1,HS%NCK
	HLR T1,HOSTN(T2)		;GET THE NAME POINTER
	TRZ T1,400000			; Clear nickname flag
	RET

;CONVERT HOST NUMBER IN AC1 TO OLD FORMAT

CVOHST::CAMN T1,[-1]		;NO HOST?
	 JRST CVOHS1		;RETURN 777
	TDZE T1,[740077,,177700];CHECK TO SEE IF FITS IN OLD FORMAT
	 MOVEI T1,400		;RETURN 400
	TRZE T1,200000		;SET THE HOST BITS
	 TRO T1,100
	TRZE T1,400000
	 TRO T1,200
CVOHS1:	ANDI T1,777
	POPJ P,

; Routine to produce (a subset of) the old NETRDY table.
; Gets status from the NCT for the "default" network.

GTBIRD::PUSH P,T2
	MOVE T1,DEFADR
	CALL FNDNCT
	 MOVE P1,NCTVT
	POP P,T2
	XCT GTBITX(T2)
	RET

GTBITX:	MOVE T1,NTRDY(P1)	; IMPRDY 0=down, .gtr. 0 =going down, -1=up
	MOVE T1,NETON(P1)	; NETON  0=network off
	SETZ T1,		; NETENT Flags to drive netser. e.g., don't allow login
	SETZ T1,		; NCPUPT Gtad of last time ncp cycled up
	SETZ T1,		; IGDMSG Most recent imp-going-down msg
	MOVE T1,NTXDNT(P1)	; IMPDNT Time of last imp ready line drop
	MOVE T1,NTXUPT(P1)	; IMPUPT Time of last imp ready line up
	SETZ T1,		; IGDTIM Time of above imp-going-down msg
IMPGTN==:.-GTBITX
> ; End of IFKA
	RESCD
;;; LCKSTR - Lock down a region of core
;;; 1 - Xtended address of start
;;  2 - Xtened address of end
;;;
;;; (probably should be in PAGEM, but this keeps the sources cleaner)
LKSTOR::
	TRZ T1,777		; Round down to nearest page
LKST1:
	PUSH P,T1		; Save start
	PUSH P,T2		; and end
	CALL MLKMA		; Lock down that page
	POP P,T2			; Rstore
	POP P,T1			; ...
	ADDI T1,PGSIZ		; Increment to next page
	CAMG T1,T2		; Past last address?
	 JRST LKST1		; Loop
	RET

	TNXEND
	END			; Of MNETDV