Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_1_19910112 - 7/ft3/monitor/stanford/mnetdv.mac
There are 10 other files named mnetdv.mac in the archive. Click here to see a list.
;[MACBETH.STANFORD.EDU]SRC:<7.FT3.MONITOR.STANFORD>MNETDV.MAC.2,  7-Dec-88 12:01:02, Edit by A.ALDERSON
; Make Crispin's correction at GTHHNN+2 (P2 +> P1)
;[MACBETH.STANFORD.EDU]SRC:<7.FT2.MONITOR.STANFORD>MNETDV.MAC.3, 20-Jun-88 18:48:27, Edit by A.ALDERSON
; V7.0 FT Clock tape
;[MACBETH]SRC:<7.FT2.MONITOR.STANFORD>MNETDV.MAC.2,  6-Apr-88 03:40:17, Edit by A.APPLEHACKS
; FT7.2 Merge
;[MACBETH]SRC:<7.FT1.MONITOR.STANFORD>MNETDV.MAC.2, 25-Jan-88 22:06:29, Edit by A.APPLEHACKS
; FT7 Merge
;;SIERRA::SRC:<6.1.MONITOR.STANFORD>MNETDV.MAC.6, 19-Jan-87 21:18:05, Edit by GROSSMAN
;; Install SRA's fix for field length overflows.
;;<6-1-MONITOR.FT6>MNETDV.MAC.5, 27-Aug-85 10:35:12, Edit by WHP4
;;Stanford changes:
;; Buffer input for HSTINI to greatly speed up host table parsing (3 x faster)
;; If DBUGIP/2, turn on networks irrespective of DBUGSW
;; MNTSTS prints a more useful message
;; FNDNCT and NETNCT know about the possibility of multiple interfaces
;; Fix MNTSET to actually start/stop/cycle the interface
;; MEIS support for 3MB and 10MB Ethernet
;; Initialize ISI domain service at system startup
;; Add locking on host table access
;; ULTRIX is a synonym for UNIX
;;Pup changes:
;; ATNVT% for Pup NVT's
;
; UPD ID= 8689, RIP:<7.MONITOR>MNETDV.MAC.6,  18-Mar-88 10:52:50 by GSCOTT
;TCO 7.1261 - Set NOADDR to be not normally dumpable.
; UPD ID= 8670, RIP:<7.MONITOR>MNETDV.MAC.5,  26-Feb-88 10:36:52 by GSCOTT
;TCO 7.1243 - Use SYSTEM:HOSTS.DEBUG if DBUGSW is greater than one.
; UPD ID= 8554, RIP:<7.MONITOR>MNETDV.MAC.4,  11-Feb-88 11:03:14 by GSCOTT
;TCO 7.1218 - Update copyright date.
; UPD ID= 8425, RIP:<7.MONITOR>MNETDV.MAC.3,   4-Feb-88 13:29:58 by GSCOTT
;TCO 7.1210 - Set NOHSTN normally not dumpable.
; UPD ID= 2123, SNARK:<6.1.MONITOR>MNETDV.MAC.11,   5-Jun-85 09:58:02 by MCCOLLUM
;TCO 6.1.1406  - Update copyright notice.
; UPD ID= 1957, SNARK:<6.1.MONITOR>MNETDV.MAC.10,  12-May-85 14:54:53 by PAETZOLD
;TCO 6.1.1380 - Make HOSTN larger.
; UPD ID= 1608, SNARK:<6.1.MONITOR>MNETDV.MAC.9,   8-Mar-85 11:53:53 by PAETZOLD
;Document BUGxxx's
; UPD ID= 1570, SNARK:<6.1.MONITOR>MNETDV.MAC.8,  26-Feb-85 17:17:32 by PAETZOLD
;document BUGxxx's
; UPD ID= 1235, SNARK:<6.1.MONITOR>MNETDV.MAC.7,  22-Dec-84 11:43:29 by PAETZOLD
;More TCO 6.1.1079 - Make the XJRST conditional based on REL6 switch for 5.4.
; UPD ID= 1178, SNARK:<6.1.MONITOR>MNETDV.MAC.6,  11-Dec-84 13:15:23 by PAETZOLD
;TCO 6.1.1079 - Use an XJRST referecing TVTJFN in ATNVT.
; UPD ID= 1038, SNARK:<6.1.MONITOR>MNETDV.MAC.5,  12-Nov-84 15:25:34 by PAETZOLD
;TCO 6.1041 - Move ARPANET to XCDSEC
; UPD ID= 999, SNARK:<6.1.MONITOR>MNETDV.MAC.4,   7-Nov-84 14:46:40 by PRATT
;TCO 6.1.1030 - Add IPCI to INTNAM for communicating over the CI
; UPD ID= 917, SNARK:<6.1.MONITOR>MNETDV.MAC.3,  23-Oct-84 19:49:20 by PAETZOLD
; UPD ID= 312, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.11,  18-Oct-84 15:41:24 by PAETZOLD
;TCO 6.1.1024 - Add .GTHLA function to GTHST%.
; UPD ID= 304, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.10,  15-Oct-84 14:46:20 by PAETZOLD
;Fix alphabetical order problem in OPSTAB.
; UPD ID= 287, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.9,  24-Sep-84 13:55:04 by PURRETTA
;Update copyright notice.
; UPD ID= 163, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.8,   3-Jun-84 17:26:35 by PAETZOLD
;Make  MNTHLT  reset  NETON  for  each interface so that it stays down. 
;Clean up MNTHLT in general.  Remove MNTKIL since no one uses it.
;Add VMS, TACs, and MSDOS to OPSTAB.
; UPD ID= 159, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.7,   1-Jun-84 11:35:17 by PAETZOLD
;AOS INTFLG in MNTSET.
; UPD ID= 156, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.6,  31-May-84 11:25:18 by PAETZOLD
;Use indirects in MNTRSV
; UPD ID= 155, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.5,  31-May-84 10:58:54 by PAETZOLD
;Add MNTRSV.  Add some ENDSV.'s.
; UPD ID= 129, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.4,  14-May-84 16:13:25 by PAETZOLD
;MNTHLT needs an EA.ENT.
; UPD ID= 33, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.3,   7-Apr-84 13:15:19 by PAETZOLD
;Remove some spaces in initial HSTINI message.
; UPD ID= 31, SNARK:<TCPIP.5.4.MONITOR>MNETDV.MAC.2,   5-Apr-84 22:46:02 by PAETZOLD
;Add IPNI to INTNAM. Change SITE-ADDRESS.TXT to INTERNET.ADDRESS. Clean
;up  MNTSTS  output.  Use  NETPRT  to  print  out  network numbers. Add
;informational message during startup when calling HSTINI.
; UPD ID= 4022, SNARK:<6.MONITOR>MNETDV.MAC.13,  31-Mar-84 16:20:59 by PAETZOLD
;TCO 6.2019 - Use ADJSPs
; UPD ID= 3941, SNARK:<6.MONITOR>MNETDV.MAC.12,  18-Mar-84 13:15:57 by PAETZOLD
;More TCO 6.1733 - Do not check for dots in GTHSIL.
; UPD ID= 3935, SNARK:<6.MONITOR>MNETDV.MAC.11,  17-Mar-84 13:01:33 by PAETZOLD
;More TCO 6.1733 - Add Fuzzballs to OPSTAB
; UPD ID= 3921, SNARK:<6.MONITOR>MNETDV.MAC.10,  14-Mar-84 10:17:06 by PAETZOLD
;More TCO 6.1733 - Add Foonex to OPSTAB as Tenex
; UPD ID= 3901, SNARK:<6.MONITOR>MNETDV.MAC.9,  11-Mar-84 14:28:21 by PAETZOLD
;More TCO 6.1733 - 5.3 needs a EA.ENT in MNTINI
; UPD ID= 3894, SNARK:<6.MONITOR>MNETDV.MAC.8,  11-Mar-84 10:36:16 by PAETZOLD
;More TCO 6.1733 - Allow  JFNs in ATNVT%. New HSTINI preference scheme.
;Make HSTINI set  up gateway (HS%GAT)  and  network  (HS%NET)  entries.
;Make  RDFLD fold case to upper. Add TAC and WAITS to OPSTAB. Check and
;dispatch for Pup JFN in .ATNVT.
; UPD ID= 3826, SNARK:<6.MONITOR>MNETDV.MAC.7,  29-Feb-84 18:15:40 by PAETZOLD
;More TCO 6.1733 - ANBSEC and MNTSEC removal.  Bug fixes.  Cleanup.
;<TCPIP.5.3.MONITOR>MNETDV.MAC.4,  6-Dec-83 23:53:55, Edit by PAETZOLD
;Call CHKI7 from MNTCHK
;TCO 6.1867 - Use SAVEAC and not SAVP1
;Add subtitles.  Make code that was RSCOD SWAPCD.
;More TCO 6.1733 - Fix day one off by one bug with NUMOPS
;More TCO 6.1733 - NCPFRK has gone away.  HSTLUK Changes.  HSTINI changes.
;<TCPIP.5.1.MONITOR>MNETDV.MAC.42,  5-Jul-83 08:28:09, Edit by PAETZOLD
;New host table support
;IP debuging switch support
;Use ANAUNV as the universal

;	COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1976, 1988.
;	ALL RIGHTS RESERVED.
;
;	THIS SOFTWARE IS FURNISHED UNDER A  LICENSE AND MAY BE USED AND  COPIED
;	ONLY IN  ACCORDANCE  WITH  THE  TERMS OF  SUCH  LICENSE  AND  WITH  THE
;	INCLUSION OF THE ABOVE  COPYRIGHT NOTICE.  THIS  SOFTWARE OR ANY  OTHER
;	COPIES THEREOF MAY NOT BE PROVIDED  OR OTHERWISE MADE AVAILABLE TO  ANY
;	OTHER PERSON.  NO  TITLE TO  AND OWNERSHIP  OF THE  SOFTWARE IS  HEREBY
;	TRANSFERRED.
;
;	THE INFORMATION IN THIS  SOFTWARE IS SUBJECT  TO CHANGE WITHOUT  NOTICE
;	AND SHOULD  NOT  BE CONSTRUED  AS  A COMMITMENT  BY  DIGITAL  EQUIPMENT
;	CORPORATION.
;
;	DIGITAL ASSUMES NO  RESPONSIBILITY FOR  THE USE OR  RELIABILITY OF  ITS
;	SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.


	SEARCH ANAUNV,PROLOG
	TTITLE (MNETDV,MNETDV,< - Internet Multinet Interface>)
	Subttl	Table of Contents

;		     Table of Contents for MNETDV
;
;				  Section		      Page
;
;
;    1. MNTINI - Initialization  . . . . . . . . . . . . . . .   3
;    2. MNETON - Turn Networks On if They Have Never Been On .   4
;    3. MNTCHK - CHKR Fork Routine . . . . . . . . . . . . . .   5
;    4. MNTSTS - Report Network State Changes  . . . . . . . .   6
;    5. NETPRT - Print Network Name or Number  . . . . . . . .   7
;    6. Low and High Priority Packet Output Queueing . . . . .   8
;    7. NTWPKT - Packet Queueing Routine . . . . . . . . . . .   9
;    8. NTSNDI - Queue an Internet Packet  . . . . . . . . . .  10
;    9. Routines to Find NCTs  . . . . . . . . . . . . . . . .  11
;   10. HSTHSH - Find Host Table Entries . . . . . . . . . . .  12
;   11. Host, Network Status and Configuration Routines  . . .  13
;   12. Routines Dealing With Network Shutdown . . . . . . . .  15
;   13. Routines Dealing With Network States . . . . . . . . .  16
;   14. Routine to Resolve Interface State . . . . . . . . . .  17
;   15. Host Table Initialization  . . . . . . . . . . . . . .  18
;   16. GTFIL - GTJFN Routine for HSTINI and ADRINI  . . . . .  29
;   17. ADRINI - Routine to Read SYSTEM:SITE-ADDRESS.TXT . . .  30
;   18. CVHST% JSYS - Convert Host Number to String  . . . . .  37
;   19. GTHST% JSYS  . . . . . . . . . . . . . . . . . . . . .  38
;   20. GTHST% JSYS - Individual Functions . . . . . . . . . .  39
;   21. ATNVT% JSYS and NETRDY GETAB Table . . . . . . . . . .  43
;   22. HSTLUK - Lookup Host Names . . . . . . . . . . . . . .  44
	SUBTTL MNTINI - Initialization

	XSWAPCD

;Called  at  system startup, initializes tables and storage needed by
;Multinet.

	XNENT (MNTINI,G)
	CALL NETINI		; initialize the 1822 buffers
	MOVEI T1,BMNTLK		; Beginning of pages needed to lock down
	SETSEC T1,INTSEC	; In proper section
	MOVEI T2,EMNTLK		; End of area to lock
	SETSEC T2,INTSEC	; Same section
	CALL LKSTOR		; Lock storage
	SETZM DEFADR		; Clear default address field
	SETZM PRFADR		; Clear preferred address field
	SETZM PRFNFD		; Also clear preferred shifted network
	SETZM PRFNET		; And preferred network
	SETZM NETSUP		; Networks not yet up
	MOVSI T1,-%NETS		; Get number of networks we handle
	SKIPA P1,NCTVT		; get link to the first NCT
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
	AOBJN T1,MNTIN0		; Loop through all
	SETZRO NTLNK,(P1)	; Clear last pointer (End of list)
	CALL ADRINI		; Init addresses
	BUG.(INF,NOADDR,MNETDV,SOFT,<ADRINI failed to find address file>,,<

Cause:	The SYSTEM:INTERNET.ADDRESS file was either not found or is corrupted.

>,,<DB%NND>)			;[7.1261]
IFN STANSW,<
	SETOM GTHLCK		; Init lock on host table
IFN FTDOM,<
	CALL DOMINI		; Initialize domain service
	 BUG.(INF,DMIFNF,MNETDV,SOFT,<GTDOM - domain service not initialized>)
>;IFN FTDOM
>;IFN STANSW
	TMSG <
[Loading Internet host names]>
	CALL HSTINI		;GET THE SYSTEM TO KNOW NAMES OF SITES
	 TRNA			; skip on error
	  JRST MNTIN1		; no error
	 BUG.(INF,NOHSTN,MNETDV,SOFT,<HSTINI failed to find host name file>,,<

Cause:	The SYSTEM:HOSTS.TXT file was not found.  The file SYSTEM:HOSTS.DEBUG
	is used if DBUGSW is 2 or greater.
>,,<DB%NND>)			;[7.1261]
	JRST MNTIN2		; continue with flow
MNTIN1:
	TMSG < [OK]
>
MNTIN2:
	CALL NETHSI		; Initialize the network hash table
IFE STANSW,<
	MOVE T1,DBUGSW		; Get system switch
	CAIG T1,1		; are we stand alone?
	 TDZA T1,T1		; we are not stand alone
	  MOVEI T1,1		; we are stand alone
	SKIPE DBUGIP		; IP Debuging?
	 XORI T1,1		; yes so reverse flag
	SKIPN T1		; System normal?
>;IFE STANSW
IFN STANSW,<
;;;DBUGIP/0 means turn on nets iff not standalone
;;;DBUGIP/1 means turn on nets iff standalone
;;;DBUGIP/2 means turn on nets always (new functionality added by this change)
	CAILE T1,1		; are we stand alone?
	 TDZA T1,T1		; we are stand alone
	  MOVEI T1,1		; we are not stand alone
	XOR T1,DBUGIP		; consider this per DBUGIP
	SKIPE T1		; System normal?
>;IFN STANSW
	 SKIPN DEFADR		; Did addresses initialize properly?
	  JRST MNTINX		; No, return now
	JRST MNTON1		; Go turn on networks

;LKSTOR - Lock down a region of core
;1 - Xtended address of start
;2 - Xtened address of end

LKSTOR:
	TRZ T1,777		; Round down to nearest page
LKST1:
	PUSH P,T1		; Save start
	PUSH P,T2		; and end
	CALLX (MSEC1,MLKMA)	; Lock down the page
	POP P,T2		; Restore ACs
	POP P,T1		; ...
	ADDI T1,PGSIZ		; Increment to next page
	CAMG T1,T2		; Past last address?
	 JRST LKST1		; Loop
	RET
	SUBTTL MNETON - Turn Networks On if They Have Never Been On

;Turn networks on if NETSUP has been off. Called by CALL MNETON$X

	XNENT (MNETON,G)
MNTON1:
	SKIPA P1,NCTVT		; Point to vector table
MNTON2:  LOAD P1,NTLNK,(P1)	; get next in list
	JUMPE P1,MNTINY		; Return when done
	MNTCALL NTINI		; Initialize network device
	SETOM NETON(P1)		; Turn it on
	SETZM NTPRIO(P1)	; Clear priority cell
	MNTCALL NTRSRT		; get it going
	JRST MNTON2		; and loop
MNTINY:	SETOM NETSUP		; Networks are now initialized
MNTINX:	RET			; And return
	SUBTTL MNTCHK - CHKR Fork Routine

;CHKR Fork routine for keeping things going on all nets. Called every
;four minutes or whenever JB0FLG is non-zero.

	XNENT (MNTCHK,G)
	SKIPA P1,NCTVT		; Point to the vector table
MNTCH0:	 LOAD P1,NTLNK,(P1)	; Get next in list
	JUMPE P1,MNTCH2		; Go check the rest 
	SKIPE NTSTCH(P1)	; Change of state?
	 CALL MNTSTS		; Yes
	SKIPN NETON(P1)		; If network off
	 JRST MNTCH0		; Loop
				; Want net on
	MNTCALL NTSCHK		; Check status, keep stuff consistent
	 JFCL			; Ignore error return
	SKIPG NETON(P1)		; If needs restarting
	 SKIPL NTRDY(P1)	; Or isn't ready
	  MNTCALL NTRSRT	; Restart it
	MOVE T1,TODCLK		; Get time now
	CAML T1,NTTOUT(P1)	; Output timed out?
	 SKIPN NTTOUT(P1)	; Output actually going?
	  JRST MNTCH1		; No timeout
	BUG.(INF,NTOHNG,MNETDV,SOFT,<Network output hung>,<<P1,D>>,<

Cause:	Multinet has declared the output interface for a network hung.

>)
	MNTCALL NTRSRT		; If timeout, reset net
MNTCH1:	MNTCALL NTISRT		; Make sure input is happening
	MOVE T1,SCTLW		; System shutdown?
	TXNN T1,<1B3>
	 JRST MNTCH0		; No, loop through all
				; System shutdown
	SETZM NTRDY(P1)		; Imp off
	SETZM NETON(P1)		; Net off
	SETZM NTORDY(P1)	; output off
	SETO T1,		; Abort entry
	MNTCALL NTKILL		; Drop ready line
	JRST MNTCH0		; and loop through the rest

MNTCH2:
	SKIPE IMPGDM		; Any "imp going down" messages?
	 CALL CHKI7		; Yes, go print it
	RET			; And return
	SUBTTL MNTSTS - Report Network State Changes
IFE STANSW,<       
MNTSTS: 			; Log network change of state
	MOVE T2,NTLADR(P1)	; Get number
	JUMPL T2,R		; Don't report if no address set
	HRROI T1,[ASCIZ /
[Internet Network /]
	PSOUT
	CALL NETPRT		; Print out the network number
	HRROI T1,[ASCIZ / on/]	; Assume it is on
	SKIPN NETON(P1)		; Is it on?
         HRROI T1,[ASCIZ / off/] ; no
	PSOUT			; output it
	HRROI T1,[ASCIZ /, Output /] ;delimit
	PSOUT			; output it
	HRROI T1,[ASCIZ /on/]	; assume on
	SKIPN NTORDY(P1)	; is output on?
         HRROI T1,[ASCIZ /off/]	; no
	PSOUT			; output it
	MOVEI T1," "		; delimit
	PBOUT			; output it
	SETZM NTSTCH(P1)	; reset the state change time
	CALL LGTAD		; get time of this change
	SKIPGE T2,T1		; If time known
	 JRST MNTC5X		; Not known.
	MOVEI T1,.PRIOU		; Still on CTY
	MOVEI T3,0		; this time
	ODTIM			; output it
MNTC5X:	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
>;IFE STANSW
IFN STANSW,<
MNTSTS:	SKIPG NTLADR(P1)	;Skip if initialized
	 RET			;Else ignore this interface
	CALLX (MSEC1,TIMSMP)	;Print time stamp
	TMSG < Internet: Interface >
	LOAD T2,NTNUM,(P1)
	CALL DECOUT		;Say which interface is involved
	HRROI T1,[ASCIZ/ is up/]
	SKIPN NTORDY(P1)
	HRROI T1,[ASCIZ/ is down/]
	PSOUT%			;Say whether host is up or down
	TMSG <, host number >
	LDB T2,[POINT 8,NTLADR(P1),11]
	CALL DECDOT		;First octet
	LDB T2,[POINT 8,NTLADR(P1),19]
	CALL DECDOT		;Second octet
	LDB T2,[POINT 8,NTLADR(P1),27]
	CALL DECDOT		;Third octet
	LDB T2,[POINT 8,NTLADR(P1),35]
	CALL DECOUT		;Forth octet
	TMSG <
>
	SETZM NTSTCH(P1)	;No more change of state
	SKIPN NTORDY(P1)	;Did the hardware come up?
	  CALLRET INTDWN	;No, signal it's down
	CALLRET	INTUP		;Signal that it's available for use

DECDOT:	TDZA T4,T4		;Here if we want a trailing dot
DECOUT:	SETO T4,		;Here for an unadorned decimal number
	MOVX T1,.PRIOU		;To the console
	MOVX T3,^D10		;Decimal
	NOUT%			;Print it 
	 NOP
	JUMPN T4,R		;Return now if no dot
	MOVEI T1,"."
	PBOUT%			;Print the dot
	RET
>;IFN STANSW
	SUBTTL NETPRT - Print Network Name or Number

NETPRT:				; Print the network number for current NCT
	STKVAR <NPRTX,NPRBP>
	MOVEI T1,.PRIOU		; Primary output
	DOBE%			; dismiss until output done
	 ERJMP .+1		; Handle errors
	MOVE T1,NTNET(P1)	; Get the network number
	LSH T1,10		; Move it over one byte
	CAMG T1,[BYTE (4)0(8)0,377,377,377] ; Class A or B?
	 LSH T1,10		; yes move it over one more byte
	CAMG T1,[BYTE (4)0(8)0,377,377,377] ; Class A?
	 LSH T1,10		; yes move it over one more byte
	MOVEM T1,NPRTX		; save it
	MOVEI T1,.GTHNS		; Get host name function
	MOVEI T2,.PRIOU		; Output to CTY
	MOVE T3,NPRTX		; Get the network number
	GTHST%			; Output the network number
	 ERJMP NETPR1		; on error assume no name
	RET 			; and return

NETPR1:				; here when we do not have a network name
	MOVX T1,<POINT 8,NPRTX,3> ; get the byte pointer
	MOVEM T1,NPRBP		; and save it
	MOVEI T4,4		; four octets
NETPR2:				; output loop
	ILDB T2,NPRBP		; get a byte
	MOVEI T1,.PRIOU		; output to cty
	MOVEI T3,12		; in decimal
	NOUT%			; output the octet
	 ERJMP .+1		; handle errors
	SOJE T4,R		; on the last one return
	MOVEI T1,"."		; otherwise get a dot
	PBOUT%			; output it
	JRST NETPR2		; and do the rest
	ENDSV.
	SUBTTL Low and High Priority Packet Output Queueing

;NTHSND - Put packet on High priority Q.
;T2/ packet pointer
;P1/ NCT address
;Returns+1	Refused
;Returns+2	Packet succesfully queued

	XRESCD

NTSNDX:	BUG.(CHK,BADADR,MNETDV,SOFT,<No NCT for address>,<<T1,ADR>>,<

Cause:	The multinet output queuing mechanism was called for a local
	address that has not been defined.

>)
	RET			; return

NTHSND::SAVEAC <P1>
	CALL FNDNCT
         JSP CX,NTSNDX		; Nope
	XMOVEI T1,NTHOBO(P1)	; Point to Q
	JRST NTQPKT		; And queue it

;NTLSND - Put packet on low priority Q
;T2/ packet pointer
;P1/ NCT address
;Returns+1	Refused
;Returns+2	Packet succesfully queued

NTLSND::SAVEAC <P1>
	CALL FNDNCT
         JSP CX,NTSNDX		; Not found
	XMOVEI T1,NTLOBO(P1)
	JRST NTQPKT
	SUBTTL NTWPKT - Packet Queueing Routine

;NTWPKT - Put packet on FIFO Q
;T1/	pointer to Q head
;T2/	packet pointer
;P1/	NCT address
;Returns+1	Refused
;Returns+2	Packet succesfully queued

NTQPKT:	SKIPN NTORDY(P1)	; Output allowed?
         RET			; No, fail
	TRNN T2,-1		; Is the address good?
	BUG.(HLT,BADBUF,MNETDV,SOFT,<Null buffer address>,,<

Cause:	Multinet has been called to queue an output buffer with a null
	address.

>)
	HRRZS 0(T2)		; Make sure succesor chain is NIL
	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
	SUBTTL NTSNDI - Queue an Internet Packet

;NTSNDI - Default routine for enquing an internet packet
;      T1/	Local host
;      T2/	packet pointer
;      P1/	NCT address
;Returns+1	Refused,  T1 has an ICMP error code
;Returns+2	Packet succesfully queued

NTSNDI::MNTCALL NTOTOK		; Can this packet be sent?
         RET			; No, T1 has reason
	MNTCALL NTLLDR		; Make a local header
	XMOVEI T1,NTIOBO(P1)	; 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
	SUBTTL Routines to Find NCTs

;FNDNCT - Host number to NCT
;T1/	Host address
;Returns+1	No NCT for that net
;Returns+2	P1/ pointer to the NCT for a (usable) interface on that net

FNDNCT::SAVET			; Save temps
IFN STANSW,<
	STKVAR <HOST>		; Declare local storage
	MOVEM T1,HOST		; Save host number
>;IFN STANSW
	NETNUM T2,T1		; Get the network number
	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
IFN STANSW,<
	MOVE T1,HOST		; Get back that host number
	CALL FNDINT		; Ensure best interface to this network
>;IFN STANSW
	RETSKP			; And skip return
IFN STANSW,<
	ENDSV.			; Flush STKVAR definition
>;IFN STANSW

;NETNCT - Host or Net to NCT of a (possibly down) interface on that net.

;T1/	Host address or Net number
;Returns+1	No NCT for that net
;Returns+2	P1/ pointer to the NCT for a (usable) interface on that net

NETNCT::SAVET			; Save temps
IFE STANSW,<
	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
>;IFE STANSW
IFN STANSW,<
	SETZ T2,		; Assume not a host address
	TXNN T1,-1B11		; Host address?
	  JRST NETNC0		; No
	MOVE T2,T1		; Yes, stash a copy in T2
	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
	CAME T1,NTNET(P1)	; Same network?
	 JRST NETNCL		; no, loop
	SKIPE T1,T2		; If we were looking for a host's NCT
	 CALL FNDINS		; Then find the best interface, strict match
	RETSKP			; Return success
>;IFN STANSW
	SUBTTL HSTHSH - Find Host Table Entries

;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,INTSEC	;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 INTSEC,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
	SUBTTL Host, Network Status and Configuration Routines

	XSWAPCD

;NETCHK - Check if our interface on a given net is up
;T1/	Host number
;Returns+1	if interface is down
;Returns+2	if it is up

NETCHK::SAVEAC <P1>
	CALL NETNCT		; Find the NCT
	 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.

;T1/	Host number
;P1/	Pointer to NCT
;Returns+1	if host is not on that interface
;Returns+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.
;T1/	Host address
;Returns+1	If no intersecting network
;Returns+2	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 (possibly with non-zero logical host
;field) is one of ours
;T1/	32 bit address
;Returns+1	if it is not one of ours
;Returns+2	if it is

LCLHST::SAVEAC <P1>
	PUSH P,T1		; Save address
	SKIPA P1,NCTVT		; First interface
LCLHS0:  LOAD P1,NTLNK,(P1)	; Next interface
	JUMPE P1,LCLHS9		; No more
	MOVE T1,(P)		; Address again
	ANDCM T1,NTNLHM(P1)	; without logical host field
	CAME T1,NTLADR(P1)	; Is this one of ours?
         JRST LCLHS0		; No, loop through all

	AOS -1(P)		; Success! it's me, skip return
LCLHS9:	POP P,T1		; Restore address
	RET
	SUBTTL Routines Dealing With Network Shutdown

;T1/ Reason, a la 1822
;T2/ GTAD when back up

	XNENT (MNTHLT,G)
				; Tell all interfaces we are going away.
	SAVEAC <P1>
	STKVAR <<MHLTRS,2>>
	DMOVEM T1,MHLTRS	; save the time and reason
	MOVX T1,<377777777777>	; Stop pings
	MOVEM T1,PINGTM		; Save new ping time
				; shutdown each interface
	SKIPA P1,NCTVT		; Get pointer to tables
MNTHL2:	 LOAD P1,NTLNK,(P1)	; Get next NCT
	JUMPE P1,R		; done?
	SETZM NETON(P1)		; No, say that we want this interface off.
	DMOVE T1,MHLTRS		; Get why/when.
	MNTCALL NTKILL		; Do halt instruction
	JRST MNTHL2		; Loop through all
	SUBTTL Routines Dealing With Network States

;MNTSET - Set a network status.
;	T1/	Network number, or host address
;	T2/	value
; Possible values are: <0 = on
;			  0 = off
;			 >0 = request cycle

MNTSET::SAVEAC <P1>
	CALL NETNCT		; Find the NCT
         RET			; If none
	SKIPGE T2
         SETO T2,		; Either -1
IFE STANSW,<
	SKIPE T2		; or      0
>;IFE STANSW
IFN STANSW,<		 ;;Don't turn -1 into 0,,-1
	SKIPLE T2		; or      0
>;IFN STANSW
         HRRZI T2,-1		; or  0,,-1
	MOVEM T2,NETON(P1)	; Set function
IFN STANSW,<
	IFE. T2
	  SETOB T1,T2		; Arguments are -1
	  MNTCALL NTKILL	; Shut off the hardware
	ELSE.
	  IFG. T2
	    SETOB T1,T2		; Want to cycle hardware.
	    MNTCALL NTKILL	; Shut off the hardware, fall thru to restart
	  ENDIF.
	  MNTCALL NTRSRT	; Restart the hardware
	  MNTCALL NTISRT	; Make sure input is happening
	ENDIF.
>;IFN STANSW
	AOS INTFLG		; Ask for the internet fork
	RETSKP			; Success return

MNTRED::			; ROUTINE TO RETURN NETWORK STATE
	SAVEAC <P1>
	SETZ T2,		; ASSUME NET IS DOWN
	CALL NETNCT		; GET THE NCT
         RET			; NO NCT
	MOVE T2,NETON(P1)	; GET THE STATE
	RETSKP			; SUCCESS RETURN
	SUBTTL Routine to Resolve Interface State

MNTRSV::			; Resolve interface state (P1/ NCT)
	SKIPL NETON(P1)		; do we want it up?
	 JRST MNTRS2		; no
	SKIPE NTRDY(P1)		; yes. is it up?
	 RET			; want up and is up so return.
	CALL @NTRSRT(P1)	; want up and is down so make it up.
	RET			; and return

MNTRS2:				; Here when not wanted up.
	SKIPE NETON(P1)		; want it down?
	 JRST MNTRS3		; no must want it cycled.
	SKIPN NTRDY(P1)		; is it down?
	 RET			; want down and is down so return.
	CALL @NTKILL(P1)	; want down and is up so take it down.
	RET			; and return to caller

MNTRS3:				; here when we want to cycle
	SKIPE NTRDY(P1)		; is it up now?
	 CALL @NTKILL(P1)	; yes so make it down
	SETOM NETON(P1)		; and say that we want it up
	RET			; and return to caller
	SUBTTL Host Table Initialization

COMMENT \

Initialize  the  Host  tables. Called at system startup (And possibly
other times). Reads in system Hostname file  and  sets  up  the  host
tables  from  it.  In order to save Section 0/1 space Host tables are
put in INTSEC. This is the new Internet host table  parser.  This  is
intended  as a stopgap measure to allow TOPS-20's to use the Internet
format host table until they can really take advantage of it.

Structures  in the Host tables For reference the Host tables have the
following formats:

Tables indexed by a hash of the host number:

	HOSTNN - The 32 bit host number
	HSTSTS - Status bits
	HOSTPN - index in HOSTN of primary name for this number

Tables indexed by order in the host name file:

	HOSTN - LH 18 bit address in HSTNAM
	        RH Index into hashed tables

HSTNAM - a block NHSTN long which holds the null terminated name strings

\
IFN STANSW,<
ND LNBFLN,<^D160/5>+1		;Length of buffer for GBCH and GETBUF

	TMPBLN==^D100		;Number of characters in TMPBUF (including
				; terminating null).
>;IFN STANSW

HSTINI::
	SAVEAC <P1>
IFE STANSW,<
	TRVAR <HTBJFN,<TMPBUF,10>,NAMPTR,NAMIDX,NAMSPC,NAMCNT,SAVEP,BOL,TERM,HSTS,HBEST,HGOOD,NAMLST,NUMLST,NETMSK,ENTTYP>
>;IFE STANSW
IFN STANSW,<
	TRVAR <HTBJFN,<TMPBUF,<<TMPBLN+4>/5>>,NAMPTR,NAMIDX,NAMSPC,NAMCNT,SAVEP,BOL,TERM,HSTS,HBEST,HGOOD,NAMLST,NUMLST,NETMSK,ENTTYP,<LINBUF,LNBFLN>,LINPTR,LINCNT,LINPBC,GBEOF>
>;IFN STANSW
	MOVEM P,SAVEP		;SAVE A STACK FENCE IN CASE OF ERRORS
IFN STANSW,<
	CALL LCKGTH		;LOCK HOST TABLE AGAINST OTHER ACCESS
>;IFN STANSW
	MOVX T1,GJ%SHT!GJ%OLD	;GTJFN FLAGS.  FILE MUST EXIST.
	MOVE T2,DBUGSW		;[7.1243] Load debug switch
	CAILE T2,1		;[7.1243] Is it 2 or above?
	SKIPA T2,[-1,,[ASCIZ/SYSTEM:HOSTS.DEBUG/]] ;[7.1243] Yes, use debug ver
	HRROI T2,[ASCIZ/SYSTEM:HOSTS.TXT/] ;[7.1243] No, usual filename
	GTJFN%			;LOOK FOR THE FILE
IFE STANSW,<
	 ERJMP R		;FILE NOT FOUND
>;IFE STANSW
IFN STANSW,<
	 RETBAD(,<CALL ULKGTH>)	;FILE NOT FOUND, UNLOCK AND RETURN
>;IFN STANSW
	MOVEM T1,HTBJFN		;SAVE THE JFN
	MOVX T2,7B5!OF%RD	;WE NEED READ ACCESS
	OPENF%			;OPEN UP THE JFN
	 ERJMP HSTIE1		;HANDLE ERRORS
	PUTSEC T1,INTSEC	;INITIAL HOSTN INDEX
	MOVEM T1,NAMIDX
	MOVEI T1,NHOSTN		;SIZE OF HOSTN
	MOVEM T1,NAMCNT		;SAVE
	MOVNI T1,NHSTN		;SIZE OF NAME SPACE
	MOVEM T1,NAMSPC		;SAVE
	PUTSEC T1,INTSEC	;INITIAL INDEX INTO NAME SPACE
	MOVEM T1,NAMPTR		;SAVE
				;...

	MOVE T1,[XWD INTSEC,HSTNAM] ;CLEAR THE CURRENT TABLES
	SETZM 0(T1)		;CLEAR FIRST WORD OF NAME SPACE
	MOVE T2,[XWD HSTNAM,HSTNAM+1] ;GET THE BLT AC
	BLT T2,NHSTN-1(T1)	;ZAP
	MOVE T1,[XWD INTSEC,HOSTN] ;GET THE ADDRESS OF HOSTN
	SETZM 0(T1)		;ZERO THE FIRST WORD
	MOVE T2,[XWD HOSTN,HOSTN+1] ;GET THE BLT AC
	BLT T2,NHOSTN-1(T1)	;ZERO THE REST OF THE TABLE
	PUTSEC T1,INTSEC	;GET AN INDEX INTO THE CORRECT SECTION
	SETZM HOSTNN(T1)	;ZERO THE FIRST WORD OF HOSTNN
	MOVE T2,[HOSTNN,,HOSTNN+1] ;GET THE BLT AC
	BLT T2,HOSTNN+NHOSTS-1(T1) ;ZERO THE REST OF HOSTNN
	SETZM HSTSTS(T1)	;ZERO THE FIRST WORD OF HSTSTS
	MOVE T2,[HSTSTS,,HSTSTS+1] ;GET THE BLT AC
	BLT T2,HSTSTS+NHOSTS-1(T1) ;ZERO THE REST OF HSTSTS
	SETZM HOSTPN(T1)	;ZERO THE FIRST WORD OF HOSTPN
	MOVE T2,[HOSTPN,,HOSTPN+1] ;GET THE BLT AC
	BLT T2,HOSTPN+NHOSTS-1(T1) ;ZERO THE REST OF HOSTNN

	MOVE T1,PRFNET		;GET PREFERRED NETWORK NUMBER
	MOVX T2,<MASKB 4,27>	;NETWORK MASK FOR CLASS C NETWORK
	LSH T1,^D8		;SHIFT INTO POSITION FOR CLASS C NETWORK
	CAMN T1,PRFNFD		;CLASS C?
	IFSKP.
	  MOVX T2,<MASKB 4,19>	;NETWORK MASK FOR CLASS B NETWORK
	  LSH T1,^D8		;SHIFT INTO POSITION
	  CAMN T1,PRFNFD	;CLASS B?
	ANSKP.
	  MOVX T2,<MASKB 4,11>	;NETWORK MASK FOR CLASS A NETWORK
	  LSH T1,^D8
	  CAME T1,PRFNFD	;CLASS A?
	  BUG.(HLT,HSTNET,MNETDV,SOFT,<PRFNFD or PRFNET incorrect>,,<

Cause:	The preferred network number is messed up.  This probably indicates
	that the SYSTEM:INTERNET.ADDRESS file is messed up.

>)
	ENDIF.
	MOVEM T2,NETMSK		;SAVE HOST MASK FOR LATER
IFN STANSW,<
	SETZM LINPTR		;NO POINTER TO LINE BUFFER YET
	SETZM LINBUF		;NO LINE BUFFER CONTENTS YET
	SETZM LINCNT		;NO COUNT OF CHARS IN LINE BUFFER YET
	SETZM LINPBC		;NO "PUT BACK" CHAR FROM BACKING UP
	SETZM GBEOF		;HAVEN'T HIT EOF IN GETBUF YET
>;IFN STANSW
HSTIN6:				;LOOP FOR PROCESSING ENTRIES
	MOVE P,SAVEP		;RESET STACK FENCE
	CALL GBOLX		;SKIP TO START OF NEXT NON-BLANK,
				;NON-COMMENT LINE @ FIRST NON-WHITE
	CALL RDFLD		;READ A VALUE
	MOVE T1,TMPBUF		;GET FIRST WORD
	SETZ T2,		;ZERO MEANS UNKNOWN TYPE OF ENTRY
	CAMN T1,[ASCIZ/HOST/]	;HOST?
	 MOVX T2,HS%SRV		;YES
	CAMN T1,[ASCIZ/NET/]	;NETWORK?
	 MOVX T2,HS%NET		;YES
	CAMN T1,[ASCIZ/GATEW/]	;GATEWAY?
	 MOVX T2,HS%GAT		;YES
	JUMPE T2,HSTIN6		;FLUSH IF AN UNKNOWN ENTRY TYPE
	MOVEM T2,ENTTYP		;SAVE ENTRY TYPE

;Should  also  check if it is a gateway, and if so fill in in routing
;tables....

	MOVEM P,NUMLST		;SAVE POINTER TO NUMBERS
HSTIN7:				;LOOP FOR READING IN ALL THE NUMBERS
	CALL RDHNUM		;READ A HOST NUMBER
	CALL HSTHSH		;HASH IT INTO THE TABLES
	 NOP			;IGNORE SKIP RETURN
	JUMPL T2,HSTIE2
	MOVEM T1,HOSTNN(T2)	;SAVE THE NUMBER
	PUSH P,T2		;AND THE INDEX
	MOVE T1,TERM		;GET FIELD TERMINATOR
	CAIE T1,":"		;END?
	 JRST HSTIN7		
	PUSH P,[-1]		;FLAG END OF LIST
				;...
				;...
				;HERE WITH ALL ADDRESSES ON THE STACK
	MOVEM P,NAMLST		;START OF NAME LIST
HSTIN9:
	CALL RDFLD		;READ THE NEXT FIELD
	JUMPE T1,HSTIE3
	ADDI T1,1		;COUNT THE NULL TERMINATOR
	IDIVI T1,5		;CONVERT CHAR COUNT TO WORD COUNT
	SKIPE T2		;ROUND UP IF NEEDED
         ADDI T1,1		;...
	PUSH P,T1		;SAVE
	ADDM T1,NAMSPC		;DECREMENT NAME SPACE LEFT
	SKIPLE NAMSPC		;TABLE FULL?
	 JRST HSTIE4
	MOVE T1,0(P)		;GET COUNT BACK
	XMOVEI T2,TMPBUF	;POINT TO NAME READ
	MOVE T3,NAMPTR		;NEXT EMPTY SPACE IN TABLE
	ADDI T3,HSTNAM		;...
	CALL XBLTA		;MOVE THE NAME
	POP P,T1		;RESTORE COUNT
	PUSH P,NAMPTR		;SAVE THIS INDEX
	ADDM T1,NAMPTR		;UPDATE TABLE
	MOVE T1,TERM		;GET TERMINATOR
	CAIE T1,":"		;END OF LIST?
	 JRST HSTIN9		;NO, ONWARD FOR THE NEXT
	PUSH P,[-1]		;FLAG END OF LIST
	MOVE T2,ENTTYP		;GET ENTRY TYPE
	CAME T2,[HS%SRV]	;SKIP IF A HOST ENTRY
	 JRST HST12A		;NETS AND GW'S SKIP MACHINE TYPE/OS/PROTOCOLS
	CALL SKPFLD		;SKIP MACHINE TYPE
	CALL RDFLD		;READ OPERATING SYSTEM
	SETZ T2,
	JUMPE T1,HSTI12
	MOVEI T1,OPSTAB		;OPERATING SYSTEM TYPE TABLE
	MOVE T2,[POINT 7,TMPBUF] ;POINT TO NAME
	TBLUK%
	 ERJMP .+1
	TXNE T2,TL%NOM!TL%AMB	;NO MATCH?
	 TDZA T2,T2		;THEN NO OPSYS
	  HRRZ T2,(T1)		;ELSE GET TABLE VALUE
HSTI12:
	TXO T2,HS%SRV		;PRETEND THEY'RE ALL SERVERS
HST12A:
	MOVEM T2,HSTS		;SAVE IT

;Now  things are set up as follows: NUMLST points to a list of HOSTNN
;indices for this host. NAMLST points to a list of HSTNAM indices for
;its names. HSTS holds the operating system type.

	HRRZ T3,NUMLST		;POINT TO LIST OF NUMBERS
	MOVE T2,NAMIDX		;INDEX OF PRIMARY NAME IN HOSTN

;Select the primary address. We will always prefer the PRFADR address
;in  the  event  this  is  our local host. Failing that, we prefer an
;address that is on PRFADR's network, which is  presumably  the  best
;network  to  reach that host. Failing that, we prefer any network we
;are directly connected to, so we can avoid  gateways.  If  all  else
;fails, we'll take the first listed address.

	SETZM HBEST		;INITIALLY NO BEST INDEX
	SETZM HGOOD		;NOR A GOOD INDEX
				;...

HSTI13:				;...
	SKIPG T4,1(T3)		;GET AN INDEX
	 JRST HSTI14		;DONE WITH THE LIST
	MOVEM T2,HOSTPN(T4)	;SAVE
	MOVE T1,HSTS		;AND OPSYS TYPE
	MOVEM T1,HSTSTS(T4)	;...
	MOVE T1,HOSTNN(T4)	;GET THE NUMBER
	CAMN T1,DEFADR		;OUR DEFAULT ADDRESS IS ALWAYS BEST
	 JRST HSTI15		;SO SET IT AS BEST UNCONDITIONALLY
	CAMN T1,PRFADR		;(PROBABLY UNNECESSARY) PREFERRED ADDRESS IS
	 JRST HSTI15		; ALMOST AS GOOD
	SKIPE HBEST		;HAVE A BEST ADDRESS YET?
	 JRST HSTI16		;YES, NO NEED TO CONSIDER ANY OTHERS
	AND T1,NETMSK		;NO, GET NETWORK BYTES ONLY
	CAME T1,PRFNFD		;IS THIS ADDRESS ON PREFERRED NETWORK?
	 JRST HSTI17
HSTI15:	MOVEM T4,HBEST		;YES, CONSIDER IT BEST
	JRST HSTI16
HSTI17:
	SKIPE HGOOD		;NOT ON DEFAULT NET, HAVE A GOOD ADDRESS YET?
	 JRST HSTI16
	MOVE T1,HOSTNN(T4)	;NO, GET ADDRESS AGAIN
	CALL NETNCT		;HAVE AN INTERFACE ON THAT NET?
	 JRST HSTI16
	MOVEM T4,HGOOD		;YES, CONSIDER IT A GOOD ADDRESS
HSTI16:
	AOJA T3,HSTI13		;LOOP THROUGH NUMBER LIST
HSTI14:
	HRRZ T2,NAMLST		;GET NAME LIST
	MOVE T3,NAMIDX		;GET INDEX INTO NAME TABLE
	SKIPE T1,HBEST		;GET BEST NUMBER INDEX
	 JRST HSTI18
	SKIPE T1,HGOOD		;NO BEST INDEX, GET A GOOD INDEX
	 JRST HSTI18
	HRRZ T1,NUMLST		;NO GOOD INDEX, POINT TO LIST OF NUMBERS
	MOVE T1,1(T1)		;USE FIRST AS DEFAULT
HSTI18:
	SKIPG T4,1(T2)		;GET NEXT NAME ON THE LIST
	 JRST HSTI19		;DONE
	STOR T4,HSTNMP,(T3)	;SET NAME POINTER
	STOR T1,HSTIDX,(T3)	;SAVE NUMBER INDEX
	MOVX T4,1B0		;NICKNAME FLAG
	HRRZ CX,NAMLST		;START OF LIST
	CAME T2,CX		;THIS THE FIRST NAME?
	 IORM T4,HOSTN(T3)	;NO, FLAG AS A NICKNAME
	ADDI T3,1		;INCREMENT NAME TABLE INDEX
	SOSG NAMCNT		;COUNT DOWN TOTAL NUMBER OF NAMES
	 JRST HSTIE5
	AOJA T2,HSTI18		;AND NAME LIST INDEX

HSTI19:
	MOVEM T3,NAMIDX		;SAVE NEW INDEX INTO NAME TABLE
	JRST HSTIN6		;ONWARD

; TBLUK% table for operating system names

OPSTAB:	XWD NUMOPS,NUMOPS
	XWD [ASCIZ/ANTS/],.HSANT
	XWD [ASCIZ/ELF/],.HSELF
	XWD [ASCIZ/FOONEX/],.HS10X
	XWD [ASCIZ/FUZZ/],.HSFUZ
	XWD [ASCIZ/ITS/],.HSITS
	XWD [ASCIZ/MSDOS/],.HSDOS
	XWD [ASCIZ/MTIP/],.HSMTP
	XWD [ASCIZ/MULTICS/],.HSMLT
	XWD [ASCIZ/TAC/],.HSTAC
	XWD [ASCIZ/TENEX/],.HS10X
	XWD [ASCIZ/TIP/],.HSTIP
	XWD [ASCIZ/TOPS10/],.HSDEC
	XWD [ASCIZ/TOPS20/],.HST20
	XWD [ASCIZ/TOPS20AN/],.HST20
IFN STANSW,<
	XWD [ASCIZ/ULTRIX/],.HSUNX
>;IFN STANSW
	XWD [ASCIZ/UNIX/],.HSUNX
	XWD [ASCIZ/VMS/],.HSVMS
	XWD [ASCIZ/WAITS/],.HSDEC
NUMOPS=.-OPSTAB-1

;GBOLX - Move to start of next line
;returns BOL - file pointer of start of this line
IFE STANSW,<
GBOLX:	MOVE T1,HTBJFN		;GET JFN BACK
GBOLX1:	BIN%			;READ A BYTE
	 ERJMP HFILDN		;END OF FILE
	CAIE T2,.CHLFD		;EOL?
	 JRST GBOLX1		;LOOP
	RFPTR%			;READ FILE POSITION
	 ERJMP HFILER		;FATAL
	MOVEM T2,BOL		;SAVE START OF THIS LINE
GBOLX2:	BIN%			;READ START OF NEXT LINE
	 ERJMP HFILDN		;END OF FILE
	CAIE T2,";"		;COMMENT?
	 CAIN T2,.CHCRT		;OR BLANK LINE?
	  JRST GBOLX1		;SKIP
	CAIE T2," "		;LSWP?
	 CAIN T2,.CHTAB		;?
	  JRST GBOLX2		;YES
	BKJFN%			;BACK UP
	 ERJMP .+1
	RET			;RETURN
>;IFE STANSW
IFN STANSW,<
GBOLX:	MOVE T1,HTBJFN
GBOLX1:	CALL GBCH
	 JRST HFILDN
	CAIE T2,.CHLFD		;EOL?
	 JRST GBOLX1		;LOOP
	RFPTR%			;READ FILE POSITION
	 ERJMP HFILER		;FATAL
	SUB T2,LINCNT		;ADJUST FOR CHARACTERS BUFFERED
	MOVEM T2,BOL		;SAVE START OF THIS LINE
GBOLX2:	CALL GBCH		;READ START OF NEXT LINE
	 JRST HFILDN		;DONE WITH FILE
	CAIE T2,";"		;COMMENT?
	 CAIN T2,.CHCRT		;OR BLANK LINE?
	  JRST GBOLX1		;SKIP
	CAIE T2," "		;LSWP?
	 CAIN T2,.CHTAB		;?
	  JRST GBOLX2		;YES
	CALL PBBCH		;BACK UP POINTER AND PUT BACK CHAR
	RET			;AND RETURN

;PUT BACK BUFFERED CHAR
PBBCH:	SAVEAC <T3,T4>
	AOS T3,LINCNT		;ADJUST COUNT OF CHARACTERS
	CAILE T3,LNBFLN*5-1
	IFSKP.
	 SETOM T3
	 MOVE T4,LINPTR
	 ADJBP T3,T4		;BACK UP POINTER BY ONE
	 MOVEM T3,LINPTR
	ELSE.
	 MOVEM T2,LINPBC	;SAVE CHAR IF BACKING UP BEFORE BUFFER HEAD
	ENDIF.
	RET			;RETURN

;GET BUFFERED CHARACTER
GBCH:	SOSG LINCNT		;ANYTHING LEFT IN BUFFER
	IFNSK.			;NO, 
	 CALL GETBUF		;GET ANOTHER BUFFER-FUL
	  RET			;BLEW IT, PASS ALONG FAILURE RETURN
	ENDIF.
	SKIPE T2,LINPBC		;DID WE PUT A CHARACTER BACK?
	IFSKP.			;NO PUT BACK CHAR, SLURP ONE FROM BUFFER
	 ILDB T2,LINPTR
	ELSE.			;WAS A PUT BACK CHAR
	 SETZM LINPBC		;DON'T RE-USE IT
	ENDIF.
	RETSKP			;SUCCESS RETURN, WE GOT A CHARACTER

;GETBUF - GET ANOTHER BUFFERFUL FOR GBCH
;TAKES T1/ JFN FOR INPUT FILE
;RETURNS +1 IF FAILURE, GBEOF SET TO -1
;	 +2 IF SUCCESSFUL, LINPTR, LINCNT UPDATED, GBEOF SET IF EOF HIT
GETBUF:	SKIPE GBEOF		;HAVE WE SEEN EOF?
	 RET			;YES, FAILURE RETURN
	SAVEAC<T3,T4>
	MOVE T2,[POINT 7,LINBUF] ;POINT AT OUR BUFFER
	MOVNI T3,LNBFLN*5-1	;THIS MANY CHARACTERS
	SIN%			
	IFJER.
	 SETOM GBEOF		;PROBABLY HIT EOF, FLAG IT
	ENDIF.
	ADDI T3,LNBFLN*5-1	;MAX CHARS + UPDATED VALUE IN T3 = NUMBER READ
	MOVEM T3,LINCNT		;FIX BUFFERED BYTE COUNT UP
	HRROI T3,LINBUF		;RESET LINPTR
	HRLI T3,(<POINT 7,>)
	MOVEM T3,LINPTR
	SKIPE LINCNT		;DID WE READ SOME CHARACTERS?
	 RETSKP			;YES, SUCCESS RETURN
	SETOM GBEOF		;NO, SIGNAL EOF
	RET			;FAILURE RETURN
>;IFN STANSW

;RDFLD - Read next field.  Terminated by a "," or  ":".
;Returns
;T1/ number of characters read
;TERM -- terminating character
;TMPBUF -- holds string (Null terminated)

RDFLD:	STKVAR <COUNT,PTR>
	SETZM COUNT		;CLEAR FIELD LENGTH
	MOVE T1,[POINT 7,TMPBUF] ;POINT TO START OF BUFFER
	MOVEM T1,PTR		; TO STORE STRING IN
	SETZM TMPBUF		;FIRST WORD OF BUFFER MBZ
	MOVE T1,HTBJFN		;GET FILE HANDLE
				; SKIP LWS
IFE STANSW,<
RDFLD1:	BIN%			;READ A BYTE
	 ERJMP PEOF
>;IFE STANSW
IFN STANSW,<
RDFLD1:	CALL GBCH		;READ A BYTE
	 JRST PEOF
>;IFN STANSW
	CAIL T2,140		;LOWER CASE?
	 TRZ T2,40		;YES SO MAKE IT UPPERCASE
	CAIE T2,.CHTAB		;TAB?
	 CAIN T2," "		;BLANK?
	  JRST RDFLD1		;YES
RDFLD2:	CAIE T2,":"		;END OF FIELD?
	 CAIN T2,","		;?
	  JRST RDFLDD		;YES
	CAIE T2," "		;?
	 CAIN T2,.CHTAB		;?
	  JRST RDFLDD		;YES
	CAIN T2,.CHCRT		;EOL?
	 JRST PEOLX		;ERROR
	CAIL T2,140		;LOWER CASE?
	 TRZ T2,40		;YES, RAISE
	IDPB T2,PTR		;SAVE CHARACTER
IFE STANSW,<
	AOS COUNT		;COUNT IT
	BIN%			;READ THE NEXT
	 ERJMP PEOF		;PREMATURE END OF FILE
>;IFE STANSW
IFN STANSW,<
	AOS T2,COUNT		;COUNT IT
	CAILE T2,TMPBLN-1	;ANY ROOM FOR THIS ONE?
	 JRST PEOLL		; NO, FIELD TOO LONG
	CALL GBCH		;READ THE NEXT
	 JRST PEOF		;PREMATURE END OF FILE
>;IFN STANSW
	JRST RDFLD2		;CONTINUE

RDFLDD:	CAIE T2,","		;FIELD TERMINATOR SEEN?
	 CAIN T2,":"		;?
	  JRST RDFLDX		;YES
	CAIN T2,.CHCRT		;EOL?
	 JRST PEOLX		;ERROR
IFE STANSW,<
	BIN%			;SKIP TWS
	 ERJMP PEOF
>;IFE STANSW
IFN STANSW,<
	CALL GBCH		;SKIP TWS
	 JRST PEOF
>;IFN STANSW
	JRST RDFLDD		;LOOP

RDFLDX:	MOVEM T2,TERM		;SAVE TERMINATOR
	SETZ T2,
	IDPB T2,PTR		;NULL TERMINATE THE STRING
	MOVE T1,COUNT		;GET SIZE OF FIELD
	RET
	ENDSV.

;SKPFLD - Skip to next field (next ":").

SKPFLD:	MOVE T1,HTBJFN
IFE STANSW,<
SKPFL1:	BIN%			;READ A BYTE
	 ERJMP PEOF
>;IFE STANSW
IFN STANSW,<
SKPFL1:	CALL GBCH		;READ A BYTE
	 JRST PEOF
>;IFN STANSW
	CAIN T2,":"		;START OF NEW FIELD?
	 RET			;YES, DONE
	CAIN T2,.CHCRT		;END OF LINE?
	 JRST PEOLX		;YES SO ERROR
        JRST SKPFL1		;NO, CONTINUE

;RDHNUM - Read a host number.
;returns number in T1

RDHNUM:	STKVAR <COUNT,HOST>
	CALL RDFLD		;Read in a field
	JUMPE T1,RDHNE1
	MOVEI T1,4		;Size of a number (bytes)
	MOVEM T1,COUNT		;Save
	SETZM HOST
	MOVE T1,[POINT 7,TMPBUF]
	MOVX T3,^D10		;Read in decimal
RDHNM3:
	NIN%			;Read part of number
	 ERJMP RDHNE2
	EXCH T2,HOST		;Get part read so far
	LSH T2,^D8		;Shift over
	ADDM T2,HOST		;Add in new part
	SOSLE COUNT		;Decrement count
	 JRST RDHNM3		;Loop
	MOVE T1,HOST		;Get number back
	RET			;And return
	ENDSV.

;ERROR handlers for HSTINI and friends

HSTIE1:				;ERROR ON OPENF
	MOVE T1,HTBJFN		;RECOVER THE JFN
	RLJFN%			;RELEASE THE JFN
	 ERJMP .+1		;IGNORE ERRORS
IFN STANSW,<
	CALL ULKGTH		;UNLOCK HOST TABLE
>;IFN STANSW
	RET			;RETURN TO CALLER

HSTIE2:	TMSG <Number tables full before end of file
>
	JRST HFILER

HSTIE3:	TMSG <Null name not allowed
>
	JRST HFILER

HSTIE4:	TMSG <NAME SPACE FULL BEFORE END OF FILE
>
	JRST HFILER

HSTIE5:	TMSG <Name table full before end of file
>
	JRST HFILER

RDHNE1:
	TMSG <Null host number
>
	JRST HFILER

RDHNE2:	TMSG <Bad host number format
>
	JRST HFILER

;PEOF -- premature end of file

PEOF:	TMSG <Premature end of file
>
	JRST HFILER

PEOLX:
	TMSG <Premature end of line
>
	JRST HFILER

IFN STANSW,<

;PEOLL -- Field too long

PEOLL:
	TMSG <Field too long
>
	JRST HFILER
>; End of IFN STANSW

;HFILER - Error printout routine.

HFILER:	MOVE T1,HTBJFN		;Get JFN
	RFPTR%			;Read current file position
	 ERJMP .+1
IFN STANSW,<
	SUB T2,LINCNT		;Adjust for buffered characters
>;IFN STANSW
	PUSH P,T2		;Save
	MOVE T2,BOL		;Get start of line pointer
	SFPTR%			;...
	 ERJMP .+1
	SUBM T2,0(P)		;Difference
HFILE2:
	MOVE T1,HTBJFN
	BIN%			;Read a byte
	 ERJMP HFILDN		;End of file
	MOVX T1,.PRIOU
	BOUT%			;Write to primary output
	 ERJMP .+1
	SOSE 0(P)		;Count down to error position
	 JRST HFILE3
	MOVEI T2,"^"
	BOUT%
	 ERJMP .+1
HFILE3:
	CAIE T2,.CHLFD		;End of line?
	 JRST HFILE2		;Loop

;HFILDN - Routine to finish up HOSTS.TXT

HFILDN:				;Here when finished
	HRRZ T1,NAMIDX		;Get count of host names
	MOVNM T1,MHOSTS		;Save
	MOVE T1,HTBJFN		;Get back JFN
	CLOSF%
	 ERJMP .+1
IFN STANSW,<
	CALL ULKGTH		;UNLOCK HOST TABLE
>;IFN STANSW
	MOVE P,SAVEP		;Get back stack fence
	RETSKP			;And return
	ENDTV.

;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
	ERJMP R			; If end of file return +1
	JUMPN T2,RSKP		; If good
	JRST GBIN		; flush NULLS
	SUBTTL GTFIL - GTJFN Routine for HSTINI and ADRINI

;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
	SUBTTL ADRINI - Routine to Read SYSTEM:SITE-ADDRESS.TXT

;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::			; Read interface descriptor file
	SAVEPQ			; Save registers clobbered
	STKVAR <NONUM,<BUFFER,10>>
	HRROI T2,[ASCIZ /SYSTEM:INTERNET.ADDRESS/]
	CALL GTFIL		; Get the file
	 RET
	SETZ T1,		; clear an index
ADRIN1:	SKIPN NLHOST(T1)	; slot used?
	 JRST ADRLP0		; no, done with table, enter main loop
	SETOM NLHOST(T1)	; empty that slot
	AOJA T1,ADRIN1		; and loop

ADRLP0:	CALL GBOL		; Start off a line
	 JRST ADRDUN		; Done with file
	MOVE T1,P1		; Get JFN

; 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
				; Now 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
				; Read in the address on that interface
ADGNUM:	CALL NXTFLD		; read to the next field
	HRROI T4,[ASCIZ/ Invalid address /]
	CALL ADG4DB		; Get 4 decimal bytes into T1
				; Goes ADRERR on error
	MOVEM T1,P2		; Get into right register
	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

ADGTYP:				; Here to read in a modifier
	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

ADDFLT:				; Here on DEFAULT keyword
	NETNUM T1,P2		; Get the network number
	MOVEM T1,DEFNET		; Save as default network number
	SKIPN PRFNET		; Preferred network set up?
	 MOVEM T1,PRFNET	; Save as preferred network number
	MOVE T2,P2		; Get number
	ANDX T2,-1B27		; mask off network number (Class C)
	CAIG T1,177777		; Class B or A?
	 ANDX T2,-1B19		; Mask for class B
	CAIG T1,377		; Class A?
	 ANDX T2,-1B11		; yes, mask appropriately
	MOVEM T2,NETFLD		; Set as default network field
	MOVEM P2,DEFADR		; Save as default address
	SKIPN PRFNFD		; Preferred network field set up?
	 MOVEM T2,PRFNFD	; Set as preferred network field
	SKIPN PRFADR		; Preferred address set up?
	 MOVEM P2,PRFADR	; Save as preferred address
				; Kludge up the 8 bit host address
	MOVE T2,P2		; 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

ADDPRF:				; Here on PREFERRED keyword
	NETNUM T1,P2		; Get the network number
	MOVEM T1,PRFNET		; Save as preferred network number
	MOVE T2,P2		; Get number
	ANDX T2,-1B27		; mask off network number (Class C)
	CAIG T1,177777		; Class B or A?
	 ANDX T2,-1B19		; Mask for class B
	CAIG T1,377		; Class A?
	 ANDX T2,-1B11		; yes, mask appropriately
	MOVEM T2,PRFNFD		; Set as preferred network field
	MOVEM P2,PRFADR		; Save as preferred address
	RET

ADNCP:				; Here on NCP keyword
	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

IFN STANSW,<
; Here on the ETHERNET and ETHER3MB keywords

ADD3MB:	SKIPA T1,[NT.3MB]	; network type is 3MB Ethernet
ADDETH:	 MOVEI T1,NT.ETH	; network type is 10MB Ethernet
	STOR T1,NTTYP,(P3)	; save in NCT
	RET			; no more to do

; Here on the HARDWARE keyword to read our 10MB Ethernet hardware address

ADDHDW:	HRROI T4,[ASCIZ/ Invalid hardware address /]
	CALL ADG4DB		; Get first four bytes of hardware address
	STOR T1,HRDW0,(P3)	; Store in NCT
	HRROI T4,[ASCIZ/ Invalid hardware address /]
	CALL ADG2DB		; Get last two bytes of hardware address
	STOR T1,HRDW1,(P3)	; Store in NCT
	RET			; return to caller
>;IFN STANSW

; 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

IFN STANSW,<
;ADG2DB - entry point used by ADDHDW to read two decimal bytes

ADG2DB:	PUSH P,BHC		; Push a zero onto the stack
	MOVEI Q1,2		; Want only two decimal bytes
	JRST ADG4D2		; Join main code
>;IFN STANSW

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 [ADJSP P,-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

; Error handler routine

NETFUL:	POP P,T4		; Clean stack
	BUG.(HLT,NORMIA,MNETDV,SOFT,<No room in host tables for local address>,,<

Cause:	Multinet is unable to allocate space in the network hash table for
	a local address from the SYSTEM:INTERNET.ADDRESS file.
>)
	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
	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

; 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 AN20,NT.ANX			; AN20 Interface
KEY IPCI,NT.CIP		  	; KLIPA Interface
KEY IPNI,NT.NIP			; KLNI Interface
IFN STANSW,<
KEY MEIS,NT.MEI			; MEIS Interface 
>;IFN STANSW
TABEND(INTNAM)

; Take of modifiers

TABLE(TYPNAM)
KEY DEFAULT,ADDFLT		; This is the 'primary' address for host
IFN STANSW,<
KEY ETHER3MB,ADD3MB		; 3MB Ethernet protocols
KEY ETHERNET,ADDETH		; 10MB Ethernet protocols
KEY HARDWARE,ADDHDW		; 10MB Ethernet hardware address
>;IFN STANSW
KEY LOGICAL-HOST-MASK,ADLHM	; Logical host mask for this network
KEY NCP,ADNCP			; network uses Arpanet NCP protocal
KEY PACKET-SIZE,ADPSIZ		; Maximum packet size allowed
KEY PREFERRED,ADDPRF		; This is the 'preferred' address for host
TABEND(TYPNAM)
	SUBTTL CVHST% JSYS - Convert Host Number to String

REPEAT 1,<			;THIS JSYS IS VERY TEMPORARY
	XNENT (.CVHST,G)
	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,INTSEC	;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
>
	SUBTTL GTHST% JSYS

;The  GTHST%  JSYS, Get information on a Host or Network, Moved here
;from NETWRK because expansion allows it  to  be  general  over  all
;Interfaces rather than just NCP. 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

IFE STANSW,<
	XNENT (.GTHST,G)
	MCENT
	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

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
	JRST GTHNLA		;(10)Get local addresses on networks
GTHMAX==.-GTHDSP		;NUMBER OF FUNCTIONS

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
	SUBTTL GTHST% JSYS - Individual 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,PRFADR		;GET PREFERRED 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,INTSEC	;IN THE RIGHT SECTION
	LOAD P2,HSTIDX,(P1)	;GET INDEX INTO HOSTNN
	SETSEC P2,INTSEC	;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
	SETSEC P4,INTSEC	;INTO PROPER SECTION
	ADDI P4,HSTNAM		;POINT TO NAME
	MOVE P3,[<POINT 7,0>!1B12] ;EXTENDED POINTER WORD
	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

GTHSTR:	CALL GTHSTN		;CONVERT STRING TO NUMBER
	SKIPL T2		;VAILD STRING FOUND?
	 RETERR(GTHSX5)		; no, return error
	MOVE P1,T2		; Save
	SETSEC P1,INTSEC	; in the right section
	SKIPN T1,T4		;COPY HOST NUMBER
	 RETERR(GTHSX2)		;NO HOST FOUND....ERROR
	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

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,INTSEC	; Put in proper section
	LOAD T1,HSTIDX,(T1)	; get index to tables
	SETSEC T1,INTSEC	; Again in right section
	SKIPA T1,HOSTNN(T1)	; Get number

GTHHNN:	MOVE T1,T3		;GET HOST NUMBER
	CALL GTHNTS		;CONVERT NUMBER TO INDEX
	JUMPL P1,[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
        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			; Retrun now if a JFN
	XCT T4		; Stick on NULL
	BKJFN			; Backup destination
	 NOP			; ...
	RET			; and return

; 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,NTXUPP-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

; Get Local Network Addresses
; Accepts   T3/ Address of where to store data
;	    T4/ Number of words
; Returns +1 if invalid offset
;	    +2 if good arguments with data in table
; Updates callers T4 count of items returned.

GTHNLA:				; Get local addresses
	SKIPG T4		; Legit count?
	 RETERR(ARGX24)		; No
	MOVE P1,NCTVT		; Get address of the first NCT
	JRST GTHLA3		; Report on this NCT
GTHLA1:				; Get the next NCT
	LOAD P1,NTLNK,(P1)	; Get address of the next NCT
	JUMPN P1,GTHLA3		; Go report on this NCT
GTHLA2:				; Here when all NCTs examined
	XCTU [SUB T4,4]		; Fix up the count
	XCTU [MOVNM T4,4]	; Save the count for the caller
	JRST SKMRTN		; And do a skip return
GTHLA3:		  		; NCT Chasing loop
	SKIPG T1,NTLADR(P1)	; Get address on this NCT
	 JRST GTHLA1		; No address defined.  get next NCT.
	UMOVEM T1,(T3)		; Save interface address for user
	SOJLE T4,GTHLA2		; Count exhausted?
	AOJA T3,GTHLA1 		; No so do the next NCT
>;IFE STANSW
IFN STANSW,<

RS GTHLCK,1			;LOCK ON HOST TABLE

	XNENT (.GTHST,G)
	MCENT			;ENTER MONITOR CONTEXT
	SKIPL T1		;CHECK RANGE OF FUNCTION CODE
	 CAIL T1,GTHMAX
	  RETERR (ARGX02)	;BAD FUNCTION CODE
	SETOB P1,P2		;NO NUMBER NOR NAME
	CALL LCKGTH		;WAIT UNTIL EXCLUSIVE LOCK ON HOST TABLE
	CALL @GTHDSP(T1)	;DO THE FUNCTION
	 RETERR (,<CALL ULKGTH>) ;PASS BACK ERROR, UNLOCK TABLE
	CALL ULKGTH		;UNLOCK TABLE
	SMRETN			;WE SUCCEEDED, SO SKIP RETURN

;LCKGTH - LOCK HOST TABLE
;RETURNS +1 ALWAYS, TABLE LOCKED AND PROCESS NOINT

LCKGTH:	SAVET			;DON'T CLOBBER ANY TEMPORARIES
LCKGT0:	NOINT			;TURN OFF PSI
	AOSN GTHLCK		;TRY FOR EXCLUSIVE LOCK
	 RET			;GOT IT.  RETURN NOINT
	OKINT			;FAILED, TURN PSI BACK ON
	MOVEI T1,GTHLCK		;ADDRESS OF LOCK WORD
	CALL DISL		;DISMISS UNTIL IT IS -1 (FREE)
	JRST LCKGT0		;TRY AGAIN

;ULKGTH - UNLOCK HOST TABLE
;RETURNS +1 ALWAYS, TABLE UNLOCKED, INTDF DECREMENTED

ULKGTH:	SETOM GTHLCK		;CLEAR LOCK
	OKINT			;REALLOW INTERRUPTS
	RET			;RETURN

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

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
	RETSKP			;SKIP RETURN TO JACKET ROUTINE
	SUBTTL GTHST% JSYS - Individual 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,PRFADR		;GET PREFERRED ADDRESS
	UMOVEM T4,4		;RETURN TO USER
	RETSKP			;DONE, RETURN TO JACKET ROUTINE

GTHIDX:	MOVN T1,MHOSTS		;GET NUMBER OF HOST NAMES IN USE
	HRRZ P1,T3		;CHECK RANGE OF HOST NAME INDEX
	CAML P1,T1
	 RETBAD (GTJIX1)	;BAD INDEX TO HOSTN
	SETSEC P1,INTSEC	;IN THE RIGHT SECTION
	LOAD P2,HSTIDX,(P1)	;GET INDEX INTO HOSTNN
	SETSEC P2,INTSEC	;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,[RETBAD(GTHSX3)] ;NO STRING FOR THAT NUMBER
;	JRST GTHTUS
; fall through

; Write host string to user space

GTHTUS:	LOAD P4,HSTNMP,(P1)	;GET THE NAME POINTER
	SETSEC P4,INTSEC	;INTO PROPER SECTION
	ADDI P4,HSTNAM		;POINT TO NAME
	MOVE P3,[<POINT 7,0>!1B12] ;EXTENDED POINTER WORD
	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

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

; Convert host string to a number

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
	 RETBAD (GTJIX1)	; Bad index
	SETSEC T1,INTSEC	; Put in proper section
	LOAD T1,HSTIDX,(T1)	; get index to tables
	SETSEC T1,INTSEC	; Again in right section
	SKIPA T1,HOSTNN(T1)	; Get number

GTHHNN:	MOVE T1,T3		;GET HOST NUMBER
	CALL GTHNTS		;CONVERT NUMBER TO INDEX
	JUMPL P2,[RETBAD (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
        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			; Retrun now if a JFN
	XCT T4		; Stick on NULL
	BKJFN			; Backup destination
	 NOP			; ...
	RET			; and return

; 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
	 RETBAD (GTHSX5)	; Return error if none
	MOVE T1,NTLADR(P1)	; Get our number there
	UMOVEM T1,T2		; Restore it to user
	RETSKP			; 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
	 RETBAD(GTHSX5)		; Bad number
	HLRE T1,T4		; Get number wanted
	MOVMS T1		; Magnitude
	ADDI T1,(T4)		; Add in first
	CAILE T1,NTXUPP-NTRDY+1	; Size of area
	 RETBAD(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
	RETSKP			; And do a skip return

; Get Local Network Addresses
; Accepts   T3/ Address of where to store data
;	    T4/ Number of words
; Returns +1 if invalid offset
;	    +2 if good arguments with data in table
; Updates callers T4 count of items returned.

GTHNLA:				; Get local addresses
	SKIPG T4		; Legit count?
	 RETBAD(ARGX24)		; No
	MOVE P1,NCTVT		; Get address of the first NCT
	JRST GTHLA3		; Report on this NCT
GTHLA1:				; Get the next NCT
	LOAD P1,NTLNK,(P1)	; Get address of the next NCT
	JUMPN P1,GTHLA3		; Go report on this NCT
GTHLA2:				; Here when all NCTs examined
	XCTU [SUB T4,4]		; Fix up the count
	XCTU [MOVNM T4,4]	; Save the count for the caller
	RETSKP			; And do a skip return
GTHLA3:		  		; NCT Chasing loop
	SKIPG T1,NTLADR(P1)	; Get address on this NCT
	 JRST GTHLA1		; No address defined.  get next NCT.
	UMOVEM T1,(T3)		; Save interface address for user
	SOJLE T4,GTHLA2		; Count exhausted?
	AOJA T3,GTHLA1 		; No so do the next NCT

>;IFN STANSW
	SUBTTL ATNVT% JSYS and NETRDY GETAB Table

; ATtach connection to NVT
; Call:	1	; [Receive] jfn of opened network connection (JCN for TCP)
;	2	; Send jfn of open network connection (NCP only)
;	ATNVT
; Returns
;	+1	; Cannot attach
;	+2	; Ok.  the jfn is released, ac 1 has line number of
;		; Attached pty.

	XNENT (.ATNVT,G)
	MCENT
	TXNE T1,AN%TCP		; Attach TCP Virtual Terminal?
         JRST TATNVT		; Yes, go to TCP code
IFE STANSW&PUPSW,<
	XJRST [MSEC1,,TVTJFN]	; we were given a JFN
>;IFE STANSW&PUPSW
IFN STANSW&PUPSW,<
JFN==11
	XCTU [HRRZ JFN,1]	; Get user's JFN 
	CALLX (MSEC1,CHKJFN)	; Check it
	 RETERR(ATNX1)		; Bogus JFN.  "Invalid receive JFN"
	 RETERR(ATNX1)		; TTY:, "Invalid receive JFN"
	 RETERR(ATNX1)		; Byte pointer or NUL:, "Invalid receive JFN"
	CALLX (MSEC1,UNLCKF)	; Unlock JFN
	HRRZ T1,FILDEV(JFN)	; Get DTB
	CAIN T1,TCPDTB		; TCP: device?
	 XJRST [MSEC1,,TVTJFN]	; Yes, go to TCP code
	CAIN T1,PUPDTB		; PUP: device?
	 JRST PATNVT		; Yes, go to PUP code
	RETERR(ATNX4)		; Neither, return error
>;IFN STANSW&PUPSW

; GNTRDY
; Get  the  NETRDY  table. Attempts to find the data from the NCT for
; the primary network

	XNENT (GNTRDY,G)
	MOVE T1,DEFADR		; get primary address
	CALL NETNCT		; Find an NCT for it
	 RETERR()		; Error
	MOVE T1,@GNTAB(T2)	; get an entry
	RET			; And return

; Indirect table for deriving the data

GNTAB:	IFIW!<P1>B17+NTRDY	; NETRDY From the NCT
	IFIW!<P1>B17+NETON	; As NETON
	IFIW+NETENT		; NETENT has its own cell
	IFIW!<P1>B17+NTIUPT	; NCPUPT
	IFIW+IGDMSG		; Last Imp going down message
	IFIW!<P1>B17+NTXDNT	; Last ready line drop
	IFIW!<P1>B17+NTXUPP	; last ready line up time
	IFIW+IGDTIM		; Last Imp going down message time
	SUBTTL HSTLUK - Lookup Host Names

HSTLUK:	SAVEPQ				;GET SOME ROOM
	MOVE Q1,T1			;SAVE POINTER
	MOVEI T3,10
	NIN				;TRY TO GET A NUMBER
	 JRST HSTLKI			;TRY A NAME
	MOVE Q1,T1			;SAVE UPDATED POINTER
	MOVE T1,T2
	CALL CVNHST
	MOVE T4,T1			;RETURN HOST NUMBER
	MOVE T1,Q1			;AND UPDATED POINTER
	SETZ T2,			;HOST NUMBER FOUND
	RET

HSTLKI:	HRLZ T2,MHOSTS			;SCAN THE TABLE
	PUTSEC P1,INTSEC		;IN THIS SECTION
HSTLK0:	MOVE T1,Q1			;DO NAME POINTER
	LOAD T4,HSTNMP,(P1)
	ADD T4,[XWD INTSEC,HSTNAM]	;POINT TO THE TABLE
	MOVE T3,[<POINT 7,0>!1B12]	;MAKE EXTENDED POINTER
HSTCMP:	ILDB Q2,T1			;COMPARE A STRING
	ILDB Q3,T3
	SKIPN Q2			;NULL BYTE?
	 JUMPE Q3,HSTCM2		;YES.  IS THE OTHER BYTE BYTE ALSO?
	CAIN Q2,(Q3)			;NOT NULL.  ARE THEY THE SAME?
	 JRST HSTCMP			;YES SO KEEP COMPARING
HSTLK2:
	AOS P1				;POINT TO NEXT SLOT IN TABLE
	AOBJN T2,HSTLK0			;STEP TO NEXT HOST
	SETZ T4,			;NO HOST FOUND
	RET

HSTCM2:	LOAD T4,HSTIDX,(P1)		;WE HAVE A MATCH.  GET THE INDEX
	SETSEC T4,INTSEC		;IN THE CORRECT SECTION
	MOVE Q3,HSTSTS(T4)		;GET ENTRY STATUS BITS
	TXNN Q3,HS%SRV			;HOST NAME?
	 JRST HSTLK2			;NO, A GW OR NET.  SKIP OVER IT.
	MOVE T4,HOSTNN(T4)		;GET THE HOST NUMBER
	HRR T2,P1			;GET THE NAME STRING ADDRESS
	RET				;AND RETURN TO CALLER

CVNHST::				;CONVERT HOST NUMBER IN AC1 TO NEW FORMAT
	CAMN T1,[-1]			;IF -1 USE LOCAL HOST NUMBER
	 MOVE T1,PRFADR			;DEFAULT LOCAL HOST
	AND T1,[HSTMSK]			;CUT DOWN TO SIZE
	TLNE T1,37700			;ANY NETWORK NUMBER STUFF?
	 RET				;YES SO RETURN
	ANDI T1,377			;TURN OFF ALL OTHER BITS
	TRZE T1,100			;SET THE HOST BITS
	 TRO T1,200000			;UNITS HOST BIT
	TRZE T1,200
	 TRO T1,400000			;TWOS HOST BIT
	JUMPE T1,R			;IF ZERO LEAVE IT ZERO
	IOR T1,NETFLD			;ADD DEFAULT NETWORK NUMBER
	RET

	TNXEND
	END