Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_1_19910112 - 6-1-monitor/tvtsrv.mac
There are 6 other files named tvtsrv.mac in the archive. Click here to see a list.
;[SRI-NIC]SRC:<6-1-MONITOR>TVTSRV.MAC.4, 27-Oct-87 03:17:39, Edit by MKL
; add BUGCHK in ASNTVT routine to prevent ILMNRF
;[SRI-NIC]XS:<SU-61SU>TVTSRV.MAC.2,  5-Dec-86 16:24:58, Edit by MKL
;;[SRI-NIC]SS:<6-1-MONITOR>TVTSRV.MAC.5,  7-Mar-86 16:34:23, Edit by MKL
;; add fixes to internet-login-message stuff under NICSW

;PS:<6-1-MONITOR>TVTSRV.MAC.25,  4-Aug-86 16:41:35, Edit by BILLW
; allow for TSMXP being smaller than a TTY buffer.
;PS:<6-1-MONITOR>TVTSRV.MAC.23, 11-Mar-86 17:33:48, Edit by BILLW
; from opscan, call FRCTVT or ENCTVT instead of FRCPKT/ENCPKT
;PS:<6-1-MONITOR>TVTSRV.MAC.21, 30-Jan-86 02:45:13, Edit by BILLW
; in TVTCSO, set bit in TVTSOQ. scan this bit table in OPSCAN.
;PS:<6-1-MONITOR>TVTSRV.MAC.16, 17-Jan-86 01:25:23, Edit by BILLW
; in OPSCAN assume that rxmit q will be empty if we are really dealing
; with echos, and otherwise allow more data to collect.
;PS:<6-1-MONITOR>TVTSRV.MAC.14, 29-Nov-85 20:09:37, Edit by BILLW
; Call SETOBF at TVTOPN
; Count TVT output in total bytes sent !
;PS:<6-1-MONITOR>TVTSRV.MAC.13, 29-Nov-85 17:43:01, Edit by BILLW
; Count TVT input and output characters and packets
;PS:<6-1-MONITOR>TVTSRV.MAC.10,  4-Nov-85 19:42:27, Edit by BILLW
; at TVTSOF, use enough output buffers to fill a packet.
;PS:<6-1-MONITOR>TVTSRV.MAC.9, 28-Oct-85 19:57:22, Edit by BILLW
; call FRCPKT instead of ENCPKT if output buffers are full. ??is this good??
;<6-1-MONITOR.FT6>TVTSRV.MAC.2, 12-Aug-85 18:14:16, Edit by WHP4
; Stanford changes:
; In TVRRH, if GTHST% fails, say "No Node Name Known"
;
; UPD ID= 2200, SNARK:<6.1.MONITOR>TVTSRV.MAC.8,   5-Jun-85 11:23:05 by MCCOLLUM
;TCO 6.1.1406  - Update copyright notice.
; UPD ID= 2000, SNARK:<6.1.MONITOR>TVTSRV.MAC.7,  23-May-85 14:53:47 by MCCOLLUM
;Fix typo in previous edit
; UPD ID= 1990, SNARK:<6.1.MONITOR>TVTSRV.MAC.6,  17-May-85 16:05:18 by MCCOLLUM
;TCO 6.1.1238 - Document the TVTNTV BUGHLT.
; UPD ID= 1422, SNARK:<6.1.MONITOR>TVTSRV.MAC.5,  29-Jan-85 11:38:44 by PAETZOLD
;TCO 6.1.1159 - Make monitor believe that TVTs are high speed.
;TCO 6.1.1158 - Decrease possible scheduler latency by incrementing PSKD1.
; UPD ID= 1044, SNARK:<6.1.MONITOR>TVTSRV.MAC.4,  12-Nov-84 15:27:52 by PAETZOLD
;TCO 6.1041 - Move ARPANET to XCDSEC
; UPD ID= 966, SNARK:<6.1.MONITOR>TVTSRV.MAC.3,   6-Nov-84 10:40:26 by PAETZOLD
;TCO 6.2268 - Make arg check in CHKTVT.
; UPD ID= 958, SNARK:<6.1.MONITOR>TVTSRV.MAC.2,   5-Nov-84 19:17:23 by PRATT
;TCO 6.1.1032 - Make TTYSRV compile independently: Rename TTANDV to TVTSRV
; UPD ID= 932, SNARK:<6.1.MONITOR>TTANDV.MAC.5,  28-Oct-84 11:31:10 by PRATT
;TCO 6.1.1022 - Add code for NTINF% "return remote hostname"
; UPD ID= 905, SNARK:<6.1.MONITOR>TTANDV.MAC.4,  20-Oct-84 12:16:29 by PRATT
;More TCO 6.1.1010 - Move TVTLEN to TTYDEF
; UPD ID= 765, SNARK:<6.1.MONITOR>TTANDV.MAC.2,  27-Aug-84 15:56:46 by PRATT
;TCO 6.1.1010 - Make TTANDV assemble independently of TTYSRV
; UPD ID= 3890, SNARK:<6.MONITOR>TTANDV.MAC.4,  11-Mar-84 10:35:20 by PAETZOLD
;More TCO 6.1733 - sendall fixes.  Accept "DO BINARY".  Fix up message TTC7SN
; UPD ID= 3519, SNARK:<6.MONITOR>TTANDV.MAC.3,  24-Jan-84 07:23:05 by HAUDEL
;TCO 6.1931 - Delete instuction that builds only 18 bit address.
; UPD ID= 2726, SNARK:<6.MONITOR>TTANDV.MAC.2,  22-Jul-83 14:58:06 by PAETZOLD
;TCO 6.1733 - Merge TCP/IP changes in release 6 again
;<TCPIP.5.1.MONITOR>TTANDV.MAC.15,  5-Jul-83 08:29:57, Edit by PAETZOLD
;TCP changes for 5.1.  Combine TTNTDV and TTTVDV.  Remove NCP code.

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


 	SEARCH ANAUNV,TTYDEF,PROLOG
	TTITLE	(TVTSRV,TVTSRV,< - ARPANET TVT Dependent routine>)


	SUBTTL	TVT Dependent Code

COMMENT	!

These  routines  support  TCP  Virtual Terminals, which are very
similar to ARPANET NVTs. They speak "new" TELNET  protcol.  TVTs
are  operated by the TCP portion of the Internet fork. This fork
does the listen, etc. and there is  no  usermode  equivalent  of
NETSRV.  The  listen  is  special in that it is marked as a TVT,
which means that the buffers  involved  are  TTYSRV  buffers  in
monitor  space  and  not  user-supplied  buffers  in some user's
space. Further, no PSI are  generated  for  buffer  completions.
Allocation  (window)  is set by the number of bytes available in
the TTY buffers.  TVTs  use  the  TELNET  protocol  through  TCP
connections.  Most  of  the  TELNET  code  is in TTNTDV and this
module uses that code.

!
	RESCD

;PARAMETERS

NEGTM0==^D30000			;NEGOTIATION TIME-OUT (BETWEEN 1 & 2 OF THESE)
TMSNTT==^D500			;TIME PER CHARACTER OF TTMSG BEFORE FLUSHING

;NVT SPECIAL CHARACTERS

IACCH==377			;INITIATE COMMAND
DNTCH==376			;DON'T
DOCH==375			;DO
WNTCH==374			;WON'T
WILCH==373			;WILL
SBCH==372			;SB BEGINNING OF SUB NEGOTIATION
GACH==371			;GA GO AHEAD
ELCH==370			;EL ERASE LINE
ECCH==367			;EC ERASE CHARACTER
AYTCH==366			;AYT ARE YOU THERE?
AOCH==365			;AO ABORT OUTPUT
IPCH==364			;IP INTERRUPT PROCESS
BRKCH==363			;BREAK
DMCH==362			;DM DATA MARK
NOPCH==361			;NOP
SECH==360			;SE END OF SUBNEGOTIATION

;NVT OPTION DEFINITIONS

BINOPT==0			;BINARY
ECHOPT==1			;ECHO
RCNOPT==2			;RECONNECTION
SGAOPT==3			;SUPPRESS GA
NAMOPT==4			;NEGOTIATE MESSAGE SIZE
STSOPT==5			;STATUS
TMKOPT==6			;TIMING MARK OPTION
RCTOPT==7			;RCTE OPTION
WILOPT==10			;OFFSET FOR REQUESTS
MAXOPT==^D18			;ONLY 1 HALF WORD OF OPTION BITS
TTNETW=TTDEV

;BITS IN TTNETW

DEFSTR PTITC,TTNETW,5,3		;COUNT, SYNC-INS
NV%WKS==1B8			;RCTE WAKEUP SEEN
MSKSTR NVWKS,TTNETW,NV%WKS
NV%RCS==1B9			;RCTE CHAAGE IN STATE
MSKSTR NVRCS,TTNETW,NV%RCS
NV%NNV==1B10			;NEW STYLE NVT
MSKSTR NVNNV,TTNETW,NV%NNV
NV%TMO==1B11			;NEGOTIATION TIME-OUT STARTED
MSKSTR NVTMO,TTNETW,NV%TMO
DEFSTR NVSTP,TTNETW,14,3	;CURRENT NVT STATE
;THE FOLLOWING NVT STATES ARE STORED IN TTNETW BITS 12-14 (NVSTP)
.DFWIL==1			;DEFERRED WILL
.DFWNT==2			;DEFERRED WONT
.DFDO==3			;DEFERRED DO
.DFDNT==4			;DEFERRED DONT
.DFIAC==5			;DEFERRED IAC
NV%GAB==1B15			;BIT IN TTNETW -- SUPPRESS GO-AHEAD
MSKSTR NVGAB,TTNETW,NV%GAB
NV%CRI==1B16			;BIT IN TTNETW, LAST CHAR IN WAS CR
MSKSTR NVCRI,TTNETW,NV%CRI
NV%CRP==1B17			;BIT IN TTNETW -- LAST CHAR OUT WAS CR
MSKSTR NVCRP,TTNETW,NV%CRP

TTBRKC=TTDDLN			;BREAK CLASSES FOR NVT'S
DEFSTR PBRCT,TTBRKC,8,9 ;BITS 0-8: OUTSTANDING BREAK COUNT
				;BITS 9-17: LAST RCTE COMMAND SENT
				;BITS 18-35: LAST BREAK CLASSES SENT
MAXBRC==777


NVTOPF=TTDDLN+1			;LH -- BIT FOR EACH OPTION IN PROGRESS
				;RH -- BIT FOR RESULT OF EACH OPTION

;TVTLEN IS DEFINED IN TTYDEF
;TEMP CODE TO DO TTYDIS AND TTYAWK CODE. REMOVED FROM TTYSRV

;ROUTINES TO ADJUST LOCK STATUS BEFORE AND AFTER DISMISSING.
;THIS CODE PUTS AN ENTRY ON THE JSB STACK IN THE EVENT THE PROCESS
;IS INTERRUPTED WHILE DISMISSED.

;PUT ENTRY ON JSB STACK, AND GO OKINT
;ACCEPTS:	T2/ ADDRESS OF DYNAMIC DATA

TTYDIS:	JE TTLCK,(T2),R		;THIS IS A HACK TO KEEP FSIINI HAPPY.
				;SINCE THE SWAPPABLE MONITOR IS NOT
				;LOADED YET, WE CAN'T USE THE NORMAL
				;LOCKING STATEGY. THIS IS ACCEPTABLE
				;HERE SINCE NO CONFUISION CAN RESULT.
	SKIPE INSKED		;IN THE SCHEDULER?
	RET			;YES. DON'T MANIPULATE THE JSB STACK
	SAVET			;SAVE ALL REGISTERS
	LOAD T1,TINTL,(T2)	;GET INTERNAL LINE NUMBER
	MOVEI T2,STKCD3		;GET PROPER CODE
	CALL JSBSTK		;QUEUE UP THE ENTRY
	OKINT			;ALLOW INTS NOW
	RET			;AND DONE

;DISMISS WAS SATISFIED. DEQUEUE THE ENTRY AND GO NOINT

TTYAWK:	JE TTLCK,(T2),R		;THIS IS A HACK TO KEEP FSIINI HAPPY.
				;SINCE THE SWAPPABLE MONITOR IS NOT
				;LOADED YET, WE CAN'T USE THE NORMAL
				;LOCKING STATEGY. THIS IS ACCEPTABLE
				;HERE SINCE NO CONFUISION CAN RESULT.
	SKIPE INSKED		;IN THE SCHEDULER?
	RET			;YES. DON'T MANIPULATE THE JSB STACK
	SAVET			;SAVE ALL REGISTERS
	NOINT			;PREVENT INTS
	LOAD T1,TINTL,(T2)	;GET INTERNAL LINE NUMBER
	MOVEI T2,STKCD3		;GET TYPE
	CALLRET JSFRMV		;REMOVE ENTRY AND DONE
;TCOBN - ENTRY FOR BINARY OUTPUT. NO TRANSLATION NO LINKS.
;TCOBQ - ENTRY FOR BINARY OUTPUT. NO TRANSLATION NO LINKS.
; NO SPECIAL HANDELING
	RESCD

;ACCEPTS:
;	T1/ CHARACTER (UP TO 9 BITS)
;	T2/ ADDRESS OF DYNAMIC DATA

;	CALL TCOBN

;RETURNS +1: ALWAYS


TCOBQ:				;HERE FOR NOW EVENTUAL WILL GO PAST
				; SPECIAL CHARATER VECTOR CALL
TCOBN:	SAVELN			;SAVE LINE NUMBER
	ANDI T1,377		;8 BITS OF CHARACTER
	CALL TCOU6		;GO OUTPUT THE CHARACTER WITHOUT ADDING
				; PARITY OR DOING LINKS
	RET			;RETURN
;TTC7SN - LINE IS A NVT. SEE IF NVT LOGINS ARE ALLOWED

TTC7SN::TXNE T1,SF%NVT		;SEE IF NVT LOGINS ALLOWED
	JRST RTRUE		;YES, GO LOGIN IN
	HRROI T1,[ASCIZ/
?Internet logins are currently disallowed
/]
	CALL TTEMES
	JRST RFALSE		;FAIL

;CKNNVT - CHECK IF THIS NVT IS USING NEW PROTOCOL
;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA
;	CALL CKNNVT

;RETURNS +1: OLD NVT PROTOCOL
;	 +2: NEW NVT PROTOCOL

CKNNVT:	JE NVNNV,TTNETW(T2),R	;OLD NVT PROTOCOL?  RETURN
	RETSKP			;NEW PROTOCOL. SKIP RETURN

TVTSOF::			;SET BUFFER COUNT FOR TVTS
	MOVE T4,IBFRC1		;TVTs NEED MULTIPLE BUFFERS
	MOVEM T4,TTBFRC(T1)	;SET COUNT FIELDS
IFN STANSW,<;;; Try to assign enough output buffers to fill an
	    ;;; entire network packet.  This is a workaround -
	    ;;; network packet should BE the output buffers.
	LOAD T4,PTVT,(T1)	;get TCB
	IFN. T4
	 SETSEC T4,INTSEC
	 LOAD T2,TSMXP,(T4)	;get maximum packet size
	ELSE.
	 MOVEI T2,^D576		;no TCB.  Assume Minimum standard Maximum
	ENDIF.
	IDIVI T2,NCHBF		;how many output buffers fit in a packet?
	CAIN T2,0		;less than one buffer per packet ?
	 MOVEI T2,1
	CAILE T2,TOMAX/NCHBF	;but not more characters than fit in TOMAX
	 MOVEI T2,TOMAX/NCHBF	; (assumes TOMAX is rightmost field!)
	STOR T2,TTNOU,(T1)	;use that as the number of output buffers
	IMULI T2,NCHBF		;how many character will this be?
	SUBI T2,2		; subtract 2 as per IBFRC calc in STG (?)
	STOR T2,TOMAX,(T1)
>;IFN STANSW
	
	RET			;AND RETURN
;NVTXGA - SEND GA

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURNS +1:  ALWAYS

NVTRRR:	STKVAR<NVTCH>
NVTRR0:	SETZM NVTCH		;ASSUME ZERO COMMAND
	JE NVRCS,TTNETW(T2),NVTRR1 ;ANY CHANGE IN STATE?
				; NO, BYPASS THIS NONSENSE.
	CALL GTBRKC		;GET BREAK CLASSES
	MOVEM T1,NVTCH		;SAVE THAT
	CALL GTSPCC		;GET BREAK CLASS FOR SPECIAL ECHO CHAR.
	IORM T1,NVTCH		;MUST BREAK ON ALL OF THEM
	SKIPE T1		;ANY SPECIAL BREAKS?
	 MOVEI T1,2		;YES, SUPPRESS ECHO OF BREAKS
	MOVE T3,TTFLGS(T2)	;GET FLAGS
	TXNN T3,<TT%ECO!TT%ECM>	;NO ECHO WANTED?
	 IORI T1,6		;SUPPRESS ALL ECHOES
	TXC T3,<TT%ECO!TT%ECM>
	TXCN T3,<TT%ECO!TT%ECM>	;SUPPRESS ECHOES OF BREAKS?
	 IORI T1,2		;YES, ...
	IORI T1,11		;CAUSE BREAK CLASS TO CHANGE
	HRLM T1,NVTCH		;SAVE THE COMMAND
	SKIPA T1,[^D10]		;NEED 4 CHARS FOR BREAK CLASSES
NVTRR1:	MOVEI T1,6		;NEED 6 FOR SB ETC
	CALL NVTRSV		;RESERVE SPACE
	 RET			;RETURN
	MOVEI T1,SBCH		;BEGINNING OF SUBNEGOTIATIONS
	CALL NVTSSP		;SEND IAC-SB
	MOVEI T1,RCTOPT
	CALL TCOBQ		;SAY WHICH OPTION WE ARE CHANGING
	HLRZ T1,NVTCH		;GET COMMAND
	CALL TCOBN		;SEND THE COMMAND
	 JUMPE T1,NVTRR3	;NO CHANGE, SKIP THE FOLLOWING
	HRRZ T1,NVTCH		;GET NEW BREAK CLASSES
	LSH T1,-8		;GET HIGH ORDER BYTE
	CALL TCOBN		;SEND IT
	HRRZ T1,NVTCH		;AND LOW ORDER TOO.
	CALL TCOBN		;SEND LOW ORDER BYTE
NVTRR3:	MOVEI T1,SECH		;END OF SUBNEGOTIATIONS
	CALL NVTSSP		;SEND SE
	LOAD T1,PBRCT,(T2)	;GET OUTSTANDING BREAKS
	MOVE T3,NVTCH		;GET BREAK INFO BACK
	SKIPE T3		;SKIP IF NONE
	MOVEM T3,TTBRKC(T2)	;SET NEW CURRENT BREAK CLASSES
	SOS T1			;DECREMENT OUTSTANDING BRKS
	STOR T1,PBRCT,(T2)	;STORE BACK
	SETZRO NVRCS,TTNETW(T2)	;CANCEL STATE CHANGE
	OKSKD1
	JUMPN T1,NVTRR0		;REPEAT IF BREAKS STILL OUTSTANDING
	RET
	ENDSV.
; TABLE OF BREAK CLASS FOR EACH CHARACTER

U==1
L==2
N==4
FC==10
CC==20
K6==40
K7==100
K8==200
K9==400

CHWTB:	BYTE(9)CC,CC,CC,CC,CC,CC,CC,CC	; ^@ - ^G
	BYTE(9)FC,FC,FC,FC,FC,FC,CC,CC	; ^H - ^O
	BYTE(9)CC,CC,CC,CC,CC,CC,CC,CC	; ^P - ^W
	BYTE(9)CC,CC,CC,CC,CC,CC,CC,FC	; ^X - EOL
	BYTE(9)K9,K6,K8,K8,K8,K8,K8,K8	; SPACE - '
	BYTE(9)K7,K7,K8,K8,K6,K8,K6,K8	; ( - /
	BYTE(9)N,N,N,N,N,N,N,N		; DIGITS
	BYTE(9)N,N,K6,K6,K7,K8,K7,K6	; 8, 9 - ?
	BYTE(9)K8,U,U,U,U,U,U,U		; @ - G
	BYTE(9)U,U,U,U,U,U,U,U		; H - O
	BYTE(9)U,U,U,U,U,U,U,U		; P - W
	BYTE(9)U,U,U,K7,K8,K7,K8,K8	; X - _
        BYTE(9)K8,L,L,L,L,L,L,L		; ' - g
	BYTE(9)L,L,L,L,L,L,L,L		; h - o
	BYTE(9)L,L,L,L,L,L,L,L		; p - w
	BYTE(9)L,L,L,K7,K7,K7,K8,CC	; x - RUBOUT

;GTBRKC - GET TERMINAL BREAK CLASSES

;ACCEPTS:
;	T2/ DYNAMIC DATA ADDRESS

;RETURNS +1: ALWAYS
;	T1/ BREAK CLASSES


GTBRKC:	SETZ T1,
	MOVE T3,TTFLGS(T2)
	TXNE T3,TT%WKA		;BREAK ON ALPHANUMERICS
	 TRO T1,7		;UPPER AND LOWER CASE AND NUMBERS
	TXNE T3,TT%WKP		;PUNCTUATION
	 TRO T1,740
	TXNE T3,TT%WKN		;NON-FORMATTING CONTROLS
	 TRO T1,20
	TXNE T3,TT%WKF		;FORMATTERS
	 TRO T1,10
	RET
;GTSPCC - GET BREAK CLASS FOR CHARACTERS NEEDING SPECIAL ECHOES

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURNS +1: ALWAYS
;	T1/ BREAK CLASS FOR CHARACTERS NEEDING SPECIAL OUTPUT

GTSPCC:	STKVAR<NVCOC1,NVCOC2,NVFMCC>
	CALL TTYGPI		;GET PI CHARACTERS AS COCFORMAT
	MOVE T1,NVCOC1		;SAVE COC WORDS FROM TTYGPI
	MOVE T3,NVCOC2
	CALL TTRCOC		;GET CONTROL CHAR OUTPUT MODES
	ANDCMI T3,377		;ONLY CONTROL CHARACTERS
	IORI T3,2B<40*2-^D36+1>	;FAKE A NORMAL ECHO FOR SPACE
	ANDCM T3,NVCOC2		;FORCE ZEROES FOR INT CHARS
	ANDCM T1,NVCOC1
	XOR T1,NVTNMD		;COMPARE TO ASSUMED ECHO MODE
	XOR T3,NVTNMD+1
	MOVE T1,NVFMCC		;SAVE T1
	MOVEI T1,FC		;ASSUME NEEDS FORMATTERS
	EXCH T1,NVFMCC		;SAY SO AND GET T1 BACK
	TDZN T1,[BYTE (2)0,0,0,0,0,0,0,0,3,3,3,3,3,3]
	TDNE T3,[BYTE (2)0,0,0,0,0,0,0,0,0,0,0,0,0,3]
	 SKIPA
	 SETZM NVFMCC		;NOT NEEDED AFTER ALL
	TDZN T1,[BYTE (2)3,3,3,3,3,3,3,3,0,0,0,0,0,0,3,3,3,3]
	TDNE T3,[BYTE (2)3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3]
	 MOVEI T1,CC		;NEED SPECIAL ECHO FOR NON-FORMATTERS
	IOR T1,NVFMCC
	TRNE T3,<BYTE (2)0,0,0,0,0,0,0,0,0,0,0,0,0,0,3>	; SPACE?
	 IORI T1,K9		;NEED SPECIAL ECHO FOR SPACE
	RET
	ENDSV.
;TTYGPI - GET NORMAL MODES FOR ECHO (MUST AGREE WITH THAT IN USER TELNET)

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURNS +1: ALWAYS
;	T1/ COC1 WORD BASED ON INTERRUPT CHARACTERS
;	T3/ COC2 WORD BASED ON INTERRUPT CHARACTERS


TTYGPI:	STKVAR<NVTCC1,NVTCC2,NVDYND>
	SETZM NVTCC1		;ZERO COC TYPE WORDS HERE
	SETZM NVTCC2
	MOVEM T2,NVDYND		;NEED THIS ACCUMULATOR
	MOVE T1,TTPSI(T2)	;GET PSI BITS
	ANDCMI T1,77		;MASK OUT EXTRANEOUS BITS
	TRZE T1,100		;IS SPACE AN INTERRUPT?
	 TRO T1,10		;YES, SET BIT 40(8)
	TRZE T1,20		;RUBOUT?
	 TRO T1,4		;SET BIT 41(8)
	LSH T1,-1		;AVOID SIGN BIT
TTGPI1:	MOVN T2,T1		;COMPLEMENT ALL BUT RIGHTMOST 1
	AND T2,T1		;GET JUST THAT BIT
	ANDCAM T2,T1		;CLEAR IT
	MUL T2,T2		;SQUARE IT
	LSH T3,1		;FILL THE GAP
	IORB T3,NVTCC2		;OR IN BITS
	IORB T2,NVTCC1
	JUMPN T1,TTGPI1		;LOOP TILL ALL ARE DONE
	LSHC T2,1
	IOR T2,NVTCC1		;OR IN BITS
	IOR T3,NVTCC2
	LSHC T2,1
	MOVE T1,T2		;MOVE FIRST WORD TO T1
	MOVE T2,NVDYND		;RESTORE ADDRESS OF DYNAMIC DATA
	RET
	ENDSV.

NVTNMD:	BYTE (2)0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2
;TTCOBN - NVT CLEAR OUTPUT BUFFERS
;ENTERS CLEAR BUFFER ROUTINE AFTER DEVICE DEPENDENT CODE TO PREVENT
; LOOPING

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA


;RETURNS +1: ALWAYS


TTCOBN:	NOSKD1
	CHNOFF DLSCHN
	CALLRET TTCOB5

;NVTDOB - PERFORM DOBE SEQUENCE CALLED FROM TTDOBE

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA

;	TDJRST OFF VDOBE	;DOBE


;RETURNS +1: ALWAYS


NVTDOB:	CALL CKNNVT		;NEW NVT?
	 RET			;NO. JUST RETURN
	MOVEI T1,TMKOPT		;TIMING MARK OPTION
	CALL NVTNGT		;GO NEGOTIATE OPTION
	 JFCL			;IGNORE FAILURE
	RET
;NVTPAR - CHECK STPAR ARGUMENT AND NEGOTIATE ANY NEEDED OPTIONS


;ACCEPTS:
;	T1/ NEW JFN MODE WORD
;	T2/ ADDRESS OF DYNAMIC DATA

;	TDCALL OFF VSTPAR	;STPAR JSYS


;RETURNS +1: ALWAYS

TVTPAR::STKVAR<NVJFMW>
	MOVEM T1,NVJFMW		;SAVE NEW JFN MODE WORD
	CALL CKNNVT		;NEW NVT?
	 JRST NVTPA1		;NO OLD STYLE
	MOVE T3,T1		;COPY NEW STATE
	XOR T1,TTFLGS(T2)	;GET DIFFERENCE
	TXNN T1,TT%DUM		;CHANGE IN ECHO?
	 JRST NVTPA2		;NO, TRY NEXT
	MOVX T1,ECHOPT+WILOPT	;ECHO OPTION REQUEST
	TXNN T3,TT%DUM		;NEGOTIATE ON?
	SKIPA T3,[IFIW!NVTNGT]	;YES NEGOTIATE ECHO
	MOVE T3,[IFIW!NVTNGF]	;NO
	CALL @T3		;CALL THE ROUTINE
	 SKIPA			;SET TO LINE HALF DUPLEX
	JRST NVTPA2		;CHECK FOR OTHER NEGOTIATIONS
	SETONE TT%DUM,NVJFMW	;SET IT	TO LINE HALF DUPLEX


NVTPA2:				;OTHER CHECKS GO HERE IF ANY
NVTPAX:	MOVE T1,NVJFMW		;RESTORE NEW JFN MODE WORD
	RET


NVTPA1:	XOR T1,TTFLGS(T2)	;GET ANY CHANGES
	TXNN T1,TT%DUM		;DUPLEX MODE
	 JRST NVTPAX		;NONE EXIT
	MOVE T1,NVJFMW
	TXNE T1,TT%DUM		;IS NEW FULL?
	 SKIPA T1,[204]		;NO. SEND "YOU ECHO"
	  MOVEI T1,203		;YES. SEND "I ECHO"
	CALL TCOBN
	JRST NVTPAX		;RETURN
	ENDSV.
;NVTNGT - NEGOTIATE AN OPTION

;ACCEPTS:
;	T1/ OPTION REQUEST
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: FAILURE COULD NOT GET OPTION
;	+2: SUCCESS GOT OPTION

NVTNGT:	MOVEI T3,[IFIW!NVTXWL	;GET ADDRESS OF WILL
		IFIW!NVTXDO]	; AND DO ROUTINES
	CALL NVTNGC		;GO NEGOTIATE THEM
	 AOS 0(P)		;SUCCESS
	RET			;FAILURE

;NVTNGF - REFUSE OPTION

;ACCEPTS:
;	T1/ OPTION REQUEST
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: SUCCESS REFUSED OPTION
;	+2: FAILURE COULD NOT REFUSE OPTION


NVTNGF:	MOVEI T3,[IFIW!NVTXWN	;GET ADDRESS OF WON'T
		IFIW!NVTXDN]	; AND DON'T ROUTINES
NVTNGC:	CAIL T1,MAXOPT		;LEGAL OPTION
	 RET			;NO
	STKVAR<NNGOPT,NNGADD,NNGDAD>
	NOINT			;MAKE SURE WE ARE NOT INTERRUPTABLE
	MOVEM T1,NNGOPT		;SAVE OPTION
	MOVEM T2,NNGDAD		;AND ADDRESS OF DYNAMIC DATA
	MOVEM T3,NNGADD		;AND ADDRESS OF ROUTINES
	MOVE T3,BITS(T1)	;CONVERT OPTION TO FLAG BITS
	IORM T3,NVTOPF(T2)	;SET OPTION NEGOTIATION IN PROGRESS BIT
	TRZN T1,WILOPT		;ARE WE ASKING FOR THIS OPTION
	AOS NNGADD		;NO.  BUMP TO DO OR DON'T
	MOVE T3,NNGADD		;GET ADDRESS OF ROUTINE
	CALL @0(T3)		;SAY "DO, WIL, DONT, WONT"
	MOVE T1,NNGOPT		;GET OPTION BACK
	ROT T1,-9		;INTO TOP 9 BITS
	MOVE T2,NNGDAD		;GET DYNAMIC DATA ADDRESS
	CALL TTYDIS		;SET UP FOR DISMISS
	MOVE T2,NNGDAD		;GET DYNAMIC DATA ADDRESS
	DYNST			;GET STATIC LINE NUMBER
	MOVSS T2		;MOVE IT TO THE LEFT HALF
	IOR T1,T2		;LINE NUMBER IN 9-17
	HRRI T1,NVTNTT		;ACTIVATION TEST
	MDISMS
	MOVE T2,NNGDAD		;GET ADDRESS OF DYNAMIC DATA
	CALL TTYAWK		;GO NOINT AGAIN
	SETZRO NVTMO,TTNETW(T2) ;CANCEL ANY TIME-OUT IN PROGRESS
	MOVE T1,NNGOPT		;GET OPTION AGAIN
	MOVS T3,BITS(T1)	;CONVERT TO FLAG
	TDNN T3,NVTOPF(T2)	;IS IT OFF
	 AOS 0(P)		;SKIP IF SUCCESSFUL
	OKINT			;INTERRUPTS ARE NOW OK
	RET
	ENDSV.
;NVTNTT - WAIT ROUTINE FOR NVT NEGOTIATIONS

;ACCEPTS T1/  BITS 18-26  OPTION NUMBER
;	      BITS 27-35  TTY NUMBER

NVTNTT:	LDB T3,[POINT 9,1,26]	;GET OPTION NUMBER
	MOVE T3,BITS(T3)
	ANDI T1,777		;LINE NUMBER
	MOVE T2,T1		;GET LINE NUMBER IN T2
	CALL STADYN		;GET ADDRESS OF DYNAMIC DATA
	 JRST T1(T4)		;NOT ACTIVE. THIS SHOULD NOT HAPPEN
	SKIPE TTNETW(T2)	;SATISFIED IF DISCONNECTED
	TDNN T3,NVTOPF(T2)
	 JRST 1(T4)		;NEGOTIATION COMPLETE
	JRST 0(T4)

NVTSTD:	IFIW!NVTNRM		;NOTHING DEFERRED
	IFIW!NVTWIL		;DEFERRED WILL
	IFIW!NVTWNT		;DEFERRED WONT
	IFIW!NVTDO		;DEFERRED DO
	IFIW!NVTDNT		;DEFERRED DONT
	IFIW!NVTIAC		;DEFERRED IAC
	IFIW!NVTNRM		;NOT USED
	IFIW!NVTNRM		;NOT USED
;NVTNRM - NORMAL NVT CHARACTER PROCESSING

;ACCEPTS:
;	T1/ CHARACTER
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: ALWAYS

NVTNRM:	CAIL T1,200		;POSSIBLE NVT CONTROL CHARACTER?
	 JRST NVTCTL		;PROCESS POSSIBLE NVT CONTROL CHARACTER
NVTDCH:	MOVE T3,NVTOPF(T2)
	TXNE T3,<1B<BINOPT+^D18>>
	 JRST NVTUPB		; Binary, skip special checks
	JE NVCRI,TTNETW(T2),[	;WAS LAST CH CR?
		CAIE T1,.CHCRT	;NO. IS THIS ONE?
		 JRST NVTUPB	;NO, PROCEED NORMALLY
		SETONE NVCRI,(T2) ;YES, REMEMBER IT
		JRST NVTUPB]	;AND SEND IT ON
	SETZRO NVCRI,(T2)	;YES, FORGET THAT
	JUMPE T1,R		;NULL?
	CAIN T1,.CHLFD		;WAS THIS ONE A LINE FEED
	RET			;YES, FORGET IT
NVTUPB:	SETZ Q2,		;NO SPECIAL FLAGS
	PUSH P,Q1		;SAVE Q1
	DYNST			;GET LINE NUMBER FOR TTCHI
	NOSKD1			;TTCHI EXPECTS TO BE CALLED NOSKED
	CALL TTCHI		;STUFF IT IN TTY BUFFER
	 NOP			;IGNORE ERROR RETURN
	OKSKD1
	POP P,Q1
	RET
;NVTCTL - TELNET CONTROL CODES RECEIVED

;ACCEPTS:
;	T1/ CHARACTER
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: ALWAYS

NVTCTL:	SKIPGE TTNETW(T2)	;IF NO SOCKETS ATTACHED,
	 JRST NVTDCH		;IGNORE CHAR
	CALL CKNNVT		;NEW STYLE NVT?
	 JRST NVTCT0		;NO, LOOK FOR OLD STYLE COMMANDS
	CAIE T1,IACCH		;YES, IS IAC
	 JRST NVTDCH		;NO, CONTINUE PROCESSING
	JRST NVTCL4		;YES. TAKE CARE OF IT

NVTCT0:	CAIN T1,202		;NOP
	 RET
	CAIN T1,200		;SYNC CHAR?
	 JRST NVTCL1
	CAIN T1,203		;ECHO OFF?
	 JRST NVTCL2
	CAIN T1,204		;ECHO ON?
	 JRST NVTCL3
	JRST NVTDCH

NVTCL1:	PUSH P,T1		;SAVE A TEMP AC
	LOAD T1,PTITC,(T2)	;SYNC COUNTS 1, INS COUNTS -1
	AOJ T1,
	STOR T1,PTITC,(T2)
	POP P,T1		;RESTORE THE AC
	RET

NVTCL3:	TDZA T1,T1		;FULLDUPLEX ZERO AC AND SKIP
NVTCL2:	MOVEI T1,.TTLDX		;LINE HALF DUPLEX
	STOR T1,TT%DUM,TTFLGS(T2) ;SET DUPLEX MODE FULL/HALF
	RET

;PROCESS IAC

NVTCL4:	MOVEI T3,.DFIAC		;SET TO DEFFERED IAC
	STOR T3,NVSTP,(T2)
	RET
;NVTIAC - PROCESS BYTE AFTER IAC

;ACCEPTS:
;	T1/ CHARACTER
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: ALWAYS


NVTIAC:	CAIGE T1,SECH		;END OF SUBNEGOTIATIONS
	 RET			;NOT A VALID COMMAND
	SETONE NVNNV,TTNETW(T2)	;MARK THIS NEW PROTOCOL
	SETZ T3,		;NEXT STATE IF ANY
	XCT NVTDTB-SECH(T1)	;DISPATCH ON THE CHARACTER
	 JRST NVTDCH		;SPECIAL FUNCTION CHARACTER
	STOR T3,NVSTP,(T2)	;NEXT STATE
	RET

NVTDTB:	RET			;(360) END OF SUBNEGOTIATION
	RET			;(361) NOP -- IGNORE
	JRST NVTCL1		;(362) NEW DATA MARK
	RET			;(363) BREAK -- IGNORE
	MOVEI T1,3		;(364) IP -- CONVERT TO ^C
	MOVEI T1,"O"-100	;(365) AO -- CONVERT TO ^O
	MOVEI T1,"T"-100	;(366) AYT -- CONVERT TO ^T
	MOVEI T1,177		;(367) EC -- CONVERT TO DEL
	MOVEI T1,"U"-100	;(370) EL -- CONVERT TO ^U
	RET			;(371) GA -- IGNORE
	RET			;(372) SB -- SHOULDN'T GET THIS
	TROA T3,.DFWIL		;(373) DEFER WILL
	TROA T3,.DFWNT		;(374) DEFER WONT
	TROA T3,.DFDO		;(375) DEFER DO
	TROA T3,.DFDNT		;(376) DEFER DONT
	JFCL			;(377) IAC IAC -- IAC
;NVTSSP - SEND SPECIAL CHARACTER

;ACCEPTS:
;	T1/ CHARACTER
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: ALWAYS

NVTSSP:	PUSH P,T1		;SAVE CHARACTER
	MOVEI T1,2		;NEED 2 CHARACTERS
	CALL NVTRSV		;RESERVE SPACE IN BUFFER (NOSKED)
	 JRST [	POP P,T1	;COULDN'T GET DON'T WAIT
		RET]		;RETURN
	HRROI T1,IACCH		;SAME AS 377, BUT PREVENT ITS DOUBLING
	CALL TCOBN		;CALL TCOBN TO GET CR-NULL IF NEEDED
	POP P,T1		;GET BACK SPECIAL CHARACTER
	CALL TCOBQ		;SEND IT
	OKSKD1
	RET
;NVTRSV - RESERVE SPACE IN BUFFER FOR CHARACTERS SPECIFIED IN 1

;ACCEPTS:
;	T1/ NUMBER OF CHARACTERS
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: FAILURE NO ROOM
;	+2 SUCCESS

NVTRSV:	NOSKD1			;MAKE SURE SPACE DOESN'T DISAPPEAR
	LOAD T3,TOMAX,(T2)	;MAXIMUM BYTES IN OUTPUT BUFFER
	SUB T3,TTOCT(T2)	;SPACE IN OUTPUT BUFFERS
	CAML T3,T1		;WILL THEY FIT
	 RETSKP			;YES. ENOUGH ROOM, RETURN SKIP
	OKSKD1
	MOVE T3,FORKX		;GET FORK NUMBER
	CAMN T3,INTFRK		;IS THIS THE INTERNET FORK?
	 RETBAD			;YES SO JUST RETURN
	SKIPN INSKED		;IN THE SCHEDULER
	SKIPE NSKED		;OR NO SKED
	RETBAD			;YES TELL HIM THERE WAS NO ROOM
	PUSH P,T1		;NO. WAIT FOR SPACE
	PUSH P,T2		;SAVE ARGUMENTS
	MOVEI T1,TCOTST		;GET ADDRESS OF WAIT ROUTINE
	CALL TTYDIS		;SET UP FOR DISMISS
	DYNST			;GET LINE NUMBER
	HRL T1,T2		;MOVE IT TO THE LEFT HALF
	MDISMS			;WAIT FOR SPACE
	POP P,T2		;RESTORE ARGUMENTS
	CALL TTYAWK		;GO NOINT AGAIN
	POP P,T1
	JRST NVTRSV		;TRY AGAIN
;NVTRFU - SEND WONT (REFUSE)

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA
;	OPTION ON TOP OF STACK

;RETURN +1: ALWAYS


NVTRFU:	MOVEI T1,WNTCH

;NVTSRP - SEND REPLY IN 1 FOR OPTION ON STACK

;ACCEPTS:
;	T1/ REPLY
;	T2/ ADDRESS OF DYNAMIC DATA
;	OPTION ON TOP OF STACK

;RETURN +1: ALWAYS


NVTSRP:	PUSH P,T1		;SAVE REPLY
	MOVEI T1,3
	CALL NVTRSV		;RESERVE SPACE FOR THREE CHARACTERS
	 JRST [	ADJSP P,-2	;NO ROOM CLEAN UP STACK
		RET]
	HRROI T1,IACCH		;SAME AS 377 BUT PREVENT DOUBLING
	CALL TCOBN		;USE TCOBN TO GET CR-NULL IF NEEDED
	POP P,T1		;GET REPLY
	CALL TCOBQ		;SEND IT
	POP P,T1		;GET OPTION
	CALL TCOBQ		;SEND IT
	OKSKD1
	RET
;NVTSWL - SEND WILL

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA
;	OPTION ON TOP OF STACK

;RETURN +1: ALWAYS

;NVTXWL - ENTRY FOR OPTION IN T1


NVTXWL:	PUSH P,T1		;SAVE OPTION
NVTSWL:	MOVEI T1,WILCH		;ENTER HERE WHEN OPTION IS ON STACK
	JRST NVTSRP		;SEND REPLY



;NVTSNR - SEND NO REPLY

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA
;	OPTION ON TOP OF STACK

;RETURN +1: ALWAYS


NVTSNR:	ADJSP P,-1		;NO REPLY NECESSARY OR POSSIBLE
	RET
;NVTSWN - SEND WONT

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA
;	OPTION ON TOP OF STACK

;RETURN +1: ALWAYS

;NVTXWN - ENTRY FOR OPTION IN T1


NVTXWN:	PUSH P,T1		;SAVE OPTION
NVTSWN:	MOVEI T1,WNTCH		;ENTER HERE WHEN OPTION ALREADY PUSHED
	JRST NVTSRP



;NVTSDO - SEND "DO"

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA
;	OPTION ON TOP OF STACK

;RETURN +1: ALWAYS

;NVTXDO - ENTRY FOR OPTION IN T1


NVTXDO:	PUSH P,T1		;SAVE OPTION
NVTSDO:	MOVEI T1,DOCH		;ENTER HERE WHEN OPTION ALREADY PUSHED
	JRST NVTSRP
;NVTSDN - SEND "DONT"

;ACCEPTS:
;	T2/ ADDRESS OF DYNAMIC DATA
;	OPTION ON TOP OF STACK

;RETURN +1: ALWAYS

;NVTXDN - ENTRY FOR OPTION IN T1


NVTXDN:	PUSH P,T1		;SAVE OPTION
NVTSDN:	MOVEI T1,DNTCH		;ENTER HERE WHEN OPTION ALREADY PUSHED
	JRST NVTSRP
;NVTDO - PROCESS "DO"

;ACCEPTS:
;	T1/ OPTION
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: ALWAYS


NVTDO:	CAIL T1,WILOPT		;ARE WE WILLING?
	 JRST NVTDO1		;NO
	MOVE T3,BITS+WILOPT(T1)	;YES GET FLAG BITS
	TDNE T3,NVTOPF(T2)	;OUTSTANDING REQUEST
	 JRST NVTWI2		;YES GO PROCESS IT
NVTDO1:	PUSH P,T1		;REMEMBER THE OPTION
	MOVSS T3			;PUT BIT IN "OPTIONS ON" HALF
	TDNE T3,NVTOPF(T2)	;IS THE OPTION ON?
	 JRST NVTSNR		;YES, SEND NO REPLY
	CAIGE T1,NVTLOP		;DO WE KNOW ABOUT THIS OPTION
	 CALL @NVTDOD(T1)	;YES. ATTEMPT EXECUTION
	  JRST NVTRFU		;CAN'T DO IT -- REFUSE
	IORM T3,NVTOPF(T2)	;SET OPTION ON
	JRST NVTSWL		;AND SEND "WILL"

NVTDOD:	IFIW!RSKP		;BINARY XMIT -- OK WITH US
	IFIW!NVTECN		;TURN ECHOS ON
	IFIW!R			;RECONNECT -- REFUSE FOR NOW
	IFIW!NVTSGA		;SUPPRESS GA -- WONDERFUL NEWS
	IFIW!R			;MESSAGE SIZE -- REFUSE
	IFIW!R			;STATUS -- REFUSE
	IFIW!NVTDTM		;TIMING MARK -- TRY TO DO IT
;	IFIW!NVTDRC		;REMOTE CONTROLLED TRANS & ECHO
	IFIW!R			;DO NOT DO IT FOR NOW
NVTLOP=.-NVTDOD

;ACTION ROUTINES FOR "DO"
;TURN ECHOES ON

NVTECN:	MOVX T1,TT%DUM
	ANDCAM T1,TTFLGS(T2)	;SET TO FULL DUPLEX
	RETSKP

;SET SUPPRESS GA BIT

NVTSGA:	SETONE NVGAB,TTNETW(T2)
	RETSKP

;DO TIMING MARK PROTOCOL

NVTDTM:	RETSKP
;NVTDNT - PROCESS "DONT"

;ACCEPTS:
;	T1/ OPTION
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: ALWAYS

NVTDNT:	CAIL T1,WILOPT		;ARE WE WILLING FOR THIS OPTION
	 JRST NVTDN1		;NO
	MOVE T3,BITS+WILOPT(T1)	;GET FLAG BITS
	TDNE T3,NVTOPF(T2)	;OUTSTANDING REQUEST
	 JRST NVTWN2		;YES
NVTDN1:	PUSH P,T1		;SAVE OPTION
	MOVSS T3		;PUT BIT IN "OPTION ON" HALF
	TDNN T3,NVTOPF(T2)	;OPTION ALREADY OFF?
	 JRST NVTSNR		;YES. SEND NO REPLY
	CAIGE T1,NVTLOP		;DO WE KNOW ABOUT THIS OPTION?
	 CALL @NVTDND(T1)	;YES. PERFORM ACTION
	ANDCAM T3,NVTOPF(T2)	;CLEAR THE OPTION
	JRST NVTSWN		;AND SEND "WON'T"

NVTDND:	IFIW!R			;DILEMMA -- HE WANTS OFF, BUT WE CAN'T
	IFIW!NVTECF		;ECHO OFF
	IFIW!R			;OPTION NOT ON, NO REPLY
	IFIW!NVTAGA		;HE WONT SUPPRESS GA -- NUTS
	IFIW!R			;MESSAGE SIZE OPTION
	IFIW!R			;STATUS OPTION
	IFIW!R			;TIMING MARK -- HUH?
	IFIW!R			;TURN OFF RCTE

;"DONT" ACTION ROUTINES
;TURN ECHOS OFF

NVTECF:	MOVX T1,TT%DUM		;DUPLEX MODE
	IORM T1,TTFLGS(T2)	;SET TO LINE HALF DUPLEX
	RET

;TURN OFF SUPPRESS GA BIT

NVTAGA:	SETZRO NVGAB,TTNETW(T2)
	RET
NVTWIL - ;PROCESS "WILL"

;ACCEPTS:
;	T1/ OPTION
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: ALWAYS


NVTWIL:	CAIL T1,WILOPT		;ONLY WILOPT OPTIONS
	 JRST NVTWI1		;OTHERS CANNOT BE OUTSTANDING
	MOVE T3,BITS(T1)	;GET THE BIT FOR THE OPTION
	TDNN T3,NVTOPF(T2)	;IS THIS OPTION OUTSTANDING?
	 JRST NVTWI1		;NO.
NVTWI2:	MOVS T1,T3		;PUT BITS IN OPTION ON HALF
	IORM T1,NVTOPF(T2)	;SET WILL BIT
	ANDCAM T3,NVTOPF(T2)	;AND CLEAR OUTSTANDING BIT
	RET

NVTWI1:	PUSH P,T1		;SAVE THE OPTION
	MOVSS T3		;PUT BIT IN "OPTONS ON" HALF
	TDNE T3,NVTOPF(T2)	;IS OPTION ALREADY ON?
	 JRST NVTSNR		;YES. SEND NO REPLY
	CAIGE T1,NVTLOP		;LEGAL OPTION?
	 CALL @NVTWID(T1)	;YES.  CALL ACTION ROUTINE
	  JRST NVTSDN		;UNIMPLEMENTED OPTION OR CAN'T COMPLY
	IORM T3,NVTOPF(T2)	;DONE. SET OPTION "ON"
	JRST NVTSDO		;AND SEND "DO"

NVTWID:	IFIW!RSKP		;WILL BINARY -- DO
	IFIW!R			;WILL ECHO -- DONT
	IFIW!R			;RECONNECT -- DONT
	IFIW!RSKP		;SUPPRESS GA -- DO, DO, DO , DO!
	IFIW!R			;MESSAGE SIZE -- DONT
	IFIW!R			;STATUS -- DONT
	IFIW!R			;TIMING MARK -- HUH?
	IFIW!R			;WHAT'S HE TRYING TO DO?
;NVTWNT - PROCESS "WONT"

;ACCEPTS:
;	T1/ OPTION
;	T2/ ADDRESS OF DYNAMIC DATA

;RETURN +1: ALWAYS


NVTWNT:	CAIL T1,MAXOPT		;LEGAL OPTION
	 JRST NVTWN1		;NO.  OPTION NOT HANDLED
	MOVE T3,BITS(T1)	;GET BIT FOR OPTION
	TDNN T3,NVTOPF(T2)	;IS THIS OPTION OUTSTANDING
	 JRST NVTWN1		;NO. REQUEST
NVTWN2:	HLR T3,T3		;YES. NEG ACKNOWLEDGE
	ANDCAM T3,NVTOPF(T2)	;CLEAR BOTH OUTSTAND AND WILL FLAGS
	RET

NVTWN1:	PUSH P,T1		;SAVE OPTION
	MOVSS T3		;PUT BIT IN "OPTIONS ON" HALF
	TDNN T3,NVTOPF(T2)	;OPTION ALREADY OFF?
	 JRST NVTSNR		;YES. SEND NO RPLY
	ANDCAM T3,NVTOPF(T2)	;STRANGELY ENOUGH, THE USER END
	JRST NVTSDN		;NEVER HAS ANY OPTIONS TO TURN OFF

; TCP PARAMETERS:

LSNPRT==27		; PORT TELNET LISTENS ON
LSNTMO==^D<5*60>	; TIMEOUT
TVTRXP==1001,,1		; TVT RETRANSMISSION PARAMETERS
			; (NO BACKOFF, CONSTANT 1 SECOND)

RS	LSNTIM		; TEMP HOLDER FOR TIME TO TRY ANOTHER LISTEN

;DOES SKIPE TTOCT(B) AND SKIPE TSALC(B) FOR TVTS
;SKIPS ONLY IF ABSOLUTELY NO CHARS TO BE HANDLED FOR LINE
;ACCEPTS DYN LINE # IN B
;RETURNS TTOCT+TSALC IN T1

TVSBE1::CALL TTSOBE
	 JRST TVSBE2		;NO SKIP IF NORMAL OUTPUT TO BE DONE
	OPSTR <SKIPN>,TSALC,(B) ;NO SKIP IF SENDALL TO BE DONE
	 RETSKP			;SKIP ONLY IF ABSOLUTELY NO CHARS
TVSBE2:	OPSTR <ADD A,>,TSALC,(B)
	RET			;NO-SKIP, COUNT IN A

;TVMSNT - TEST TO SEE IF SEND ALL SHOULD BE DONE
;FNCALL OFF TTVT36	One Line
;FNCALL OFF TTVT37	All Lines
;ACCEPTS:
;	T2/ LINE NUMBER
;RETURNS: +1 DO NOT SEND MESSAGE
;	  +2 SEND MESSAGE

	SWAPCD

TVMSNT::SASUBR <MSPT,MSLN,MSCT>
	JUMPL T2,R		; return now if no such lines
	CALL LCKTTY		;GET DYNAMIC DATA ADDRESS IF IT EXIST
	JRST TVMSN1		;NO DYNAMIC DATA DO NOT SEND
	SKIPG TTNETW(T2)	;ANY CONNECTIONS?
	JRST TVMSN1		;NO DO NOT SEND MESSAGE
	CALL ULKTTY		;YES UNLOCK TTY DATABASE
	AOS TVTNOF		;INDICATE OUTPUT FOR TVTS
	MOVE T2,MSCT		;GET COUNT OF CHARACTERS IN MESSAGE
	IMULI T2,TMSNTT		;MULTIPLY BY ALLOWABLE TIME PER CHAR.
	ADD T2,TODCLK		;GET TIME MESSAGE TO BE DISCARDED
	MOVEM T2,TVMSTM		;SAVE TIME FOR TCP FORK
	RETSKP			;SEND MESSAGE

TVMSN1:	CALL ULKTTY		;UNLOCK TTY
	RETBAD			;NO DO NOT SEND MESSAGE
;TVMNTR
;ROUTINE TO CLEAR ALL TVT SNDALL REQUEST

;Called NOSKED from OPSCAN on TVMSTM timeout set by TVMSNT

	RESCD

TVMNTR::MOVE T3,TVTPTR		;GET AOBJN COUNTER FOR TVT'S
TMSNR1:	SKIPN T2,TTACTL(T3)	;GET ADDRESS OF DYNAMIC DATA
	 JRST TMSNR2		;IF NON-STANDARD BLOCK CHECK
	JE TTSAL,(T2),TMSNR2	;IF DOING SENDALL CLEAR IT
	CALL CLRSAL		;CLEAR SENDALL FROM LINE
TMSNR2:	AOBJN T3,TMSNR1		;HAVE WE DONE ALL OF THE LINES
	RET			;YES RETURN
;TVRFIL
;Routine to signal TVT buffer refill when empty.  Called from GTTCI.

TVRFIL:
	SKIPG TTNETW(T2)	;STILL CONNECTED TO NETWORK?
	 RET			;NO, NOTHING TO DO
	SAVEAC <T1,T2,T3,T4,TCB> ;SAVE ACS
	NOSKED			;OWN THE SYSTEM
	SKIPL RA+PRCLCK		;IS REASSEMBLER RUNNING ALREADY?
	 JRST TVRFI3		;YES SO AVOID LOCK CONTENTION
        LOAD TCB,PTVT,(T2)	;NO, GET TCB IF EXISTS
	JUMPE TCB,TVRFI3	;IF NO TCB THEN GET OUT OF HERE
	SETSEC TCB,INTSEC	;TCB'S ARE IN INTSEC
	JN TRCB,(TCB),TVRFI2	;IF RECV BUFFER EXISTS RUN THE RA
        LOAD T1,QNEXT,<+TCBRPQ(TCB)> ;NO, GET NEXT ITEM ON RA QUEUE
        CAIN T1,TCBRPQ(TCB)	;IS RA QUEUE EMPTY?
         JRST TVRFI3		;YES NO NEED TO RUN THE RA
TVRFI2:				;HERE TO RUN RA
	$SIGNL(RA,20)		;RUN REASSEMBLER AFTER SHORT DELAY
TVRFI3:				;HERE WHEN ALL DONE
	OKSKED			;RETURN THE SYSTEM
	RET
;ASNTVT
;ASSIGN A TCP VIRTUAL TERMINAL

;T1/ TCB (WITH AN%NTP flag for new protocol)
;CALL ASNNVT
;RETURNS +1: FAILURE
;	 +2: SUCESS
;T1/ LINE NUMBER
;T2/ ADDRESS OF DYNAMIC DATA AND DATA BASE LOCKED

	SWAPCD

ASNTVT::STKVAR <FLGTCB,TVLIN>
	MOVEM T1,FLGTCB
	HRRZ T1,TVTPTR		;GET FIRST TVT LINE NUMBER
	SETZ T3,		;START WITH FIRST TVT
	NOSKED
ASNTV1:	MOVE T2,T1		;GET FIRST TVT OFFSET
	ADD T2,T3		;ADD CURRENT TVT
	MOVEM T2,TVLIN		;SAVE LINE NUMBER
	CALL STADYN		;IS IT INITIALIZED
	 JUMPE T2,ASNTV4	;NO. NO DYNAMIC DATA
	SKIPG TTNETW(T2)	;FREE?
	 JRST ASNTV3		;YES.
ASNTV2:	CAIGE T3,NTTTVT-1	;LOOKED AT ALL TVT'S?
	 AOJA T3,ASNTV1		;NO
	OKSKED			;YES,
	RETBAD			;RETURN BAD

ASNTV3:
ifn  nicsw,<
	trnn t2,-1		;bogus pointer?
	 jrst asntvb		;yes
>
	LOAD T2,TCJOB,(T2)	;GET JOB FOR WHICH THIS IS A CNTRL TTY.
	CAIN T2,-1		;IS THERE ONE
	  JRST ASNTV4		; No, use this one
	HLRZ T2,JOBPT(T2)	; Yes, is it really there?
	CAMN T2,TVLIN		; Skip if TCJOB has obsolete data
	  JRST ASNTV2		;YES. TTY ALREADY ATTACHED?

; if job-0 ought to use TTYASC
; if other job, ought to use TTYASO
; For now, they are essentially the same

ASNTV4:
	MOVE T2,TVLIN		;GET LINE NUMBER BACK
	CALL TTYASC		;ASSIGN TVT
	 JRST ASNTV6		;COULD NOT ASSIGN IT

	MOVE T2,TVLIN		;GET LINE NUMBER
	CALL LCKTTY		;AND LOCK DATA BASE
	 JRST ASNTV5		;CANNOT LOCK DATA BASE. SHOULD'NT HAPPEN
	SETONE TCJOB,(T2)	;INDICATE NO CONTROLLING JOB FOR TERM.
	SETONE TTPRM,(T2)	;MAKE DATA PERMANENT UNTIL NVT CLOSED
	MOVE T1,FLGTCB		; Get arg back
	TXNN T1,AN%NTP		;NEW TELNET PROTOCOL REQUEST?
	 TLZA T3,-1		;NO, MAKE ZEROES
	  MOVX T3,NVNNV		;YES, MAKE NEW NVB BIT
	HLLZM T3,TTNETW(T2)	;CLEAR TTNETW EXCEPT FOR NVNNV
	SETZM NVTOPF(T2)	;CLEAR OPTION STATUS
	HRRZ T1,FLGTCB		; Get the TCB
	STOR T1,PTVT,(T2)	;REMEMBER UNIT
	SETONE TT%DUM,TTFLGS(T2) ;SET DUPLEX MODE
	MOVEI T1,.TTIDL		;SET TO BE AN "IDEAL" TERMINAL
	STOR T1,TTTYP,(T2)
	MOVE T1,TVLIN		;RETURN LINE NUMBER
	OKSKED
	RETSKP

ASNTV5:	CALL ULKTTY		;UNLOCK DATA BASE
ASNTV6:	HRRZ T1,TVTPTR		;GET FIRST TVT
	MOVE T3,TVLIN		;SET UP TO TRY NEXT LINE
	SUB T3,T1		;GET TVT NUMBER IN 3
	JRST ASNTV2		;AND TRY NEXT TVT
ifn nicsw,<
ASNTVB:	move t2,tvlin
	BUG.(CHK,ASNTVJ,TVTSRV,SOFT,<Invalid TTACTL entry for TTY>,<<T2,TTYLIN>>,<
Cause: unknown

Data:  TTYLIN -- tty line number
>)
	jrst asntv2		;skip to next tty
>

	ENDSV.
;TVTCSO
;START OUTPUT TO A LINE CALLED FROM STRTOU
;RETURNS +2: ALWAYS

	RESCD

TVTCSO::
	AOS TVTNOF		; request tty scan
	AOS TCPFLG		; Say it is TCP that needs to run
	AOS INTFLG		; Get the Internet fork to run it
	AOS PSKD1		; Get the scheduler out of the null job
IFN STANSW,<
	JUMPL T2,TCSOAL		;want to scan ALL tvts?
	DYNST T3		;get real line number
	HRRZ T1,TVTPTR		;get first TVT number
	SUB T3,T1		;Convert line number to TVT number
	CAIL T3,NTTTVT		;Range check
	 JRST TVTCSX		;We were handed garbage - PUNT
	IDIVI T3,^D36		;Calculate word (T3) and bit (T4) offsets
	MOVE T1,BITS(T4)	;Get the bit
	IORM T1,TVTSOQ(T3)	;And set it in the correct word
	RETSKP
TVTCSX:	BUG.(CHK,CSONTV,TTYSRV,SOFT,<TVTCSO called with non-TVT>)
	RETSKP			;punt

TCSOAL:	MOVSI T2,-NTVTQN	;get count of words
	SETOM TVTSOQ(T2)	;set all the bits on.
	AOBJN T2,.-1
	RETSKP
>;IFN STANSW
;TVTDOB
;TVT dismiss until output buffer empty

;Avoid  doing  a  TELNET  timing  mark option negotiation if the
;connection is closing since the other end will not respond.

	SWAPCD

TVTDOB:	LOAD TCB,PTVT,(T2)	; Get TCB if exists
	 JUMPE TCB,R		; Return if none
	SETSEC TCB,INTSEC	; TCBs are in INTSEC
	LOAD T1,TSSYN,(TCB)	; Get send state
	CAIE T1,SYNCED		; Can we send?
	 RET			; No
	LOAD T1,TRSYN,(TCB)	; Get receive side state
	CAIE T1,SYNCED		; Can other end reply?
	 RET			; No
	JRST NVTDOB		; Yes and yes.  Do normal TELNET stuff
;TVTCOB
;TVT CLEAR OUTPUT BUFFER CALLED FROM TTCBF2

;ACCEPTS:
;T2/ ADDRESS OF DYNAMIC DATA
;RETURNS +1: ALWAYS

	RESCD

TVTCOB::
	SKIPE INSKED		;IN SCHEDULER
	 RET			;YES RETURN IMMEDIATELY
	PUSH P,TCB
	SKIPG TCB,TTNETW(T2)	;STILL CONNECTED TO NETWORK?
	 JRST TVTCO3		;NO.  RETURN
	SETSEC TCB,INTSEC	; TCBs in Internet section
	JN TERR,(TCB),TVTCO3	; Don't DM if connection error
	NOINT			;PROTECT POSSIBLE ILOCKS
	CALL CKNNVT		;NEW STYLE NVT?
	 JRST TVTCO1		;OLD STYLE
	MOVEI T1,DMCH		;DATA MARK CHARACTER
	CALL NVTSSP		;SEND NEW DM
	JRST TVTCO2

TVTCO1:	MOVX T1,1		;RESERVE ONE CHARACTER
	CALL NVTRSV		;GO REESERVE IT
	 JRST TVTCO2		;NONE AVAILABLE CANNOT WAIT
	MOVX T1,200
	CALL TCOBN		;SEND CHARACTER
	OKSKD1
TVTCO2:
	OKINT
TVTCO3:	POP P,TCB
	RET
;CHECK OVERDUE NEGOTIATIONS

	RESCD

TVTNCK::STKVAR <TVTCTR>
	MOVE T2,TVTPTR		;POINTER TO TVTS
TVTNCL:	MOVEM T2,TVTCTR		;SAVE TVT COUNTER
	HRRZ T2,T2		;GET JUST RIGHT HALF
	CALL LCKTTY		;GET ADDRESS OF DYAMIC DATA AND LOCK
	 JRST TVTNCE		;NOT ACTIVE
	SKIPGE TTNETW(T2)	;ATTACHED?
	 JRST TVTNCE		;NO, SKIP IT
	MOVX T3,NVTMO		;TIME OUT
	HLLZ T1,NVTOPF(T2)	;GET OUTSTANDING OPTIONS
	 JUMPE T1,[ANDCAM T3,TTNETW(T2) ;NONE, CANCEL TIME-OUT IF ANY
		JRST TVTNCE]
	XORB T3,TTNETW(T2)	;YES, COUNT COUNTER
	TXNN T3,NVTMO		;COUNT FROM 1 TO 0?
	 HRRZS NVTOPF(T2)	;YES, CANCEL OUTSTANDING OPTION
TVTNCE:	CALL ULKTTY		;UNLOCK DATA BASE
	MOVE T2,TVTCTR		;GET AOBJ COUNTER
	AOBJN T2,TVTNCL		;ANY MORE TVT'S
	MOVE T1,TODCLK		;NO.  GET TIME OF DAY
	ADDI T1,NEGTM0		;ADD TIME OUT QUANITY
	MOVEM T1,TVTNTM		;SAVE TIME FOR NEXT CHECK
	RET
	ENDSV.
;SNDTVT
;Send virtual terminal data

;TCB/	Locked connection block
;PKT/	Pointer to Internet portion of packet being filled
;TPKT/	Pointer to TCP portion of packet
;T1/	Max number of characters to send
;T2/	Line block address
;CALL SNDTVT
;Ret+1:	Always.  Terminal data moved into packet. T1 has number of chrs.

SNDTVT::LOCAL <XFRCNT,LINBLK,PKTPTR,CNT>
IFN STANSW,< ;;; keep TVT statistics
	ADDM T1,TVTOBC		;count output TVT characters
	AOS TVTOPK		;count output TVT packets
>;IFN STANSW
	DMOVEM T1,XFRCNT	; T1,2 to XFRCNT and LINBLK
	LOAD PKTPTR,PTDO,(TPKT)	; Get TCP data offset
	HRLI PKTPTR,(<POINT 8,.-.(TPKT)>) ; Pointer to data area
	MOVEI CNT,0		; Init number moved to packet
	MOVEI T3,(1B<RCTOPT+WILOPT>) ; RCTE-on bit
	TDNE T3,NVTOPF(T2)	; Have we said we will do RCTE?
	CALL CKNNVT		; And is this a "new" TELNET terminal?
	 JRST SNDTV1		; No.
	JE PBRCT,(T2),SNDTV1	; Check the break count
	CALL NVTRRR		; Try to send
SNDTV1:	SKIPG TTNETW(T2)	; Still connected?
	 JRST SNDTV2		; No
	JE TERR,(TCB),SNDTV3	; Error on connection (retrans timeout)?
SNDTV2:	IFQN. TTSAL,(T2)	; Check for sendall in progress
	 CALL CLRSAL		; Clear it
	ENDIF.
	CALL TTCOBN		; Flush output buffer
	JRST SNDTV9		; And return

SNDTV3:	SETONE TTOTP,(T2)	; Indicate output active

; Move characters from the terminal output buffer(s) into the packet.
; XFRCNT has space left in packet and CNT will be left with number
; moved.

SNDTV4:	SOJL XFRCNT,SNDTV5	; Jump if packet filled
	MOVE T2,LINBLK		; Restore address of data area
	NOSKD1
	CALL TTSND		; Get a chr from output buf to T3
	JRST SNDTV6		; Failed to get any
	OKSKD1
	IDPB T1,PKTPTR		; Add to packet
	AOJA CNT,SNDTV4		; Count it up and try for another
SNDTV6:
	OKSKD1			; Go OKSKED again
	JRST SNDTV9		; And join below

SNDTV5:	SETZRO TTOTP,(LINBLK)	; Clear output active bit
SNDTV9:	MOVE T1,CNT		; Return number in packet
IFN STANSW,< ;;; Count TVT characters in total bytes output!
	ADDM T1,BYTSCT
>;IFN STANSW
	RESTORE
	RET
;PRCTVT
;Process TCP Virtual Terminal data

;T1/	Byte pointer into packet where to begin (index by TPKT)
;T2/	Pointer to dynamic line data block
;T3/	Maximum number of characters to do
;PKT/	Pointer to Internet portion of packet
;TPKT/	Pointer to TCP portion of packet
;TCB/	Locked connection block
;CALL PRCTVT
;Ret+1:	Always.  Given number of characters have been moved.

PRCTVT::LOCAL <LINBLK,XFRCNT,PKTPTR>
	MOVEM T1,PKTPTR
	DMOVEM T2,LINBLK
IFN STANSW,< ;;; Keep TVT statistics
	ADDM T3,TVTIBC		;count total TVT input characters
	AOS T3, TVTIPK		;count TVT input "packets"
>;IFN STANSW
PRCTV1:	SOJL XFRCNT,PRCTVX	; Jump if all done
	ILDB T1,PKTPTR		; Get a character
	MOVE T2,LINBLK		; Line block address
	LOAD T3,NVSTP,(T2)	; Current Telnet command state
	SETZRO NVSTP,(T2)	; Reset for normal dispatch next time
	PUSH P,LINBLK		; Some of these are crashed by TTYSRV
	PUSH P,XFRCNT		; or TELNET
	PUSH P,PKTPTR
	CALL @NVTSTD(T3)	; Dispatch to Telnet routine
	POP P,PKTPTR
	POP P,XFRCNT
	POP P,LINBLK
	JRST PRCTV1		; Do another
PRCTVX:	RESTORE
	RET
;CHKTVT
;SEE IF THIS LINE NUMBER IS A TVT

;ACCEPTS:
;T2/ INTERNAL LINE NUMBER
;CALL CHKTVT
;RETURNS +1: IF NOT TVT
;	 +2: IF TVT

	RESCD

CHKTVT::
	ACVAR <W1>		;GET AN AC TO WORK WITH
	SKIPL T2		;LEGIT LINE NUMBER?
	 CAIL T2,NLINES		;LEGIT LINE NUMBER?
	  RETBAD       		;NO
	LOAD W1,TTSTY,(T2)	;GET LINE TYPE FOR THIS LINE
	CAIE W1,TT.TVT		;IS IT A TVT?
	RETBAD			;NO. FAILURE
	RETSKP			;RETURN SUCCESS
	ENDAV.			;END ACVAR

	SWAPCD

;TVTCHK
;See if this line is a TCP Virtual terminal

;T2/	Internal line number
;	CALL TVTCHK
;Ret+1: Line not initialized.	T2  0	Inactive	Not locked, okint
;				T2 -1	Becoming active	Not locked, okint
;				T2 adr	Non-standard blk Locked, noint
;   +2:	Line initialized.	T2 adr	Std dynamic data Locked, noint

TVTCHK::
	CAIL T2,NLINES		; Legal terminal line number?
	 JRST TVTCH8		; TCP Never calls with non-TVT
	LOAD T1,TTSTY,(T2)	; Line type for this line
	CAIE T1,TT.TVT		; Is it a TVT?
	 JRST TVTCH8		; No.
	CALL LCKTTY		; Get addr of dynamic data and lock
	 RET			; Line not initialized
	JRST TVTCHX		; Return with line blk addr in T2
TVTCH8:	BUG.(HLT,TVTNTV,TTYSRV,SOFT,<TVTCHK called with non-TVT>,,<

Cause:	TVTCHK was called to determine the status of a TVT line, but the
	line number provided by TCP is not a TVT line. TCP should never
	call TVTCHK with a non-TVT line.
>)
TVTCHX:	RETSKP
;TVTISP
;Get number of holes in input buffer

;T2/	Pointer to line block
;	CALL TVTISP
;Ret+1:	Always.  Space available in T1

TVTISP::LOAD T1,TIMAX,(T2)	; Max capacity of line
	SUB T1,TTICT(T2)	; Less what is already there
	RET			; Gives amount left

;TVTOSP	Get number of bytes in output buffer
;T2/	Line block pointer
;	CALL TVTOSP
;Ret+1:	Always.  Number in T1.

TVTOSP::LOAD T1,TSALC,(T2)	; Sendall count plus
	SKIPE T1		; If sendall, bump count so
	  ADDI T1,1		; extra TTSND clears sndall info
	ADD T1,TTOCT(T2)	; regular count
	JE <TTSFG,TTRXF,TTSHT>,(T2),TVTOSX
	MOVEI T1,0		; Hung on ^S, say no avail for output
TVTOSX:	RET
;TVTDTS
;Close a full duplex TCP virtual terminal connection upon carrier-off

;T2/	Line number
;	CALL TVTDTS
;Ret+1:	Always

	RESCD

TVTDTS::CALL TVTDTT		; Detach the TVT
	 RET
	RET			; Success
;TVTDET
;Detach  a job from a TCP virtual terminal connection returns to
;caller's caller, TVTDTT returns to caller.  Called  from  HLTJB
;when a job logs off

;T2/	Line number
;CALL TVTDET	(FNCALL off of TTVT11, TTVT19)
;Ret+1:	Failure.  T1/	1B0 + Addr of routine if dismiss needed
;		  or,   Error code if failed
;Ret+2:	Success

TVTDET::POP P,0(P)		; Flush return address
TVTDTT:	SE1CAL			; Enter section 1
	SAVEPQ			; Save local ACs
	STKVAR <TVTDLN,TVTDAD>	; Space for line number and block addr
	MOVEM T2,TVTDLN		; Save the line number
	CALL TVTCHK		; See if this is a TVT
	 RETSKP			; Not assigned.  Return.
	MOVEM T2,TVTDAD		; Save addr of dynamic data area
	CALL CLRPRM		; Clear permanent bit, allowing deassign
	SKIPG TTNETW(T2)	; Is there a connection?
	 JRST TVTDE1		; No
	PUSH P,TCB
	LOAD TCB,PTVT,(T2)	; Get the TCB
	SETSEC TCB,INTSEC	; Make extended address
	JE TSUOP,(TCB),TVTDE0	; Already closed?
	XMOVEI T1,TCBLCK(TCB)	; Lock to lock
	MOVX T2,<XCDSEC,,CLOSE1> ; Function to call
	IFE REL6,<CALL LCKCAL> 	; Do a cross-job close
	IFN REL6,<CALLX (XCDSEC,LCKCAL)> ; Do a cross-job close
TVTDE0:
	SETZRO TVTL,(TCB)	; Prevent OPSCAN from finding this TCB
	POP P,TCB
	MOVE T2,TVTDAD		; Restore pointer to data block
TVTDE1:
	SETZM TTNETW(T2)	; Flush the connection
	LOAD T3,TCJOB,(T2)	; Get owning job
	CAIN T3,-1		; Is there one?
	 JRST TVTDT2		; No. Just go deallocate data block.
	MOVE T2,TVTDLN		; Get TTY line number
	MOVEI T1,.TTDES(T2)	; Make into device designator
	CALL CHKDES		; Get index to device tables
	 JRST [	MOVE T2,TVTDAD	; Get dynamic data address back
		CALL ULKTTY
		RETBAD]		; Invalid device designator?????
	SETZRO DV%OPN,DEVCHR(T2) ; Permit RELD at LGOUT to win
	MOVE T2,TVTDAD		; Dynamic data block address
	MOVE T1,TVTDLN		; Terminal line number
	CAMN T1,CTRLTT		; Controlling terminal for this job?
	 JRST TVTDT2		; Yes.  Go deassign database
	LOAD T3,TCJOB,(T2)	; Get owning job
	HLRZ T3,JOBPT(T3)	; Get controlling terminal of job
	CAME T1,T3		; Is this a controlling terminaL
	 JRST TVTDT2		; No.  Go detach it

; A job exists on this line and the net connection has been broken.
; Generate a carrier off PSI for the top fork.  This will cause the
; terminal data block to be deassigned.

	MOVE T2,TVTDLN		; Get line number
	NOSKD1
	CALL NTYCOF		; Start the carrier off action
	OKSKD1
	MOVE T2,TVTDAD		; Get address
	CALL ULKTTY		; Unlock the data block
	RETSKP			; And give a good return

; Deassign the terminal's data block

TVTDT2:	JE TTSAL,(T2),TVTDT3	; Doing a Send-All?
	CALL CLRSAL		; No longer doing a sendall
TVTDT3:
	CALL ULKTTY		; Unshare the data block
	MOVE T2,TVTDLN		; TVT Line number
	MOVEI T1,.TTDES(T2)	; Form device designator
	CALL CHKDES		; Get index to device tables
	 RETBAD			; Invalid device designator????
	MOVEM T2,TVTDAD		; Save index to device tables
	MOVE T2,TVTDLN		; Get terminal line number
	CALL TTYDE0		; Deallocate the line
	 RETBAD			; Return error or test routine
	MOVE T2,TVTDAD		; Device table index
	HRROS DEVUNT(T2)	; Set owning job to -1
	SETZRO DV%ASN!DV%OPN,DEVCHR(T2) ; Not assigned or openned
	MOVE T2,TVTDLN		; Get line number
	CAME T2,CTRLTT		; Controlling terminal
	 RETSKP			; No.
	SETOM CTRLTT		; Yes. Indicate no terminal
	MOVE T2,JOBNO		; Get job number
	HRROS JOBPT(T2)		; This nob no longer has a terminal
	RETSKP
	ENDSV.

TVTIGA::RET
;TVTOPR
;Main routine to operate TVTs

;CALL TVTOPR
;Ret+1:	Always.

TVTOPR::SKIPLE TVTNOF		; Output scan needed?
	  CALL OPSCAN		; Yes.  Signal PZ where possible
	MOVE T1,TODCLK		; Now
	CAML T1,TVTNTM		; Time for check on overdue
	  CALL TVTNCK		; Telnet negotiations
	MOVE T1,LSNTIM		; Get time for listening
	SKIPE TVTLSN		; if no socket
	 CAMG T1,TODCLK		; time for another stab?
	  CALL LISTEN		; Try a listen
	RET

;LISTEN
;Set up a TCB listening on the TELNET port

;CALL LISTEN
;Ret+1:	Always.  TVTLSN set ge 0 if error,  le 0 if OK.

LISTEN:	MOVE T1,FACTSW		; broadcast req
	TXNN T1,SF%NVT		; NVT logins allowed?
	 JRST LSN1		; No, Don't open
	MOVE T1,[TCP%PS+TCP%VT+TVTCDB]
	MOVEI T2,LSNTMO		; Timeout
	SETZ T3,		; Default re-transmission algorithm
	OPEN%			; Do the listen
	 CAIA			; Don't save if failed
	  MOVEM T1,TVTLSN	; Save
LSN1:	MOVE T1,TODCLK		; Get clock
	ADDI T1,^D60000		; in one minute
	MOVEM T1,LSNTIM		; try again regardless
	RET			; Return

TVTCDB:	BLOCK .TCPCS		; Connection block
.X==.
	RELOC TVTCDB+.TCPLP
	LSNPRT
	RELOC .X
	PURGE .X

;TVTOPN
;Open a TCP Virtual Terminal; Called in Job-0 context

;TCB/	Pointer to TCB
;CALL TVTOPN
;Ret+1:	Always, T1 zero if OK or error code (ELT+^D4) otherwise

TVTOPN::HRRZ T1,TCB		; Needs TCB
	TXO T1,AN%NTP		; Say it will speak new Telnet
	CALL ASNTVT		; Assign a virtual terminal
	  JRST TVTOP7		; Failed (not available, etc)
	STOR T1,TVTL,(TCB)	; Save in connection block
	PUSH P,T2		; Save line block address
	MOVE T2,T1		; Put line number in right place
	MOVEI T1,"C"-100	; Get a control-C to awaken the job
	NOSKD1
	CALL TTCHI		; Type it for the guy
	  JFCL			; Ignore error return
	OKSKD1
	SETZM TVTLSN		; Get another listen done
	SETZM TVTNTM		; Get done quickly
IFN STANSW,< ;;; Set up output buffers dependent on Segment size
	MOVE T1,(P)		;get dynamic data address
	LOAD T2,TVTL,(TCB)	;get line number back
	CALL SETOBF		;set up output buffers
>;IFN STANSW
	POP P,T2		; Restore line block address
	CALL ULKTTY		; Block now stable
	SETZ T1,		; No error
	JRST TVTOPX

TVTOP7:	MOVX T1,ELT+^D4		; Out of resources error
TVTOPX:	RET
;TVTCLS
;Close a TCP Virtual Terminal

;T1/	Code for reason
;TCB/	Pointer to connection block
;CALL TVTCLS
;Ret+1:	Always.

	RESCD
TVTCLS::LOCAL <CCODE>
	MOVEM T1,CCODE
	CAIE CCODE,XFP+^D12	; "Closing" or
	 CAIN CCODE,EFP+^D7	; "Connection error or rejected"
	  CAIA			; (other end restarted)
	   JRST TVTCL1		; No.  Something else

;Here  when  other end restarted and we received a RESET. PRCRST
;called [USRERR with EFP+^D7] ABTCON with  EFP+^D7.  Beware:  it
;may be THE listening connection.

;Here  when  remote  end  is  closing.  We are in the process of
;sending and ACK for his  FIN,  but  may  not  be  done  sending
;everything  from  this end yet -- for instance, "Detached job N
;..." msg. So, get the job to clean itself up  and  call  TVTDTS
;via  TTHNGU  (from  FLOGO1 as called from JOBCOF by top fork of
;the job), or via TTYDEA as called from TTYDAS  from  LDTACH  or
;HLTJB.

	LOAD T2,TVTL,(TCB)	; Get the line number
	JUMPE T2,TVTCL2		; TVT may not be assigned if during
	NOSKD1			;  OPEN (if so, need another listen)
	CALL NTYCOF		; Start the carrier off sequence
	OKSKD1
	JRST TVTCLX		; and leave

TVTCL1:	CAIN CCODE,XLP+^D3	; "Closed"
	 JRST TVTCL4		; Yes, just go detach it
	CAIN CCODE,ELT+^D4	; "No free terminals"
	  JRST TVTCL2		; Go fake CLOSE & release JCN
	CAIE CCODE,ELP+^D14	; "Connection reset" due to
				;  Retransmission timeout?
	 JRST TVTCLX		; No, Something else.  Ignore it.
;Here  when a connection OPENed correctly but there were no free
;TVTs. PRCACK (or PRCSYN) called USREVT(OK) which called  TVTOPN
;which  called  ASNTVT  which  failed.  TVTOPN  tried  to send a
;message and  then  a  RST  to  the  other  end  before  calling
;ABTCON(ELT+^D4)   which  called  USREVT(ELT+^D4)  which  called
;TVTCLS(ELT+^D4). The state is NOT.NOT but we  have  to  fake  a
;CLOSE and release the JCN.

;Here  when we have suffered a retransmission timeout on an open
;connection. REXMIT called [USRERR with ELP+^D9,  "RX  timeout",
;and]  ABTCON  with ELP+^D14, "Connection reset", which made the
;connection dead (state is NOTSYN in both directions) and called
;USREVT with ELP+^D14 who called us. All that remains is to  get
;the  job  detached.  Note that the job may or may not be logged
;in.

TVTCL2:	SETZRO TSUOP,(TCB)	; Don't send a FIN

;If  this  is a valid Job0 JCN we are dealing with the LISTENing
;port. The "said open" bit tells whether  the  timeout  happened
;while  the  connection  was opening (must do another listen) or
;after it had opened (next listen is already in progress).

	JN TSOPN,(TCB),TVTCL4	; Jump if next listen already done
	LOAD T1,TJCN,(TCB)	; or if not a valid Job0
	CAIN T1,-1		; JCN
	  JRST TVTCL4
	SETZM TVTLSN		; Get another listen done
	SETZM TVTNTM		; Now.
TVTCL4:
	LOAD T2,TVTL,(TCB)	; Get line number
	SKIPE T2		; TVT not assigned if during open
	  CALL TVTDTS		; Detach owning job
	JN TOWNR,(TCB),TVTCL5	; Jump if TVT not owned by Job-0 (never)
	LOAD T1,TJCN,(TCB)	; Get our (Job-0) handle on the TCB
	CALLX (XCDSEC,RETJCN)  	; Release it
	SETZRO TJCN,(TCB)	; (RETJCN can't do this if TJCN was -1)
TVTCL5:
TVTCLX:	RESTORE
	RET
	SWAPCD
;OPSCAN	Get packets sent on each connection with output waiting
;CALL OPSCAN
;Ret+1:	Always.

OPSCAN:	LOCAL <TVTP,LINADR>
	PUSH P,TCB
	SETZM TVTNOF		; Clear the run request flag
IFE STANSW,< ;;; scan bit table rather than look at all TVTs
	MOVE TVTP,TVTPTR	; AOBJN for all TVTs
OPSCA1:	HRRZ T2,TVTP		; Next line number
>;IFE STANSW
IFN STANSW,< ;;; scan bit table rather than look at all TVTs
	MOVSI TVTP,-NTVTQN	;How many words in bit table?
OPSCA1:	SKIPN T1,TVTSOQ(TVTP)	;Swap zero for a possible bit mask
	 JRST OPSCA9		;Try next word if no bits set 
	JFFO T1,OPSCA0		;Jump if we find a bit set
	 JRST OPSCA9		;No bits set, try next word
OPSCA0:	MOVE T3,BITS(T2)	;Get the appropriate bit
	ANDCAM T3,TVTSOQ(TVTP)	;Clear the flag
	MOVEI T1,^D36		;One word worth of offset
	IMULI T1,(TVTP)		;Times number of words
	ADDI T2,(T1)		;Add offset onto jffo bit to get PNV number
	CAIL T2,NTTTVT		;A valid TVT offset?
	 JRST OPSCA9		;no (???)  Ignore it.
	HRRZ T1,TVTPTR		;get unmber of first TVT
	ADDI T2,(T1)		;Add TTY number of first TVT
>;IFN STANSW
	CALL LCKTTY		; Lock and get dynamic area to T2, NOINT
	 JUMPLE T2,OPSCA8	; Non standard block
	MOVE LINADR,T2		; Save the terminal block ptr
	LOAD TCB,PTVT,(T2)	; Have a TCB?
	JUMPE TCB,OPSCA7	; Jump if not there (??)
	SETSEC TCB,INTSEC	; Make extended address
	JE TTVT,(TCB),OPSCA7	; Jump if not a TVT (??)
	LOAD T3,TVTL,(TCB)	; Get the line number
	JUMPE T3,OPSCA7		; USREVT released the TVT line (??)
	CALL TVSBE1		; Any output waiting?
	 SKIPA T4,T1		; Yes.  Get PZ to call SNDTVT
	  JRST OPSCA7		; No.
IFE STANSW,<
	MOVX T1,^D200		; The function to queue for PZ if a lot
	MOVX T2,<XCDSEC,,ENCPKT> ; to send - wait a bit, maybe more
	CAIGE T4,^D8		; Less that 8 is echoing so
	 MOVX T2,<XCDSEC,,FRCPKT> ; Force it now
	CALL (T2)		; See Note above
>;IFE STANSW
IFN STANSW,<	;;; there is not going to be any more output if all of the
		;;; output buffers are full, so send packets immediately.
	CALL TTSOBF		;output buffer full?
	CAIGE T4,^D8		; or looks like echoing.
	 SKIPA T2,[FRCTVT] ; Force it now
	  MOVX T2,<ENCTVT> ;  otherwise wait for more data
	LOAD T1,QNEXT,<+TCBRXQ(TCB)>	;check if retranmission queue empty?
	CAIE T1,TCBRXQ(TCB)	;skip if RXQ empty
	CAIL T4,^D8		; or if a large packet
	 TRNA
	  MOVX T2,<ENCTVT> ; otherwise wait for more data
	MOVEI T1,^D200		;	for a couple hundred millisecs.
	CALL (T2)		;call appropriate packet routine.
>;IFN STANSW
OPSCA7:	MOVE T2,LINADR		; Restore address of terminal block
OPSCA8:	CALL ULKTTY		; Decrease reference count, OKINT
IFN STANSW,< ;;; use bit table rather than aobjn over all TVTs
	JRST OPSCA1		;Try for more bits in this word
OPSCA9:
>;IFN STANSW
	AOBJN TVTP,OPSCA1	; Loop over all TVTs
	SKIPE T2,TVMSTM		; Any TTMSG's out?
	CAMLE T2,TODCLK		; Yes, time to flush yet?
	 JRST OPSCAX		; No, return.
	NOSKED			; Prevent anyone from changing data
	CALL TVMNTR		; Flush all TTMSG's to TVTs
	OKSKED
	SETZM TVMSTM		; Clear timer
OPSCAX:	POP P,TCB
	RESTORE
	RET
;TVTMSG
;Routine to output a greeting message to a TVT

	TVMSGZ==^D60		; size of buffer for TVTMSG in words

TVTMSG::			; Routine to type out a greeting message
	STKVAR <TVMSGJ,<TVMSGB,TVMSGZ>>
	MOVX T1,<GJ%SHT!GJ%OLD>	; The file must allready exist
	HRROI T2,[ASCIZ/SYSTEM:INTERNET-LOGIN-MESSAGE.TXT/]
	GTJFN%			; Get the JFN
	 ERJMP R	       	; assume file does not exist
	MOVEM T1,TVMSGJ		; Save the JFN
	MOVX T2,<7B5!OF%RD>	; we want read access
	OPENF%			; open up the file
	 ERJMP TVMSG2		; handle errors
IFN NICSW,<
TVMSG0:	MOVE T1,TVMSGJ
 >
	SETZM TVMSGB		; zero the first word of the buffer
	MOVEI T2,1+TVMSGB      	; get the address of the block
	HRLI T2,-1(T2)		; build complete BLT ac
	BLT T2,TVMSGZ-1+TVMSGB	; zero the whole buffer
	HRROI T2,TVMSGB		; destination pointer
	MOVNI T3,<<TVMSGZ*5>-1> ; read as much as we can
	SIN%			; read in the string from the file
	 ERJMP .+1		; handle errors
	ADDI T3,<TVMSGZ*5>-1	; get the number of characters read
	JUMPE T3,TVMSG1		; skip this stuff if none read
	MOVEI T1,.PRIOU		; output to primary designator
	MOVEI T2,TVMSGB		; get the address of the buffer
	HRLI T2,440700		; build a byte pointer
	MOVNS T3		; exact number of characters to output
	SOUT%			; output the string
	 ERJMP .+1		; handle errors
IFN NICSW,<
	JRST TVMSG0		; read until eof
>
TVMSG1:				; here also when buffer was empty
	MOVE T1,TVMSGJ		; get the JFN
	CLOSF%			; close it
	 ERJMP .+1
	RET			; return to caller

TVMSG2:				; here when the OPENF% failed
	MOVE T1,TVMSGJ		; get the JFN
	RLJFN			; release it
	 ERJMP .+1
	RET			; return to caller

;TVRRH - TVT device dependent "return remote host" code
;
; Given the line #, returns the originating hostname, line and
; network type. Places this info in the users NTINF% .NWRRH 
; argument block.  NTINF has already checked the user arguments 
; for validity.
;
; Call with T1/ address of internal arg block
;
;   ARG+.NWABC/ # of bytes available for host name
;   ARG+.NWFNC/ not used
;   ARG+.NWNNP/ byte pointer to store hostname string
;   ARG+.NWLIN/ address of dynamic data for line
;   ARG+.NWTTF/ flags, and network and terminal types
;   ARG+.NWNNU/ node # word 1
;   ARG+.NWNU1/ node # word 2
;
; Returns + 1 on error with T1/ error code
;	  + 2 on success

	SWAPCD

TVRRH::	STKVAR <UAB>
	MOVEM T1,UAB		;SAVE POINTER TO ARG BLOCK
	MOVX T4,NW%TCP		;SET NETWORK TYPE
	DPB T4,[POINT 9,.NWTTF(T1),17] ;STORE NETWORK TYPE
	NOSKED			;DON'T LET TCB GO AWAY
	MOVE T2,.NWLIN(T1)	;GET TDB ADDRESS
        LOAD T3,PTVT,(T2)	;GET TCB IF IT EXISTS
	JUMPE T3,[OKSKED	;GO SET "NO NODE NAME KNOWN" AND RETURN
		   CALLRET TVRRH1]		
	SETSEC T3,INTSEC	;TCB'S ARE IN INTSEC
	LOAD T3,TFH,(T3)	;GET FOREIGN HOST
	OKSKED			;ALL OKAY AGAIN
	MOVEM T3,.NWNNU(T1)	;SAVE IT
	MOVE T2,.NWNNP(T1)	;GET POINTER FOR DEPOSITING HOSTNAME
	MOVX T1,.GTHNS		;RETURN PRIMARY NAME
	GTHST%
IFE STANSW,<
	 ERJMP .+1    		;GOT AN ERROR
>;IFE STANSW
IFN STANSW,<
	 ERJMPS TVRRH1		;GOT AN ERROR, SAY "NO NODE NAME KNOWN'
>;IFN STANSW
	TDZA T1,T1		;HAVE A NODE NAME
TVRRH1:	MOVX T1,NW%NNN		;GET "NO NODE NAME KNOWN" FLAG
	MOVE T3,UAB
	SKIPE T1 		;GOT A NODE NAME ?
	IORM T1,.NWTTF(T3)	;NO - SET THE "NO NODE NAME KNOWN" FLAG
	RETSKP
IFN STANSW,<;;; code to encourage/force pktize to run on TVTs
; We want to use a bit other than TSFP/TSEP.  They are used when
; a packet MUST be sent (eg, an ACK), whereas with TVTs, we don't
; want to send a packet if the window is 0, for example.
;
	XSWAPCD
;FRCTVT
; This TCB has data ready for it that needs to be sent NOW, if at
; all possible.
;TCB/	(Extended) Locked connection block
;	CALL FRCTVT
;Ret+1:	always

FRCTVT:	IFQE. <TSTVO,TSFP>,(TCB) ; Filter extra calls
	 SETONE TSTVO,(TCB)	; Set TVT output required bit
	 $SIGNL(PZ,0)		; Make Packetizer run now
	ENDIF.
	RET
;ENCTVT
;Encourage generation of a packet.
; There is data to be sent on this connection, but there is likely
; to be more data within a little while.
;TCB/	(Extended) Locked connection block
;T1/	# msec to wait
;	CALL ENCTVT
;Ret+1:	always

ENCTVT:	SETONE TSTVO,(TCB)	; Remember a packet should be sent
	IFQE. TSFP,(TCB)	;packet already being forced?
	 MOVE T2,T1		; Desired delay for SIGNAL
	 SKIPN TCBQPZ(TCB)	; Already queued?
	 IFSKP.
	  MOVE T1,TCBTPZ(TCB)	; When
	  SUB T1,TODCLK
	  CAMG T1,T2		; This request sooner?
	   RET			; no.
	 ENDIF.
	 XMOVEI T1,PZ		; Select Packetizer
	 CALL SIGNAL
	ENDIF.
	RET
>;IFN STANSW

	TNXEND
	END