Google
 

Trailing-Edge - PDP-10 Archives - BB-H311D-RM - arpanet-sources/mnetdv.mac
There are 10 other files named mnetdv.mac in the archive. Click here to see a list.
; UPD ID= 4961, SNARK:<6.MONITOR>MNETDV.MAC.15,  18-Oct-84 16:14:21 by PAETZOLD
;TCO 6.1.1024 - Add .GTHLA function to GTHST%.
; UPD ID= 4851, SNARK:<6.MONITOR>MNETDV.MAC.14,  17-Sep-84 11:50:34 by PURRETTA
;Update copyright notice
; 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
;GIDNEY::<PAETZOLD.TCP>MNETDV.MAC.3, 16-Mar-84 18:03:06, Edit 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

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT  (C)  DIGITAL  EQUIPMENT  CORPORATION  1982, 1984.
;ALL RIGHTS RESERVED.


	SEARCH ANAUNV,PROLOG
	TTITLE MNETDV

	IFNDEF REL6,<REL6==:1>
	SUBTTL MNTINI - Initialization

	SWAPCD

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

MNTINI::
	IFE REL6,<EA.ENT>	; enter section one
	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
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>)
	CALL HSTINI		;GET THE SYSTEM TO KNOW NAMES OF SITES
	  BUG.(INF,NOHSTN,MNETDV,SOFT,<HSTINI failed to find host name file>)
	CALL NETHSI		; Initialize the network hash table
	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?
	 SKIPN DEFADR		; Did addresses initialize properly?
	  JRST MNTINX		; No, return now
	JRST MNETON		; 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
	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
	SUBTTL MNETON - Turn Networks On if They Have Never Been On

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

MNETON::
	SKIPA P1,NCTVT		; Point to vector table
MNTIN2:  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 MNTIN2		; 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.

MNTCHK::
	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>>)
	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
       
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 Number /]
	PSOUT
	MOVX T1,.PRIOU		; Primary output
	MOVE T2,NTNET(P1)	; Get Net number
	MOVX T3,^D10		; output in decimal
	NOUT			; ...
         NOP			; Shouldn't fail
	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
	SETZM NTSTCH(P1)
	CALL LGTAD		; Report time of this change
	SKIPGE T2,T1		; If time known
	 JRST MNTC5X		; Not known.
	MOVEI T1,.PRIOU		; Still on CTY
	MOVEI T3,0
	ODTIM
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
	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

	RESCD

NTSNDX:	BUG.(CHK,BADADR,MNETDV,SOFT,<No NCT for address>,<<T1,ADR>>)
	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>)
	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
	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
	RETSKP			; And skip return

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

	SWAPCD

;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

;MNTHLT - Tell  all  networks  we are going away. 
;T1/ Reason, a la 1822
;T2/ GTAD when back up

MNTHLT::
	SAVEAC <P1>
	PUSH P,T1		; Save reason and
	PUSH P,T2		; When back up
	MOVX T1,<377777777777>	; Stop pings
	MOVEM T1,PINGTM		; Save new ping time
				; Pass info to each interface
	SKIPA P1,NCTVT		; Get pointer to tables
MNTHL2:	  LOAD P1,NTLNK,(P1)	; Get link
	JUMPE P1,MNTHL6		; If done
	DMOVE T1,-1(P)		; Get why/when
	MNTCALL NTKILL		; Do halt instruction
	JRST MNTHL2		; Loop through all

MNTHL6:	ADJSP P,-2		; CLEAR STACK
	RET

;MNTKIL - Turn hardware off on a specific network.
;	T1/	network number, or host address
;	T2/	Why, or -1
;	T3/	When back up or garbage
; Returns+1	Always, network off instruction executed if network exists

MNTKIL::SAVEAC <P1>
	CALL NETNCT		; Get the NCT
         RET			; No such net, already off
	MOVE T1,T2		; Why or -1
	MOVE T2,T3		; When back up
	MNTCALL NTKILL		; Turn the hardware off
	RET			; And return
	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
	SKIPE T2		; or      0
         HRRZI T2,-1		; or  0,,-1
	MOVEM T2,NETON(P1)	; Set function
	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 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

\

HSTINI::
	SAVEAC <P1>
	TRVAR <HTBJFN,<TMPBUF,10>,NAMPTR,NAMIDX,NAMSPC,NAMCNT,SAVEP,BOL,TERM,HSTS,HBEST,HGOOD,NAMLST,NUMLST,NETMSK,ENTTYP>
	MOVEM P,SAVEP		;SAVE A STACK FENCE IN CASE OF ERRORS
	MOVX T1,GJ%SHT!GJ%OLD	;GTJFN FLAGS.  FILE MUST EXIST.
	HRROI T2,[ASCIZ/SYSTEM:HOSTS.TXT/] ;FILENAME
	GTJFN%			;LOOK FOR THE FILE
	 ERJMP R		;FILE NOT FOUND
	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,NHOSTS		;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
	PUTSEC T4,INTSEC	;MAKE POINTER TO SECTION
	MOVEI T2,NHOSTS		;COUNT OF TABLE SIZE
HSTIN4:				;LOOP FOR CLEARING ENTRIES
	SETZM HOSTN(T4)		;CLEAR OLD NUMBER
	SETZM HOSTNN(T4)	;CLEAR NUMBER
	SETZM HSTSTS(T4)	;AND STATUS
	SETZM HOSTPN(T4)	;AND PRIMARY NAME
	ADDI T4,1		;INCREMENT POINTER
	SOJG T2,HSTIN4		;AND LOOP THROUGH ALL
	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 MESSED UP>)
	ENDIF.
	MOVEM T2,NETMSK		;SAVE HOST MASK FOR LATER
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/MTIP/],.HSMTP
	XWD [ASCIZ/MULTICS/],.HSMLT
	XWD [ASCIZ/TAC/],.HSTIP
	XWD [ASCIZ/TENEX/],.HS10X
	XWD [ASCIZ/TIP/],.HSTIP
	XWD [ASCIZ/TOPS10/],.HSDEC
	XWD [ASCIZ/TOPS20/],.HST20
	XWD [ASCIZ/TOPS20AN/],.HST20
	XWD [ASCIZ/UNIX/],.HSUNX
	XWD [ASCIZ/WAITS/],.HSDEC
NUMOPS=.-OPSTAB-1

;GBOLX - Move to start of next line
;returns BOL - file pointer of start of this line

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

;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
RDFLD1:	BIN%			;READ A BYTE
	 ERJMP PEOF
	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
	AOS COUNT		;COUNT IT
	BIN%			;READ THE NEXT
	 ERJMP PEOF		;PREMATURE END OF FILE
	JRST RDFLD2		;CONTINUE

RDFLDD:	CAIE T2,","		;FIELD TERMINATOR SEEN?
	 CAIN T2,":"		;?
	  JRST RDFLDX		;YES
	CAIN T2,.CHCRT		;EOL?
	 JRST PEOLX		;ERROR
	BIN%			;SKIP TWS
	 ERJMP PEOF
	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
SKPFL1:	BIN%			;READ A BYTE
	 ERJMP PEOF
	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
	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

;HFILER - Error printout routine.

HFILER:	MOVE T1,HTBJFN		;Get JFN
	RFPTR%			;Read current file position
	 ERJMP .+1
	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
	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::SE1CAL			; Call section 1
	SAVEPQ			; Save registers clobbered
	STKVAR <NONUM,<BUFFER,10>>
	HRROI T2,[ASCIZ /SYSTEM:SITE-ADDRESS.TXT/]
	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

; 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 [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>)
	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
TABEND(INTNAM)

; Take of modifiers

TABLE(TYPNAM)
KEY DEFAULT,ADDFLT		; This is the 'primary' address for host
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
.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,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

.GTHST::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 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
        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
	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.

.ATNVT::MCENT
	TXNE T1,AN%TCP		; Attach TCP Virtual Terminal?
         JRST TATNVT		; Yes, go to TCP code
	JRST TVTJFN		; we were given a JFN

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

GNTRDY::
	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