Trailing-Edge
-
PDP-10 Archives
-
BB-H311D-RM
-
arpanet-sources/ttandv.mac
There are 2 other files named ttandv.mac in the archive. Click here to see a list.
; UPD ID= 5056, SNARK:<6.MONITOR>TTANDV.MAC.6, 6-Nov-84 10:37:58 by PAETZOLD
;TCO 6.2268 - Make arg check in CHKTVT.
; UPD ID= 4843, SNARK:<6.MONITOR>TTANDV.MAC.5, 17-Sep-84 11:38:30 by PURRETTA
;Update copyright notice
; 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 1982, 1984.
;ALL RIGHTS RESERVED.
IFN .TVFLG,< ; If supporting TCP terminals
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=TTDDLN+2
;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
;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: 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
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
RETSKP
;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>
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
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
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>)
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
XMOVEI T2,CLOSE1 ; Function to call
CALL 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
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
CALL 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
MOVE TVTP,TVTPTR ; AOBJN for all TVTs
OPSCA1: HRRZ T2,TVTP ; Next line number
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.
MOVX T1,^D200 ; The function to queue for PZ if a lot
XMOVEI T2,ENCPKT ; to send - wait a bit, maybe more
CAIGE T4,^D8 ; Less that 8 is echoing so
XMOVEI T2,FRCPKT ; Queue for PZ promptly
CALL (T2) ; See Note above
OPSCA7: MOVE T2,LINADR ; Restore address of terminal block
OPSCA8: CALL ULKTTY ; Decrease reference count, OKINT
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
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
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
> ;END OF IFN .TVFLG