Google
 

Trailing-Edge - PDP-10 Archives - BB-4170H-SM - sources/netwrk.mac
There are 6 other files named netwrk.mac in the archive. Click here to see a list.
; UPD ID= 186, SNARK:<4.MONITOR>NETWRK.MAC.55,   4-Jan-80 09:15:18 by R.ACE
;UPDATE COPYRIGHT DATE
;MAKE RLNTBF PRESERVE T1
; UPD ID= 73, SNARK:<4.MONITOR>NETWRK.MAC.54,  30-Nov-79 13:50:27 by ZIMA
;TCO 4.2585 - Make NETRBG into a BUGCHK.
;<4.MONITOR>NETWRK.MAC.53,  8-Oct-79 12:27:33, Edit by LCAMPBELL
; Proper case in HSTINI error messages
;<OSMAN.MON>NETWRK.MAC.1, 10-Sep-79 15:46:03, EDIT BY OSMAN
;TCO 4.2412 - Move definition of BUGHLTs, BUGCHKs, and BUGINFs to BUGS.MAC
;<4.MONITOR>NETWRK.MAC.51, 29-May-79 17:27:39, Edit by LCAMPBELL
; Don't return error code in 1 for CVHST
;<4.MONITOR>NETWRK.MAC.14, 13-Apr-79 20:52:09, EDIT BY JBORCHEK
;FIX BYTE POINTER SETUP IN DMPBUF
;<4.MONITOR>NETWRK.MAC.41, 11-Jan-79 23:13:47, EDIT BY ZIMA
;FIX SPELLING IN BUG MESSAGE
;<4.MONITOR>NETWRK.MAC.40,  9-Jan-79 13:55:11, Edit by LCAMPBELL
; Update copyright notice
;<4.MONITOR>NETWRK.MAC.39, 21-Dec-78 11:22:51, Edit by LCAMPBELL
;<4.MONITOR>NETWRK.MAC.38, 13-Dec-78 17:32:59, Edit by LCAMPBELL
; Remove redundant error mnemonics
;<BBN-3A-MONITOR>NETWRK.MAC.10006, 17-Nov-78 19:12:31, EDIT BY JBORCHEK
;ADD HOST TYPES FOR TOPS-20 AND UNIX
;<JBORCHEK>NETWRK.MAC.1, 16-Nov-78 18:26:43, EDIT BY JBORCHEK
;GTHST NOW TAKES JFNS
;<4.MONITOR>NETWRK.MAC.34,  6-Nov-78 16:26:44, EDIT BY JBORCHEK
;GTNCP WILL NOW TAKE .CTTRM AS NVT
;<BBN-3A-MONITOR>NETWRK.MAC.206, 26-Oct-78 19:03:32, EDIT BY JBORCHEK
;CHANGES TO LHOSTN
;<BBN-3A-MONITOR>NETWRK.MAC.202,  2-Oct-78 05:18:36, EDIT BY JBORCHEK
;HSTCHK DID NOT RETURN ERROR CODE ALL THE TIME
;<BBN-3A-MONITOR>NETWRK.MAC.201, 23-Sep-78 18:06:41, EDIT BY JBORCHEK
;SAVE THE EVENT AND OLD STATE AT DOFSM
;CLEAR HOST TABLES COMPLETELY AT HSTINI
;<4.MONITOR>NETWRK.MAC.23,  2-Sep-78 17:45:32, EDIT BY JBORCHEK
;<4.MONITOR>NETWRK.MAC.3,  1-Sep-78 18:43:19, EDIT BY JBORCHEK
;FIX MORE BUGS IN IMPHRT AND HSTSTS
;<4.MONITOR>NETWRK.MAC.21,  1-Sep-78 15:09:50, EDIT BY JBORCHEK
;FIX BUGS IN IMPHRT AND HSTSTS SIMULATIONS
;<4.MONITOR>NETWRK.MAC.20,  1-Sep-78 13:03:47, EDIT BY JBORCHEK
;LOAD JFN INTO T1 BEFORE RLJFN AT HSTINI
;<4.MONITOR>NETWRK.MAC.19,  1-Sep-78 10:45:51, Edit by LCAMPBELL
;<4.MONITOR>NETWRK.MAC.18, 30-Aug-78 14:14:21, Edit by LCAMPBELL
; Change ERCALs to CALLs after GTHST and GTNCP, and make
;  GDSTS return old-style host number
;<4.MONITOR>NETWRK.MAC.17, 29-Aug-78 14:37:55, Edit by LCAMPBELL
;<4.MONITOR>NETWRK.MAC.16, 28-Aug-78 19:21:48, Edit by LCAMPBELL
; Simulate IMPHRT and HSTSTS GETABs so old utilites still work
;<4.MONITOR>NETWRK.MAC.15, 26-Aug-78 21:23:47, EDIT BY JBORCHEK
;ANFHS MUST BE 36 BITS WIDE
;<3A-JBORCHEK>NETWRK.MAC.3, 24-Aug-78 19:55:30, EDIT BY JBORCHEK
;<3-CLEMENTS>NETWRK.MAC.21, 21-Aug-78 13:20:07, EDIT BY JBORCHEK
;FIX BUGS IN GTHST
;<3-CLEMENTS>NETWRK.MAC.20, 19-Aug-78 00:53:34, EDIT BY JBORCHEK
;<3-CLEMENTS>NETWRK.MAC.16, 18-Aug-78 18:44:25, EDIT BY JBORCHEK
;ADD NEW GTHST FUNCTIONS
;<3-CLEMENTS>NETWRK.MAC.12, 16-Aug-78 16:18:01, EDIT BY CLEMENTS
; Add STHSTJ routine
;<3-CLEMENTS>NETWRK.MAC.11, 16-Aug-78 15:54:21, EDIT BY CLEMENTS
;<3-CLEMENTS>NETWRK.MAC.10, 16-Aug-78 15:38:20, EDIT BY CLEMENTS
; Make MAXBPM and MAXWPM back into constants, from literals
;<JBORCHEK>NETWRK.MAC.2, 16-Aug-78 13:38:23, EDIT BY JBORCHEK
;<4-JBORCHEK>NETWRK.MAC.2, 14-Aug-78 12:54:05, EDIT BY JBORCHEK
;<3-CLEMENTS>NETWRK.MAC.6, 11-Aug-78 23:44:53, EDIT BY CLEMENTS
;<3-CLEMENTS>NETWRK.MAC.5, 11-Aug-78 22:56:41, EDIT BY CLEMENTS
;<3-CLEMENTS>NETWRK.MAC.4, 11-Aug-78 16:20:42, EDIT BY CLEMENTS
;<3-CLEMENTS>NETWRK.MAC.3, 11-Aug-78 16:18:45, EDIT BY CLEMENTS
;<3-CLEMENTS>NETWRK.MAC.2, 11-Aug-78 15:09:27, EDIT BY CLEMENTS
; Remove use of local IMPLT bit
;<4.MONITOR>NETWRK.MAC.10,  7-Jul-78 01:15:43, Edit by JBORCHEK
;ADD GTNCP JSYS
;<4.MONITOR>NETWRK.NEW.7,  6-Jul-78 08:01:14, Edit by JBORCHEK
;ADD GTHST JSYS
;<4.MONITOR>NETWRK.MAC.3, 26-Jun-78 16:43:46, Edit by JBORCHEK
;<4.MONITOR>NETWRK.MAC.1, 26-Jun-78 02:48:39, Edit by JBORCHEK
;ADD HASH LOOKUP OF HOSTS
;<4.MONITOR>NETWRK.NEW.11, 18-Jun-78 14:54:55, Edit by JBORCHEK
;MORE NEW HOST STUFF
;<4.MONITOR>NETWRK.MAC.8,  9-Jun-78 23:01:08, Edit by JBORCHEK
;USE IMPPAR DEFINITIONS
;<4.MONITOR>NETWRK.MAC.2,  6-Jun-78 01:32:06, Edit by JBORCHEK
;ADD SEARCH OF IMPPAR
;<3A.MONITOR>NETWRK.MAC.6, 28-May-78 01:48:11, Edit by BORCHEK
;REMOVE OPENING NET IN 7 BIT MODE
;<3A-MONITOR>NETWRK.MAC.4, 22-Apr-78 20:37:51, Edit by BORCHEK
;SPEED UP NETWORK FTP
;<HACKS>NETWRK.MAC.8,  2-Apr-78 02:27:39, EDIT BY JBORCHEK
;USE AN ADJBP AT DMPBUF
;<3A.MONITOR>NETWRK.MAC.2, 19-Mar-78 13:07:41, Edit by BORCHEK
;GET DIR # FROM JSBSDN IN NETVER
;ONLY 8, 32, 36 BIT CONNECTIONS ALLOWED
;<4.MONITOR>NETWRK.MAC.2, 29-Jan-78 16:59:49, Edit by BORCHEK
;FIX DIR NET:<*> FROM HANGING JOB. CHECK AT NETSET FOR <*>

;This software is furnished under a license and may only be used
;  or copied in accordance with the terms of such license.
;
;Copyright (C) 1976,1977,1978,1979,1980 Digital Equipment Corporation
; Maynard, Mass.

	SEARCH PROLOG,IMPPAR,MACSYM,MONSYM
	TTITLE	NETWRK

; Macros to turn imp on and off

DEFINE	NCPON<CALL ULKNCP>

DEFINE	NCPOFF<CALL LCKNCP>

; Local accumulators

DEFAC (UNIT,Q1)			;PSEUDO-UNIT NUMBER
DEFAC (IOS,Q2)			;STATUS FLAGS (FROM NETSTS(UNIT))
DEFAC (HN,Q3)
DEFAC (STS,P1)
DEFAC (JFN,P2)
DEFAC (PTR,P3)
DEFAC (DEV,P4)
DEFAC (F1,P5)

;PARAMETERS

NLNKBW==<LLINK+^D35>/^D36	;LENGTH OF LINK BITTABLE

; NCP DATA CLUSTER

DEFSTR ANFHS,NETHST,35,36	;FOREIGN HOST
DEFSTR ANLNK,NETAWD,8,9		;LINK
DEFSTR ANCLKS,NETAWD,23,6	;TIME-OUT COUNTDOWN
DEFSTR ANINPI,NETFRK,5,6	;INS/INR PSI CHAN
DEFSTR ANFSPI,NETFRK,17,6	;FSM PSI CHAN
DEFSTR ANFSM,NETSTS,3,4		;FSM STATE
DEFSTR ANBSIZ,NETSTS,17,6	;BIT STREAM BYTE SIZE
DEFSTR ANPVST,NETSTS,35,16	;PREVIOUS 4 STATES
DEFSTR HSTIDX,HOSTN,35,18	;INDEX TO STATUS TABLE
DEFSTR HSTNMP,HOSTN,17,16	;POINTER TO NAME STRING

MSGALL==2			;DESIRED MESSAGE ALLOCATION LEVEL

;FLAGS IN LH OF NETSTS

FLG(BFSND,L,IOS,020000)		;BUFFERED SEND MODE
FLG(ERRB,L,IOS,010000)		;ERROR HAS OCCURRED
FLG(EOTF,L,IOS,004000)		;END OF TRANSMISSION FLAG
FLG(SVCIF,L,IOS,002000)		;SERVICE INTERRUPTION IN PROGRESS
FLG(CLZF,L,IOS,001000)		;CONNECTION IS BEING CLOSED
FLG(DEDF,L,IOS,000400)		;HOST IS DEAD
FLG(PROGF,L,IOS,000200)		;SET IF PROGRAM IS WATCHING THIS CONNECTION
FLG(ALLFF,L,IOS,000100)		;ALLOCATION RESYNC HAS BEEN DONE
; Bbn socket numbers description
; A socket number is a 32-bit number which in conjunction with
; A host number specifies one end of a connection
; For bbn sockets, the 32 bit field is divided in 3 parts:
; The high 17 bits is used as follows:
;  if 0:      then this is a system socket
;  if <100000 then the number is a bbn user number and the socket is
;             is called a user socket
;  if >99999  then the number is tss job-number plus 100000, and the
;             socket is called a job socket

; A job socket is analogous to a temporary file and is guaranteed to
; Be unique to that job.  a user socket is analogous to a regular file
; And is guaranteed to be unique to that user.  a system socket is
; For use as agreed upon by members of the network for such purposes
; As inter system communication, memo-distribution etc.

; The next 14 bits are an arbitrary number which may be defaulted
; To the jfn associated with the socket or specified by the name field
; Of the file name string.  the low order bit is determined by
; The gender of the socket.  a socket opened for for writing
; Will have this bit equal to one. a socket opened for reading will
; Have this bit equal to zero.
; Network dispatch table

	SWAPCD

NETDTB::DTBDSP (NETSET)		;DIRECTORY SETUP
	DTBDSP (NETNAM)		;NAME LOOKUP
	DTBDSP (NETEXT)		;EXTENSION LOOKUP
	DTBDSP (NETVER)		;VERSION LOOKUP
	DTBBAD (DESX9)		;PROTECTION INSERT
	DTBBAD (DESX9)		;ACCOUNT INSERT
	DTBBAD (DESX9)		;STATUS INSERT
	DTBDSP (NETOPN)		;OPEN
	DTBDSP (NETSQI)		;BYTE INPUT
	DTBDSP (NETSQO)		;BYTE OUTPUT
	DTBDSP (NETCLZ)		;CLOSE
	DTBBAD (DESX9)		;RENAME
	DTBBAD (DESX9)		;DELETE
	DTBBAD (DESX9)		;DUMP
	DTBBAD (DESX9)	
	DTBBAD (DESX9)		;MOUNT
	DTBBAD (DESX9)		;DISMOUNT
	DTBBAD (DESX9)		;INITIALIZE
	DTBDSP (NETMTP)		;MTOPR
	DTBDSP (NETGST)		;GET STATUS
	DTBDSP (NETSST)		;SET STATUS
	DTBSKP			;RECORD OUT
	DTBDSP (RFTADN)		;READ TAD
	DTBDSP (SFTADN)		;SET TAD
	DTBDSP (BIOINP)		;SET JFN FOR INPUT
	DTBDSP (BIOOUT)		;SET JFN FOR OUTPUT
	DTBBAD (GJFX49)		;CHECK ATTRIBUTE

	DTBLEN==:.-NETDTB	;GLOBAL LENGTH OF DISPATCH TABLE

; Network lock and unlock

LCKNCP::AOS NCPLCN		; COUNT CALLS TO THIS ROUTINE
	NOINT
	LOCK NCPLCK,<JRST LCKNC1>
LCKNC2:	PUSH P,FORKX
	POP P,NCPLLK		; SAVE LAST LOCKER
	RET

LCKNC1: AOS NCPLFC		; COUNT FAILURES
	PUSH P,T1
	MOVEI T1,NCPLKT
	MDISMS
	POP P,T1
	JRST LCKNC2

	RESCD

NCPLKT:	AOSE NCPLCK
	 JRST 0(T4)
	JRST 1(T4)

	SWAPCD

ULKNCP::UNLOCK NCPLCK
	OKINT
	RET
; Initialize network stuff

NETINI::SE1CAL			;ENTER SECTION 1 FOR THIS ROUTINE
	SETZM NETSTS
	MOVE T1,[NETSTS,,NETSTS+1]
	BLT T1,NETSTS+NSKT-1
	SETZM NETCNC
	SETZM FUNNYC
	MOVE T1,[ANBSEC,,NTBUFS]
	MOVEM T1,NETFRE		;INITIAL FREE LIST
	MOVEI T2,NNTBFS		 ; SIZE OF BUFFER AREA
	IDIV T2,MAXWPM		;IN CASE NOT AN EVEN MULTIPLE
	IMUL T2,MAXWPM		; ..
	MOVEM T2,NETFRE+2	;FREE SPACE LEFT IN BUFFER AREA
	MOVEM T1,NETFRE+3	;START OF BUFFER AREA
	ADDI T1,-1(T2)		;END OF BUFFER AREA
	MOVEM T1,NETFRE+4

;INITIALIZE FREE LIST INTO ITEMS OF MAXWPM EACH

	MOVEI T2,NNTBFS		;SIZE OF BUFFER REGION
	IDIV T2,MAXWPM		;NUMBER OF BUFFERS IN REGION
	MOVE T3,[ANBSEC,,NTBUFS] ;SET UP C TO POINT TO NET BUFFERS
NETIN2:	MOVE T1,T3		;COPY C INTO A
	ADD T3,MAXWPM		;RH(T3) POINTS TO NEXT BUFFER
	HRLOM T3,0(T1)		;STORE THAT IN LEFT HALF IN CURRENT BUFFER
	SOJG T2,NETIN2		;DO ANOTHER
	HRRZS 0(T1)		;LAST ITEM POINTER IS 0

	SETOM NETFRE+1		;NETWORK BUFFER LOCK
	SETOM NCPLCK
	MOVE T1,DBUGSW		;IN SYSTEM DEBUG MODE?
	CAIGE T1,2		;IF SO, DON'T TURN ON NET.
	SETOM NETON		;NET ON
	MOVE T1,MAXWPM		;GET SIZE OF EACH BUFFER
	IMULI T1,^D16		;TIMES RESERVE
	MOVEM T1,ASNTHR		;SETS BUFFER SPACE LOW THRESHOLD
	RET
; Prepare to lookup network names

NETSET:	TQNE <STEPF>		;WANT TO STEP?
	RETBAD (GJFX17)		;YES. CAN'T DO IT
	NOINT			;PREVENT INTS
	JRST SK2RET		;AND SAY IT IS SET

; Name lookup routine

NETNAM:	JUMPE T1,NAMBAD		; *. -- failure
	HRLI T1,(<POINT 7,0,35>); Make lookup pointer into byte pointer
	CALL NAMDEC		; Decode name
	JRST NAMBAD		; Bad syntax
OKRET:	TQNE <UNLKF>
	JRST SK2RET
	OKINT
	JRST SK2RET

NAMBAD:	MOVEI T1,GJFX18
	JRST ERRET		; Error return

ERRET:	OKINT
	RET

; Extension lookup routine

NETEXT:	JUMPE T1,NAMBAD		; .* -- failure
	HRLI T1,(<POINT 7,0,35>); Make lookup pointer into byte pointer
	CALL EXTDEC		; Decode extension to check syntax
	JRST EXTBAD		; Bad syntax
	JRST OKRET		; Success

EXTBAD:	MOVEI T1,GJFX19
	JRST ERRET

; Version lookup

NETVER:	HRRES T1		; Extend sign
	CAIL T1,^D100000	; If geq 100000
	 JRST NETVR1		; Use job related socket
	HLLZ T1,JSBSDN		; Get structure
	LSH T1,-6
	ADD T1,JSBSDN		; Add in directory
	ANDI T1,177777		; Clear junk
NETVR1:	TQNE <UNLKF>
	RETSKP
	OKINT
	RETSKP
; Decode extension string
; Called both at gtjfn and openf to decode extension string into
; Foreign socket number and host number

EXTDEC:	MOVE T4,T1
	ILDB T4,T4
	JUMPE T4,[SETOB T1,T2
		RETSKP]
	MOVE T3,T1			;GET SCRATCH POINTER
	SETZ T4,			;ASSUME NO - FOUND
EXTDE1:	ILDB T2,T3			;GET A BYTE
	CAIN T2,"-"			;SAVE LAST - FOUND
	 MOVE T4,T3
	JUMPN T2,EXTDE1			;DO WHOLE STRING
	JUMPE T4,R			;NO - MEANS ERROR
	DPB T2,T4			;END HOST WITH NUL
	CALL HSTLUK			;LOOKUP HOST
	MOVEI T3,"-"			;RESTORE THE -
	DPB T3,T1
	JUMPG T2,R			;NO HOST FOUND
	MOVEI T3,10			;GET OCTAL SOCKET NUMBER
	NIN
	 RET
	MOVE T1,T4
	RETSKP
HSTLUK:	SAVEQ				;GET SOME ROOM
	MOVE UNIT,T1			;SAVE POINTER
	MOVEI T3,10
	NIN				;TRY TO GET A NUMBER
	 JRST HSTLKI			;TRY A NAME
	MOVE UNIT,T1			;SAVE UPDATED POINTER
	MOVE T1,T2
	CALL CVNHST
	MOVE T4,T1			;RETURN HOST NUMBER
	MOVE T1,UNIT			;AND UPDATED POINTER
	SETZ T2,			;HOST NUMBER FOUND
	RET

HSTLKI:	HRLZ T2,MHOSTS			;SCAN THE TABLE

HSTLK0:	MOVE T1,UNIT			;DO NAME POINTER
	LOAD T3,HSTNMP,(T2)
	ADD T3,[POINT 7,HSTNAM]

HSTCMP:	ILDB IOS,T1			;COMPARE A STRING
	ILDB HN,T3
	SKIPN IOS
	 JUMPE HN,[LOAD T4,HSTIDX,(T2)
		   MOVE T4,HOSTNN(T4)
		   RET]
	CAIN IOS,(HN)
	 JRST HSTCMP
	AOBJN T2,HSTLK0			;STEP TO NEXT HOST
	SETZ T4,			;NO HOST FOUND
	RET

	RESCD

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
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
	CAIL T2,NHOSTS			;WRAP AROUND IF NEEDED
	 SUBI T2,NHOSTS
	SOJG T3,HSTHLP			;COUNT DOWN GUESSES
	SETO T2,			;-1 TABLE FULL
	RET

;CONVERT HOST NUMBER IN AC1 TO NEW FORMAT

CVNHST::CAMN T1,[-1]		;IF -1 USE LOCAL HOST NUMBER
	 MOVE T1,NLHOST
	AND T1,[HSTMSK]		;CUT DOWN TO SIZE
	TLNE T1,37700
	 RET
	ANDI T1,377
	TRZE T1,100		;SET THE HOST BITS
	 TRO T1,200000
	TRZE T1,200
	 TRO T1,400000
	IOR T1,NETFLD		;ADD NETWORK NUMBER
	RET

;CONVERT HOST NUMBER IN AC1 TO OLD FORMAT

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

	SWAPCD
; Decode name string
; Called both at gtjfn and openf to decode name string into
; Local socket number

NAMDEC:	MOVEI T3,10		; Perhaps this should be decimal?
	NIN			; Convert to a number
	JRST NAMDE1		; Failure: no number there
	LDB T3,T1		; Get terminator
	CAIE T3,"#"		; If not number sign
	JRST NAMDE2		; Then ordinary
	MOVE T3,CAPMSK		; Else system socket
	TRNN T3,SC%WHL!SC%OPR!SC%NAS;MUST BE WHEEL, OPR, OR
				; HAVE ABSOLUTE SOCKET CAPABILITY
	RET			; Else fail
	ILDB T3,T1		; Get next ch
	TDZA T1,T1		; Zero for high 17 bits
NAMDE2:	HRRZ T1,FILVER(JFN)	; Use filver for high 17 bits
	JUMPN T3,R		; String too long
	SKIPE T1
	 ANDI T2,77777		; If not system socket, retain 15 bits
	TRZ T2,1		; Clear gender
	ROT T1,^D15
	IOR T1,T2
	RETSKP

NAMDE1:	MOVE T2,JFN		; Default to jfn
	IDIVI T2,MLJFN		; Get the jfn
	LSH T2,1		; Jfn will end up lsh'ed 1
	LDB T3,T1
	JRST NAMDE2

NETDED::MOVE T1,NETSTS(UNIT)	; GET STATUS
	TXNE T1,DEDF+EOTF	; HOST DEAD OR DONE
	 RET
	RETSKP

NETHLK::LOAD T1,ANFHS,(UNIT)	; HOST
	LOAD T2,ANLNK,(UNIT)	; LINK
	RET
; Open network file

NETOPN:	TQNE <XCTF,RNDF>
	JRST ILLACC		; Illegal to access in append or xct
	TQNE <READF>
	TQNN <WRTF>
	TQNN <READF,WRTF>
	JRST ILLACC		; Must be only one of read or write
	LDB T1,PBYTSZ
	CAIN T1,^D8		; Check for 8 32 or 36 bit bytes
	 CAIA
	CAIN T1,^D32
	 CAIA
	CAIN T1,^D36
	 CAIA
	JRST [	MOVEI T1,SFBSX2
		RET]		; Bad byte size
	HLRZ T1,FILNEN(JFN)
	HRLI T1,(<POINT 7,0,35>)
	CALL NAMDEC		; Decode name
	JRST ILLACC		; Can only happen if wheel lost
	TQNE <WRTF>
	TROA T1,1		; If writing set gender bit for local
	TRZ T1,1		; Else clear it
	PUSH P,T1		; Save for later
	HRRZ T1,FILNEN(JFN)
	HRLI T1,(<POINT 7,0,35>)
	CALL EXTDEC		; Decode extension
	BUG(NETIEF)
	TQNE <READF>
	TROA T2,1		; If reading set gender bit for forskt
	TRZ T2,1		; Else clear
	POP P,T3
	LDB T4,PBYTSZ		; Get file byte size
	JUMPL T1,OPNLSN		; No foreign socket, do a listen
	CALL CONNECT		; Connect
	 RET
	TQZ <WNDF>
NETOP1:	HRLM UNIT,FILSKT(JFN)	;REMEMBER UNIT NUMBER
	SETZ IOS,		; Clear status bits
	LDB T1,[POINT 4,STS,35]
	CAIE T1,5		; In modes 5
	CAIN T1,7		; Or 7
	TQO <BFSND>		; DO BUFFERED TRANSMISSION
	IORB IOS,NETSTS(UNIT)	; Set it in status word
	MOVEI T1,^D36
	LDB T2,PBYTSZ
	IDIV T1,T2		; Get bytes per WORD
	XCTBU [LDB T3,[POINT 6,2,17]];GET DESIRED SIZE OF BUFFER
	IMUL T1,T3		; DESIRED BYTES
	HRLM T1,NETBUF(UNIT)	; Gives bytes per buffer
	SETZM FILBYN(JFN)	; About to reference byte 0 of buffer
	SETZM FILOFN(JFN)	; NEXT BYTE TO XMIT = 0
	TQO <SIZF>		; CANNOT CHANGE BYTE SIZE
	TQOE <WNDF>		; NO BUFFER YET. ALSO IF LISTEN
	RETSKP			; Return immediately
	LDB T1,[POINT 4,STS,35]
	CAIE T1,6		; Also in modes 6
	CAIN T1,7		; And 7
	RETSKP			; Return immediately
	LOAD T1,ANFSM,(UNIT)	; No. get current state
	CAIN T1,RFCS		; Will usually be rfcs
	CALL WATNOT		; If so, wait for it to not be
	LOAD T1,ANFSM,(UNIT)	; Get state
	MOVE IOS,NETSTS(UNIT)
	TQNN <EOTF>		; IF LEFT OPND
	CAIN T1,OPND		; OR STILL OPENED
	 RETSKP			; THEN SUCCEED
	MOVX T2,PROGF
	ANDCAM T2,NETSTS(UNIT)	; Program not watching
	CALL NETCLD		; FSM close
	TQNE <ERRB>		; ERRB REMEMBERS BAD BYTE SIZE
	SKIPA T1,[OPNX22]	; MAKE THAT THE ERROR CODE
	MOVEI T1,OPNX21		; ELSE IT WAS REJECTED
	RET			; And give bad return

OPNLSN:	CALL LISTEN
	 RET			; Can't listen
	TQO <WNDF>		; TO REMEMBER THAT THIS WAS A LISTEN
	JRST NETOP1		; First bin/out is accept

ILLACC:	MOVEI T1,OPNX14
	RET
; Wait for fsm to leave state given in a

WATNOT:	HRLI T1,NOTTST		; TEST ROUTINE ADDRESS
WATNO1:	MOVE T2,UNIT		; COMPUTE SCHEDULER TEST ARGUMENT
	ROT T2,-9
	MOVSS T1
	IOR T1,T2
	SKIPE INSKED
	BUG(NETWNS)
	MDISMS
	RET

; Wait for fsm to enter a particular state

WATFOR:	HRLI T1,WATTST
	JRST WATNO1

	RESCD

NOTTST:	LDB T2,[POINT 9,T1,26]	; EXTRACT UNIT
	ANDI T1,777		; AND STATE TO TEST AGAINST
	LOAD T3,ANFSM,(T2)	; GET CURRENT STA(E
	CAME T1,T3		; IS IT THE SAME
	JRST 1(T4)		; NO, READY TO GO
	JRST WATTS1		; YES, MAKE OTHER TESTS

; SCHEDULER TEST WAITING FOR CONNECTION TO GET TO A STATE

WATTST:	LDB T2,[POINT 9,T1,26]	; EXTRACT UNIT
	ANDI T1,777		; AND STATE
	LOAD T3,ANFSM,(T2)	; GET CURRENT STATE
	CAMN T3,T1		; SAME?
	JRST 1(T4)		; YES, READY TO GO
WATTS1:	MOVE T3,FKINT(HN)	; Look for deferred interrupts
	TLNN T3,(1B1)
	JRST 0(T4)		; None. return no skip
	SETZ T3,
	STOR T3,ANCLKS,(T2)	; Set clock to zero to hasten time-out
	JRST 0(T4)

;SCHEDULER TEST FOR BIT ALLOCATION

;CONNECTION NUMBER IN T1

BALTST:	LOAD T2,ANBSIZ,(T1)	;GET BIT STREAM BYTE SIZE
	LOAD T3,LTIDX,(T1)	;GET LINK TABLE INDEX
	SKIPN IMPLT4(T3)	;SKIP IF NEITHER MSG ALLOC OR BUFFER
	 JRST BALTS1
	CAMG T2,NETBAL(T1)	;MSG OK, HOW ABOUT BITS?
	 JRST 1(T4)
BALTS1:	MOVE T3,NETSTS(T1)	;GET STATUS INFO
	TXNE T3,DEDF+EOTF	;ALLOC BAD. BUT IF DEAD..STILL OK
	 JRST 1(T4)		;TAKE SKIP RETURN
	JRST 0(T4)		;RETURN
	SWAPCD

; Close network file

NETCLZ:	HLRZ UNIT,FILSKT(JFN)
	TQNN <WNDF>		; IF NO BUFFER EVER ASSIGNED
	TQNN <WRTF>		; OR IF READING
	JRST NETCL1		; Then skip the following
	CALL DMPBUF		; Dump last buffer
	 JRST NETCLW		; NOT ALL SENT. GO WAIT.
NETCL1:
   REPEAT 0,<
	TQNE <ERRF>		; ANY FINAL ERRORS
	 JRST [	MOVEI T1,IOX5
		RET]		; DON'T CLOSE IF ANY UN-HANDLED ERRORS
   >
	HRROS FILSKT(JFN)	; IN CASE JFN RE-OPENED, SET UNIT TO -1
	SETOM NETFRK(UNIT)
	HRRZ T2,NETBUF(UNIT)	;GET BUFFER ADDRESS
	JUMPE T2,NETCL3		;IS THERE A BUFFER
	MOVEI T1,JSBFRE		;THIS IS ALSO THE BLOCK TO FREE
	CALL RELFRE		;YES. RELEASE IT
NETCL3:	CALL NETCLD		; FSM close
	UMOVE T1,1
	TDNN T1,[1,,400000]
	TLNN T1,(1B1)
	 JRST NETCL2		; Return immediately if no bit 1
	LOAD T2,ANFSM,(UNIT)
	MOVEI T1,FREE
	CAIE T2,FREE
	CALL WATFOR
NETCL2:	MOVX T1,PROGF
	ANDCAM T1,NETSTS(UNIT)	; No program wants this any more
	RETSKP

NETCLD:	TQNN <WRTF>		; IF NOT SENDING
	SKIPA T1,[CLZR]		; THEN DO CLZR
	MOVEI T1,CLZS		; ELSE do clzs
	CALLRET DOFSM

NETCLW:	MOVEI T2,^D60		; 5 MINUTES OF TICKS
	STOR T2,ANCLKS,(UNIT)
	MOVX IOS,CLZF
	IORB IOS,NETSTS(UNIT)
	MDISMS
	JRST NETCLZ		; AND GO TRY AGAIN

; Close nvt

NVTCLZ::MOVE T1,LSKT(UNIT)
	TRNN T1,1
	SKIPA T1,[CLZR]
	MOVEI T1,CLZS
	CALLRET DOFSM
; Network mtopr routines

NETMTP:	TQNN <OPNF>		;CHECK TO SEE IF OPENED
	RETBAD (CLSX1)		;NOT OPENED
	HLRZ UNIT,FILSKT(JFN)
	MOVE IOS,NETSTS(UNIT)
	CAIG T2,26
	CAIGE T2,20
	 RETSKP			; ANYTHING ELSE IS A NOP
	JRST .+1-20(T2)
	JRST NETACP
	JRST NETDMP
	JRST SNDINT
	JRST ABTCON
	JRST NETINT
	JRST NETRDY
	JRST NETFAL

NETACP:	LOAD T2,ANFSM,(UNIT)
	MOVEI T1,ACPT
	CAIN T2,RFCR
	 CALL DOFSM
	RETSKP

NETDMP:	TQNE <BFSND>		;SENDING BY BUFFER?
	TQNN <WRTF>		;AND A SEND CONNECTION?
	 RETSKP			;NO, A NOP
	TQNE <WNDF>		;YES. BUFFER SET UP?
	 RETSKP			;NO, NOTHING TO SEND
	CALL DMPBUF
	 JRST WATXXX
	RETSKP

SNDINT:	LOAD T1,ANFHS,(UNIT)
	LOAD T2,ANLNK,(UNIT)
	MOVE T4,LSKT(UNIT)
	TRNE T4,1
	SKIPA T4,[IMPINS]
	MOVEI T4,IMPINR
	NCPOFF
	LOAD T3,ANFSM,(UNIT)
	CAIN T3,OPND
	CALL (T4)
	NCPON
	RETSKP
; WAIT FOR READY TO SEND AT LEAST ONE BYTE

ABTCON:	MOVE T1,CAPENB
	TXNN T1,SC%NWZ
	 JRST [	MOVEI T1,NTWZX1	; NOT A NET WIZARD. FAIL.
		RET]
	CALL SKTDWN
	RETSKP

NETRDY:	TQNN <WRTF>		; RECEIVE OR SEND?
	 JRST NETRD1		; RECEIVE. SEND ALLOCATES OUT
	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	CALL PKCHK		; GET BYTES THAT CAN BE SENT
	JUMPE T2,[CALL WATBAL	; COMPUTE ACTIVATION TEST
		JRST WATXXX]	; AND WAIT
	CALL PKULCK
	RETSKP

NETRD1:	TQNN <WNDF>		;HAS ALLOCATION ALREADY BEEN SENT?
	RETSKP
	CALL FIRSTI		;NO. SEND IT OUT.
	RET			;PASS ON DOWN BLOCK
	RETSKP

NETINT:	UMOVE T2,3
	HRR T2,FORKX		; REMEMBER THIS FORK, AND USER'S
	MOVEM T2,NETFRK(UNIT)	;  REQUESTED PI CHANNELS
	RETSKP

NETFAL:	TQNE <WNDF,WRTF>	; IF READ AND FIRSTI NOT DONE
	RETSKP
	CALL FIRSTI		;  SET UP BUFFERS AND SEND ALLOCATE
	RET			;PASS ON DOWN BLOCK
	RETSKP

; HERE WHEN A FORK IS KILLED, TO FORGET THE PSI INFO

NETKFK::SAVEQ
	MOVSI UNIT,-NSKT
NETKF1:	HRRE IOS,NETFRK(UNIT)
	CAMN IOS,FORKX
	 SETOM NETFRK(UNIT)
	AOBJN UNIT,NETKF1
	RET
; HERE FROM LOGOUT CODE TO RELEASE JOB-WIDE NET RESOURCES

NETLGO::SETO T1,0		;RELEASE ALL SPECIAL QUEUES
	RELSQ
	RET			; THAT'S ALL

; SKIP IF NET INPUT BUFFER EMPTY

NTSIBE::HRRZ T1,DEV		;SEE IF NETWORK JFN
	CAIE T1,NETDTB
	 RETSKP
	HLRZ UNIT,FILSKT(JFN)
	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	MOVSI T2,777777
	TDNN T2,IMPLT4(T1)
	TDNE T2,IMPLT3(T1)
	 RET
	RETSKP
; Network file sequential byte input

NETSQI:	HLRZ UNIT,FILSKT(JFN)
	MOVE IOS,NETSTS(UNIT)
	TQNN <WNDF>
	JRST NTSQI1
	CALL FIRSTI		; Wait for listen set up buffers etc.
	RET			;PASS ON DOWN BLOCK
NTSQI1:	SOSL FILCNT(JFN)
	JRST NTSQI2
	CALL LODBUF		; Get another bufferful
	RET			;PASS ON DOWN BLOCK
NTSQI2:	TQNE <EOFF>
	RET
	ILDB T1,FILBYT(JFN)
	AOS FILBYN(JFN)
	RET

LODBUF:	MOVX IOS,ERRB
	TDNE IOS,NETSTS(UNIT)
	TQO <ERRF>
	ANDCAB IOS,NETSTS(UNIT)
	MOVE T3,NETBUF(UNIT)	;GET ADDRESS OF BUFFER
	HLL T3,FILBYT(JFN)	;GET THE BYTE SIZE
	TLZ T3,770000		;SET AT END OF FIRST WORD
	TLNN T3,700		;36 BIT MODE?
	 TLO T3,40000		;NO GET BYTE OFFSET RIGHT
	MOVEM T3,FILBYT(JFN)	;SAVE BYTE POINTER
	HLRZ T4,NETBUF(UNIT)	;GET BUFFER SIZE
	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	CALL UPMSG		;UNPACK MESSAGE(S) INTO BUFFER
	 JRST [MOVX IOS,EOTF	;GET END OF FILE FLAG
		TDNE IOS,NETSTS(UNIT) ;IS IT SET FOR THIS CONNECTION
		 JRST [ TQO <EOFF> ;YES SET FOR THIS JFN
			RETSKP]	;AND RETURN
		JRST WATXXX]	;BACK OUT AND WAIT THEN START OVER
	HLRZ T2,NETBUF(UNIT)	;GET BUFFER SIZE IN BYTES
	SUB T2,T4		;BYTES LOADED
	MOVEM T2,FILCNT(JFN)	;SET BYTES IN BUFFER FOR THIS JFN
	ADDM T2,FILLEN(JFN)	;UPDATE NUMBER OF BYTES ON THIS CONN.
	LOAD T4,ANBSIZ,(UNIT)	;GET BYTE SIZE
	IMUL T4,T2		;BITS RECEIVED
	ADDM T4,NETBTC(UNIT)	;KEEP COUNT OF BITS RECEIVED
	MOVN T2,T4		;GET NEGATIVE OF BITS RECIEVED
	ADDM T2,NETBAL(UNIT)	;DEBIT ALLOCATION FOR MESSAGE RECEIVED
	CALL NETRAL		;RE-ALLOCATE IF NEEDED
	SOSGE FILCNT(JFN)	;DID WE GET ANYTHING?
	JRST LODBUF		;NO BYTES GO TRY AGAIN
	RETSKP

NETRAL::NCPOFF			; PREVENT CONFUSION
	MOVE IOS,NETSTS(UNIT)
	TQNE <EOTF,DEDF>
	 JRST NETRAX		; DON'T BOTHER IF DEAD OR DONE
	STKVAR<NETRBA,NETRMA>
	MOVE T4,NETDAL(UNIT)	; GET DESIRED BIT ALLOCATION
	MOVE T2,T4
	ASH T2,-1		; HALVE
	MOVEM T2,NETRBA
	MOVEI T3,MSGALL		; DESIRED LEVEL OF MSG ALLOC
	MOVE T2,T3
	ASH T2,-1		; HALVE
	MOVEM T2,NETRMA
	LOAD T2,LTIDX,(UNIT)	; GET LINK TABLE INDEX
	HRRZ T2,IMPLT4(T2)	; OUTSTANDING MSG ALLOC
	SUB T3,T2		; NEEDED INCREMENT
	SUB T4,NETBAL(UNIT)	; NEEDED INCREMENT
	LOAD T1,ANFHS,(UNIT)
	LOAD T2,ANLNK,(UNIT)
	CAMGE T4,NETRBA		; IF GREATER THAN HALF
	CAML T3,NETRMA		; FOR EITHER ONE
	 CALL IMPALL		; THEN SEND AN ALLOCATE
NETRAX:	NCPON
	RET

FIRSTI:	CALL FRSTIO		; SET UP BUFFER
	RET			;PASS ON DOWN BLOCK
	JUMPG T2,FRSTI1		; BUFFER SPECIFIED. USE FOR ALLOCATION
	PUSH P,T1
	MOVE T1,MAXBPM		; MAXIMUM BITS IN A MESSAGE
	LOAD T2,ANBSIZ,(UNIT)	; CONNECTION BYTE SIZE
	IDIV T1,T2		; BYTES
	IMULI T1,MSGALL		; TIMES MESSAGE ALLOCATION
	POP P,T2		; THAT PLUS FILE BUFFER BYTES
	ADD T2,T1		; IS WHAT TO USE
FRSTI1:	LOAD T4,ANBSIZ,(UNIT)	; GET BYTES SIZE
	IMUL T4,T2		; BITS IN BUFFERS
	MOVEM T4,NETDAL(UNIT)	; SAVE DESIRED LEVEL
	CALL NETRAL		; SEND ALLOCATE AS NEEDED
	RETSKP
WATLSN:	LOAD T1,ANFSM,(UNIT)	; Get state of this connection
	CAIN T1,OPND
	 RETSKP
	CAIN T1,RFCR
	 JRST [	MOVEI T1,ACPT
		CALL DOFSM
		RETSKP]
	CAIN T1,RFCS		; If still waiting for rfc
	 JRST WATLS1		; Continue waiting
	CAIE T1,LSNG
	 JRST [	MOVX IOS,EOTF
		TDNE IOS,NETSTS(UNIT)
		 RETSKP		; Null file sent
		MOVX IOS,ERRB!EOTF ; Connection never actually opened
		IORB IOS,NETSTS(UNIT)
		RETSKP]


WATLS1:	MOVE T2,UNIT		;GET UNIT
	ROT T2,-9		;PUT IN BITS 0-8
	HRLI T1,NOTTST		;TEST ROUTINE ADDRESS,,STATE 
	MOVSS T1		;STATE TO WAIT FOR,,TEST ROUTINE ADDRESS
	IOR T1,T2		;UNIT/STATE,,TEST ROUTINE
	TQO <BLKF>		;BLOCK FOR STATE CHANGE
	RET



WATXXX:	TQO <BLKF>		;TELL LOWER LEVEL TO BLOCK
	RET
; Network file sequential byte output

NETSQO:	HLRZ UNIT,FILSKT(JFN)
	MOVE IOS,NETSTS(UNIT)
	TQNE <DEDF,ERRB>
	 TQO <ERRF>
	TQNE <DEDF,EOTF>
	 RET
	PUSH P,T1
	TQNN <WNDF>
	JRST NTSQO4
	CALL FIRSTO
	 JRST [POP P,0(P)	;CLEAN UP STACK
		RET]		;PASS ON DOWN BLOCK
NTSQO4:	TQNE <BFSND>		; IMMEDIATE SEND?
	 JRST NTSQO1		; No
	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	CALL PKCHK		; HOW MANY BYTES CAN WE SEND?
	POP P,T3
	JUMPE T2,NTSQO3		; NOT ENOUGH
	CALL PKBYT
	 TRN
	LOAD T1,ANBSIZ,(UNIT)
	ADDM T1,NETBTC(UNIT)
	MOVNS T1
	ADDM T1,NETBAL(UNIT)
	MOVEI T1,^D24
	STOR T1,ANCLKS,(UNIT)	; RESET CLOCK TO TWO MINUTES
	RET

NTSQO1:	SOSL FILCNT(JFN)
	 JRST NTSQO2
	CALL DMPBUF
	 JRST [POP P,T3		;CLEAN UP STACK
		JRST WATXXX]	; Can't dump now, wait
NTSQO2:	AOS FILBYN(JFN)
	POP P,T1
	IDPB T1,FILBYT(JFN)
	RET

NTSQO3:	CALL WATBAL		;WAIT FOR BITS AND A MSG TO BE ALLOCATED
	JRST WATXXX		; ..
DMPBUF:	MOVX IOS,ERRB		;GET ERROR HAS OCCURED FLAG
	TDNE IOS,NETSTS(UNIT)	;HAS ERROR OCCURED?
	 TQO <ERRF>		;YES.  INDICATE IT FOR THE JFN
	ANDCAB IOS,NETSTS(UNIT)	;CLEAR ERROR FLAG FOR CONNECTION
	MOVE T4,FILOFN(JFN)	;GET CURRENT OUTPUT POINT
	CAML T4,FILBYN(JFN)	;DONE?
	 JRST DMPDUN		;YES
	TQNE <EOTF,DEDF>	;END OF FILE OR DEAD HOST
	 JRST [ TQO <ERRF>	;YES.  SET ERROR FOR JFN
		SETZM FILBYT(JFN) ;ZERO BYTE POINTER
		SETZM FILBYN(JFN) ;BYTE COUNT
		SETZM FILOFN(JFN) ;AND CURRENT POSITION IN FILE
		HRLOI T1,377777	;AND SET NUMBER OF BYTES TO INFINITY
		MOVEM T1,FILCNT(JFN)
		RETSKP]
	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	CALL PKCHK		;HOW MANY BYTES CAN WE SEND?
	JUMPE T2,WATBAL		;NONE, WAIT
	MOVE T4,FILBYN(JFN)	;GET BYTE COUNT
	SUB T4,FILOFN(JFN)	;GET NUMBER OF BYTES IN BUFFER
	CAML T4,T2
	MOVE T4,T2		;TAKE MIN OF THE TWO
	MOVE T3,NETBUF(UNIT)	;GET BUFFER ADR
	HLL T3,FILBYT(JFN)	;GET BYTE SIZE
	TLZ T3,770000		;END OF FIRST WORD
	TLNN T3,700		;36 BIT MODE?
	 TLO T3,40000		;NO GET BYTE OFFSET RIGHT
	MOVE T1,FILOFN(JFN)	;GET BYTE OFFSET
	TLNE T3,6700		;8 BIT?
	 JRST DMPBF1		;NO
	IDIVI T1,4		;GET WORDS TO ADJUST IN T1
	HRRZS T3		;WE WILL ADD IN THE PROPER LH
	ADD T3,[041000,,0	;CASE 0. POINT TO PREVIOUS WORD
		341000,,1	;SO PKMSG WILL DO A BLT
		241000,,1	;OTHERS CASES USE STD. PTR
		141000,,1](T2)
DMPBF1:	ADDI T3,(T1)		;DO WORD OFFSET
	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	PUSH P,T4		;SAVE COUNT WE ARE ASKING FOR
	CALL PKMSG		;GO PACK MESSAGE AND SEND IT
	POP P,T4		;GET BYTE COUNT BACK
	ADDM T4,FILOFN(JFN)	;UPDATE BYTE COUNT OF BUFFER
	LOAD T3,ANBSIZ,(UNIT)	;GET BYTE SIZE
	IMUL T4,T3		;GIVES BITS JUST SENT
	ADDM T4,NETBTC(UNIT)	;KEEP COUNT OF BITS SENT
	MOVNS T4		;GET NEGATIVE OF BITS SENT
	ADDM T4,NETBAL(UNIT)	;UPDATE BIT ALLOCATION
	MOVEI T1,^D24
	STOR T1,ANCLKS,(UNIT)	;RESET CLOCK FOR THIS CONNECTION
	JRST DMPBUF		;GO CHECK FOR ERRORS
DMPDUN:	SETZM FILBYN(JFN)	;ZERO BYTE COUNT FOR BUFFER
	SETZM FILOFN(JFN)	;ZERO CURRENT OUTPUT POINT
	MOVE T1,NETBUF(UNIT)	;GET ADDRESS OF BUFFER
	HLL T1,FILBYT(JFN)	;GET THE BYTE SIZE
	TLZ T1,770000		;SET AT END OF FIRST WORD
	TLNN T1,700		;36 BIT MODE?
	 TLO T1,40000		;NO GET BYTE OFFSET RIGHT
	MOVEM T1,FILBYT(JFN)	;SAVE BYTE POINTER
	HLRZ T1,NETBUF(UNIT)	;GET BUFFER SIZE
	SUBI T1,1		;DECREMENT IT BY ONE
	MOVEM T1,FILCNT(JFN)	;AND SAVE IT AS BYTES IN BUFFER
	RETSKP

WATBAL:	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	CALL PKULCK		;UNLOCK CONNECTION TOO
	MOVEI T1,BALTST		;GET ADDRESS OF TEST ROUTINE
	HRL T1,UNIT		;AND UNIT TO WAIT ON
	RET
FIRSTO:	TQNN <BFSND>		; BUFFERED?
	 JRST [	CALL WATLSN	; NO, WAIT FOR CONNECTION TO OPEN
		RET		;PASS ON DOWN BLOCK
		TQZ <WNDF>
		RETSKP]
	CALL FRSTIO		; YES, SET UP BUFFER ETC
	RET			;PASS ON DOWN BLOCK
	RETSKP

;FRSTIO -  SET UP BUFFER IN JSB FREE SPACE

;ACCEPTS  UNIT/   NETWORK PSEUDO UNIT NUMBER

;RETURNS +1  FAILURE
;	 +2  SUCCESS   
;		RH NETBUF(UNIT)  HAS BUFFER ADDRESS

FRSTIO:	CALL WATLSN		; Wait for connection complete
	 RET			; Pass on down block
	STKVAR <FRSTBY,FRSTBF>
	MOVEI T1,^D36		; Bits per word
	LOAD T3,ANBSIZ,(UNIT)	; Connection byte size
	IDIV T1,T3		; Connection bytes per word
	IMUL T3,T1		; Used bits per word
	MOVE T2,MAXBPM		; Max bits per net message
	IDIVM T2,T3		; Max words per net message
	MOVEI T1,^D36		; Bits per machine word
	LDB T2,PBYTSZ		; File byte size
	IDIVM T1,T2		; File bytes per word
	MOVEM T2,FRSTBY		; Save file bytes per word
	HLRZ T1,NETBUF(UNIT)	; Desired bytes per buffer
	IDIV T1,T2		; Number of words needed
	SKIPE T1		; If zero
	CAML T1,T3		; Or bigger than max
	 MOVE T1,T3		; Use max
	MOVEM T1,FRSTBF		; Save bytes per buffer
	AOS T2,T1		; Plus header
	CALL ASGJFR		;ASSIGN A PAGE IN JOB AREA
	 JRST [TQO <ERRF>	;INDICATE AN ERROR
		RETBAD]		;RETURN
	HRRM T1,NETBUF(UNIT)	;SAVE BUFFER ADDRESS
	MOVE T3,FRSTBF		;GET SIZE AVAILABLE FOR BUFFER
	MOVE T1,FRSTBY		;GET BYTES/WORD BACK
	IMUL T1,T3		;CALCULATE BYTES BUFFER WILL HOLD
	HLRZ T2,NETBUF(UNIT)	;RETURN AS VALUE
	HRLM T1,NETBUF(UNIT)	;REAL BYTES PER BUFFER
	TQZ <WNDF>
	RETSKP
; Attach sockets to pty
; Call:	1	; Receive jfn of opened network connection
;	2	; Send jfn of opened network connection
;	ATNVT
; Returns
;	+1	; Cannot attach
;	+2	; Ok.  the jfns are released, ac 1 has line number of
;		; Attached pty.

.ATNVT::MCENT
	STKVAR <ATUNTS,ATRCJF,ATNDAD>
	UMOVE JFN,1
	HRRZS JFN
	CALL CHKJFN		; Check jfn of receive connection
	 JRST ATPER0		; Only real jfns are legal
	 JRST ATPER0
	 JRST ATPER0
	MOVEI T1,ATNX2		; Error code if test skips
	TQNE <READF>		; MUST BE OPENED FOR READING
	CALL CHKATP		; Check for dev=net, open, no buffer
	 JRST ATPER1		; Failed one of the above
	HLRZ UNIT,FILSKT(JFN)
	MOVEM UNIT,ATUNTS	;SAVE DEV AND JFN
	MOVEM JFN,ATRCJF
	UMOVE JFN,2		; Get send jfn
	CALL CHKJFN		; Check it
	JRST ATPER2		; Must also be a real jfn
	JRST ATPER2
	JRST ATPER2
	MOVEI T1,ATNX2		; Becomes atNx8 at atper3
	TQNE <WRTF>		; THIS ONE MUST BE FOR WRITING
	CALL CHKATP		; And dev=net, open, no buffer
	 JRST ATPER3		; Failed above tests
	HLRZ UNIT,FILSKT(JFN)
	LOAD T1,ANFSM,(UNIT)
	CAIN T1,RFCS
	CALL WATNOT		; Wait for response from foreign host
	MOVEI T1,ATNX12		; Error code for refused send
	LOAD T2,ANFSM,(UNIT)	; Now get state
	CAIE T2,OPND		; If not opnd
	JRST ATPER4		; Then fail
	HRLM UNIT,ATUNTS	;SAVE SEND JFN IN LEFT HALF
	HRRZ UNIT,ATUNTS	;SWITCH TO RECEIVE CONNECTION
	LOAD T1,ANFSM,(UNIT)	; Get its state
	CAIN T1,RFCS
	CALL WATNOT		; Wait for response from foreign host
	MOVEI T1,ATNX6		; Error code for refused receive
	LOAD T2,ANFSM,(UNIT)
	CAIE T2,OPND		; If not opnd
	JRST ATPER4		; Then fail
	NCPOFF
	LOAD T1,ANFSM,(UNIT)
	CAIE T1,OPND
	 JRST [	MOVEI T1,ATNX6
		JRST ATPERZ]
	HLRZ UNIT,ATUNTS	;GET SEND UNIT
	LOAD T1,ANFSM,(UNIT)
	CAIE T1,OPND
	 JRST [	MOVEI T1,ATNX12
		JRST ATPERZ]
	UMOVE 1,1		; GET OPTION FLAGS
	HRR T1,ATUNTS		;SET UP ARGS, RECEIVE UNIT IN 1
	HLRZ T2,ATUNTS		;SEND UNIT IN 2
	CALL ASNNVT		; Assign NVT to these units
	 JRST [	MOVEI T1,ATNX13	; Can't, no pty's
		JRST ATPERZ]
	MOVEM T2,ATNDAD		;SAVE ADDRESS OF DYNAMIC DATA
	HRRZ UNIT,ATUNTS	;RECIEVE UNIT
	MOVX T3,PROGF
	ANDCAM T3,NETSTS(UNIT)	; PROGRAM NO LONGER LOOKING
	HRRM T1,NETBUF(UNIT)	; Store pty number here
	HLRZ UNIT,ATUNTS	;SEND UNIT
	ANDCAM T3,NETSTS(UNIT)	; NOT HERE EITHER
	HRRM T1,NETBUF(UNIT)	; Also here
	NCPON
	IORI T1,400000		; Convert pty to tty designator
	UMOVEM T1,1		; Return to user
	CALL RELJFN		; Release send jfn
	MOVE JFN,ATRCJF
	CALL RELJFN		; And receive jfn
	HRRZ UNIT,ATUNTS	;GET RECIEVE UNIT
	MOVE T2,ATNDAD		;GET ADDRESS OF DYNAMIC DATA
	CALL NVTRAL		;GO REALLOCATE
	MOVE T2,ATNDAD		;GET ADDRESS OF DYNAMIC DATA
	CALL ULKTTY		;UNLOCK DATA BASE
	SMRETN			;RETURN SKIPPING
; Check validity of jfn for atpty

CHKATP:	MOVEI T1,ATNX3		; Receive not open
	TQNN <OPNF>		; IS IT OPEN?
	RET			; NO
	HRRZ T2,DEV
	MOVEI T1,ATNX4
	CAIE T2,NETDTB
	RET
	MOVEI T1,ATNX5
	TQNN <WNDF>
	RET
	RETSKP

ATPERZ:	NCPON
	JRST ATPER4

ATPER2:	MOVEI T1,ATNX7		; Bad send jfn
	JRST ATPER5

ATPER3:	ADDI T1,ATNX7-ATNX1	; Convert receive errors to send errors
ATPER4:	CALL UNLCKF
ATPER5:	MOVE JFN,ATRCJF		;GET RECIEV JFN
	MOVE STS,FILSTS(JFN)
ATPER1:	CALL UNLCKF
	JRST MRETNE		; Save error return in ac1

ATPER0:	MOVEI T1,ATNX1		; Bad receive jfn
	JRST MRETNE
; Convert jfn to absolute network socket number
; Call:	1	; Jfn
;	CVSKT
; Returns
;	+1	; Error
;	+2	; Ok, in 2 the absolute socket number

.CVSKT::MCENT
	MOVE JFN,T1
	CALL CHKJFN
	 RETERR (CVSKX1)
	 RETERR (CVSKX1)
	 RETERR (CVSKX1)
	CAIE PTR,NETDTB
	 RETERR (CVSKX1,<CALL UNLCKF>)
	HLRZ T1,FILNEN(JFN)
	HRLI T1,(<POINT 7,0,35>)
	CALL NAMDEC
	 RETERR (CVSKX2,<CALL UNLCKF>)
	CALL UNLCKF
	UMOVEM T1,2
	JRST SKMRTN

;ROUTINE TO PRODUCE THE OLD HOSTN TABLE

GHOSTN::LOAD T4,HSTIDX,(T2)		;GET INDEX
	MOVE T1,HOSTNN(T4)		;GET THE HOST NUMBER
	CALL CVOHST			;CONVERT TO OLD FORMAT
	MOVE T3,HSTSTS(T4)		;GET HOST STATUS
	ANDI T3,777000			;GET THE RIGHT BITS
	IORI T1,(T3)			;BUILD LH
	SKIPGE HOSTN(T2)		;NICKNAME?
	 TXO T1,HS%NCK
	MOVSI T1,(T1)
	LOAD T3,HSTNMP,(T2)		;GET THE NAME POINTER
	HRRI T1,(T3)
	RET
;ROUTINE TO PRODUCE THE OLD NETAWD TABLE

GNTAWD::LOAD T1,ANFHS,(T2)		;GET THE HOST NUMBER
	CALL CVOHST			;CONVERT TO OLD FORMAT
	MOVSI T1,(T1)			;HOST NUMBER TO LH
	MOVE T3,NETAWD(T2)		;GET REST OF WORD
	TLZ T3,777			;CLEAR OUT SLOT FOR HOST
	IOR T1,T3			;PUT IT TOGETHER
	RET

;ROUTINE TO PRODUCE OLD IMPHRT GETAB TABLE.

GTBHRT::SAVEQ			;NEED SOME ACS
	HRRZ UNIT,T2		;GET INDEX
	IMULI UNIT,^D36		;CONVERT TO 1ST HOST NUMBER
	HRLI UNIT,-^D36		;LOOP COUNTER
	SETO IOS,		;SET TO ALL UP

GTBHR1:	ROT IOS,1		;MAKE ROOM FOR NEXT BIT
	HRRZ T1,UNIT		;GET NEXT HOST NUMBER
	CAIL T1,400		;OUT OF RANGE
	 JRST GTBHR2
	CALL CVNHST		;CONVERT TO NEW FORMAT
	CALL HSTHSH		;LOOKUP HOST INDEX
	 TRNA			;NOT THERE SO NOT UP
	SKIPL HSTSTS(T2)	;UP?
GTBHR2:	 TXZ IOS,1		;NO, CLEAR BIT
	AOBJN UNIT,GTBHR1	;LOOP FOR ALL 36 HOSTS IN THIS WORD
	MOVE T1,IOS		;RETURN WORD FOR GETAB
	RET

;ROUTINE TO PRODUCE OLD HSTSTS GETAB TABLE.

GTBHSS::SAVEQ			;NEED WORK SPACE
	HRRZ IOS,T2		;GET INDEX
	LSH IOS,1		;TURN INTO HOST NUMBER
	MOVE T1,IOS		;HOST N
	CALL GTBHSH		;GET RIGHT STATUS
	HLLZ UNIT,T1		;RESULT FOR HOST N IN LEFT HALF
	AOS T1,IOS		;HOST N+1
	CALL GTBHSH		;GET RIGHT STATUS
	HLR UNIT,T1		;RESULT FOR HOST N+1 IN RIGHT HALF
	MOVE T1,UNIT		;RETURN WORD FOR GETAB
	RET

GTBHSH:	CALL CVNHST		;CONVERT TO NEW FORMAT
	CALL HSTHSH		;LOOKUP HOST INDEX
	 JRST RFALSE		;NO SUCH HOST, RETURN 0
	SKIPL T1,HSTSTS(T2)	;UP?
	 TXOA T1,<1B0+1B1>	;SET VALID AND DEAD BITS
	MOVX T1,<1B0>		;OTHERWISE JUST SET VALID
	RET
;GTNCP RETURNS A TABLE OF DATA FOR AN NCP CONNECTION

.GTNCP::MCENT
	SKIPL T1			;CHECK RANGE OF FUNCTION
	 CAIL T1,GTNMAX
	  RETERR (ARGX02)		;BAD FUNCTION NUMBER
	XCT GTNDSP(T1)			;DO FUNCTION
GTNCPX:	SKIPL UNIT			;GET THE INDEX
	 CAIL UNIT,NSKT
	  RETERR (GTJIX1)		;BAD INDEX
	UMOVE T3,3			;GET AC3 AND AC4 FROM USER
	UMOVE T4,4
GTNCPL:	HRRZ T1,T4			;OUT OF THINGS?
	CAIL T1,NCPLEN
	 JRST GTNCLX			;YES
	XCT NCPTAB(T1)			;LOAD DATA WORD
	UMOVEM T1,(T3)			;RETURN TO USER
	AOJ T3,
	AOBJN T4,GTNCPL			;LOOP
GTNCLX:	UMOVEM T4,4			;UPDATE COUNTER
	JRST SKMRTN

NCPTAB:	MOVE T1,UNIT			;(00)NCP UNIT
	LOAD T1,ANFHS,(UNIT)		;(01)FOREIGN HOST
	MOVE T1,LSKT(UNIT)		;(02)LOCAL SOCKET
	MOVE T1,FSKT(UNIT)		;(03)FOREIGN SOCKET
	LOAD T1,ANFSM,(UNIT)		;(04)FINITE STATE
	LOAD T1,ANLNK,(UNIT)		;(05)LINK
	CALL [	HRRZ T1,NETBUF(UNIT)	;(06)RETURN NVT IF
		CAIGE T1,1000		;THERE IS ONE
		 JUMPN T1,R
		JRST RTRUE]
	LOAD T1,ANBSIZ,(UNIT)		;(07)BYTE SIZE OF CONNECTION
	CALL [	LOAD T1,LTIDX,(UNIT)	;(10)MSG ALLOC
		HRRZ T1,IMPLT4(T1)
		RET]
	MOVE T1,NETBAL(UNIT)		;(11)BIT ALLOC
	MOVE T1,NETDAL(UNIT)		;(12)DESIRED ALLOC
	MOVE T1,NETBTC(UNIT)		;(13)BITS XFERRED
	HLRZ T1,NETBUF(UNIT)		;(14)BYTES/BUFFER
	LOAD T1,ANCLKS,(UNIT)		;(15)TIMEOUT
	MOVE T1,NETSTS(UNIT)		;(16)STATUS OF CONN
NCPLEN==.-NCPTAB
GTNDSP:	JRST GTNSIZ			;(00)GET TABLE SIZE
	HRRZ UNIT,T2			;(01)INDEX GIVEN
	JRST GTNNVI			;(02)INPUT NVT
	JRST GTNNVO			;(03)OUTPUT NVT
	JRST GTNJFN			;(04)JFN
GTNMAX==.-GTNDSP			;NUMBER OF FUNCTIONS

GTNSIZ:	MOVSI T2,-NSKT			;-LENGTH,,1ST INDEX
	UMOVEM T2,2			;RETURN TO USER
	MOVE T3,NVTPTR			;-# NVTS,,1ST NVT
	UMOVEM T3,3
	JRST SKMRTN			;DONE

GTNJFN:	MOVE JFN,T2			;CHECK THE JFN
	CALL CHKJFN
	 RETERR (GTNCX1)
	 RETERR (GTNCX1)
	 RETERR (GTNCX1)
	HLRZ UNIT,FILSKT(JFN)		;GET THE UNIT
	CALL UNLCKF
	CAIE PTR,NETDTB			;MAKE SURE IS NET:
	 RETERR (GTNCX1)
	JRST GTNCPX			;REJOIN MAIN CODE

GTNNVI:	SKIPA UNIT,[NVTIPU]		;GET INPUT UNIT
GTNNVO:	MOVEI UNIT,NVTOPU		;USE OUTPUT UNIT
	CAIN T2,.CTTRM			;WANT CONTROLLING TTY?
	 MOVE T2,CTRLTT			;YES
	ANDI T2,377777			;CLEAR 400000
	CALL NVTCHK
	 RETERR (GTNCX2)		;BAD NVT
	CALL (UNIT)			;CALL ROUTINE
	 SETO UNIT,			;CATCH ERROR AS BAD UNIT
	CALL ULKTTY			;UNLOCK TTY DATA BASE
	JRST GTNCPX			;REJOIN MAIN CODE
;GET INFOMATION ABOUT HOSTS

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

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

GTHDSP:	JRST GTHSIZ			;(00)GET NAME TABLE SIZE
	JRST GTHIDX			;(01)INDEX INTO NAME SPACE
	JRST GTHNUM			;(02)CONVERT NUMBER TO STRING
	JRST GTHSTR			;(03)CONVERT STRING TO NUMBER
	JRST GTHHNN			;(04)STATUS BY NUMBER
	JRST GTHHNI			;(05)STATUS BY INDEX
GTHMAX==.-GTHDSP			;NUMBER OF FUNCTIONS

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

GTHIDX:	MOVN T1,MHOSTS			;GET NUMBER OF HOST NAMES IN USE
	HRRZ HN,T3			;CHECK RANGE OF HOST NAME INDEX
	CAML HN,T1
	 RETERR (GTJIX1)		;BAD INDEX TO HOSTN
	LOAD DEV,HSTIDX,(HN)		;GET INDEX INTO HOSTNN
	JRST GTHTUS			;WRITE THE STRING

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

GTHTUS:	LOAD PTR,HSTNMP,(HN)		;GET THE NAME POINTER
	MOVEI PTR,HSTNAM(PTR)		;POINT TO NAME
	HRLI PTR,(<POINT 7,0>)
	CALL GTHSOU			;WRITE STRING
	JRST GTHSXX			;EXIT

GTHNTS:	CALL CVNHST			;MAKE IT NEW FORMAT
	CALL HSTHSH			;GET ITS INDEX
	 RET				;NOT THERE
	HRRZ DEV,T2			;INDEX TO DEV
	HRLZ T2,MHOSTS			;SCAN TABLE FOR THIS INDEX
GTHSLP:	LOAD T3,HSTIDX,(T2)		;GET INDEX
	CAMN T3,DEV			;THE SAME?
	 JRST [	HRRZ HN,T2		;GET NAME INDEX
		RET]
	AOBJN T2,GTHSLP			;LOOP
	RET				;ONLY NUMBER FOUND

GTHSTR:	CALL GTHSTN			;CONVERT STRING TO NUMBER	
	SKIPGE T2			;VAILD STRING FOUND?
	 HRRZ HN,T2			;SAVE POINTER TO HOSTN
	MOVE T1,T4			;GET INDEX TO HOSTNN
	CALL CVNHST
	CALL HSTHSH
	 RETERR(GTHSX2)
	HRRZ DEV,T2
	JRST GTHSXX			;EXIT

GTHSTN:	STKVAR <<GTHSBF,10>>
	MOVEI PTR,GTHSBF		;MAKE BYTE POINTER
	HRLI PTR,(<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
	 RETERR (GTJIX1)		;BAD INDEX
	SKIPA T1,HOSTNN(T1)		;GET THE NUMBER

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

GTHSIN:	UMOVE T1,2		; GET POINTER
	MOVE JFN,[XCTBU [ILDB T2,T1]]
	TLNN T1,777777		; IF JFN DO THE JSYS
	 MOVE JFN,[BIN]
	TLC T1,777777		; CHECK FOR LH -1
	TLCN T1,777777
	 HRLI T1,(<POINT 7,0>)	; USE STANDARD POINTER
	MOVEI STS,MAXLC		; UP TO 39 CHARS
GTHSIL:	XCT JFN			; DO RIGHT OPERATION
	SOSG STS
	 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
	IDPB T2,PTR
	JUMPG T2,GTHSIL
	BKJFN
	 JFCL
	UMOVEM T1,2
	RET

GTHSOU:	UMOVE T1,2		; GET POINTER
	MOVE JFN,[XCTBU [IDPB T2,T1]]
	TLNN T1,777777		; IF JFN DO THE JSYS
	 MOVE JFN,[BOUT]
	TLC T1,777777		; CHECK FOR LH -1
	TLCN T1,777777
	 HRLI T1,(<POINT 7,0>)	; USE STANDARD POINTER
GTHSOL:	ILDB T2,PTR
	XCT JFN			; DO RIGHT OPERATION
	JUMPG T2,GTHSOL		; END ON NULL
	BKJFN
	 JFCL
	UMOVEM T1,2
	RET
; Flush host

.FLHST::MCENT
	MOVEI T2,SC%WHL!SC%OPR
	TDNN T2,CAPENB
	 ITERR (WHELX1)
	CALL CVNHST		;CONVERT HOST NUMBER
	CALL HSTDED
	CALL IMSRST
	JRST MRETN

; Convert host number to string

.CVHST::MCENT
	SETOB HN,DEV		;NO NAME YET
	MOVE T1,T2		;GET HOST NUMBER IN RIGHT PLACE
	CALL GTHNTS		;CONVERT NUMBER TO STRING
	JUMPL HN,[EMRETN(CVHST1)] ;STRING NOT FOUND
	LOAD T1,HSTNMP,(HN)
	MOVEI T1,HSTNAM-1(T1)
	CALL JFNSS
	JRST SKMRTN

; Set local host number routine. Takes old or new style number.
; Sets to new style, and puts it in NLHOST.

STHSTJ::MOVE T1,T2		; To right AC
	CALL CVNHST		; Put T1 into new host format
	MOVEM T1,NLHOST		; Store it
	CALL CVOHST		; Set the old format number too
	MOVEM T1,NOHOST
	RET

; Get net status

NETGST:	HLRZ UNIT,FILSKT(JFN)
	LOAD T1,ANFHS,(UNIT)
	CALL CVOHST		; Convert to old host format
	UMOVEM T1,3
	HLLZ T1,NETSTS(UNIT)
	MOVE T2,FSKT(UNIT)
	UMOVEM T2,4

; Set net status

NETSST:	RET

; ASSIGN BUFFERS IN NETWORK AREA

	RESCD

ASNTBF::MOVE T1,FORKX		; IS THIS THE NCP FORK?
	CAMN T1,NCPFRK
	 JRST ASNTB3		; YES, GIVE HIM BUFFER IF WE CAN
	MOVE T1,NETFRE+2	; NO, GIVE BUFFER ONLY IF ABOVE ASNTHR
	CAMG T1,ASNTHR
	 RET			; REFUSE REQUEST -- NOT ENOUGH SPACE

ASNTB3:	CAMLE T2,MAXWPM		; BE SURE REQUEST NOT LARGER THAN WHAT WE HAVE
	 BUG (NETRBL)
	AOS ASNTBC		; COUNT CALLS
	NOINT
	LOCK NETFRE+1		;LOCK NETWORK BUFFER FREE LIST
	MOVE T1,NETFRE		;GET POINTER TO CURRENT BUFFER
	JUMPE T1,ASNTB2		;THERE ISN'T ONE
	HRL T2,0(T1)		;GET CURRENT SIZE FIELD
	HRRM T2,0(T1)		;STASH REQUESTED SIZE
	HLRZS T2		;MOVE OLD SIZE FIELD TO RH, CLEARING LH
	CAMG T2,MAXWPM		;MAKE SURE ITS NOT IN USE
	 BUG (NETBAU)
	HLRZ T2,0(T1)		;GET POINTER TO NEXT ONE IN LIST
	HRLI T2,ANBSEC		;PUT ON SECTION ADDRESS
	MOVEM T2,NETFRE		;THAT BECOMES FIRST ONE
	AOS 0(P)		;INDICATE SUCCESS
	MOVN T2,MAXWPM		;MAINTAIN TOTAL SPACE AS A MATTER
				;OF INTEREST
	ADDM T2,NETFRE+2
ASNTB2:	UNLOCK NETFRE+1		;UNLOCK FREE LIST
	OKINT
	RET

; RELEASE NETWORK BUFFERS
; (ALL AC'S PRESERVED)

RLNTBF::PUSH P,T1		;SAVE T1
	MOVE T1,NETFRE+3	;GET LOWER BUFFER AREA BOUNDARIES
	CAMGE T2,T1		;RETURNED BUFFER .GE. LOWER BOUND?
	JRST RLNTER		;NO, CRASH
	MOVE T1,NETFRE+4	;GET UPPER BOUND
	CAML T2,T1		;.LT. UPPER BOUND?
RLNTER:	JRST [	BUG (NETRBG)	;REPORT THE PASSING OF BAD ARGUMENTS
		RET]		; AND RETURN WITHOUT RELEASING GARBAGE
	NOINT
	LOCK NETFRE+1		;LOCK FREE LIST
	HRRZ T1,0(T2)		;GET COUNT FIELD
	CAMLE T1,MAXWPM		;MAKE SURE NOT ALREADY ON FREELIST
	BUG (NETBAF)
	MOVE T1,-1(P)		;GET PC OF CALLER
	HRL T1,NETFRE		;GET POINTER TO CURRENT FIRST BUFFER
	MOVEM T2,NETFRE		;RETURNED ONE IS NOW FIRST
	MOVEM T1,0(T2)		;AND POINTS TO OLD FIRST ONE
				;SIZE FIELD IS PC OF CALLER
	MOVE T1,MAXWPM		;MAINTAIN TOTAL SPACE COUNT
	ADDM T1,NETFRE+2
	UNLOCK NETFRE+1		;UNLOCK FREE LIST
	OKINT
	POP P,T1		;RESTORE T1
	RET

	SWAPCD
; The following code and tables PROVIDE a finite state machine
; Implementation of the transitions and actions produced by various
; Events associated with a connection
; Assumed are that unit indexes the proper local socket

; Events are numbered as follows

RRFC==0		; Received an rfc
CLSR==1		; Cls for a receive socket
CLSS==2		; Cls for a send socket
CLZR==3		; Close done on a receive socket
CLZS==4		; Close done on a send socket
ACPT==5		; Program issued an accept
CONN==6		; Program issued a connect
LISN==7		; Program issued a listen
RRFN==10	; Received a rfnm with no more data outstanding
HUNG==11	; Time out event (happens 2 minutes after last dofsm)
RRFB==12	; RECEIVED RFC WITH NON-MATCHING BYTE SIZE

; Actions are numbered as follows

ANOP==0		; No operation
AFNY==1		; No operation (unexpected event)
ACLS==2		; Send cls
ARFC==3		; Send rfc
AOPB==4		; Send rfc and open link
AOPL==5		; Open link
ACLL==6		; Close link
ACLO==7		; Close link and send cls
AEOR==10	; END OF RECEIVE
AEOS==11	; END OF SEND
AES1==12	; END OF SEND WHEN ABORTED BY FOREIGN HOST
AABT==13	; CONNECTION ABORTED BY FAR END
ACKA==14	; CHECK ALLOCATION

; States are numbered as follows

DEAD==0		; Never used
CLZD==1		; Closed
PNDG==2		; Pending. rfc received while closed
LSNG==3		; Listening. listen issued while closed
RFCR==4		; Rfc received while listening
CLW1==5		; Close wait alternate. clzr from opnd
RFCS==6		; Rfc sent
OPND==7		; Opened
CLSW==10	; Waiting for a cls
DATW==11	; Waiting for all data to be sent
RFN1==12	; Waiting for last rfnm
CLZW==13	; Waiting for program close
RFN2==14	; Waiting for rfnm after clss
NUSE==15	; THIS STATE NO LONGER USED
FREE==16	; Not in use
; The following table of byte pointers is used to get to the next state
; Given the current state and the event
; This table is indexed by event, the table addressed by this table
; Is indexed by old state

RADIX ^D10

QQ==3

CBPFSM:	REPEAT 9,<
	POINT 4,NXTSTT(T2),QQ
QQ==QQ+4>
QQ==3
	REPEAT 9,<
	POINT 4,NXTSTT+1(T2),QQ
QQ==QQ+4>

; Following table of pointers is used to get the action to be taken
; Given the current state and the event
; This table is indexed by event, the table addressed by this table
; Is indexed by old state

QQ==3
CBAFSM:	REPEAT 9,<
	POINT 4,ACTION(T2),QQ
QQ==QQ+4>
QQ==3

	REPEAT 9,<
	POINT 4,ACTION+1(T2),QQ
QQ==QQ+4
>

; This is the transition table
; Each word contains the new state for a given old state
; Successive bytes are used for different events

; Event rrfc clsr clss clzr clzs acpt conn lisn rrfe hung rrfb old state

NXTSTT:
BYTE (4)DEAD,DEAD,DEAD,DEAD,DEAD,DEAD,DEAD,DEAD,DEAD,DEAD,DEAD	; Dead
BYTE (4)PNDG,CLZD,CLZD,CLZD,CLZD,CLZD,RFCS,LSNG,CLZD,CLZD,CLZD	; Clzd
BYTE (4)PNDG,FREE,FREE,PNDG,PNDG,PNDG,OPND,RFCR,PNDG,CLW1,PNDG	; Pndg
BYTE (4)RFCR,LSNG,LSNG,FREE,FREE,LSNG,LSNG,LSNG,LSNG,LSNG,CLSW	; Lsng
BYTE (4)RFCR,CLZW,CLZW,CLW1,CLW1,OPND,RFCR,RFCR,RFCR,RFCR,RFCR	; Rfcr
BYTE (4)CLW1,FREE,FREE,CLW1,CLW1,CLW1,CLW1,CLW1,CLW1,FREE,CLW1	; Clw1
BYTE (4)OPND,CLZW,CLZW,CLW1,CLW1,RFCS,RFCS,RFCS,RFCS,CLSW,CLSW	; Rfcs
BYTE (4)OPND,CLZW,RFN2,CLW1,DATW,OPND,OPND,OPND,OPND,OPND,OPND	; Opnd
BYTE (4)CLSW,CLZW,CLZW,CLW1,CLW1,CLSW,CLSW,CLSW,CLSW,CLZW,CLSW	; Clsw
BYTE (4)DATW,DATW,RFN1,DATW,DATW,DATW,DATW,DATW,CLW1,CLW1,DATW	; Datw
BYTE (4)RFN1,RFN1,RFN1,RFN1,RFN1,RFN1,RFN1,RFN1,FREE,FREE,RFN1	; Rfn1
BYTE (4)CLZW,CLZW,CLZW,FREE,FREE,CLZW,CLZW,CLZW,CLZW,CLZW,CLZW	; Clzw
BYTE (4)RFN2,RFN2,RFN2,RFN1,RFN1,RFN2,RFN2,RFN2,CLZW,CLZW,RFN2	; Rfn2
BYTE (4)NUSE,NUSE,NUSE,NUSE,NUSE,NUSE,NUSE,NUSE,NUSE,NUSE,NUSE	; Nuse
BYTE (4)FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE	; Free
; This is the action table
; It is referenced the same as the transition table

; Event rrfc clsr clss clzr clzs acpt conn lisn rrfe hung rrfb old state

ACTION:
BYTE (4)AFNY,AFNY,AFNY,AFNY,AFNY,ANOP,AFNY,AFNY,AFNY,ANOP,AFNY	; Dead
BYTE (4)ANOP,AFNY,AFNY,AFNY,AFNY,ANOP,ARFC,ANOP,AFNY,ANOP,AFNY	; Clzd
BYTE (4)AFNY,ACLS,ACLS,AFNY,AFNY,ANOP,AOPB,ANOP,AFNY,ACLS,AFNY	; Pndg
BYTE (4)ANOP,AFNY,AFNY,ANOP,ANOP,ANOP,AFNY,AFNY,AFNY,ANOP,ACLS	; Lsng
BYTE (4)AFNY,ACLS,ACLS,ACLS,ACLS,AOPB,AFNY,AFNY,AFNY,ANOP,AFNY	; Rfcr
BYTE (4)AFNY,ACLL,ACLL,AFNY,AFNY,ANOP,AFNY,AFNY,AFNY,ACLL,AFNY	; Clw1
BYTE (4)AOPL,ACLS,ACLS,ACLS,ACLS,ANOP,AFNY,AFNY,AFNY,ACLS,ACLS	; Rfcs
BYTE (4)AFNY,AEOR,AES1,ACLS,AEOS,ANOP,AFNY,AFNY,AFNY,ACKA,AFNY	; Opnd
BYTE (4)ANOP,ANOP,ANOP,ANOP,ANOP,ANOP,AFNY,AFNY,AFNY,ANOP,AFNY	; Clsw
BYTE (4)AFNY,AFNY,AES1,AFNY,AFNY,ANOP,AFNY,AFNY,ACLS,ACLS,AFNY	; Datw
BYTE (4)AFNY,AFNY,AFNY,AFNY,AFNY,ANOP,AFNY,AFNY,ACLO,ACLO,AFNY	; Rfn1
BYTE (4)AFNY,AFNY,AFNY,ACLL,ANOP,ANOP,AFNY,AFNY,AFNY,ANOP,AFNY	; Clzw
BYTE (4)AFNY,AFNY,AFNY,ANOP,ANOP,ANOP,AFNY,AFNY,ACLO,ACLO,AFNY	; Rfn2
BYTE (4)AFNY,AFNY,AFNY,AFNY,AFNY,AFNY,AFNY,AFNY,AFNY,AFNY,AFNY	; Nuse
BYTE (4)AFNY,AFNY,AFNY,ANOP,ANOP,AABT,AFNY,AFNY,AFNY,ANOP,AFNY	; Free

;DISPATCH TABLE FOR ACTIONS
;ROUTINES ARE CALLED EFFECTIVELY BY CALL @ACTAB(ACTION#)

ACTAB:	IFIW!R			;NOP
	IFIW!FUNNY		;UNEXPECTED EVENT
	IFIW!SNDCLS		;SEND CLS
	IFIW!SNDRFC		;SEND STR OR RTS
	IFIW!NETOPB		;SNED RFC AND OPEN LINK
	IFIW!NETOPL		;OPEN LINK
	IFIW!NETCLL		;CLOSE LINK
	IFIW!NETCLB		;CLOSE LINK AND SEND CLS
	IFIW!DOEOR		;FINISH UP INPUT
	IFIW!DOEOS		;FINISH UP OUTPUT
	IFIW!DOES1		;END OF SEND IF TRANSMISSION ABORTED
	IFIW!DOABT		;ACCEPT ON ABORTED CONNECTION
	IFIW!CKALL		;ALLOCATIN CHECK FOR OPENED CONN

RADIX 8
;UNEXPECTED EVENT

;	T1/   EVENT 
;	UNIT/ UNIT INDEX

FUNNY:	HLL T1,NETSTS(UNIT)	;GET STATUS
	LOAD T2,ANFHS,(UNIT)	;GET FOREIGN HOST
	BUG(NCPFUN,<<T1,D>,<T2,D>,<UNIT,D>>)
	AOS FUNNYC		;COUNT THEM
	MOVE T1,T2
	SETZ T2,
	JRST NCPERR		;AND SEND TYPE 0 ERR

; ACCEPTED AN ABORTED REQUEST

DOABT:	MOVX IOS,EOTF		; SET FLAG TO CAUSE ERROR
	IORB IOS,NETSTS(UNIT)	; IN STATUS WORD
	RET

; CHECK ALLOCATION

CKALL:	MOVE T1,LSKT(UNIT)
	TRNN T1,1		; SEND SOCKET?
	 RET			; NO. DO NOTHING
	TQNE <ALLFF>		; Allocation failure??
	TQNN <CLZF>		; BEING CLOSED?
	 JRST CKALL1		; NO, IGNORE
	TQO <ERRB,EOTF>		; SIGNAL ERROR, AND STOP TRANSMISSION
	HLLM IOS,NETSTS(UNIT)
	RET

CKALL1:	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	LOAD T2,ANBSIZ,(UNIT)
	CAMG T2,NETBAL(UNIT)	; SUFFICIENT BIT ALLOCATION?
	SKIPN IMPLT4(T1)	; AND MESSAGE SPACE?
	 JRST CKALL2		; NO
	TQZ <ALLFF>
	HLLM IOS,NETSTS(UNIT)
	RET

CKALL2:	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	CALL IMPSYN		; RESYNC ALLOCATION
	MOVX IOS,ALLFF
	IORB IOS,NETSTS(UNIT)	; REMEMBER WE DID THIS ONCE
	RET
; END OF SEND

DOES1:	CALL DOEOS
	CALLRET IMPABL		; FLUSH QUEUED MESSAGES

DOEOS:	MOVX IOS,EOTF
	IORB IOS,NETSTS(UNIT)
	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	CALLRET IMPSDB		; SET DONE BIT IN LINK TABLE

; End of receive

DOEOR:	CALL SNDCLS
	HRRZ T2,NETBUF(UNIT)
	JUMPE T2,DOEOS
	CAIL T2,1000
	JRST DOEOS
	CALL DOEOS		; DO SAME AS END OF SEND
	NCPON			; NCP BACK ON SO NVTDET CAN USE IT
EORNV0:	HRRZ T2,NETBUF(UNIT)	; PICK UP LINE NUMBER
	JUMPE T2,EORNV1		;ALREADY GONE
	PUSH P,UNIT
	CALL LCKDVL		;LOCK DEVICE LOCK, GO NOINT
	CALL NVTDET
	 JRST EORNV2		;FAILURE
EORNV3:	UNLOCK DEVLCK		;UNLOCK THE DEVICE LOCK
	OKINT			;DEVLCK WENT NOINT
	POP P,UNIT
EORNV1:	NCPOFF			; BACK OFF SO CALLER IS NOT CONFUSED
	RET

EORNV2:	TXZN T1,1B0		;WAIT OR ERROR?
	JRST [	BUG (NETDET,<<T1,D>>)
		JRST EORNV3]	;GO CLEAN UP
	UNLOCK DEVLCK		;UNLOCK THE DEVICE LOCK
	OKINT			;DEVLCK WENT NOINT
	POP P,UNIT
	HRL T1,NETBUF(UNIT)	;GET TTY NUMBER
	MDISMS			;WAIT UNTIL DEALLOCATE IS POSSIBLE
	JRST EORNV0		;GO TRY AGAIN

; Close link

NETCLL:	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	CALLRET IMPCLL

NETCLB:	CALL NETCLL
SNDCLS:	LOAD T1,ANFHS,(UNIT)	; Get foreign host
	MOVE T2,LSKT(UNIT)	; And local socket
	MOVE T3,FSKT(UNIT)	; And foreign socket
	TQNN <DEDF>
	 CALL IMPCLS		; Send the control message
	RET
; OPEN LINK

NETOPL:	LOAD T1,ANFHS,(UNIT)
	LOAD T2,ANLNK,(UNIT)
	LOAD T3,ANBSIZ,(UNIT)
	MOVE T4,LSKT(UNIT)
	TRNE T4,1		; Send socket?
	 JRST NETOPS		; Yes, open send link
	CALL IMPOPL		; No, open a receive link
	SKIPA
NETOPS:	CALL IMPOPS		; Open a send link
	STOR T1,LTIDX,(UNIT)	; Keep the link index
	RET

; Send rfc and open link

NETOPB:	CALL NETOPL

; Send rfc

SNDRFC:	TQNE <DEDF>
	 RET
	LOAD T1,ANFHS,(UNIT)	; Get foreign host
	MOVE T2,LSKT(UNIT)	; And local socket
	MOVE T3,FSKT(UNIT)
	LOAD T4,ANBSIZ,(UNIT)	; Byte size
	TRNE T2,1
	JRST IMPSTR
	LOAD T4,ANLNK,(UNIT)
	JRST IMPRTS		; Send control message
; This here is the main fsm routine

DOFSM:	MOVE IOS,NETSTS(UNIT)
	TQNN <DEDF>
	 JRST DOFSMA
	CALL DOFSMA
	LOAD T1,ANFSM,(UNIT)
DOFSMB:	PUSH P,T1
	MOVEI T1,HUNG
	CALL DOFSMA
	LOAD T1,ANFSM,(UNIT)
	POP P,T2
	CAME T1,T2
	 JRST DOFSMB
	RET

DOFSMA:	NCPOFF			; Allow no control messages while here
	MOVEI T2,^D24		; Time out in 2 minutes
	STOR T2,ANCLKS,(UNIT)
	LOAD T2,ANFSM,(UNIT)	; Get old state
	MOVE T4,T2		; Save old state
	LSH T2,1		; Two words per old state
	LDB T3,CBPFSM(T1)	; Get new state
	STOR T3,ANFSM,(UNIT)
	LDB T2,CBAFSM(T1)	; Get action
	CAME T3,T4		; State changed?
	 CALL STCPSI		; GENERATE STATE CHANGE PSI
	CALL @ACTAB(T2)		; Call action routine
	NCPON
	RET

; Generate state change PSI

STCPSI:	SAVET
	LOAD T1,ANPVST,(UNIT)	; Save previous 4 states
	LSH T1,4
	IOR T1,T4
	STOR T1,ANPVST,(UNIT)	; Save previous state
	HRRE T1,NETFRK(UNIT)
	JUMPL T1,R		; No fork for interrupts
	LOAD T2,ANFSPI,(UNIT)	; Get psi channel
	CAIL T2,^D36
	 RET
	EXCH T1,T2
	CALLRET PSIRQ
; Make a socket or find existing one

GETSKT:	TDZA T4,T4
MAKSKT:	SETO T4,
	PUSH P,T4
	PUSH P,T1		; Save foreign host
	PUSH P,T2		; Save foreign socket
	PUSH P,T3		; Save local socket
	MOVE UNIT,T3
	XOR UNIT,T2
	TRNN UNIT,1		; Homosexual?
	JRST MAKSKX		; Yes, go tell Anita
	ROT T3,-4
	MOVS UNIT,T3
	IMULI T3,123431
	XOR UNIT,T3		; Randomize from local socket
	LSH UNIT,-1
	MULI UNIT,NSKT		; Initial probe
	MOVEI T4,NSKT
	SETO T3,
	NCPOFF
MAKSKL:	LOAD T1,ANFSM,(UNIT)	; Get state of this socket
	CAIE T1,FREE
	CAIN T1,DEAD
	JRST MAKSK1
	CAIN T1,CLZW		; WAITING FOR USER TO CLOSE?
	JRST MAKSKN		; YES. DON'T PICK THIS ONE
	MOVE T2,LSKT(UNIT)	; What local socket is this for?
	CAME T2,(P)
	JRST MAKSKN		; Not the one we're after, try next
	SKIPGE -2(P)
	JRST MAKSK6
	LOAD T2,ANFHS,(UNIT)
	MOVE T1,FSKT(UNIT)
	JUMPL T2,[SKIPN -3(P)	; Was getskt called?
		JRST MAKSKN	; Yes, getskt called
		POP P,T3	; Makskt...suceed
		JRST MAKSKF]
	CAMN T2,-2(P)
	CAME T1,-1(P)
	 JRST MAKSKN		; Foreign host or socket doesn't match
	AOS -4(P)		; EVERYTHING MATCHES. SKIP RETURN
	NCPON
	JRST MAKSKV		; NCPON, POP STACK


MAKSK6:	POP P,T3
	SUB P,BHC+3
	MOVE T2,FSKT(UNIT)
	LOAD T1,ANFHS,(UNIT)
	NCPON
	RETSKP

MAKSKN:	SOJLE T4,MAKSKE		; Full, error
	SOJGE UNIT,MAKSKL	; Loop back for next slot
	MOVEI UNIT,NSKT-1
	JRST MAKSKL
MAKSK1:	SKIPGE T3
	MOVE T3,UNIT		; Save where it's at
	CAIE T1,DEAD
	JRST MAKSKN		; Space keeper, test next
MAKSK5:	SKIPN -3(P)
	JRST MAKSKR
	MOVE UNIT,T3
	SETZM NETHST(UNIT)
	SETZM NETSTS(UNIT)
	SETZM NETBUF(UNIT)
	SETZM NETAWD(UNIT)
	SETZM NETBAL(UNIT)
	SETZM NETBTC(UNIT)
	SETOM NETFRK(UNIT)
	MOVEI T1,CLZD
	STOR T1,ANFSM,(UNIT)	; Set its state to be closed
	POP P,T3
	MOVEM T3,LSKT(UNIT)
MAKSKF:	MOVE T1,-1(P)		; Foreign host
	MOVE T2,LSKT(UNIT)
	TRNE T2,1		; Receive?
	 JRST MAKSKQ
	CALL ASNLNK		; Assign link for that host
	 JRST [	LOAD T1,ANFSM,(UNIT)
		MOVEI T2,FREE
		CAIN T1,CLZD	; Just created?
		STOR T2,ANFSM,(UNIT) ; Yes, delete it
		PUSH P,LSKT(UNIT)
		JRST MAKSKR]	; And fail
MAKSKQ:	POP P,T2		; Common for old and new
	MOVEM T2,FSKT(UNIT)
	POP P,T1
	STOR T1,ANFHS,(UNIT)
	SUB P,BHC+1
	NCPON
	RETSKP

MAKSKE:	JUMPGE T3,MAKSK5
	TDZA T1,T1		; FULL
MAKSKR:	MOVEI T1,4		; NON-EXISTENT
	NCPON
	SKIPA			; RETURN 0 OR FOUR ERROR CODE
MAKSKX:	MOVEI T1,3		; BAD PARAMETERS
	MOVEM T1,-1(P)		; STORE ERROR CODE
MAKSKV:	POP P,T3
	POP P,T2
	POP P,T1
	SUB P,BHC+1
	RET
; Assign link number for this connection

ASNLNK:	SAVET
	MOVEI T4,1(P)		; Where bits will be
	PUSH P,[<1B<FLINK>-1>_1+1]
	REPEAT NLNKBW-2,<PUSH P,[-1]>
	PUSH P,[-<1B<LLINK-<^D36*<NLNKBW-1>>>>]
	PUSH P,UNIT		; Preserve unit
	PUSH P,T1
	MOVSI UNIT,-NSKT
ASNLNL:	LOAD T1,ANFSM,(UNIT)
	CAIE T1,FREE
	CAIN T1,DEAD
	 JRST ASNLNN
	LOAD T1,ANFHS,(UNIT)
	CAME T1,0(P)		; Check all connection to this host
	 JRST ASNLNN		; Get next
	MOVE T1,LSKT(UNIT)
	TRNE T1,1		; Only receive connections
	 JRST ASNLNN
	LOAD T1,ANLNK,(UNIT)	; Get link assigned
	IDIVI T1,^D36		; Separate word and bit
	MOVE T2,BITS(T2)	; Get the bit
	ADD T1,T4
	ANDCAM T2,0(T1)		; Clear bits for links in use
ASNLNN:	AOBJN UNIT,ASNLNL	; Loop thru all connections
	HRLI T4,-NLNKBW		; Prepare to look at all bits
	SETZ T3,
ASNLNC:	MOVE T1,0(T4)
	JFFO T1,ASNLNF
	ADDI T3,^D36
	AOBJN T4,ASNLNC
	RET

ASNLNF:	ADD T2,T3
	POP P,T1
	POP P,UNIT
	STOR T2,ANLNK,(UNIT)
	SUB P,BHC+NLNKBW
	RETSKP
; Do a listen (openf for file with no foreign host/socket)

LISTEN:	CALL HSTCHK
	RET
	PUSH P,T4		; Save byte size
	CALL MAKSKT		; Make a socket
	 JRST [	POP P,T4
		MOVEI T1,OPNX10
		RET]		; No room
	MOVEI T1,LISN
	JRST CONNE1

; Do a connect (openf for file with foreign host/socket specified)

CONNEC:	CALL HSTCHK
	RET
	PUSH P,T4		; Save byte size
	CALL MAKSKT		; Make a socket or find existing one
	 JRST [	POP P,T4
		MOVEI T1,OPNX10
		RET]		; No room
	MOVEI T1,CONN
CONNE1:	NCPOFF
	LOAD T2,ANFSM,(UNIT)
	CAIN T2,CLZD		; Received any rfc here?
	 JRST CONNE2		; No
	CAIN T2,PNDG		; Same question
	 JRST CONNE3		; Yes
	MOVEI T1,OPNX9		; Already in use
	POP P,T4
	NCPON
	RET

CONNE2:	MOVX T4,PROGF
	IORM T4,NETSTS(UNIT)	; Mark as attached to program
	NCPON
	POP P,T4		; My choice of byte size
	STOR T4,ANBSIZ,(UNIT)	; Set byte size
	CALL DOFSM		; Send rfc etc
	RETSKP

CONNE3:	TRNE T3,1		; Are we sender?
	 JRST CONNE2		; Also our choice
	LOAD T4,ANBSIZ,(UNIT)	; Get his byte size
	CAMN T4,0(P)		; Does byte size agree?
	 JRST CONNE2		; Yes, same as if my choice
	NCPON
	MOVEI T1,HUNG		; Flush his connection attempt
	CALL DOFSM
	POP P,T4
	MOVEI T1,OPNX22		; Bad byte size error
	RET
; Check if host is available

HSTCHK:	SKIPL IMPRDY
	 JRST [	MOVEI T1,OPNX19
		RET]
	JUMPL T1,RSKP		; ALWAYS OK IF LISTEN
	CALL HSTCK0		; CHECK THE HOST
	 JRST [	MOVEI T1,OPNX20	; NO RESPONSE
		RET]
	JRST RSKP		; UP AND READY

HSTCK0:	SAVET
	LDB T2,[POINT 8,T1,19]
	CAIL T2,FKHOST
	 RET
	CALL HSTHSH		; Get the host index
	 JRST RSKP		; No room, try anyway
	SKIPGE HSTSTS(T2)	; Up?
	 RETSKP			; Yes
	PUSH P,T2
	CALL IMSRST		; Reset him
	POP P,T2
	MOVEI T3,^D10		; Wait 5 sec
HSTCK1:	MOVEI T1,^D500		; Wait
	DISMS
	SKIPGE HSTSTS(T2)	; Up?
	 RETSKP
	SOJG T3,HSTCK1
	RET
; Routines to call when control messages are received

; Receive cls
; Reccls(fhost,fskt,lskt)--nil

RECCLS::CALL GETSKT		; Get the socket entry
	 JRST NCPERR
RECCL1:	MOVE T2,LSKT(UNIT)
	TRNN T2,1
	SKIPA T1,[CLSR]
	MOVEI T1,CLSS
	CALLRET DOFSM

; RECEIVED INCORRECT MESSAGE
; REPLY WITH ERR

NCPERR:	SAVET
	SAVEQ
	MOVE T3,I8COP		; GET LAST OP CODE
	MOVE HN,[I8CAL,,T4]	; COMPLAIN ABOUT LAST CONTROL MESSAGE
	BLT HN,HN
	CALLRET IMPERR

; Receive str
; Recstr(fhost,fskt,lskt)--nil

RECSTR::PUSH P,T4		; Save byte size
RCSTR0:	CALL MAKSKT
	 JRST [	POP P,T4
		JRST NCPERR]
	MOVE T4,0(P)
	CALL CHKSKT		; MAKE SURE THIS SOCKET NOT IN USE
	 JRST RCSTR0		; IT WAS. DELETED. NOW TRY AGAIN.
	LOAD T1,ANFSM,(UNIT)	; What is state of this connection
	CAIE T1,CLZD		; If not clzd
	 JRST [	LOAD T4,ANBSIZ,(UNIT) ; Then get user's byte size
		CAMN T4,0(P)	; If not the same
		JRST .+1
		MOVEI T1,RRFB	; RECEIVED BAD BYTE SIZE
		CALL DOFSM
		MOVX T1,ERRB
		IORM T1,NETSTS(UNIT)
		POP P,T4
		RET]
	POP P,T4
	STOR T4,ANBSIZ,(UNIT)
	MOVEI T1,RRFC
	CALL DOFSM
	MOVE T1,UNIT
	LOAD T2,ANLNK,(UNIT)
	RET

CHKSKT:	SAVET
	LOAD T1,ANFSM,(UNIT)	; GET STATE
	CAIE T1,RFCS		; STATES WHERE RFC IS EXPECTED
	CAIN T1,CLZD
	 RETSKP
	CAIN T1,LSNG
	 RETSKP
	CALLRET SK2DWN		; KILL THE OLD ONE

CHKLNK:	SAVET
	STKVAR<CHKLLK,CHKLHS>
	MOVEM T1,CHKLHS
	MOVEM T4,CHKLLK
	MOVSI UNIT,-NSKT
CHKLK1:	LOAD T2,ANLNK,(UNIT)	; GET THE LINK
	LOAD T3,ANFHS,(UNIT)	; AND HOST
	CAMN T2,CHKLLK
	CAME T3,CHKLHS
	 JRST CHKLK2
	MOVE T2,LSKT(UNIT)
	TRNN T2,1
	 JRST CHKLK2		; SKIP SEND CONNECTIONS
	LOAD T2,ANFSM,(UNIT)	; LINK-HOST MATCHES. GET STATE
	CAIE T2,DEAD
	CAIN T2,FREE
	 JRST CHKLK2
	CAIE T2,CLZD
	CAIN T2,RFCS
	 JRST CHKLK2
	CAIE T2,LSNG
	CAIN T2,CLZW
	 JRST CHKLK2
	CALL SK2DWN
CHKLK2:	AOBJN UNIT,CHKLK1
	RET
; Receive rts
; Recrts(fhost,fskt,lskt,link)

RECRTS::CALL CHKLNK		; CHECK AND DELETE ANY MATCHING LINKS
	PUSH P,T4		; SAVE LINK
	CALL MAKSKT		; MAKE SOCKET TABLE ENTRY
	 JRST [	POP P,T4	; FAILED, SEND ERR
		JRST NCPERR]
	POP P,T4		; RESTORE LINK
	CALL CHKSKT		; MAKE SURE NO DUPLICATES
	 JRST RECRTS		; PREVIOUS CONNECTION CLOSED. TRY AGAIN
	STOR T4,ANLNK,(UNIT)
	MOVEI T1,RRFC
	CALLRET DOFSM

; Receive rfnm

RCFRFN::MOVEI T1,RRFN
	CALLRET DOFSM

; Receive ins/inr

RECINR::
RECINS::LOAD T2,ANINPI,(UNIT)
	LOAD T1,ANFSM,(UNIT)
	CAIGE T2,^D36		; RETURN IF CHANNEL IS 77 OCTAL
	CAIE T1,OPND
	 RET
	HRRZ T1,NETBUF(UNIT)
	SKIPE T1
	CAIL T1,1000
	CAIA
	 RET
	HRRE T1,NETFRK(UNIT)
	JUMPL T1,R
	EXCH T1,T2
	CALLRET PSIRQ

; INITIATE SERVICE INTERRUPTION (HOST DEAD)

SVCINT::MOVX IOS,SVCIF
	IORB IOS,NETSTS(UNIT)
	CALLRET STCPSI		; GENERATE STATE CHANGE PSI

; TERMINATE SERVICE INTERRUPTION

SVCRST::MOVX IOS,SVCIF
	ANDCAB IOS,NETSTS(UNIT)
	CALLRET STCPSI
; Receive reset message

RECRST::CALL NETHDN
	JRST IMPRRP

; Kill all connection -- net is down

NETDWN::MOVSI UNIT,-NSKT
	CALL SKTDWN
	AOBJN UNIT,.-1

; Periodic check of all connections for time-out

NETCHK::MOVSI UNIT,-NSKT
NETCKL:	LOAD T1,ANFSM,(UNIT)
	CAIE T1,DEAD
	CAIN T1,FREE
	 JRST NETCKN
	MOVX T1,DEDF
	TDNN T1,NETSTS(UNIT)
	SKIPL IMPRDY
	JRST NETCK1
	LOAD T2,ANCLKS,(UNIT)
	SOS T2
	STOR T2,ANCLKS,(UNIT)
	JUMPG T2,NETCKN
NETCK1:	MOVEI T1,HUNG
	CALL DOFSM
NETCKN:	AOBJN UNIT,NETCKL
	MOVEI T1,^D5000
	SKIPL IMPRDY
	MOVEI T1,^D500
	ADD T1,TODCLK
	MOVEM T1,NETTIM
	RET
; Host has died

NETHDN::MOVSI UNIT,-NSKT
	PUSH P,T1
NETHDL:	LOAD T1,ANFSM,(UNIT)
	CAIE T1,FREE
	CAIN T1,DEAD
	JRST NETHDX
	LOAD T1,ANFHS,(UNIT)
	CAMN T1,(P)
	CALL SKTDWN
NETHDX:	AOBJN UNIT,NETHDL
	POP P,T1
	RET

SK2DWN::HRRZ T2,NETBUF(UNIT)
	CALL NVTCHK		; AN NVT?
	 JRST SKTDWN		; NO, TREAT NORMALLY
	PUSH P,UNIT
	PUSH P,T2
	CALL SKTDWN
	MOVE T2,0(P)
	CALL NVTIPU		;GET INPUT UNIT
	 TRNA			;NO UNITS FOR THIS LINE
	CALL SKTDWN		; CLOSE THE OTHER HALF
	POP P,T2		;GET ADDRESS OF DYNAMIC DATA FOR TTY
	CALL ULKTTY		;UNLOCK DATA BASE
	POP P,UNIT
	RET

SKTDWN:	LOAD T1,ANFSM,(UNIT)	; GET STATE
	CAIN T1,LSNG		; IF LSNG
	 RET			; IGNORE
	MOVX T2,ERRB!DEDF
	IORM T2,NETSTS(UNIT)
	CAIE T1,CLSW		; IF WAITING FOR CLOSE,
	CAIN T1,CLW1
	CALL SKTDW2		; PRETEND ONE HAPPENED.
	CAIE T1,RFCR
	CAIN T1,OPND		; If opnd
SKTDW2:	CALL RECCL1		; Simulate receipt of cls
	MOVEI T1,HUNG
	CALLRET DOFSM
HSTINI::SAVEPQ
	MOVX T1,<GJ%OLD+GJ%SHT>
	HRROI T2,[ASCIZ /SYSTEM:HSTNAM.TXT/]
	GTJFN
	 RET
	MOVE JFN,T1
	MOVE T2,[7B5+OF%RD]
	OPENF
	 JRST [	MOVE T1,JFN
		RLJFN
		TRN
		RET]
	SETZB HN,HSTNAM		; CLEAR OLD STUFF IN TABLE
	MOVSI T4,HSTNAM		; (TELNET FAILS IF THIS ISN'T DONE
	HRRI T4,HSTNAM+1	; AND IT LOOKS NEATER TO HAVE WHOLE
	BLT T4,HSTNAM+NHSTN-1	; WORD OF NULL AFTER EACH NAME)
	MOVSI T4,-NHOSTS	; CLEAR HOST TABLES
HSTCLR:	SETZM HOSTN(T4)
	HLLZS HSTSTS(T4)	; PRESERVE HOST UP BIT
	SKIPGE IMPRDY		; IF NET IS UP
	 JRST HSTCL1
	SETZM HOSTNN(T4)
	SETZM HSTSTS(T4)
HSTCL1:	AOBJN T4,HSTCLR
	SETZ PTR,
LUP0:	MOVE T1,JFN
	CALL GCH
	 JRST DONE
	MOVE UNIT,T3		; SAVE IN CASE THIS IS ALINE
	CAIN T2,.CHLFD
	 JRST LUP0
	CAIGE HN,NHOSTS
	 CAIL PTR,NHSTN
	  JRST FULL
	BKJFN
	 TRN
	RFPTR
	 TRN
	MOVE STS,T2
	MOVEI T3,10
	NIN
	 JRST [	HRLI T4,[ASCIZ /Bad number/]
		MOVE T3,STS
		JRST SYNERR]
	MOVE T1,T2
	CALL CVNHST			;GET NEW FORMAT IF NEEDED
	CALL HSTHSH
	 JUMPL T2,FULL
	MOVE DEV,T2
	MOVEM T1,HOSTNN(DEV)
	STOR DEV,HSTIDX,(HN)
	MOVE T1,JFN
	BKJFN
	 TRN
	CALL GCH
	 JRST PEOF
	CAIE T2,","
	 JRST [	HRLI T4,[ASCIZ /Missing comma after host number/]
		JRST SYNERR]
	MOVEI T4,HSTNAM(PTR)
	HRLI T4,(<POINT 7,0>)
	MOVEI STS,MAXLC		; MAX OF 39 CHAR IN HOST NAME
LUP1:	CALL GCH		; READ NEXT CHARACTER
	 JRST PEOF
	CAIE T2,.CHLFD		; TERMINATE ON END OF LINE
	CAIN T2,","
	 SETZ T2,		; OR COMMA
	IBP T4
	HRRZ T1,T4		; WHERE ARE WE GOING TO PUT THIS?
	CAIL T1,HSTNAM+NHSTN	; OFF END OF TABLE?
	 JRST FULL		; YES, SAY FULL
	DPB T2,T4		; STORE THE BYTE
	SOSLE STS		; DON'T STORE ANYMORE CHARACTERS
	 JUMPN T2,LUP1		; LOOP IF NOT THE END
	MOVE T1,JFN
	BKJFN			; GET THE TERMINATOR AGAIN
	 TRN
	MOVX STS,HS%NAM		; THIS HOST HAS A NAME
LUP2:	CALL GCH
	 JRST PEOF
LUP2A:	CAIN T2,.CHLFD
	 JRST LUP2X		; DONE IF END OF LINE
	CAIE T2,","		; SCAN UNTIL COMMA FOUND
	 JRST LUP2
	CALL GCH		; GET FIRST LETTER OF WORD
	 JRST PEOF
	CAIN T2,","
	 JRST LUP2A		; JUMP IF NULL WORD
	CAIN T2,12
	 JRST LUP2X		; DONE IF END OF LINE
	SETZ T1,		; PUT VALUE OF WORD HERE
	CAIN T2,"A"
	 MOVX T1,.HSANT
	CAIN T2,"D"
	 MOVX T1,.HSDEC
	CAIN T2,"E"
	 MOVX T1,.HSELF
	CAIN T2,"I"
	 MOVX T1,.HSITS
	CAIN T2,"M"
	 JRST [	CALL GCH
		 JRST PEOF
		CAIN T2,"U"
		 MOVX T1,.HSMLT
		CAIN T2,"T"
		 MOVX T1,.HSMTP
		JRST ELUP3]
	CAIN T2,"N"
	 JRST [	CALL GCH
		 JRST PEOF
		CAIN T2,"E"
		 MOVX T1,HS%NEW
		CAIN T2,"I"
		 MOVX T1,HS%NCK		;FLAG AS NICKNAME
		JRST ELUP3]
	CAIN T2,"S"
	 MOVX T1,HS%SRV
	CAIN T2,"T"
	 JRST [	CALL GCH
		 JRST PEOF
		CAIN T2,"E"
		 MOVX T1,.HS10X
		CAIN T2,"I"
		 MOVX T1,.HSTIP
		CAIN T2,"O"
		 MOVX T1,.HST20
		JRST ELUP3]
	CAIN T2,"U"
	 JRST [	CALL GCH
		 JRST PEOF
		CAIN T2,"N"
		 MOVX T1,.HSUNX
		CAIN T2,"S"
		 MOVX T1,HS%USR
		JRST ELUP3]
ELUP3:	HRLI T4,[ASCIZ /Unrecognized flag name/]
	JUMPE T1,SYNERR		; JUMP IF NO MATCH FOUND
	MOVX T2,HS%STY
	HRLI T4,[ASCIZ /Multiple system type specification/]
	TDNE T2,STS		; ALREADY HAVE A SYSTEM TYPE?
	TDNN T2,T1		; YES AND IS THIS TRYING TO SET IT?
	 TRNA
	  JRST SYNERR		; YES. ERROR
	IOR STS,T1		; ACCUMULATE BITS
	JRST LUP2		; AND SKIP TO COMMA/EOL

LUP2X:	STOR PTR,HSTNMP,(HN)	; STORE NAME POINTER
	MOVEI PTR,1-HSTNAM(T4)
	MOVX T4,<1B0>		; NICKNAME FLAG (MUST BE B0)
	TXZE STS,HS%NCK		; A NICKNAME?
	 IORM T4,HOSTN(HN)	; SET FLAGS
	HRRM STS,HSTSTS(DEV)	; STORE STATUS
	AOJA HN,LUP0
PEOF:	MOVE T1,JFN
	RFPTR
	 TRN
	MOVE T3,T2
	HRLI T4,[ASCIZ /Premature end of file/]
SYNERR:	HLRO T1,T4
	PSOUT
	HRROI T1,[ASCIZ / in host descriptor file
/]
	PSOUT
	MOVE T2,UNIT
	MOVE T1,JFN
	SFPTR			; SET BACK TO BEGINNING OF LINE
	 TRN
	SETO UNIT,
PERLP:	MOVE T1,JFN
	RFPTR
	 TRN
	CAME T2,T3
	 JRST PERLP1
	MOVEI T1,.PRIOU
	RFPOS
	HRRZ UNIT,T2
PERLP1:	MOVE T1,JFN
	CALL GCH1
	 MOVEI T2,.CHLFD
	CAIN T2,.CHLFD
	 JRST PERLPX
	MOVE T1,T2
	PBOUT
	JRST PERLP

PERLPX:	HRROI T1,[ASCIZ /
/]
	PSOUT
	JUMPLE UNIT,PMRK
	MOVEI T1," "
	PBOUT
	SOJG UNIT,.-1
PMRK:	MOVEI T1,"^"
	PBOUT
	HRROI T1,[ASCIZ /

/]
	PSOUT
	JRST LUP0

FULL:	HRROI T1,[ASCIZ /Host tables full before end of file
/]
	PSOUT
DONE:	CLOSF
	 TRN
	MOVNM HN,MHOSTS		; SAVE -NUMBER OF HOST NAMES
	CALL SWPMWE		; WRITE ENABLE SWAP MON
	MOVN HN,MHOSTS		; SWPMWE CLOBBERES IT
	HRLM HN,GTTAB+.HOSTN	; LENGTH OF HOSTN TABLE
	HRLM PTR,GTTAB+.HSTNA	; LENGTH OF HSTNAM TABLE
	CALL SWPMWP		; WRITE PROTECT
	RETSKP

GCH:	MOVE T1,JFN
	RFPTR
	 TRN
	MOVE T3,T2
GCH2:	CALL GCH1
	 RET
	CAIN T2,";"
	 JRST GCHSMC
	CAIE T2,.CHTAB
	CAIN T2," "
	 JRST GCH2
	RETSKP

GCH1:	CALL GBIN
	 RET
	CAIE T2,.CHCRT
	CAIN T2,.CHFFD
	 JRST GCH1
	RETSKP

GCHSMC:	CALL GBIN
	 RET
	CAIN T2,.CHLFD
	 RETSKP
	JRST GCHSMC

GBIN:	BIN				;GET A CHAR
	JUMPN T2,RSKP
	GTSTS				;NULL SO CHECK FOR ERR OR EOF
	TXNN T2,<GS%EOF+GS%ERR>
	 JRST GBIN			;FLUSH NULLS
	RET

	TNXEND
	END