Google
 

Trailing-Edge - PDP-10 Archives - BB-4170G-SM - sources/netwrk.mac
There are 6 other files named netwrk.mac in the archive. Click here to see a list.
;<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 <*>
;<4.MONITOR>NETWRK.MAC.1, 29-Nov-77 12:24:13, EDIT BY CROSSLAND
;PREVENT CLOBBERING OF WAIT ROUTINE ADDRESS ON BOUT.
;<3-MONITOR>NETWRK.MAC.22, 20-Nov-77 19:50:49, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.21,  9-Nov-77 09:55:22, EDIT BY KIRSCHEN
;MORE COPYRIGHT UPDATING...
;<3-MONITOR>NETWRK.MAC.20, 19-Oct-77 00:59:37, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.19, 12-Oct-77 14:01:52, EDIT BY KIRSCHEN
;UPDATE COPYRIGHT FOR RELEASE 3
;<3-MONITOR>NETWRK.MAC.18,  6-Oct-77 03:18:01, EDIT BY CROSSLAND
;FIX EXPRESSIONS CONTAINING ANBSEC
;<3-MONITOR>NETWRK.MAC.17,  6-Oct-77 00:27:55, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.16,  1-Sep-77 11:52:02, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.15,  3-Aug-77 23:48:46, EDIT BY CROSSLAND
;MAKE NEW TELNET NVT'S WORK
;<3-MONITOR>NETWRK.MAC.14, 23-Jul-77 22:55:57, EDIT BY CROSSLAND
;MOVE BUFFERS TO ANBSEC SECTION
;<3-MONITOR>NETWRK.MAC.13, 30-Jun-77 20:04:56, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.12, 29-Jun-77 04:20:19, EDIT BY CROSSLAND
;FIX MODEL B ADDRESSING PROBLEMS
;<3-MONITOR>NETWRK.MAC.11, 17-Jun-77 05:36:27, EDIT BY CROSSLAND
;MORE CONVERSION FOR MODEL B
;<3-MONITOR>NETWRK.MAC.10, 11-Jun-77 03:29:02, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.9,  9-Jun-77 04:28:25, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.8,  6-Jun-77 00:48:49, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.7, 21-May-77 23:26:44, EDIT BY BOSACK
;ELIMINATE USE MACRO
;<3-MONITOR>NETWRK.MAC.6, 19-May-77 08:01:14, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.5, 14-May-77 19:26:51, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.4,  8-May-77 18:16:34, EDIT BY CROSSLAND
;<3-MONITOR>NETWRK.MAC.3,  6-May-77 11:56:44, EDIT BY HURLEY
;ADD SET INPUT/OUTPUT AND ATTRIBUTE CHECK ENTRIES IN DISPATCH TABLE
;<3-MONITOR>NETWRK.MAC.2, 27-Apr-77 17:09:26, EDIT BY CROSSLAND
; TCO 1742 MERGE ARPA SOURCES 
;<A-MONITOR>NETWRK.MAC.10, 27-Dec-76 14:41:45, EDIT BY CROSSLAND
;CHANGE ERROR CODES ATPX?? TO ATPNX??
;<A-MONITOR>NETWRK.MAC.9,  3-Dec-76 17:10:38, EDIT BY CLEMENTS
; GIVE FLHST AN ITRAP ERROR IF NO CAPS. RANGE CHECK ITS ARG.
;<A-MONITOR>NETWRK.MAC.8,  1-Dec-76 14:40:53, EDIT BY CLEMENTS
;<A-MONITOR>NETWRK.MAC.7, 23-Nov-76 18:36:34, EDIT BY CLEMENTS
;<134-TENEX>NETWRK.MAC;240     4-NOV-75 12:00:04    EDIT BY ALLEN

;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 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

	SEARCH PROLOG,MACSYM,MONSYM
	TTITLE	NETWRK
	SUBTTL	R.S.Tomlinson

; Macros to turn imp on and off

DEFINE	NCPON<PUSHJ P,ULKNCP>

DEFINE	NCPOFF<PUSHJ P,LCKNCP>

; Local accumulators

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



;PARAMETERS

NLNKBW==<LLINK+^D35>/^D36	;LENGTH OF LINK BITTABLE
;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
EOTF==:EOTF			;MAKE THESE INTERNAL
DEDF==:DEDF			; ..
; Pointers to various fields of a connection

	RESCD


PLINK::	POINT 9,NETAWD(UNIT),8	; Pointer to link number
PFHST::	POINT 9,NETAWD(UNIT),17	; Pointer to foreign host number
PCLKS:	POINT 6,NETAWD(UNIT),23	; Pointer to time-out counter
PINTCH:	POINT 6,NETFRK(UNIT),5	; Pointer to ins/inr psi channel
PFSMCH:	POINT 6,NETFRK(UNIT),17	; Pointer to psi channel for fsm change
PFSM:	POINT 4,NETSTS(UNIT),3	; Pointer to current state of fsm
PBPBYT:	POINT 6,NETSTS(UNIT),17	; Pointer to net bit stream byte size
PBFSIZ:	POINT 18,NETBUF(UNIT),17; Pointer to bytes per buffer

; 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
;	LOCK NCPLCK,<JRST LCKNC1>,SPQ	;SHOULD BE SPECIAL Q IF SUCCEED
	LOCK NCPLCK,<JRST LCKNC1>
LCKNC2:	PUSH P,FORKX
	POP P,NCPLLK		; SAVE LAST LOCKER
	POPJ P,

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

	RESCD

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

	SWAPCD

ULKNCP::
;	UNLOCK NCPLCK,RESIDENT,SPQ
	UNLOCK NCPLCK		;SIMPLER LOCK MACRO FOR TOPS20
	POPJ P,
; Initialize network stuff

NETINI::SE1CAL			;ENTER SECTION 1 FOR THIS ROUTINE
	SETZM NETSTS
	MOVE A,[NETSTS,,NETSTS+1]
	BLT A,NETSTS+NSKT-1
	SETZM NETCNC
	SETZM FUNNYC
	MOVE A,[ANBSEC,,NTBUFS]
	MOVEM A,NETFRE		;INITIAL FREE LIST
	MOVEI B,NNTBFS		;SIZE OF BUFFER AREA
	MOVEM B,NETFRE+2	;FREE SPACE LEFT IN BUFFER AREA
	MOVEM A,NETFRE+3	;START OF BUFFER AREA
	MOVE A,[ANBSEC,,NTBUFS+NNTBFS-1] ;END OF BUFFER AREA
	MOVEM A,NETFRE+4

;INITIALIZE FREE LIST INTO ITEMS OF MAXWPM EACH
	IDIVI B,MAXWPM		;COMPUTE NUMBER OF BUFFERS
	SKIPE C
	BUG (HLT,NETNNI,<NETINI: NNTBFS NOT INTEGRAL MULTIPLE OF MAXWPM>)

	MOVE C,[ANBSEC,,NTBUFS]	;SET UP C TO POINT TO NET BUFFERS
NETIN2:	MOVE A,C		;COPY C INTO A
	ADDI C,MAXWPM		;RH(C) POINTS TO NEXT BUFFER
	HRLOM C,0(A)		;STORE THAT IN LEFT HALF IN CURRENT BUFFER
	SOJG B,NETIN2		;DO ANOTHER
	HRRZS 0(A)		;LAST ITEM POINTER IS 0

	SETOM NETFRE+1		;NETWORK BUFFER LOCK
	SETOM NCPLCK
	MOVE A,DBUGSW		;IN SYSTEM DEBUG MODE?
	CAIGE A,2		;IF SO, DON'T TURN ON NET.
	SETOM NETON		;NET ON
	MOVEI A,MAXWPM		;GET SIZE OF EACH BUFFER
	ASH A,3			;TIMES 8
	MOVEM A,ASNTHR		;SETS BUFFER SPACE LOW THRESHOLD
	POPJ P,

; 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 A,NAMBAD		; *. -- failure
	HRLI A,(<POINT 7,0,35>)	; Make lookup pointer into byte pointer
	PUSHJ P,NAMDEC		; Decode name
	JRST NAMBAD		; Bad syntax
OKRET:	TQNE <UNLKF>
	JRST SK2RET
	OKINT
	JRST SK2RET

NAMBAD:	MOVEI A,GJFX18
	JRST ERRET		; Error return

ERRET:	OKINT
	POPJ P,
; Extension lookup routine

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

EXTBAD:	MOVEI A,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>
	JRST RSKP
	OKINT
	JRST RSKP
; Decode extension string
; Called both at gtjfn and openf to decode extension string into
; Foreign socket number and host number

EXTDEC:	PUSH P,A
	ILDB D,A
	POP P,A
	JUMPE D,[SETOB A,B
		JRST RSKP]
	CAIGE D,"8"
	CAIGE D,"0"
	 JRST EXTDES		; Symbolic
	MOVEI C,10
	NIN
	 POPJ P,
	CAIL B,0
	CAILE B,377
	 POPJ P,
	MOVE D,B
	LDB B,A
	CAIE B,"-"
	 POPJ P,
	NIN
	 POPJ P,
	MOVE A,D
	JRST RSKP

EXTDES:	HRLZ D,MHOSTS		;SCAN ALL HOSTS IN NAME TABLES
EXTDE1:	PUSH P,A
	HRRZ C,HOSTN(D)
	ADD C,[POINT 7,HSTNAM]
	PUSH P,C
EXTDE2:	ILDB B,A
	ILDB C,0(P)
	JUMPE C,EXTDE3
	CAMN C,B
	 JRST EXTDE2
EXTDE4:	ADJSP P,-1
	POP P,A
	AOBJN D,EXTDE1
	POPJ P,

EXTDE3:	CAIE B,"-"
	 JRST EXTDE4		; Not this one
	MOVEI C,10
	NIN			; Convert remainder of string to number
	 JRST EXTDE4		; Must not be this one
	LDB C,A			; Get terminator
	JUMPN C,EXTDE4		; Not this one
	ADJSP P,-2		; This is it, flush stack
	LDB A,[POINT 9,HOSTN(D),17]
	JRST RSKP
; Decode name string
; Called both at gtjfn and openf to decode name string into
; Local socket number

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

NAMDE1:	LDB C,A
	JUMPN C,CPOPJ		; Not number, fail
	MOVE B,JFN		; Default to jfn
	PUSH P,T3		;SAVE T3 OVER DIVIDE
	IDIVI T2,MLJFN		;GET THE JFN
	POP P,T3		;RESTORE T3
	LSH B,1			; Jfn will end up lsh'ed 1
	JRST NAMDE2
; 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 A,SFBSX2
		POPJ P,]	; Bad byte size
	HLRZ A,FILNEN(JFN)
	HRLI A,(<POINT 7,0,35>)
	PUSHJ P,NAMDEC		; Decode name
	JRST ILLACC		; Can only happen if wheel lost
	TQNE <WRTF>
	TROA A,1		; If writing set gender bit for local
	TRZ A,1			; Else clear it
	PUSH P,A		; Save for later
	HRRZ A,FILNEN(JFN)
	HRLI A,(<POINT 7,0,35>)
	PUSHJ P,EXTDEC		; Decode extension
	BUG(HLT,NETIEF,<NETOPN: EXTDEC FAILURE AFTER PREVIOUS NON-FAILURE.>)
	TQNE <READF>
	TROA B,1		; If reading set gender bit for forskt
	TRZ B,1			; Else clear
	POP P,C
	LDB D,PBYTSZ		; Get file byte size
	JUMPL A,OPNLSN		; No foreign socket, do a listen
	PUSHJ P,CONNECT		; Connect
	 POPJ P,
	TQZ <WNDF>
NETOP1:	HRLM UNIT,FILSKT(JFN)	;REMEMBER UNIT NUMBER
	SETZ IOS,		; Clear status bits
	LDB A,[POINT 4,STS,35]
	CAIE A,5		; In modes 5
	CAIN A,7		; Or 7
	TQO <BFSND>		; DO BUFFERED TRANSMISSION
	IORB IOS,NETSTS(UNIT)	; Set it in status word
	MOVEI A,^D36
	LDB B,PBYTSZ
	IDIV A,B		; Get bytes per WORD
	XCTBU [	LDB C,[POINT 6,2,17]] ; GET DESIRED SIZE OF BUFFER
	IMUL A,C		; DESIRED BYTES
	DPB A,PBFSIZ		; 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
	JRST RSKP		; Return immediately
	LDB A,[POINT 4,STS,35]
	CAIE A,6		; Also in modes 6
	CAIN A,7		; And 7
	JRST RSKP		; Return immediately
	LDB A,PFSM		; No. get current state
	CAIN A,RFCS		; Will usually be rfcs
	PUSHJ P,WATNOT		; If so, wait for it to not be
	MOVE IOS,NETSTS(UNIT)	; GET STATE
	LDB A,[POINT 4,IOS,3]
	TQNN <EOTF>		; IF LEFT OPND
	CAIN A,OPND		; OR STILL OPENED
	 JRST RSKP		; THEN SUCCEED
OPNFAI:	MOVX B,PROGF
	ANDCAM B,NETSTS(UNIT)	; Program not watching
	TQNE <ERRB>		; ERRB REMEMBERS BAD BYTE SIZE
	SKIPA A,[OPNX22]	; MAKE THAT THE ERROR CODE
	MOVEI A,OPNX21		; ELSE IT WAS REJECTED
	POPJ P,			; And give bad return

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

ILLACC:	MOVEI A,OPNX14
	POPJ P,
; Wait for fsm to leave state given in a

WATNOT:	HRLI A,NOTTST		; TEST ROUTINE ADDRESS
WATNO1:	MOVE B,UNIT		; COMPUTE SCHEDULER TEST ARGUMENT
	ROT B,-9
	MOVSS A
	IOR A,B
	SKIPE INSKED
	BUG(HLT,NETWNS,<WATNOT: WAS CALLED FROM SCHEDULER LEVEL.>)
	MDISMS
	POPJ P,

; Wait for fsm to enter a particular state

WATFOR:	HRLI A,WATTST
	JRST WATNO1

	RESCD

NOTTST:	LDB B,[POINT 9,A,26]	; EXTRACT UNIT
	ANDI A,777		; AND STATE TO TEST AGAINST
	EXCH UNIT,B
	LDB C,PFSM		; GET CURRENT STA(E
	EXCH UNIT,B
	CAME A,C		; IS IT THE SAME
	JRST 1(4)		; NO, READY TO GO
	JRST WATTS1		; YES, MAKE OTHER TESTS

; SCHEDULER TEST WAITING FOR CONNECTION TO GET TO A STATE

WATTST:	LDB B,[POINT 9,A,26]	; EXTRACT UNIT
	ANDI A,777		; AND STATE
	EXCH B,UNIT
	LDB C,PFSM		; GET CURRENT STATE
	EXCH B,UNIT
	CAMN C,A		; SAME?
	JRST 1(4)		; YES, READY TO GO
WATTS1:	MOVE C,FKINT(7)		; Look for deferred interrupts
	TLNN C,(1B1)
	JRST 0(4)		; None. return no skip
	EXCH B,UNIT		; Deferred interrupt, get back unit
	SETZ C,
	DPB C,PCLKS		; Set clock to zero to hasten time-out
	EXCH B,UNIT
	JRST 0(4)

;SCHEDULER TEST FOR BIT ALLOCATION

;CONNECTION NUMBER IN T1

BALTST:	EXCH UNIT,T1		;GET CONNECTION NUMBER IN UNIT
	LDB T2,PBPBYT		;GET BIT STREAM BYTE SIZE
	LOAD T3,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	SKIPE IMPLT4(T3)	;SKIP IF NEITHER MSG ALLOC OR BUFFER
	CAMLE T2,NETBAL(UNIT)	;MSG OK, HOW ABOUT BITS?
	JRST [	HLL T3,NETSTS(UNIT) ; GET STATUS INFO
		TXNE C,DEDF+EOTF ; ALLOC BAD. BUT IF DEAD..STILL OK
		JRST BALTS1	;OK.  TAKE SKIP RETURN
		JRST BALTS2]	;WAIT SOME MORE
BALTS1:	AOS T4			;TAKE SKIP RETURN
BALTS2:	EXCH UNIT,T1		;RESTORE UNIT
	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
	PUSHJ P,DMPBUF		; Dump last buffer
	 JRST NETCLW		; NOT ALL SENT. GO WAIT.
NETCL1:
   REPEAT 0,<
	TQNE <ERRF>		; ANY FINAL ERRORS
	 JRST [	MOVEI A,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:	TQNN <WRTF>		; IF NOT SENDING
	SKIPA A,[CLZR]		; THEN DO CLZR
	MOVEI A,CLZS		; ELSE do clzs
	PUSHJ P,DOFSM
	UMOVE A,1
	TDNN A,[1,,400000]
	TLNN A,(1B1)
	 JRST NETCL2		; Return immediately if no bit 1
	LDB B,PFSM
	MOVEI A,FREE
	CAIE B,FREE
	PUSHJ P,WATFOR
NETCL2:	MOVX A,PROGF
	ANDCAM A,NETSTS(UNIT)	; No program wants this any more
	JRST RSKP

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

; Close nvt

NVTCLZ::MOVE A,LSKT(UNIT)
	TRNN A,1
	SKIPA A,[CLZR]
	MOVEI A,CLZS
	PUSHJ P,DOFSM
	POPJ P,
; Network mtopr routines

NETMTP:	HLRZ UNIT,FILSKT(JFN)
	MOVE IOS,NETSTS(UNIT)
	CAIG B,26
	CAIGE B,20
	 RETSKP			; ANYTHING ELSE IS A NOP
	JRST .+1-20(B)
	JRST NETACP
	JRST NETDMP
	JRST SNDINT
	JRST ABTCON
	JRST NETINT
	JRST NETRDY
	JRST NETFAL

NETACP:	LDB B,PFSM
	MOVEI A,ACPT
	CAIN B,RFCR
	 PUSHJ P,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
	PUSHJ P,DMPBUF
	 JRST WATXXX
	RETSKP

SNDINT:	LDB A,PFHST
	LDB B,PLINK
	MOVE D,LSKT(UNIT)
	TRNE D,1
	SKIPA D,[IFIW!IMPINS]
	MOVE D,[IFIW!IMPINR]
	NCPOFF
	LDB C,PFSM
	CAIN C,OPND
	PUSHJ P,@D
	NCPON
	RETSKP
; WAIT FOR READY TO SEND AT LEAST ONE BYTE

ABTCON:	MOVE A,CAPENB
	TXNN A,SC%NWZ
	 JRST [	MOVEI A,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
	PUSHJ P,PKCHK		; GET BYTES THAT CAN BE SENT
	JUMPE B,[PUSHJ P,WATBAL	; COMPUTE ACTIVATION TEST
		JRST WATXXX]	; AND WAIT
	CALL PKULCK
	RETSKP

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

NETINT:	UMOVE B,3
	HRR B,FORKX		; REMEMBER THIS FORK, AND USER'S
	MOVEM B,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::PUSH P,UNIT
	PUSH P,A
	MOVSI UNIT,-NSKT
NETKF1:	HRRE A,NETFRK(UNIT)
	CAMN A,FORKX
	 SETOM NETFRK(UNIT)
	AOBJN UNIT,NETKF1
	POP P,A
	POP P,UNIT
	POPJ P,
; HERE FROM LOGOUT CODE TO RELEASE JOB-WIDE NET RESOURCES

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

; SKIP IF NET INPUT BUFFER EMPTY

NTSIBE:	HLRZ UNIT,FILSKT(JFN)
	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	MOVSI B,777777
	TDNN B,IMPLT4(A)
	TDNE B,IMPLT3(A)
	 POPJ P,
	JRST RSKP
; Network file sequential byte input

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

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
	LDB T4,PBFSIZ		;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
	LDB T2,PBFSIZ		;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.
	LDB T4,PBPBYT		;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
	MOVE D,NETDAL(UNIT)	; GET DESIRED BIT ALLOCATION
	MOVE B,D
	ASH B,-1		; HALVE
	PUSH P,B		; SAVE
	MOVEI C,MSGALL		; DESIRED LEVEL OF MSG ALLOC
	MOVE B,C
	ASH B,-1		; HALVE
	PUSH P,B		; AND SAVE
	LOAD T2,LTIDX,(UNIT)	; GET LINK TABLE INDEX
	HRRZ B,IMPLT4(B)	; OUTSTANDING MSG ALLOC
	SUB C,B			; NEEDED INCREMENT
	SUB D,NETBAL(UNIT)	; NEEDED INCREMENT
	LDB B,PLINK
	LDB A,PFHST
	CAMGE D,-1(P)		; IF GREATER THAN HALF
	CAML C,0(P)		; FOR EITHER ONE
	 PUSHJ P,IMPALL		; THEN SEND AN ALLOCATE
	ADJSP P,-2
NETRAX:	NCPON
	POPJ P,
FIRSTI:	PUSHJ P,FRSTIO		; SET UP BUFFER
	RET			;PASS ON DOWN BLOCK
	JUMPG B,FRSTI1		; BUFFER SPECIFIED. USE FOR ALLOCATION
	PUSH P,A
	MOVEI A,MAXBPM		; MAXIMUM BITS IN A MESSAGE
	LDB B,PBPBYT		; CONNECTION BYTE SIZE
	IDIV A,B		; BYTES
	IMULI A,MSGALL		; TIMES MESSAGE ALLOCATION
	ADDM A,0(P)		; THAT PLUS FILE BUFFER BYTES
	POP P,B			; IS WHAT TO USE
FRSTI1:	LDB D,PBPBYT		; GET BYTES SIZE
	IMUL D,B		; BITS IN BUFFERS
	MOVEM D,NETDAL(UNIT)	; SAVE DESIRED LEVEL
	PUSHJ P,NETRAL		; SEND ALLOCATE AS NEEDED
	RETSKP
WATLSN:	LDB A,PFSM		; Get state of this connection
	CAIN A,OPND
	 RETSKP
	CAIN A,RFCR
	 JRST [	MOVEI A,ACPT
		PUSHJ P,DOFSM
		RETSKP]
	CAIN A,RFCS		; If still waiting for rfc
	 JRST WATLS1		; Continue waiting
	CAIE A,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>
	 POPJ P,
	PUSH P,A
	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
	PUSHJ P,PKCHK		; HOW MANY BYTES CAN WE SEND?
	POP P,C
	JUMPE B,NTSQO3		; NOT ENOUGH
	PUSHJ P,PKBYT
	 JFCL
	LDB A,PBPBYT
	ADDM A,NETBTC(UNIT)
	MOVNS A
	ADDM A,NETBAL(UNIT)
	MOVEI A,^D24
	DPB A,PCLKS		; RESET CLOCK TO TWO MINUTES
	POPJ P,

NTSQO1:	SOSL FILCNT(JFN)
	 JRST NTSQO2
	PUSHJ P,DMPBUF
	 JRST [POP P,C		;CLEAN UP STACK
		JRST WATXXX]	; Can't dump now, wait
NTSQO2:	AOS FILBYN(JFN)
	POP P,A
	IDPB A,FILBYT(JFN)
	POPJ P,

NTSQO3:	PUSHJ P,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 T2,NETBUF(UNIT)	;GET BUFFER ADR
	HLL T2,FILBYT(JFN)	;GET BYTE SIZE
	TLZ T2,770000		;END OF FIRST WORD
	TLNN T2,700		;36 BIT MODE?
	 TLO T2,40000		;NO GET BYTE OFFSET RIGHT
	MOVE T3,FILOFN(JFN)	;GET BYTE OFFSET
	ADJBP T3,T2		;GET OFFSET POINTER
	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
	LDB T3,PBPBYT		;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
;	HRRM T2,NETSTS(UNIT)	;NEED TO HAVE MESSAGES GENERATED
	MOVEI T1,^D24
	DPB T1,PCLKS		;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
	LDB T1,PBFSIZ		;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 [	PUSHJ P,WATLSN	; NO, WAIT FOR CONNECTION TO OPEN
		RET		;PASS ON DOWN BLOCK
		TQZ <WNDF>
		RETSKP]
	PUSHJ P,FRSTIO		; YES, SET UP BUFFER ETC
	RET			;PASS ON DOWN BLOCK
	RETSKP

;FRSTIO -  SET UP BUFFER N 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>
	LDB T2,PBYTSZ		;GET BYTE SIZE FROM JFN BLOCK
	MOVEI T1,^D36		;GET WORD SIZE
	IDIVM T1,T2		;CALCULATE BYTES PER WORD
	MOVEM T2,FRSTBY		;SAVE BYTES PER WORD
	LDB T3,PBPBYT		;GET NET CONNECTION BIT PER BYTE
	IDIV T1,T3		;GET BYTES PER WORD
	IMUL T3,T1		;CALCULATE BITS USED PER WORD
	MOVEI T1,MAXBPM		;GET MAXIMUM BITS PER MESSAGE
	IDIVM T1,T3		;CALCULATE MAX WORDS FOR MESSAGE
	LDB T1,PBFSIZ		;GET DESIRED BYTES IN BUFFER
	MOVE T2,FRSTBY		;GET BYTES PER WORD
	IDIVM T1,T2		;CALCULATE NUMBER OF WORDS/ BUFFER
	SKIPE T2		;ZERO WORDS REQUESTED
	CAML T2,T3		;OR GREATER THAN MAX
	MOVE T2,T3		;YES.  USE MAX WORDS/ BUFFER
	MOVEM T2,FRSTBF		;SAVE WORDS/ BUFFER
	AOS T2			;NEED 1 WORD FOR FREE SPACE 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
	LDB T2,PBFSIZ		;RETURN AS VALUE
	DPB T1,PBFSIZ		;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
	PUSHJ P,CHKJFN		; Check jfn of receive connection
	 JRST ATPER0		; Only real jfns are legal
	 JRST ATPER0
	 JRST ATPER0
	MOVEI A,ATNX2		; Error code if test skips
	TQNE <READF>		; MUST BE OPENED FOR READING
	PUSHJ P,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
ATNVT1:	UMOVE JFN,2		; Get send jfn
	PUSHJ P,CHKJFN		; Check it
	JRST ATPER2		; Must also be a real jfn
	JRST ATPER2
	JRST ATPER2
	MOVEI A,ATNX2		; Becomes atNx8 at atper3
	TQNE <WRTF>		; THIS ONE MUST BE FOR WRITING
	PUSHJ P,CHKATP		; And dev=net, open, no buffer
	 JRST ATPER3		; Failed above tests
	HLRZ UNIT,FILSKT(JFN)
	LDB A,PFSM
	CAIN A,RFCS
	PUSHJ P,WATNOT		; Wait for response from foreign host
	MOVEI A,ATNX12		; Error code for refused send
	LDB B,PFSM		; Now get state
	CAIE B,OPND		; If not opnd
	JRST ATPER4		; Then fail
	HRLM UNIT,ATUNTS	;SAVE SEND JFN IN LEFT HALF
	HRRZ UNIT,ATUNTS	;SWITCH TO RECEIVE CONNECTION
	LDB A,PFSM		; Get its state
	CAIN A,RFCS
	PUSHJ P,WATNOT		; Wait for response from foreign host
	MOVEI A,ATNX6		; Error code for refused receive
	LDB B,PFSM
	CAIE B,OPND		; If not opnd
	JRST ATPER4		; Then fail
ATNVT2:	NCPOFF
	LDB A,PFSM
	CAIE A,OPND
	 JRST [	MOVEI A,ATNX6
		JRST ATPERZ]
	HLRZ UNIT,ATUNTS		;GET SEND UNIT
	LDB A,PFSM
	CAIE A,OPND
	 JRST [		MOVEI A,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
	PUSHJ P,ASNNVT		; Assign NVT to these units
	 JRST [	MOVEI A,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)	; Put pty here also
	NCPON
	IORI A,400000		; Convert pty to tty designator
	UMOVEM A,1		; Return to user
	PUSHJ P,RELJFN		; Release send jfn
	MOVE JFN,ATRCJF
	PUSHJ P,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 A,ATNX3		; Receive not open
	TQNN <OPNF>		; IS IT OPEN?
	POPJ P,			; NO
	HRRZ B,DEV
	MOVEI A,ATNX4
	CAIE B,NETDTB
	POPJ P,
	MOVEI A,ATNX5
	TQNN <WNDF>
	POPJ P,
	JRST RSKP

ATPERZ:	NCPON
	JRST ATPER4

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

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

ATPER0:	MOVEI A,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,1
	PUSHJ P,CHKJFN
	 JRST CVSER0
	 JRST CVSER0
	 JRST CVSER0
	HLRZ A,FILNEN(JFN)
	HRLI A,(<POINT 7,0,35>)
	PUSHJ P,NAMDEC
	 JRST CVSER1
	TRZ A,1
	PUSHJ P,UNLCKF
	UMOVEM A,2
	JRST SKMRTN

CVSER1:	PUSHJ P,UNLCKF
	SKIPA A,[CVSKX2]
CVSER0:	MOVEI A,CVSKX1
	JRST MRETNE
; Flush host

.FLHST::MCENT
	MOVEI B,SC%WHL!SC%OPR
	TDNN B,CAPENB
	 ITERR (WHELX1)
	ANDI A,377		;MAXIMUM HOST NUMBER ALLOWED IS 8 BITS
	PUSHJ P,HSTDED
	PUSHJ P,IMSRST
	JRST MRETN

; Convert host number to string

.CVHST::MCENT
	HRLZ D,MHOSTS		;SCAN ALL HOSTS IN NAME TABLES
	LDB C,[POINT 9,HOSTN(D),17]
	CAME C,B
	 AOBJN D,.-2
	JUMPGE D,[EMRETN <CVHST1>] ;GET ERROR CODE AND RETURN TO USER
	HRRZ A,HOSTN(D)
	ADDI A,HSTNAM-1
	PUSHJ P,JFNSS
	JRST SKMRTN

; Get net status

NETGST:	HLRZ UNIT,FILSKT(JFN)
	MOVE A,NETSTS(UNIT)
	LDB B,PFHST
	UMOVEM B,3
	MOVE B,FSKT(UNIT)
	UMOVEM B,4
	POPJ P,

; Set net status

NETSST:	POPJ P,


; ASSIGN BUFFERS IN NETWORK AREA

	RESCD

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

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

; RELEASE NETWORK BUFFERS

RLNTBF::MOVE A,NETFRE+3		;GET LOWER BUFFER AREA BOUNDARIES
	CAMGE B,A		;RETURNED BUFFER .GE. LOWER BOUND?
	 JRST RLNTER		;NO, CRASH
	MOVE A,NETFRE+4		;GET UPPER BOUND
	CAML B,A		;.LT. UPPER BOUND?
RLNTER:	 BUG (HLT,NETRBG,<RLNTBF: ATTEMPT TO RELEASE BUFFER AT GARBAGE LOCATION>)
	LOCK NETFRE+1		;LOCK FREE LIST
	HRRZ A,0(B)		;GET COUNT FIELD
	CAILE A,MAXWPM		;MAKE SURE NOT ALREADY ON FREELIST
	BUG (HLT,NETBAF,<RLNTBF: ATTEMPT TO RELEASE BUFFER ALREADY ON FREE LIST>)
	MOVE A,0(P)		;GET PC OF CALLER
	HRL A,NETFRE		;GET POINTER TO CURRENT FIRST BUFFER
	MOVEM B,NETFRE		;RETURNED ONE IS NOW FIRST
	MOVEM A,0(B)		;AND POINTS TO OLD FIRST ONE
				;SIZE FIELD IS PC OF CALLER
	MOVEI A,MAXWPM		;MAINTAIN TOTAL SPACE COUNT
	ADDM A,NETFRE+2
	UNLOCK NETFRE+1		;UNLOCK FREE LIST
	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(B),QQ
QQ==QQ+4>
QQ==3
	REPEAT 9,<
	POINT 4,NXTSTT+1(B),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(B),QQ
QQ==QQ+4>
QQ==3

	REPEAT 9,<
	POINT 4,ACTION+1(B),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  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,CLSW,PNDG	; Pndg
BYTE (4)RFCR,LSNG,LSNG,FREE,FREE,LSNG,LSNG,LSNG,LSNG,LSNG,CLSW	; Lsng
BYTE (4)RFCR,FREE,FREE,CLSW,CLSW,OPND,RFCR,RFCR,RFCR,RFCR,RFCR	; Rfcr
BYTE (4)CLW1,FREE,FREE,CLW1,CLW1,CLW1,CLW1,CLW1,CLW1,FREE,CLW1	; Clw1
BYTE (4)OPND,FREE,FREE,CLSW,CLSW,RFCS,RFCS,RFCS,RFCS,CLSW,CLSW	; Rfcs
BYTE (4)OPND,CLZW,RFN2,CLW1,DATW,OPND,OPND,OPND,OPND,OPND,OPND	; Opnd
BYTE (4)CLSW,FREE,FREE,CLSW,CLSW,CLSW,CLSW,CLSW,CLSW,FREE,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  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 PUSHJ P,@ACTAB(ACTION#)

ACTAB:	IFIW!CPOPJ		;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
	LDB T2,PFHST		;GET FOREIGN HOST
	BUG(INF,NCPFUN,<NCP FSM RECIEVED FUNNY INPUT>,<T1,T2,UNIT>)
	AOS FUNNYC		;COUNT THEM
	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
	POPJ P,

; CHECK ALLOCATION

CKALL:	MOVE A,LSKT(UNIT)
	TRNN A,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
	MOVEM IOS,NETSTS(UNIT)
	RET

CKALL1:	LOAD T1,LTIDX,(UNIT)	;GET LINK TABLE INDEX
	LDB B,PBPBYT
	CAMG B,NETBAL(UNIT)	; SUFFICIENT BIT ALLOCATION?
	SKIPN IMPLT4(A)		; AND MESSAGE SPACE?
	 JRST CKALL2		; NO
	TQZ <ALLFF>
	MOVEM 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:	PUSHJ P,DOEOS
	PUSHJ P,IMPABL		; FLUSH QUEUED MESSAGES
	POPJ P,

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

; End of receive

DOEOR:	PUSHJ P,SNDCLS
	HRRZ B,NETBUF(UNIT)
	JUMPE B,DOEOS
	CAIL B,1000
	JRST DOEOS
EORNVT:	PUSHJ P,DOEOS		; DO SAME AS END OF SEND
	NCPON			; NCP BACK ON SO NVTDET CAN USE IT
EORNV0:	HRRZ B,NETBUF(UNIT)	; PICK UP LINE NUMBER
	JUMPE B,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
	POPJ P,

EORNV2:	TXZN T1,1B0		;WAIT OR ERROR?
	JRST [	BUG (CHK,NETDET,<NVTDET: COULD NOT CLOSE NVT>,<T1>)
		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
	PUSHJ P,IMPCLL
	POPJ P,

NETCLB:	PUSHJ P,NETCLL
SNDCLS:	LDB A,PFHST		; Get foreign host
	MOVE C,FSKT(UNIT)	; And foreign socket
	MOVE B,LSKT(UNIT)	; And local socket
	TQNN <DEDF>
	PUSHJ P,IMPCLS		; Send the control message
	POPJ P,
; OPEN LINK

NETOPL:	LDB A,PFHST
	MOVE B,LSKT(UNIT)
	TRNE B,1		; Send socket?
	 IORI A,1000		; Mak as such
	LDB B,PLINK		; Get link
	LDB C,PBPBYT
	PUSHJ P,IMPOPL
	STOR T1,LTIDX,(UNIT)	;SAVE LINK TABLE INDEX
	POPJ P,

; Send rfc and open link

NETOPB:	PUSHJ P,NETOPL
	JRST SNDRFC

; Send rfc

SNDRFC:	TQNE <DEDF>
	 POPJ P,
	LDB A,PFHST		; Get foreign host
	MOVE B,LSKT(UNIT)	; And local socket
	MOVE C,FSKT(UNIT)
	LDB D,PBPBYT		; Byte size
	TRNE B,1
	JRST IMPSTR
	LDB D,PLINK
	JRST IMPRTS		; Send control message
; This here is the main fsm routine

DOFSM:	MOVE IOS,NETSTS(UNIT)
	TQNN <DEDF>
	 JRST DOFSMA
	PUSHJ P,DOFSMA
	LDB A,PFSM
DOFSMB:	PUSH P,A
	MOVEI A,HUNG
	PUSHJ P,DOFSMA
	LDB A,PFSM
	POP P,B
	CAME A,B
	 JRST DOFSMB
	POPJ P,

DOFSMA:	NCPOFF			; Allow no control messages while here
	PUSH P,A		; Save event for footprints
	MOVEI B,^D24		; Time out in 2 minutes
	DPB B,PCLKS
	LDB B,PFSM		; Get old state
	PUSH P,B
	LSH B,1			; Two words per old state
	LDB C,CBPFSM(A)		; Get new state
	LDB B,CBAFSM(A)		; Get action
	DPB C,PFSM
	PUSH P,B		; Save action
	MOVE B,-1(P)		; Get old state
	CAME C,B		; State changed?
	 PUSHJ P,STCPSI		; GENERATE STATE CHANGE PSI
DOFSM2:	POP P,B			; GET ACTION
	ADJSP P,-1		; FLUSH OLD STATE
	POP P,A			; Restore event
	PUSHJ P,@ACTAB(B)	; Call action routine
	NCPON
	POPJ P,

; Generate state change PSI

STCPSI:	HRRE A,NETFRK(UNIT)
	JUMPL A,CPOPJ		; No fork for interrupts
	LDB B,PFSMCH		; Get psi channel
	CAIL B,^D36
	 POPJ P,
	EXCH A,B
	PUSHJ P,PSIRQ
	POPJ P,
; Make a socket or find existing one

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


MAKSK6:	POP P,C
	ADJSP P,-3
	MOVE B,FSKT(UNIT)
	LDB A,PFHST
	NCPON
	JRST RSKP

MAKSKN:	SOJLE D,MAKSKE		; Full, error
	SOJGE UNIT,MAKSKL	; Loop back for next slot
	MOVEI UNIT,NSKT-1
	JRST MAKSKL
MAKSK1:	MOVX B,PROGF
	TDNE B,NETSTS(UNIT)
	 JRST MAKSKN		; Ignore those assigned to programs
	SKIPGE C
	MOVE C,UNIT		; Save where it's at
	CAIE A,DEAD
	JRST MAKSKN		; Space keeper, test next
MAKSK5:	SKIPN -3(P)
	JRST MAKSKR
	MOVE UNIT,C
	SETZM NETSTS(UNIT)
	SETZM NETBUF(UNIT)
	SETZM NETAWD(UNIT)
	SETZM NETBAL(UNIT)
	SETZM NETBTC(UNIT)
	SETOM NETFRK(UNIT)
	MOVEI A,CLZD
	DPB A,PFSM		; Set its state to be closed
	POP P,C
	MOVEM C,LSKT(UNIT)
MAKSKF:	MOVE A,-1(P)		; Foreign host
	MOVE B,LSKT(UNIT)
	TRNE B,1		; Receive?
	 JRST MAKSKQ
	PUSHJ P,ASNLNK		; Assign link for that host
	 JRST [	LDB A,PFSM
		MOVEI B,FREE
		CAIN A,CLZD	; Just created?
		 DPB B,PFSM	; Yes, delete it
		PUSH P,LSKT(UNIT)
		JRST MAKSKR]	; And fail
MAKSKQ:	POP P,B			; Common for old and new
	MOVEM B,FSKT(UNIT)
	POP P,A
	DPB A,PFHST
	ADJSP P,-1
	NCPON
	JRST RSKP

MAKSKE:	JUMPGE C,MAKSK5
MAKSKW:	SKIPA A,[0]		; FULL
MAKSKR:	MOVEI A,4		; NON-EXISTENT
MAKSKV:	NCPON
	SKIPA A,A
MAKSKX:	MOVEI A,3		; BAD PARAMETERS
	HRLM A,-2(P)		; STORE ERROR CODE
	POP P,C
	POP P,B
	POP P,A
	ADJSP P,-1
	POPJ P,
; Assign link number for this connection

ASNLNK:	PUSH P,B
	PUSH P,C
	PUSH P,D
	MOVEI D,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>>-1>>]
	PUSH P,UNIT		; Preserve unit
	PUSH P,A
	MOVSI UNIT,-NSKT
ASNLNL:	LDB A,PFSM
	CAIE A,FREE
	CAIN A,DEAD
	 JRST ASNLNN
	LDB A,PFHST
	CAME A,0(P)		; Check all connection to this host
	 JRST ASNLNN		; Get next
	MOVE A,LSKT(UNIT)
	TRNE A,1		; Only receive connections
	 JRST ASNLNN
	LDB A,PLINK		; Get link assigned
	IDIVI A,^D36		; Separate word and bit
	MOVE B,BITS(B)		; Get the bit
	ADD A,D
	ANDCAM B,0(A)		; Clear bits for links in use
ASNLNN:	AOBJN UNIT,ASNLNL	; Loop thru all connections
	HRLI D,-NLNKBW		; Prepare to look at all bits
	SETZ C,
ASNLNC:	MOVE A,0(D)
	JFFO A,ASNLNF
	ADDI C,^D36
	AOBJN D,ASNLNC
	JRST ASNLN1		; Failed

ASNLNF:	ADD B,C
ASNLN0:	POP P,A
	POP P,UNIT
	DPB B,PLINK
	ADJSP P,-NLNKBW
	AOS -3(P)
ASNLN1:	POP P,D
	POP P,C
	POP P,B
	POPJ P,
; Do a listen (openf for file with no foreign host/socket)

LISTEN:	PUSHJ P,HSTCHK
	POPJ P,
	PUSH P,D		; Save byte size
	PUSHJ P,MAKSKT		; Make a socket
	 JRST [	POP P,D
		MOVEI A,OPNX10
		POPJ P,]	; No room
	MOVEI A,LISN
	JRST CONNE1

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

CONNEC:	PUSHJ P,HSTCHK
	POPJ P,
	PUSH P,D		; Save byte size
	PUSHJ P,MAKSKT		; Make a socket or find existing one
	 JRST [	POP P,D
		MOVEI A,OPNX10
		POPJ P,]	; No room
	MOVEI A,CONN
CONNE1:	NCPOFF
	LDB B,PFSM
	CAIN B,CLZD		; Received any rfc here?
	 JRST CONNE2		; No
	CAIN B,PNDG		; Same question
	 JRST CONNE3		; Yes
	MOVEI A,OPNX9		; Already in use
	POP P,D
	NCPON
	POPJ P,

CONNE2:	MOVX D,PROGF
	IORM D,NETSTS(UNIT)	; Mark as attached to program
	NCPON
	POP P,D			; My choice of byte size
	DPB D,PBPBYT		; Set byte size
	PUSHJ P,DOFSM		; Send rfc etc
	JRST RSKP

CONNE3:	TRNE C,1		; Are we sender?
	 JRST CONNE2		; Also our choice
	LDB D,PBPBYT		; Get his byte size
	CAMN D,0(P)		; Does byte size agree?
	 JRST CONNE2		; Yes, same as if my choice
	NCPON
	MOVEI A,HUNG		; Flush his connection attempt
	PUSHJ P,DOFSM
	POP P,D
	MOVEI A,OPNX22		; Bad byte size error
	POPJ P,
; Check if host is available

HSTCHK:	SKIPL IMPRDY
	 JRST [	MOVEI A,OPNX19
		POPJ P,]
	JUMPL 1,RSKP		; ALWAYS OK IF LISTEN
	PUSH P,B
	PUSH P,A
	IDIVI A,^D36
	MOVE B,BITS(B)
	TDNE B,IMPBHT(A)
	 JRST [	MOVEI A,OPNX20
		JRST HSTCHF]
	TDNE B,IMPHRT(A)
	 JRST HSTCHO
	MOVE A,0(P)
	PUSH P,3
	PUSH P,4
	PUSH P,5
	PUSHJ P,IMSRST		; RESET HIM
	POP P,5
	POP P,4
	POP P,3
	MOVE A,TODCLK		; GET NOW
	ANDI A,377777
	ADDI A,^D5000		; PLUS 5 SECONDS
	ANDI A,777777-377	; LEAVE ROOM FOR HOST
	IOR A,0(P)
	HRLI A,HUPTST		; TEST ADDRESS
	MOVSS A
	MDISMS
	MOVE A,0(P)
	IDIVI A,^D36
	MOVE B,BITS(B)
	TDNN B,IMPHRT(A)
	 JRST [	MOVEI A,OPNX20
		JRST HSTCHF]
HSTCHO:	POP P,A
	AOSA -1(P)
HSTCHF:	ADJSP P,-1
	POP P,B
	POPJ P,

	RESCD

HUPTST:	MOVE 2,1
	ANDI 2,377
	IDIVI 2,^D36
	MOVE 3,BITS(3)
	TDNE 3,IMPHRT(2)
	 JRST 1(4)
	ANDCMI 1,377
	JRST BLOCKW		; CHECK TIME RUN OUT

	SWAPCD
; Routines to call when control messages are received

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

RECCLS::PUSHJ P,GETSKT		; Get the socket entry
	 JRST NCPERR
RECCL1:	MOVE B,LSKT(UNIT)
	TRNN B,1
	SKIPA A,[CLSR]
	MOVEI A,CLSS
	PUSHJ P,DOFSM
	POPJ P,

; RECEIVED INCORRECT MESSAGE
; REPLY WITH ERR

NCPERR:	PUSH P,1		; SAVE AC'S
	PUSH P,2
	PUSH P,3
	PUSH P,4
	PUSH P,5
	MOVE 5,[I8CAL,,3]	; COMPLAIN ABOUT LAST CONTROL MESSAGE
	BLT 5,5
	HLRZ 2,1		; SUBCODE TYPE FOR "ERR" MSG
	HRRZS 1			; AND HOST TO COMPLAIN TO.
	PUSHJ P,IMPERR
	POP P,5
	POP P,4
	POP P,3
	POP P,2
	POP P,1
	HRRZS 1
	POPJ P,

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

RECSTR::PUSH P,D		; Save byte size
RCSTR0:	PUSHJ P,MAKSKT
	 JRST [	POP P,D
		JRST NCPERR]
	MOVE D,0(P)
	PUSHJ P,CHKSKT		; MAKE SURE THIS SOCKET NOT IN USE
	 JRST RCSTR0		; IT WAS. DELETED. NOW TRY AGAIN.
	LDB A,PFSM		; What is state of this connection
	CAIE A,CLZD		; If not clzd
	 JRST [	LDB D,PBPBYT	; Then get user's byte size
		CAMN D,0(P)	; If not the same
		JRST .+1
		MOVEI A,RRFB	; RECEIVED BAD BYTE SIZE
		PUSHJ P,DOFSM
		MOVX A,ERRB
		IORM A,NETSTS(UNIT)
		POP P,D
		POPJ P,]
	POP P,D
	DPB D,PBPBYT
	MOVEI A,RRFC
	PUSHJ P,DOFSM
	MOVE A,UNIT
	LDB B,PLINK
	POPJ P,

CHKSKT:	PUSH P,A
	PUSH P,B
	PUSH P,C
	PUSH P,D
	LDB A,PFSM		; GET STATE
	CAIE A,RFCS		; STATES WHERE RFC IS EXPECTED
	CAIN A,CLZD
	 JRST SKTCK1
	CAIN A,LSNG
SKTCK1:	 AOSA -4(P)		; OK, SKIP RETURN
	PUSHJ P,SK2DWN		; ELSE KILL THE OLD ONE
	POP P,D
	POP P,C
	POP P,B
	POP P,A
	POPJ P,

CHKLNK:	PUSH P,A
	PUSH P,B
	PUSH P,C
	PUSH P,D
	MOVSI UNIT,-NSKT
CHKLK1:	LDB B,PLINK		; GET THE LINK
	LDB C,PFHST		; AND HOST
	CAMN B,0(P)
	CAME C,-3(P)
	 JRST CHKLK2
	MOVE B,LSKT(UNIT)
	TRNN B,1
	 JRST CHKLK2		; SKIP SEND CONNECTIONS
	LDB B,PFSM		; LINK-HOST MATCHES. GET STATE
	CAIE B,DEAD
	CAIN B,FREE
	 JRST CHKLK2
	CAIE B,CLZD
	CAIN B,RFCS
	 JRST CHKLK2
	CAIE B,LSNG
	CAIN B,CLZW
	 JRST CHKLK2
	PUSHJ P,SK2DWN
CHKLK2:	AOBJN UNIT,CHKLK1
	POP P,D
	POP P,C
	POP P,B
	POP P,A
	POPJ P,
; Receive rts
; Recrts(fhost,fskt,lskt,link)

RECRTS::PUSHJ P,CHKLNK		; CHECK AND DELETE ANY MATCHING LINKS
	PUSH P,D		; SAVE LINK
	PUSHJ P,MAKSKT		; MAKE SOCKET TABLE ENTRY
	 JRST [	POP P,D		; FAILED, SEND ERR
		JRST NCPERR]
	POP P,D			; RESTORE LINK
	PUSHJ P,CHKSKT		; MAKE SURE NO DUPLICATES
	 JRST RECRTS		; PREVIOUS CONNECTION CLOSED. TRY AGAIN
	DPB D,PLINK
	MOVEI A,RRFC
	PUSHJ P,DOFSM
	POPJ P,

; Receive rfnm

RCFRFN::MOVEI A,RRFN
	PUSHJ P,DOFSM
	POPJ P,

; Receive ins/inr

RECINR::
RECINS::LDB B,PINTCH
	LDB A,PFSM
	CAIGE B,^D36		; RETURN IF CHANNEL IS 77 OCTAL
	CAIE A,OPND
	 POPJ P,
	HRRZ A,NETBUF(UNIT)
	SKIPE A
	CAIL A,1000
	CAIA
	 POPJ P,
	HRRE A,NETFRK(UNIT)
	JUMPL A,CPOPJ
	EXCH A,B
	PUSHJ P,PSIRQ
	POPJ P,

; INITIATE SERVICE INTERRUPTION (HOST DEAD)

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

; TERMINATE SERVICE INTERRUPTION

SVCRST::MOVX IOS,SVCIF
	ANDCAB IOS,NETSTS(UNIT)
	PUSHJ P,STCPSI
	POPJ P,

; Receive reset message

RECRST::PUSHJ P,NETHDN
	JRST IMPRRP
; BITS AND FIELD VALUES FOR B0-8 OF HOSTN TABLE

SERVER==400000
USER==200000
NICKNAME==100000

TENEX==1000
ITS==2000
DEC==3000
TIP==4000
MTIP==5000
ELF==6000
ANTS==7000
MULTICS==10000
OPST20==11000
HSTINI::PUSH P,7
	PUSH P,6
	PUSH P,5
	MOVEI 1,400000
	RCM			; GET CHANNELS THAT ARE ON
	PUSH P,1		; REMEMBER THEM
	MOVEI 1,400000
	MOVSI 2,(1B10)
	DIC			; TURN OFF EOF CHANNEL
	MOVSI 1,(1B2+1B17)
	HRROI 2,[ASCIZ \<SYSTEM>HSTNAM.TXT\]
	GTJFN
	  JRST HSTINF		; FAIL
	PUSH P,1
	MOVE 2,[7B5+1B19]
	OPENF
	 JRST [	POP P,1
		RLJFN
		 JFCL
		JRST HSTINF]	; FAIL
	SETZM HSTNAM		; CLEAR OLD STUFF IN TABLE
	MOVSI 4,HSTNAM		; (TELNET FAILS IF THIS ISN'T DONE
	HRRI 4,HSTNAM+1		; AND IT LOOKS NEATER TO HAVE WHOLE
	BLT 4,HSTNAM+NHSTN-1	; WORD OF NULL AFTER EACH NAME)
	SETZM NWPBT		; ALSO CLEAR NEW PROTOCOL BIT TABLE
	MOVSI 4,NWPBT
	HRRI 4,NWPBT+1
	BLT 4,NWPBT+^D<<256+35>/36>-1
	MOVEI 4,HOSTN
	MOVEI 5,HSTNAM
LUP0:	PUSHJ P,GCH
	 JRST DONE
	MOVEM 3,7		; SAVE IN CASE THIS IS ALINE
	CAIN 2,12
	 JRST LUP0
	CAIGE 4,HOSTN+NHOSTS
	CAIL 5,HSTNAM+NHSTN
	 JRST FULL
	BKJFN
	 JFCL
	RFPTR
	 JFCL
	PUSH P,2
	MOVEI 3,10
	NIN
	 JRST [	HRLI 6,[ASCIZ /BAD NUMBER/]
		POP P,3
		JRST SYNERR]
	POP P,3
	CAILE 2,0
	CAILE 2,377
	 JRST [	HRLI 6,[ASCIZ /HOST NUMBER OUT OF RANGE/]
		JRST SYNERR]
	HRLZM 2,0(4)		; STORE HOST NUMBER
	BKJFN
	 JFCL
LUP4:	PUSHJ P,GCH
	 JRST PEOF
	CAIE 2,","
	 JRST [	HRLI 6,[ASCIZ /MISSING COMMA AFTER HOST NUMBER/]
		JRST SYNERR]
	MOVE 6,5		; TEMP FOR BYTE POINTER
	SUBI 6,HSTNAM		; MAKE RELATIVE POINTER
	HRRM 6,0(4)		; STORE IN RH OF HOSTN
	MOVE 6,5		; TEMP POINTER AGAIN
	HRLI 6,440700		; 7 BIT LEFT JUSTIFIED
LUP1:	PUSHJ P,GCH		; READ NEXT CHARACTER
	 JRST PEOF
	CAIE 2,12		; TERMINATE ON END OF LINE
	CAIN 2,","
	 SETZ 2,		; OR COMMA
	IBP 6
	HRRZ 1,6		; WHERE ARE WE GOING TO PUT THIS?
	CAIL 1,HSTNAM+NHSTN	; OFF END OF TABLE?
	 JRST FULL		; YES, SAY FULL
	DPB 2,6			; STORE THE BYTE
	JUMPN 2,LUP1		; LOOP IF NOT THE END
	MOVE 1,0(P)
	BKJFN			; GET THE TERMINATOR AGAIN
	 JFCL
LUP2:	PUSHJ P,GCH
	 JRST PEOF
LUP2A:	CAIN 2,12
	 JRST LUP2X		; DONE IF END OF LINE
	CAIE 2,","		; SCAN UNTIL COMMA FOUND
	 JRST LUP2
LUP3:	PUSHJ P,GCH		; GET FIRST LETTER OF WORD
	 JRST PEOF
	CAIN 2,","
	 JRST LUP2A		; JUMP IF NULL WORD
	CAIN 2,12
	 JRST LUP2X		; DONE IF END OF LINE
GWORD:	SETZ 1,			; PUT VALUE OF WORD HERE
	CAIN 2,"A"
	 MOVSI 1,ANTS
	CAIN 2,"D"
	 MOVSI 1,DEC
	CAIN 2,"E"
	 MOVSI 1,ELF
	CAIN 2,"I"
	 MOVSI 1,ITS
	CAIN 2,"M"
	 JRST [	PUSHJ P,GCH
		 JRST PEOF
		CAIN 2,"U"
		 MOVSI 1,MULTICS
		CAIN 2,"T"
		 MOVSI 1,MTIP
		JRST ELUP3]
	CAIN 2,"N"
	 JRST [	PUSHJ P,GCH
		 JRST PEOF
		CAIN 2,"E"
		 JRST SETNWP
		CAIN 2,"I"
		 MOVSI 1,NICKNAME
		JRST ELUP3]
	CAIN 2,"S"
	 MOVSI 1,SERVER
	CAIN 2,"T"
	 JRST [	PUSHJ P,GCH
		 JRST PEOF
		CAIN 2,"E"
		 MOVSI 1,TENEX
		CAIN 2,"I"
		 MOVSI 1,TIP
		JRST ELUP3]
	CAIN 2,"U"
	 MOVSI 1,USER
ELUP3:	HRLI 6,[ASCIZ /UNRECOGNIZED FLAG NAME/]
	JUMPE 1,SYNERR		; JUMP IF NO MATCH FOUND
	MOVSI 2,(17B8)
	HRLI 6,[ASCIZ /MULTIPLE SYSTEM TYPE SPECIFICATION/]
	TDNE 2,0(4)		; ALREADY HAVE A SYSTEM TYPE?
	TDNN 2,1		; YES AND IS THIS TRYING TO SET IT?
	 SKIPA
	  JRST SYNERR		; YES. ERROR
	IORM 1,0(4)		; ACCUMULATE BITS
	JRST LUP2		; AND SKIP TO COMMA/EOL

LUP2X:	MOVEI 5,1(6)		; START NEXT STRING IN NEXT WORD
	AOJA 4,LUP0		; STEP TO NEXT HOSTN SLOT AND LOOP

SETNWP:	LDB 1,[POINT 8,0(4),17]	; GET HOST NUMBER
	IDIVI 1,^D36
	MOVE 2,BITS(2)
	IORM 2,NWPBT(1)
	JRST LUP2
PEOF:	MOVE 1,0(P)
	RFPTR
	 JFCL
	MOVE 3,2
	HRLI 6,[ASCIZ /PREMATURE END OF FILE/]
SYNERR:	HLRO 1,6
	PSOUT
	HRROI 1,[ASCIZ / IN HOST DESCRIPTOR FILE
/]
	PSOUT
	MOVE 2,7
	MOVE 1,0(P)
	SFPTR			; SET BACK TO BEGINNING OF LINE
	 JFCL
	SETO 7,
PERLP:	MOVE 1,0(P)
	RFPTR
	 JFCL
	CAME 2,3
	 JRST PERLP1
	MOVEI 1,101
	RFPOS
	HRRZ 7,2
PERLP1:	MOVE 1,0(P)
	PUSHJ P,GCH1
	 MOVEI 2,12
	CAIN 2,12
	 JRST PERLPX
	MOVE 1,2
	PBOUT
	JRST PERLP

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

/]
	PSOUT
	JRST LUP0

FULL:	HRROI 1,[ASCIZ /HOST TABLES FULL BEFORE END OF FILE
/]
	PSOUT
	JRST DONE
DONE:	PUSH P,5
	MOVE 2,4
	SUBI 2,HOSTN
	MOVNM 2,MHOSTS		; SAVE FOR CVHST, ...
	MOVEI 1,GTTAB+.HOSTN
	CALL SETGTB
	POP P,2
	SUBI 2,HSTNAM
	MOVEI 1,GTTAB+.HSTNA
	CALL SETGTB
	POP P,1
	CLOSF
	 JFCL
	AOS -4(P)		; SUCCESS RETURN
HSTINF:	POP P,2			; GET CHANNELS THAT WERE ON BEFORE
	MOVEI 1,400000
	AIC			; TURN THEM BACK ON
	POP P,5
	POP P,6
	POP P,7
	POPJ P,

SETGTB:	PUSH P,2
	PUSH P,1
	CALL FPTA
	PUSH P,1
	CALL MRPACS
	HRLZ 2,1
	PUSH P,2
	TLO 2,40000
	MOVE 1,-1(P)
	CALL MSPACS
	push p,3
	MOVE 2,-4(P)
	move 3,-3(P)
	HRLM 2,(3)
	pop p,3
	POP P,2
	POP P,1
	CALL MSPACS
	POP P,1
	POP P,2
	POPJ P,

GCH:	MOVE 1,-1(P)
	RFPTR
	 JFCL
	MOVEM 2,3
GCH2:	PUSHJ P,GCH1
	 POPJ P,
	CAIN 2,";"
	 JRST GCHSMC
	CAIE 2,11
	CAIN 2,40
	 JRST GCH2
GCHX:	CAIN 2,37
	 MOVEI 2,12
	AOS 0(P)
	POPJ P,

GCH1:	BIN
	CAIE 2,15
	CAIN 2,14
	 JRST GCH1
	JUMPN 2,RSKP
GCHNUL:	GTSTS
	TLNE 2,1000
	 POPJ P,
	JRST GCH1

GCHSMC:	BIN
	CAIE 2,37
	CAIN 2,12
	 JRST GCHX
	JUMPN 2,GCHSMC
	GTSTS
	TLNN 2,1000
	 JRST GCHSMC
	POPJ P,
; Kill all connection -- net is down

NETDWN::MOVSI UNIT,-NSKT
	PUSHJ P,SKTDWN
	AOBJN UNIT,.-1

; Periodic check of all connections for time-out

NETCHK::MOVSI UNIT,-NSKT
NETCKL:	LDB A,PFSM
	CAIE A,DEAD
	CAIN A,FREE
	 JRST NETCKN
	MOVX A,DEDF
	TDNN A,NETSTS(UNIT)
	SKIPL IMPRDY
	JRST NETCK1
	LDB B,PCLKS
	SOS B
	DPB B,PCLKS
	JUMPG B,NETCKN
NETCK1:	MOVEI A,HUNG
	PUSHJ P,DOFSM
NETCKN:	AOBJN UNIT,NETCKL
	MOVEI A,^D5000
	SKIPL IMPRDY
	MOVEI A,^D500
	ADD A,TODCLK
	MOVEM A,NETTIM
	POPJ P,
; Host has died

NETHDN::MOVSI UNIT,-NSKT
	PUSH P,A
NETHDL:	LDB A,PFSM
	CAIE A,FREE
	CAIN A,DEAD
	JRST NETHDX
	LDB A,PFHST
	CAMN A,(P)
	PUSHJ P,SKTDWN
NETHDX:	AOBJN UNIT,NETHDL
	POP P,A
	POPJ P,

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

SKTDWN:	LDB A,PFSM		; GET STATE
	CAIN A,LSNG		; IF LSNG
	 POPJ P,		; IGNORE
	MOVX B,ERRB!DEDF
	IORM B,NETSTS(UNIT)
	CAIE A,CLSW		; IF WAITING FOR CLOSE,
	CAIN A,CLW1
	PUSHJ P,SKTDW2		; PRETEND ONE HAPPENED.
	CAIE A,RFCR
	CAIN A,OPND		; If opnd
SKTDW2:	PUSHJ P,RECCL1		; Simulate receipt of cls
	MOVEI A,HUNG
	PUSHJ P,DOFSM
	POPJ P,
	TNXEND
	END