;SUBROUTINE C.NEXT RETURN THE NEXT CHAR FROM THE DAP MESSAGE POINTED
; TO BY P1 (WITH SUB-MESSAGE LENGTH IN P4)
;
;CALL MOVE P1,BYTE POINTER TO FIRST CHAR OF DATA IN MESSAGE (AFTER TYP)
; MOVE P4,COUNT OF DAP DATA BYTES
; SETZ P3, ;CLEAR THE REPEAT COUNT
; PUSHJ P,C.NEXT
;RETURN CPOPJ ;NO CHAR AVAILABLE (MESSAGE COUNTED OUT, OR
; ; SOMETHING WAS WRONG WITH THE MESSAGE)
; CPOPJ1 ;T1 := THE NEXT 12 BIT CHAR FROM THE STREAM
;
;NOTE. WHEN THIS ROUTINE IS DECOMPRESSING CHARACTERS IT USES P3 AS
; A REPEAT COUNT. IF YOU CLOBBER P3 BETWEEN CALLS TO C.NEXT, YOU
; WILL GET GARBAGE.
C.NEXT: ;MAIN ENTRY TO GET NEXT 12 BYTE CHAR.
JUMPN P3,C.RPT ;IF WE ARE IN A REPEAT, GO USE LH OF P3
C.NXT0: ;RECURSIVE ENTRY POINT WHEN PICKING
; A REPEATED CHARACTER
SOJL P4,C.IERR ;COUNT OFF NEXT BYTE (ERROR IF MESSAGE IS DONE)
ILDB T1,P1 ;FETCH THE NEXT CHARACTER
TRZE T1,1_7 ;IS THIS A "COMPRESSED" CHAR
JRST C.NXT1 ; IF SO, EXPAND IT AND RETURN
TRZE T1,1_6 ;IS THIS A REPEATED BLANK?
JRST C.NXT2 ; IF SO, SET COUNT AND LET C.RPT LOOSE ON IT.
TRZE T1,1_5 ;IS THIS A REPEAT COUNT?
JRST C.NXT3 ; IF SO, THEN GET NEXT CHAR AND REPEAT IT.
TRZE T1,1_4 ;IS IT AN "UNUSED" FORM...
JRST C.IERR ; IF SO, THEN SOMETHING IS WRONG.
MOVEI T2,(T1) ;IT MUST BE THE FIRST 4 BITS OF A TWO BYTE CHAR
LSH T2,^D8 ;SHIFT UP THE MOST SIGNIFICANT 4 BITS
SOJL P4,C.IERR ;COUNT DOWN THE NEXT BYTE
ILDB T1,P1 ;GET THE NEXT CHAR
IORI T1,(T2) ;OR IN THE HIGH FOUR BITS
JRST CPOPJ1## ;GIVE A GOOD RETURN
C.NXT1: ;HERE IF THIS IS A "COMPRESSED" CHAR
IDIVI T1,20 ;SEPARATE THE ZONES (CLEVER DON'T YOU THINK...)
LSHC T2,-2 ;NOW T2 := WORD INDEX, T3(B0, B1) HAS BYTE INDEX
MOVE T2,[BYTE (9)000,400,200,100 ;NOW LOAD T2 WITH A WORD THAT
BYTE (9)040,020,010,004 ; HAS FOUR DIFFERENT LOW ORDER
BYTE (9)002,001,202,102 ; BYTES. WE WILL THEN CLEVERLY
BYTE (9)042,022,012,006](T2) ; POSITION IT AT THE TOP OF T2
TLZE T3,(1B0) ;SKIP IF TOP HALF-WORD IS RIGHT.
HRLZI T2,(T2) ;MAKE UPPER HALF CONTAIN THE DESIRED BYTE
TLZE T3,(1B1) ;SKIP IF THE TOP BYTE IS RIGHT.
LSH T2,^D9 ;MOVE THE SECOND BYTE UP TO WHERE IT BELONGS
LSHC T1,^D9 ;(REMEMBER THAT T1 HAS TOP 4 BITS ALREADY)
JRST CPOPJ1## ;ALL DONE. THE CHAR IS THE LOW 12 BITS IN T1!
C.NXT2: ;HERE IF WE HAVE REPEATED BLANKS
JUMPN P3,C.IERR ;NESTED REPEATS ARE ILLEGAL!
MOVEI P3,(T1) ;COPY THE REPEAT COUNT
JUMPE P3,C.NEXT ;IGNORE ZERO LENGTH REPEATS
PJRST C.RPT ;PASS THE BUCK TO C.RPT.
C.NXT3: ;HERE TO REPEAT AN ARBITRARY CHAR.
JUMPN P3,C.IERR ;NEXTED REPEATS ARE NOT ALLOWED.
MOVEI P3,(T1) ;COPY THE REPEAT COUNT
PUSHJ P,C.NXT0 ;CALL OURSELF RECURSIVLY FOR THE REPEATED CHAR.
PJRST C.IERR ;?? THIS IS WRONG. WE SHOULD HAVE ANOTHER CHAR.
JUMPE P3,C.NEXT ;LET ZERO LENTGH REPEATS WORK. (WONT HAPPEN)
HRLI P3,(T1) ;COPY THE CHAR TO REPEAT SO C.RPT WILL SEE IT.
; PJRST C.RPT ;LET C.RPT DO THE REST.
C.RPT: HLRZ T1,P3 ;GET THE CHAR THAT'S BEING REPEATED
SUBI P3,1 ;DECREMENT THE COUNT
TRNN P3,77 ;SEE IF WE HAVE COUNTED DOWN ALL CHARS.
SETZ P3, ; IF WE HAVE, CLEAR THE REPEAT CHAR
JRST CPOPJ1## ;GIVE A GOOD RETURN
C.IERR: POPJ P, ;GIVE ERROR RETURN (WHAT ELSE CAN I DO??)

;DDPCAS - ASSIGN (CREATE IF NEEDED) DDP DEVICE
;NOTE THAT THE DDP WILL HAVE BEEN CREATED IF NECESSARY BY THE DVCNSG
;PRIOR TO MAIN FUNCTION DISPATCH . . .
DDPCAS: PUSHJ P,DDPCAZ ;SEE IF WE CAN MUNCH ON THE DDP
JRST DDE%OU ;OTHER USER HAS THE DDP
MOVEI T1,ASSCON ;THE "IN USE BY ASSIGN COMMAND" FLAG
IORM T1,DEVMOD(F) ;WE NOW OWN THE DDP
DPB J,PJOBN## ;MAKE SURE "WE" IS US
JRST CPOPJ1## ;SUCCESSFUL RETURN
;DDPCZP - ZAP (DESTROY) THE DDP DEVICE
DDPCZP: PUSHJ P,DDPCAZ ;SEE IF WE CAN MUNCH ON THE DDP
JRST DDE%OU ;OTHER USER HAS THE DDP
TLNE S,IOSDDK ;IS THE DDP IN USE AS A KONTROLLER?
PUSHJ P,DDPKZP ;YES, ZAP THE KONTROLLER USER FIRST
MOVEI T1,ASSCON ;THE "IN USE" BY ASSIGNMENT FLAG
ANDCAM T1,DEVMOD(F) ;ALLOW UUOCON TO KRUMP ON THE DDB NOW
PUSHJ P,URELEA## ;NOW DO UUO-LEVEL DDB ZAPPING
; (EVENTUALLY WINDING UP IN ZAPNET/ZAPDDP)
JRST CPOPJ1## ;SUCCESSFUL RETURN
;HELPER FOR DDPCAS/DDPCZP
;
;RETURNS CPOPJ IF THE DDP DDB IS NOT AVAILABLE TO THIS JOB (I.E., SOME OTHER
;JOB HAS THE DDB "IN USE"); RETURNS CPOPJ1 IF THE DDB CAN BE ASSIGNED TO
;THIS JOB.
DDPCAZ: MOVEI T1,ASSCON!ASSPRG;THE "IN USE" FLAGS
LDB T2,PJOBN## ;THE JOB NUMBER (IF ANY) USING THE DDP
TDNE T1,DEVMOD(F) ;IS THE DDB IN USE BY A JOB?
CAMN T2,J ;YES, IS THAT JOB THIS JOB?
AOS (P) ;EITHER AVAILABLE, OR ALREADY IN USE BY US
POPJ P, ;RETURN AS APPROPRIATE

;CONTINUED FROM PREVIOUS PAGE
;PROCESS THE MML AND FEA FIELDS
PUSHJ P,NTDCNF## ;SLURP UP MML AND RLN
JFCL ;NOT USED
;WE LIKE THE DEVICE, ACCEPT THE CONNECT (SEND A CONNECT CONFIRM)
MOVE T1,[NTDXMN##,,NTDXPN##] ;SPN AND DPN ROUTINES
PUSHJ P,NCSCNC## ;SEND CONNECT CONFIRM
JRST DPCIE1 ;AFTER ALL THAT WORK, CAN'T BUILD A MESSAGE!
;THE DEVICE IS NOW READY AND RARING TO GO. FOR LACK OF ANYTHING BETTER
;TO DO (AND BECAUSE IT WAS THE REASON FOR CREATING DDP'S IN THE FIRST
;PLACE) MAKE THE DDP INTO A DECNET KONTROLLER
PUSHJ P,DDPCKN ;MAKE A KONTROLLER OUT OF IT
STOPCD .,STOP,DDPKON, ;++ CAN'T MAKE A KONTROLLER OUT OF DDP
MOVEI T2,DD.DEC ;USER: DECNET
PUSHJ P,DDPCU2 ;ANNOUNCE NEW KONTROLLER TO DECNET
JRST [PUSHJ P,DDPCDV ;WELL! UNMAKE IT A KONTROLLER
STOPCD .,STOP,DDPBAU, ;++ BEING AWFULLY UNCOOPERATIVE!
JRST UPOPJ1##] ;AND LEAVE DEVICE LYING AROUND
;ALL DONE
JRST UPOPJ1## ;SUCCESSFUL RETURN

;HERE WHEN NETSER IS OUT OF MEMORY - TRY TO REQUEUE THE MESSAGE BLOCK
DDPKPU: POP P,T1 ;PITCH THE UNUSEABLE BYTE COUNT
NETOFF ;BACK TO DIDDLING THE QUEUE
MOVE T1,MB.NXT(P1) ;MB THAT WE LEFT AS THE NEXT IN THE QUEUE
CAME T1,DDPQOB(F) ;STILL THERE?
JUMPN T1,DDPKP5 ;QUEUE HAS CHANGED (UNLESS NEW ENTRY APPEARED)
MOVE T1,DDPQOB(F) ;GET PENDING HEAD OF QUEUE
MOVEM T1,MB.NXT(P1) ;PRE-PEND THE DE-QUEUED MESSAGE BLOCK
; (THIS IS NEEDED FOR THE CASE WHERE
; THE DE-QUEUED MB WAS THE ONLY ENTRY IN
; THE QUEUE, THEN A NEW ENTRY WAS ADDED
; AFTER THIS ONE GOT DE-QUEUED)
MOVEM P1,DDPQOB(F) ;RE-QUEUE THE DE-QUEUED MESSAGE BLOCK
DDPKP2: NETON ;SAFE AGAIN
PJRST DDPKK7 ;TRY TO OUTPUT DATA REQUESTS (IF NEEDED)
;HERE WHEN WE CAN'T RE-QUEUE THE MESSAGE 'CUZ THE QUEUE CHANGED. PROBABLY
;KONTROLLER GOT HALTED OR SOMETHING LIKE THAT. PITCH THE MESSAGE AND LET
;THE DRIVER WORRY ABOUT IT. THIS SHOULD NOT HAPPEN OFTEN.
DDPKP5: NETON ;HO HUM
MOVE T3,P1 ;ADDRESS OF MESSAGE BLOCK
DDPKP7: MOVEI T1,DI.ODN ;FUNCTION: LIE AND SAY "OUTPUT DONE"
PUSHJ P,DDPDV1 ;TELL DRIVER OUR WOES
JFCL ;IGNORE ERROR
POPJ P,

;HERE WHEN RECEIVE DATA REQUESTS FROM REMOTE
;
;ENTERED WITH NETSER INTERLOCK . . .
DDPKIQ: PUSHJ P,NTDRDQ## ;ACCUMULATE DATA REQUESTS FOR OUTPUT
STOPCD .,STOP,DDPRDQ, ;++ NTDRDQ FAILED
PUSHJ P,DDPKKO ;KICK THE OUTPUT STUFF
JRST CPOPJ1## ;SKIP RETURN (FOR NCTDSP)
;HERE WHEN WE'VE RECEIVED AN NCL MESSAGE FOR THIS DDP, MAY BE DATA, STATUS,
;ETC. LET NETSER DO THE BRUNT OF THE PARSING AND DISPATCHING (BACK TO DDPSER
;VIA NDEVDP DISPATCH - AND NO, THIS IS NOT RECURSIVE, EVEN THOUGH WE GOT
;HERE VIA SAID NDEVDP DISPATCH).
;
;ENTERED WITH NETSER INTERLOCK . . .
;*** AT THIS POINT, WE REALLY SHOULD CHECK FOR ANY DATA LEFT OVER FROM
;*** "UUO" DAYS (READ, "DEVPCB") SINCE IT IS POSSIBLE THAT BETWEEN THE
;*** CREATION OF THE DDP AS A DEVICE (DDB) AND THE SWITCHING OF THE
;*** DDP INTO KONTROLLER MODE ONE OR MORE DATA MESSAGES IN THE PIPE
;*** ARRIVED AND GOT QUEUED FOR "IN" UUOS . . .
DDPKIL: PUSHJ P,NTDILD## ;GO PROCESS NCL INPUT
; PJRST DDPKKO ;GO KICK THE OUTPUT ROUTINES

TITLE NETMCR - NETWORK MONITOR CONTROL ROUTINES VERSION 001
SUBTTL NETMCR -- WEM/ 4-JUN-78
SEARCH F,S,NETPRM
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
; COPYRIGHT (C) 1978,1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VNEMCR,001 ;PUT VERSION NUMBER IN GLOB AND LOADER MAP
NETMCR::ENTRY NETMCR
NDEVMC==:777740 ;DUMMY DEVSER DISPATCH FOR NDT MACRO

;COME HERE ON SPECIAL CALLS FROM SCNSER
;CODE IN T3:
;1 = BUFFER LOW
;2 = CHARACTER NOT STORED
;3 = CONTROL O PROCESSING.
D85REM: CAILE T3,IRRINV ;VALIDATE RANGE
CAILE T3,IRRTMO ; ...
POPJ P, ;IGNORE IF NOT IN RANGE
JRST @.(T3) ;OTHERWISE DISPATCH
IFIW MCRBFL ;BUFFER LOW
IFIW MCRCNS ;CHARACTER NOT STORED
IFIW MCRCTO ;CONTROL O
IFIW MCRCSA ;CHUNK SPACE AVAILABLE
IFIW MCRDIS ;DISCONNECT
IFIW MCRCIB ;CLEAR INPUT BUFFER
IFIW MCRTMO ;AUTO-DISCONNECT TIMEOUT
;THESE ARE NO-OPS FOR NOW.
MCRCNS==CPOPJ##
MCRCSA==CPOPJ##
MCRCIB==CPOPJ##
;COME HERE ON CONTROL O ACTION. THE CONTROL O MAY HAVE BEEN
; SET EITHER ON OR OFF. CHECK THE LDB TO DETERMINE WHICH AND
; SEND A CHARACTER GOBBLER IF IT HAS BEEN SET ON.
MCRCTO: MOVSI T2,LRLSCG## ;GET AND SET THE BIT
IORM T2,LDBREM##(U) ; SAYING WE WANT A CHAR GOBBLER SENT
PJRST D85CHP ;NOW QUEUE THE LDB FOR SERVICE
;COME HERE IF INPUT BUFFER IS FULL
;THIS TELLS THE FRONT END THAT AN XOFF IS NEEDED
; SKIP RETURNS IF MESSAGE GETS SENT
MCRBFL: MOVSI T2,LRLXOF## ;GET THE XOFF FLAG
IORM T2,LDBREM##(U) ;SET IT SO SCNMC7 WILL SEE IT
AOS (P) ;GIVE A GOOD SKIP RETURN
PJRST D85CHP ;AND QUEUE THE LDB
;COME HERE ON AUTO-DISCONNECT TIMEOUT FROM SCNSEC.
; THIS WILL TRY TO DISCONNECT THE TERMINAL IF AT ALL REASONABLE.
MCRTMO: MOVEI T2,LDRDSD## ;DATASET BIT
TDNN T2,LDBDCH##(U) ;IS IT ONE?
PJRST MCRDIS ;NO, TRY IT THIS WAY
PUSHJ P,MCRCHK ;SEE IF A LEGAL TERMINAL
POPJ P, ;RETURN FAILURE IF NOT
PJRST D85OFF ;JUST DO THE DISCONNECT IF SO
;COME HERE ON USER DISCONNECT REQUEST (E.G., FROM TRMOP. .TODNT).
; THIS WILL SEND THE DISCONNECT IF REASONABLE.
MCRDIS: PUSHJ P,MCRCHK ;SEE IF A LEGAL TERMINAL
POPJ P, ;RETURN IF NOT
MOVE T2,LDBREM##(U) ;NO, GET ITS REMOTE STATUS BITS
TRNN T2,LRRSHC## ;CAN THIS LINE HANDLE A DISCONNECT?
POPJ P, ;NO, DON'T DISCONNECT IT
MOVSI T2,LRLTMO## ;YES, GET TIME-OUT BIT
IORM T2,LDBREM##(U) ;LIGHT IT
JRST CPOPJ1## ;NMCSEC WILL DISCONNECT THE LINE

SUBTTL 3.3 OUTPUT PCB MANIPULATION
;THE FOLLOWING FOUR ROUTINES ARE USED FOR HANDLING TERMINAL PCB'S. THE
; REASON THAT THEY ARE SO COMPLEX IS TO MAKE IT EASY TO SEND
; MULTI-PART MESSAGES.
;
;TRQPCB REQUEST A TERMINAL PCB.
;CALL PUSHJ P,TRQPCB
;ARGS T1 := MINIMUM NUMBER OF BYTES REQUIRED (LESS COUNT FIELD)
;RET CPOPJ ;COULD NOT GET THE PCB. "U" NOT SET UP.
; CPOPJ1 ;DID GET THE PCB. THE FOLLOWING HAS BEEN DONE:
; ; A) P2 := BYTE POINTER (TO IDPB WITH)
; ; B) P3 := ZERO (USE TO COUNT BYTES)
; ; C) P4 := MAX NUMBER OF BYTES LEFT IN THIS
; ; SUB MESSAGE. (IE. TO END OF PCB)
; ; D) A "PUSH P,P2" HAS BEEN DONE. (IE THIS
; ; ROUTINE HAS LEFT A COPY OF P2 ON THE STACK)
; ; THIS IS TO MAKE IT EASY TO FILL IN THE
; ; COUNT FIELD LATER. TWRPCB MUST BE CALLED
; ; TO PERFORM THIS ACTION. (CANNOT BE CALLED WITH
; ; A ZERO COUNT)
;
;TWRPCB WRITE BACK THE PCBPTR AND PCBCTR FIELDS AND POP OLD BYTE
; POINTER OFF OF THE STACK
;CALL PUSHJ P,TSRPCB
;RET CPOPJ
;
;TSDPCB SEND THE CURRENT PCB. (QUEUE IT FOR OUTPUT)
;CALL PUSHJ P,TSDPCB
;RET CPOPJ ;NTRPCB WILL BE CLEARED TO INDICATE PCB WAS SENT.

SUBTTL 3.3.1 REQUEST AN OUTPUT PCB
;TRQPCB GET A TERINAL PCB
; T1 := MINIMUM NUMBER OF BYTES
;RETURN CPOPJ ;NO CORE
; CPOPJ1 ;PCB ACQUIRED SUCCESSFULY
TRQPCB::SKIPLE T1 ;WE DON'T ALLOW NEGATIVE REQUESTS
CAIL T1,NTTPLN##*4-7 ;HERE MAKE SURE HE ASKED FOR A REASONABLE AMT.
STOPCD .,STOP,RTM, ;++REQUESTED TOO MUCH.
PUSH P,T1 ;REMEMBER THIS FOR LATER
PUSH P,U ;SAVE THE LDB (WILL SWAP FOR PCB LATER)
HRRZ U,NTRPCB ;NOW GET CURRENT PCB (IF ANY)
SKIPE U ; IF THERE WAS ONE, THEN
JRST [MOVE P3,PCBCTR(U) ; SET UP THE COUNT AND SKIP THE CODE THAT
JRST TRQP.2] ; TRIES TO ALLOCATE A NEW PCB
TRQP.1: MOVEI T1,NTTPLN## ;GET LENGTH OF A TERMINAL PCB
SETZ F, ;MAKE SURE MAKPCB DOESN'T HACK ANY DDB
PUSHJ P,MKNPCB## ; AND GO GET A NEW PCB.
JRST [POP P,U ;NO CORE. RESTORE THE LDB
JRST TPOPJ##] ; AND GIVE AN ERROR RETURN
HRRM U,NTRPCB ;NOW STORE THE FACT WE HAVE A PCB.
MOVE P2,PCBPTR(U) ; AND SET UP THE INITIAL BYTE POINTER
MOVEI T1,NCT.IT ;GET THE NCT BITS
PUSHJ P,NCSWHD## ;WRITE THE NCL HEADER.
SETZ P3, ;NOW WRITE OUR DLA. TO DO THIS WE MUST
EXCH U,(P) ; GET BACK OUR LDB,
LDB T1,LDPDLA## ; USE IT TO EXTRACT OUR DESTINATION LINK,
PUSHJ P,BI2EBI ; AND THIS WILL WRITE IT OUT.
EXCH U,(P) ;NOW GET BACK THE PCB POINTER,
ADDB P3,PCBCTR(U) ; UPDATE THE POINTERS, AND DROP INTO MAIN FLOW
TRQP.2: MOVEI P4,NTTPLN##*4 ;HERE WE MUST CALCULATE TO SEE IF THE CURRENT
SUBI P4,1(P3) ; PCB WILL HOLD AS MUCH AS OUR CALLER
CAMGE P4,-1(P) ; REQUESTED IT SHOULD. IF IT CAN'T, THEN
JRST [PUSHJ P,TSDPCB ; SEND THIS PCB OUT, AND
JRST TRQP.1] ; START ON A NEW ONE.
POP P,U ;RESTORE THE LDB
POP P,T1 ; THE REQUEST (WHICH WE CAN NOW IGNORE)
POP P,T1 ; AND POP OFF OUR RETURN ADDRESS.
PUSH P,P2 ;NOW SAVE A BYTE POINTER TO COUNT FIELD
IBP P2 ; AND MAKE POINTER POINT TO THE TYP FIELD
SETZ P3, ;SET THE INITIAL COUNT TO ZERO.
JRST 1(T1) ;ALL DONE. RETURN TO CALLER.
; (WITH UNESTHETIC GARBAGE ON THE STACK ...)

SUBTTL 3.3.2 CLOSE OFF A DAP SUB-MESSAGE
;TWRCPB THIS ROUTINE WRITES BACK THE COUNT FIELD AND UPDATES THE POINTER
; IN THE PCB. IT ALSO REMOVES UNESTHETIC GARBAGE FROM THE STACK
;CALL PUSHJ P,TWRPCB
;RETURN CPOPJ ;WITH ONE LESS WORD ON THE STACK
TWRPCB::SKIPG P3 ;IF NO-ONE WROTE ANYTHING, THEN COMPLAIN
STOPCD .,STOP,NWA, ;++NO-ONE WROTE ANYTHING?
PUSH P,U ;SAVE THE LDB, AND
HRRZ U,NTRPCB ; GET BACK A POINTER TO THE PCB
SKIPE U ;HERE JUST MAKE A LITTLE CHECK ON U'S VALIDITY
CAILE P3,(P4) ; AND MAKE SURE NO ONE WROTE TOO FAR
STOPCD .,STOP,SNS, ;++NTRPCB NOT SETUP??
ADDM P3,PCBCTR(U) ;NOW UPDATE THE COUNT AND
AOS PCBCTR(U) ; DON'T FORGET ABOUT THE 'COUNT' BYTE
POP P,U ;RESTORE THE LDB,
POP P,T1 ; GET OUR RETURN ADDRESS,
POP P,T2 ; AND GET BACK THE POINTER TO THE COUNT FIELD.
IDPB P3,T2 ;STORE THE COUNT,
JRST (T1) ; AND RETURN

SUBTTL 4.0 UTILITY ROUTINES AND INTERFACE TO UUOCON
SUBTTL 4.1 PARSE THE NCL CONNECT MESSAGE FOR A TERMINAL
;TTYRPN ROUTINE TO READ THE "SPN" FIELD OF A CONNECT AND LOOK FOR OPR TERMINALS.
;CALL MOVEI U,LDB ;OF TTY BEING CONNECTED
; P1, P4 POINT TO THE "SPN" FIELD OF THE CONNECT (OBJ AND PID)
;RETURN CPOPJ ;WITH NDBOPR SET IF THIS WAS TERMINAL #0
TTYRPN: ;HERE TO READ THE "SPN" ON A MCR CONNECT
;SPN(OBJ)
PUSHJ P,EBI2BI## ;GET THE OBJECT TYPE
CAIE T1,OBJ.TY ;SEE IF IT'S A TERMINAL.
PJRST XSKIP## ;DON'T LET TASKS BECOME "OPR'S"
;SPN(PID)
PUSHJ P,EBI2BI## ;READ THE LINE NUMBER
DPB T1,LDPRLN## ;SAVE IT FOR POSTERITY
CAIN T1,0 ;IS IT THE OPR'S LINE
HRRM U,NDBOPR(W) ;IF SO, REMEMBER THIS LDB
POPJ P,

SUBTTL 4.3 CONNECT TO REMOTE TERMINALS
;MCRCNT ROUTINE TO SEND A CONNECT TO A REMOTE TERMINAL.
;CALL MOVE T1,[XWD NODE#,LINE#]
; PUSHJ P,MCRCNT
;RETURN CPOPJ ;CONNECT REJECTED, NO CORE, NO LDB'S, ...
; CPOPJ1 ;CONNECTED. U := LDB THAT WAS USED.
;NOTE! THIS ROUTINE WILL SEND A CONNECT EVEN IF THE TERMINAL IS ALREADY
; CONNECTED. USE ASGTTY IF YOU JUST WANT THE LINE.
MCRCNT::PUSHJ P,SAVE3## ;WE CLOBBER THESE WHEN SENDING THE MESSAGE
PUSHJ P,SAVJW## ;THESE WHEN WE LOOK AT THE NDB
PUSH P,T1 ;SAVE THE ARGUMENT FOR LATER.
HLRZ T1,T1 ;GET THE NODE NUMBER
PUSHJ P,SRCNDB## ; AND TRY TO FIND THE NDB.
JRST TPOPJ## ; GIVE ERROR RETURN IF NO NDB
PUSHJ P,MCRGET ;GET A NEW ANF/MCR LDB
JRST TPOPJ## ; GIVE ERROR RETURN IF NONE AVAILABLE
MOVE T1,U ;LDB ADDRESS FOR GETSLA
TLO T1,LAT.TY ;FLAG THAT THIS IS AN LDB-STYLE ADDRESS
MOVEI T2,LAT.CC ;WHOSE INITIAL STATE IS CONNECT-CONFIRM
PUSHJ P,GETSLA## ;TRY TO ASSIGN AN SLA
JRST MCRCN8 ; NO LUCK. CLEAN UP AND FAIL
DPB T1,LDPSLA## ;REMEMBER THE LAT ADDRESS
HRRZ T1,(P) ;GET THE NUMBER OF THE LINE TO CONNECT TO
DPB T1,LDPRLN## ; AND SAVE IT SO THAT MCRXCN CAN SEND IT
SKIPN J,.CPJOB## ;LOAD OUR JOB NUMBER
STOPCD .,STOP,MCRJIZ ;++ JOBNUMBER IS ZERO
DPB J,LDPJOB## ;STORE OUR JOB NUMBER (FOR NMCWAK)
PUSHJ P,MCRXCN ;ATTEMPT TO SEND A CONNECT.
JRST MCRCN8 ;NO CORE. CLEAN UP AND RETURN
;CONTINUED ON NEXT PAGE

SUBTTL 4.5 DISCONNECT/RECONNECT TERMINALS (SET HOST)
HOST.U::SE1ENT ;ENTER SECTION 1
PUSHJ P,TTYFNU## ;SET UP U & F
JUMPE U,CPOPJ## ;0 IN U IS AN ERROR TO US
MOVE T1,LDBDCH##(U) ;GET THE CHARACTERISTICS
TRNE T1,LDRPTY## ;PTY'S CAN'T SET HOST
POPJ P, ; WITHOUT CONFUSING THE HELL OUT OF BATCON
HRR M,T2 ;GET THE LOCATION OF THE ARGUMENT
PUSHJ P,GETWDU## ;GET THE NODE NUMBER
PUSHJ P,SAVE4## ;SAVE THE P'S
NETDBJ ;INTERLOCK THE REST OF THIS
PUSHJ P,SRCNDB## ;GO FIND THE NODE
POPJ P, ;IF NO NODE, GIVE THE ERROR RETURN
CAIN W,NETNDB## ;SEE IF HE'S TRYING TO SET HOST HERE
RETSKP ; IF SO, JUST GIVE A GOOD RETURN
LDB T1,NETCNF## ;SEE IF THE NODE HAS A MCR
JUMPE T1,CPOPJ## ; IF NO MCR, DON'T LET HIM SET HOST
SKIPL LDBTTW##(U) ;IF THIS IS A NON-ANF TERMINAL
PJRST VTMHST## ; CALL NETVTM TO DO THE WORK
MOVE T1,LDBREM##(U) ;GET THE REMOTE BITS, AND
TRNN T1,LRRSHC## ; MAKE SURE THIS STATION ISN'T A 72
POPJ P, ;GIVE ERROR IF STATION DOESN'T ALLOW SET HOST
PJRST HOSTDT ;GO DETACH THE GUY AND DO THE SET HOST

HOST.A::SE1ENT ;DO THIS IN SECTION 1
MOVE T2,LDBDCH##(U) ;GET THE CHARACTERISTICS
TRNE T2,LDRPTY## ;IF THIS IS A PTY, GIVE HIM AN ERROR
JRST [MOVEI T1,[ASCIZ /PTYs cannot be switched by SET HOST./]
S0JRST ERRMES##] ;SINCE JOBSTS WON'T WORK OVER THE NET
MOVE S,T1 ;SAVE NAME
JSP T2,SAVCTX## ;RUN THE REST OF THIS AS A JOB
MOVE T1,S ;RESTORE NAME
NETDBJ ;GET THE NETSER INTERLOCK
PUSHJ P,SRCNDB## ;LOOKUP UP THE NDB
JRST [MOVE T1,NRTUNN## ;GET THE "NO SUCH NODE" ERROR MSG
S0JRST ERRMES##] ; AND GO PRINT IT
CAIN W,NETNDB## ;SEE IF IT'S SET HOST SELF
JRST [MOVEI T1,[ASCIZ /% Already at node /]
S0PSHJ CONMES## ;PRINT THE FIRST PART
S0PSHJ TYPNOD## ;PRINT THE NODE NAME
S0JRST PCRLF##] ;FINISH OFF THE MESSAGE AND EXIT
LDB T1,NETCNF## ;SEE IF THE NODE HAS A MCR
JUMPE T1,[MOVEI T1,[ASCIZ /Node does not support remote terminals./]
S0JRST ERRMES##] ;PRINT THE ERROR
SKIPL LDBTTW##(U) ;IF THIS IS A NON-ANF TERMINAL
PJRST VTMHST## ; CALL NETVTM TO DO THE WORK
MOVE T1,LDBREM##(U) ;GET THE REMOTE BITS, AND
TRNN T1,LRRSHC## ; SEE IF THIS STATION HAS SET HOST CAPABILITY
JRST [MOVEI T1,[ASCIZ /Your station does not support SET HOST./]
S0JRST ERRMES##] ;PRINT THE MESSAGE AND EXIT
HOSTDT: PUSHJ P,TSETBI## ;CLEAR OUT THE INPUT BUFFER
PUSHJ P,TSETBO## ; AND THE OUTPUT BUFFER
MOVE T1,LDBREM##(U) ;NOW, SINCE I CAN'T SEEM TO FATHOM THE
TLNN T1,LRLCON ; OBSCURITIES OF SAVCTX, MAKE SURE WE ARE
POPJ P, ; STILL "CONNECTED". (SHOULDN'T HAPPEN BUT)
MOVEI P4,RSN.RC ;BUILD THE ARGUMENTS FOR TRMXDC
HLL P4,NDBNNM(W) ;ARG IS "XWD NODE,REASON" REASON = RECONNECT
LDB T1,LDPRNN## ;GET THE NODE NUMBER OF THIS TERMINALS STATION
PUSHJ P,SRCNDB## ;FIND HIS NDB SO WE CAN SEND HIM A DISCONNECT
STOPCD .,STOP,MCRNSN, ;++ NO SOURCE NODE FOR TERMINAL
MOVE T1,P4 ;GET THE ARGUMENT WE JUST CONSTRUCTED
PJRST TRMXDC ; AND GO SEND THE DISCONNECT/RECONNECT

SUBTTL 4.8 TABLES
;TABLES FOR FILL. THE TABLE ENTRIES ARE FOR BS, TAB, LF, VT,
; FF AND CR FROM LEFT TO RIGHT, AND FILL 0-3 FROM TOP
; TO BOTTOM. THE VALUE OF THE ENTRY IS THE NUMBER OF FILL
; CHARACTERS. THIS IS CONVERTED TO MILLISECONDS BY DIVIDING
; BY THE TRANSMIT SPEED OVER 1000. SOMEDAY MAYBE THE USER
; WILL BE ABLE TO SET THE TIMES DIRECTLY, BUT THIS METHOD
; IS USED NOW FOR COMPATABLILTY WITH LOCAL FILLING, WHICH SENDS
; RUBOUTS INSTEAD OF USING TIMEING.
FILTAB: POINT 6,[BYTE (6) 0,0,0,0,00,0] ;CLASS 0
POINT 6,[BYTE (6) 2,2,2,2,14,2] ;CLASS 1
POINT 6,[BYTE (6) 6,0,6,6,25,4] ;CLASS 2
POINT 6,[BYTE (6) 6,2,6,6,25,4] ;CLASS 3

SUBTTL 4.8 VARIABLES
$LOW
NTRPCB: EXP 0 ;CELL THAT CONTAINS A POINTER TO THE CURRENT
; PCB IN USE WHEN CONSTRUCTING A "MCR" MSG.
; BECAUSE ALL THIS CODE RUNS UNDER THE NETSER
; INTERLOCK WE CAN USE A GLOBAL CELL WITH OUT
; FEAR OF RACES.
$HIGH
XLIST ;DON'T LIST THE LITERALS
$LIT
LIST
NMCEND::PRGEND

TITLE NETPLT - NETWORK PLOTTER ROUTINES - V001
SUBTTL JAC/ 21 SEP 81
SEARCH F,S,NETPRM
$RELOC
$HIGH
XP VNETPL,001 ;PUT VERSION NUMBER IN GLOB AND LOADER MAP
COMMENT \
Digital no longer supports ANF remote plotters. The NETPLT module is
included only as a convenience for those customers who might wish to
try it.
\
NETPLT::ENTRY NETPLT
REPEAT 0,< CCS Edit History
----------------
Edit Date Who Comment
---- ---- --- -------
The following updates were made to keep NETPLT in line with NETLPT.
They are not actual CCS edits, but have been assigned nominal CCS edit
numbers for convenience.
001) 840808 AGM Define global symbol NPLTCI, used by COMNET.
002) 840808 AGM Clean up code and comments. No functional changes.
003) 840808 AGM Updates to error recovery.
004) 840808 AGM Decrement data request count at end of first time code.
------------------------>

TITLE NETRDX - REMOTE DATA ENTRY SERVICE ROUTINE TO SUPPORT MCS10 - V001
SUBTTL D. TODD/WEM 26 JUL 83
SEARCH F,S,NETPRM
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
; COPYRIGHT (C) 1978,1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;XP VRDXSER,052 ;PUT VERSION NUMBER IN GLOB AND LOADER MAP
NETRDX::ENTRY NETRDX
;RDX ONLY DEVICE STATUS BITS
IOSDRP==IOSFFB ;INDICATES THAT THIS IS A MULTIDROP RDX

TITLE NETTSK - TASK TO TASK COMMUNICATION SERVICE ROUTINE - V001
SUBTTL W. E. MATSON/WEM 20 SEP 83
SEARCH F,S,NETPRM
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
; COPYRIGHT (C) 1978,1979,1980,1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;XP VTSKSER,001 ;PUT VERSION NUMBER IN GLOB AND LOADER MAP
NETTSK::ENTRY NETTSK ;LOADING IF IN LIBRARY SEARCH MODE

COMMENT @
The first NPD in the UUO argument list is the Right-hand one (RH(DEVNPD))
The second NPD is the Left-hand one (LH(DEVNPD))
For the passive task.
1) The enter passive state uuo
- NPD1 := Name we wish to be identified as (our process name)
- NPD2 := The "pattern" we wish to match
2) After a successful connection,
- NPD1 := The "actual" that the pattern successfully matched
- NPD2 := The name of the remote process that sent the connect.
For the active task.
1) The enter active state uuo
- NPD1 := The name we want to return as "ours" on the confirm
- NPD2 := The the "actual" we try to connect to.
2) After a successful connection,
- NPD1 := The name the remote thinks we are.
- NPD2 := The name he gave us as "his"
@

SUBTTL 1.3 INPUT UUO.
;T.IN ROUTINE TO HANDLE THE "IN" UUO ENTRY TO THE TSK DEVICE
T.IN: PUSHJ P,SAVE4## ;WE CLOBBER MOST OF THEM
MOVSI S,IOSUSI ;CLEAR "UUOCON STOPED INPUT" SINCE ITS
ANDCAB S,DEVIOS(F) ; OBVIOUSLY TRYING TO START IT AGAIN
TILOOP: PUSHJ P,NTDSET## ;USE COMMON SETUP ROUTINE (S, W, ETC)
MOVE S,DEVIOS(F) ;GET STATUS BITS BACK AFTER A POSSIBLE SLEEP
TLNE S,IOBEG ;IS THIS THE FIRST TIME THROUGH
JRST TIFRST ;IF SO, LOOK FOR PSEUDO NON-BLOCKING CONNECT
MOVSI S,IO ;CLEAR THE DIRECTION BIT SO THAT
ANDCAB S,DEVIOS(F) ; UUOCON WON'T GET CONFUSED.
PUSHJ P,NTDIBA## ;IS THERE AN INPUT BUFFER AVAILABLE?
POPJ P, ;IF NOT, WE ARE DONE.
HRRZ T1,DEVPCB(F) ;GET A POINTER TO THE LIST OF INPUT PCB'S
JUMPE T1,TIWAIT ;IF NO DATA, WE MUST WAIT
PUSHJ P,NTDDID## ;DO THE DELAYED INPUT DISPATCH
JRST TILOOP ;KEEP IT UP TILL WE RUN OUT OF DATA.

;TIFRST HERE WE CHECK TO SEE IF WE ARE CONNECTED. IF NOT, AND THIS IS NON-
; BLOCKING STYLE I/O. THEN WE DO A DEVERR RETURN TO UUOCON. OTHERWISE WE JUST
; WAIT. WHEN WE FINNALY GET CONNECTED. WE MUST REMEMBER TO TURN OFF "IOSERR"
; WHICH GOT SET BY NTDSET.
TIFRST: TLNE S,IOSCON ;ARE WE CONNECTED YET
JRST [MOVSI S,IOBEG!IOSERR!IOSREL ;IF WE ARE CONNECTED, CLEAR
ANDCAB S,DEVIOS(F) ; THESE BITS,
JRST TILOOP] ; AND TRY ONCE AGAIN TO PROCESS DATA.
PUSHJ P,NTDWTI## ;IF NON CONNECTED, THEN WAIT FOR CONNECT/DATA
POPJ P, ;IF NONBLOCKING, RETURN TO UUOCON
JRST TILOOP ;TRY ONCE MORE TO DO INPUT
;TIWAIT HERE IF WE HAVE NO INPUT PCB'S TO PROCESS. FIRST MAKE SURE WE HAVEN'T
; BEEN DISCONNECTED. IF SO, SET EOF. OTHERWISE SEND DATA REQUESTS, AND
; WAIT IT OUT.
TIWAIT: PUSHJ P,NTDONL## ;IS THERE ANY PARTICULAR PROBLEM??
JRST T.EOF ; IF SO, GO SEE WHAT IT IS
PUSHJ P,NTDXDQ## ;SEE IF WE ARE BEHIND ON OUR DATA-REQUESTS
PUSHJ P,NTDWTI## ;WAIT FOR DATA
POPJ P, ;RETURN TO UUOCON IF NON-BLOCKING
JRST TILOOP ;AND GO MUNCH IT
;T.EOF ROUTINE TO RETURN END-OF-FILE ON FIRST "IN" AFTER DISCONNECT.
T.EOF: TLNE S,IOEND ;SEE IF END-OF-FILE ALREADY SET
JRST T.HUNG ;YUP, GET SERIOUS ABOUT ERROR STATUS
MOVSI S,IOEND ;NO, SET EOF NOW
JRST T.SET ;AND LET UUOCON WORRY ABOUT IT
;T.HUNG DEVICE IS OFFLINE (NTDONL), SEE IF STILL CONNECTED
T.HUNG: TLNN S,IOSCON ;STILL CONNECTED?
PJRST NTDGON## ;NO, GIVE ERROR
;YES, FALL INTO T.SERR
;T.IMPM, T.SERR ROUTINES TO SET ERROR BITS AND RETURN
T.SERR: MOVE S,[XWD IOSERR,IODERR] ;THE TWO DEVICE ERROR BITS
JRST T.SET ; AND SET THEM IN DEVIOUS
T.IMPM: MOVEI S,IOIMPM ;IMPROPER MODE (NOT LOOKED UP/ENTERED)
T.SET: IORB S,DEVIOS(F) ;SET THE BITS
POPJ P, ;RETURN TO UUOCON.

SUBTTL 1.6 CLOSE UUO.
;T.CLS ROUTINE TO HANDLE THE CLOSE ENTRY FROM UUOCON
;CALL MOVEI F,DDB
; PUSHJ P,T.CLS ;FROM CLOSE1 CODE IN UUOCON
;RETURN CPOPJ
;
;THE CLOSE UUO CODE DOES NOTHING IF THE TSK HAS NOT BEEN CLOSED ON BOTH INPUT
; AND OUTPUT. IF IT HAS, IT DOES THE FINAL "OUT" TO FLUSH THE BUFFERS, AND
; SENDS A DISCONNECT INITIATE WAITING FOR THE DISCONNECT CONFIRM.
T.CLSO: TLNE F,ENTRB ;DON'T FORCE OUTPUT IF NOT ENTERED
PUSHJ P,NTDCLO## ;FORCE OUT THE LAST BUFFER (AND WAIT)
TLZA F,ENTRB ;SIGNIFY THAT WE ARE NO LONGER "ENTERED"
T.CLSI: TLZ F,LOOKB ;SIGNIFY THAT WE ARE NO LONGER "LOOKED UP"
T.CLS: TLNE F,ICLOSB ;IF WE HAVEN'T CLOSED BOTH INPUT AND
TLNN F,OCLOSB ; OUTPUT, THEN
POPJ P, ; DON'T ATTEMPT TO DISCONNECT THIS TASK
PUSHJ P,T.WAIT ;WAIT FOR CONNECTS/DISCONNECTS TO FINISH
MOVE S,DEVIOS(F) ;NOW SEE IF WE ARE CONNECTED
TLNN S,IOSCON
JRST T.CLS4 ;DON'T SEND DISCONNECT IF NOT CONNECTED
T.CLS2: MOVEI T1,RSN.OK ;STANDARD REASON
PUSHJ P,NTDXDS## ;SEND THE DISCONNECT
JRST [PUSHJ P,NETSLP## ;IF WE CAN'T SEND THE DISCONNECT, THEN
JRST T.CLS2] ; THEN WAIT FOR A BIT AND TRY AGAIN
T.CLS3: PUSHJ P,NETHIB## ;WAIT FOR THE CONFIRM
LDB T1,NETSLA## ;GET OUR LAT ADDRESS
JUMPE T1,T.CLS5 ;THE DISCONNECT CONFIRM CODE WILL ZERO IT
IFN PARANOID&P$LAT,< ;MAKE SURE LAT ENTRY IS RIGHT
LDB T1,LATSTA## ;GET THE STATE
CAIE T1,LAT.DC ;SHOULD STILL BE DISCONNECT CONFIRM
STOPCD .,STOP,TSKNID, ;++ NOT IN DISCONNECT CONFIRM
>
JRST T.CLS3 ;MUST HAVE BEEN A SPURIOUS WAKE

;VTMREC ROUTINE TO PROCESS LOCALLY INPUT CHARS THAT ARE DESTINED FOR
; A REMOTE MCR.
;CALL U := POINTER TO THE LDB OF THE "VTM" LINE
; T3 := THE CHAR
;RETURN CPOPJ ;ALWAYS
VTMREC::MOVE T2,LDBREM##(U) ;GET THE REMOTE STATUS BITS
TLNN T2,LRLCON## ;MAKE SURE WE'RE CONNECTED
JRST [PUSHJ P,PCRLF##;GIVE THE USER A HINT AS TO HOW HE'S SCREWED
MOVEI T1,[ASCIZ /Waiting for connect confirm./]
PJRST CONMES##]; IF THE CONNECT IS NOT COMPLETE
TLNE T2,LRLDIP## ;IF A DISCONNECT IS IN PROGRESS,
JRST [PUSHJ P,PCRLF##;TELL THE TYPIST THAT HIS CHARACTER IS LOST
MOVEI T1,[ASCIZ /Waiting for disconnect confirm./]
PJRST CONMES##]; AND WAIT TILL THE CONFIRM FINALLY COMES IN
;MAKE SURE WE HAVE THE RESOURCES (CHUNKS) TO HANDLE THIS CHARACTER.
MOVE T2,LDBTIC##(U) ;GET THE NUMBER OF CHARS IN THE INPUT BUFFER.
; (DON'T BOTHER WITH COUNT IN LDBECC)
CAIG T2,^D150 ;IF MORE THAN THIS ARBITRARY NUMBER,
SKIPG TTFREN## ; OR THERE ARE NO MORE CHUNKS,
JRST [MOVE T2,FLPBEL## ;THEN DING THE USER'S BELL TO TELL
PJRST SETXNP##]; THE USER HIS CHARACTER WAS DESTROYED
CAIL T2,^D100 ;IF MORE THAN THIS ARBITRARY NUMBER,
PUSHJ P,SNDXOF## ; THEN TELL THE USER'S MACHINE TO STOP
;CHECK FOR ^S
MOVE T2,LDBREM##(U) ;GET THE DAP STATUS BITS
MOVEI T1,(T3) ;GET A COPY OF THE CHARACTER
ANDI T1,177 ; AND IGNORE THE PARITY BIT
TRNN T2,STY.TP ;IF WE'RE NOT IN "TERMINAL PAGE" MODE
JRST VTMRE1 ; DON'T STOP OUTPUT.
CAIE T1,"S"-100 ;IF IT'S NOT A ^S,
JRST VTMRE0 ; THEN CHECK FOR ^Q
MOVSI T1,LOLSTP## ;GET SCNSER'S BIT MEANING THE SAME THING,
IORM T1,LDBOST##(U) ; AND SET IT SO OUTPUT WILL STOP.
JRST VTMRE3 ;GO SHIP THE ^S TO THE REMOTE MCR.

;CHECK FOR ^Q
VTMRE0: CAIE T1,"Q"-100 ;IF IT'S NOT A ^Q,
JRST VTMRE1 ; THEN KEEP GOING
MOVSI T1,LOLSTP## ;GET SCNSER'S BIT MEANING THE SAME THING
ANDCAM T1,LDBOST##(U) ; AND CLEAR IT SO OUTPUT WILL START.
PUSHJ P,SETCHP## ; AND START OUTPUT
JRST VTMRE3 ;GO SHIP THE ^Q TO THE REMOTE MCR
;SEE IF IMAGE INPUT MODE. IF NOT, DO AUTO-CRLF, ^S AND CASE CONVERSION
VTMRE1: TRNE T2,STY.II ; AND SEE IF WE'RE IN IMAGE INPUT.
JRST VTMRE3 ; IF IMAGE INPUT, SKIP THE NEXT FEW CHECKS.
ANDI T3,177 ;NOT IMAGE MODE, SO GET RID OF PARITY BIT
JUMPE T3,CPOPJ## ;THROW AWAY ANY NULL CHARACTERS.
;CHECK FOR CASE CONVERSION
TRNN T2,STY.CV ;SEE IF CASE CONVERSION IS ENABLED
JRST VTMRE2 ;IF NOT ENABLED, DON'T DO IT.
CAIL T3,140 ;RANGE CHECK THE CHARACTER
CAIL T3,175 ; TO SEE IF IT SHOULD BE CONVERTED
JRST VTMRE2 ;IF NOT A LOWER CASE CHAR, DON'T CONVERT IT
TRZ T3,40 ;MAKE UPPER CASE LOWER CASE
JRST VTMRE3 ;SKIP NEXT CHECK SINCE CHAR ISN'T A SPACE
;NOW DO AUTO-CRLF CHECK.
VTMRE2: CAIE T3,40 ;IS THE CHAR A SPACE?
JRST VTMRE3 ; IF NOT, DON'T CONVERT IT TO A CR.
LDB T4,LDPACR## ;GET THE "AUTO-CRLF" POSITION
JUMPE T4,VTMRE3 ; IF AUTO-CRLF NOT ENABLED, CHECK NO FARTHER
PUSHJ P,HPOS## ;GET OUR CURRENT HORIZONTAL POSITION.
CAIL T2,(T4) ; AND IF WE'RE PAST THE "AUTO-CRLF" LOCATION
MOVEI T3,15 ; THEN PRETEND THE USER TYPE "CR" NOT SPACE.
;ALL LOCAL CHARACTER PROCESSING IS DONE (EXCEPT POSSIBLY ECHO). NOW
; IT'S TIME TO SHIP THE CHARACTER TO THE REMOTE MCR.
VTMRE3: SCNOFF ;IN PREPARATION FOR TICKLING CHUNK CHAINS
MOVE T2,LDBREM##(U) ;GET THE DAP STATUS ONCE AGAIN
TRNE T2,STY.DE ; AND SEE IF WE'RE IN DEFERED (MCR) ECHO
JRST [PUSHJ P,VTMSTI ; IF DEFERED ECHO, FIRST STORE THE CHARACTER
LDB T1,LDPEPM##;GET THE OLD ECHO PIPELINE SERIAL
AOS T1 ; AND MAKE A NEW ONE
DPB T1,LDPEPM##;STORE NEW ONE SO MARKER FROM HOST WON'T MATCH
SCNON ;INTERRUPTS OK NOW.
PJRST VTMENQ] ;QUEUE THE LINE SO THE DATA GETS SENT TO MCR.
;HERE IF WE'RE IN LOCAL ECHO. NOW CHECK TO SEE IF THERE IS ANY REASON
; FOR GOING INTO DEFERED ECHO.
CAIG T3,176 ;SEE IF THIS CHARACTER IS
CAIGE T3,40 ; IN THE RANGE OF BREAK CHARACTERS
JRST [CAIE T3,11 ; OR IF IT IS THE "NON BREAK" TAB
JRST VTMRE4 ;IF IT'S A BREAK GO ENTER DEFERED ECHO
JRST .+1] ;NON-BREAK TAB. STAY IN LOCAL ECHO
PUSHJ P,VTMSTE ;GO STORE THE CHARACTER AS "ECHOED"
PUSHJ P,VTMSTO ;ECHO THE CHARACTER BY PUTTING IN OUTPUT STREAM
SCNON ;INTERRUPTS OK NOW.
PUSHJ P,TOPOKE## ;START THE OUTPUT GOING.
MOVE T1,LDBECC##(U) ;GET THE COUNT OF ECHOED CHARACTERS
CAIL T1,^D72 ; AND IF MORE THAN 30 WAITING TO GO,
PUSHJ P,VTMENQ ; THEN QUEUE THE LINE FOR SERVICE.
POPJ P, ;RETURN. CHAR HAS BEEN STORED AND ECHOED.
;HERE WHEN WE RECEIVE A BREAK CHARACTER WHILE WE ARE IN LOCAL ECHO MODE.
; WE MUST STORE THE CHARACTER, ENTER DEFERED ECHO MODE, AND QUEUE
; THE LINE SO THE DATA GETS SHIPPED TO THE MCR. NOTE THAT "CR" IS
; SPECIAL IN THAT IT IS THE ONLY BREAK CHARACTER THAT IS ECHOED LOCALLY.
; THIS IMPROVES THE "FEEL" OF THE NETWORK AND GIVES AN ILLUSION OF
; GREAT SPEED.
VTMRE4: CAIE T3,15 ;WAS THIS A "CR"
JRST VTMRE5 ; IF NOT, DON'T DO THE FANCY LOCAL ECHO
PUSHJ P,VTMSTE ;STORE THE CHAR AS AN "ECHOED" CHAR
PUSHJ P,VTMSTO ; AND ECHO A "CR" TO THE OUTPUT STRING
MOVEI T3,12 ;GET A "LF"
PUSHJ P,VTMSTO ; AND PUT THAT IN THE OUTPUT STRING TOO.
SCNON ;ALL CHARS STORED. INTERRUPTS OK NOW.
PUSHJ P,TOPOKE## ;START UP OUTPUT TO GET THE ECHO OUT.
PJRST VTMEDM ;ENTER DEFERED ECHO MODE (QUEUE LINE) & EXIT
VTMRE5: PUSHJ P,VTMSTI ;STORE THE CHAR AS A NORMAL NON-ECHOED CHAR
SCNON ;INTERRUPTS OK NOW...
PJRST VTMEDM ;QUEUE THE LINE SO MCR GETS DATA & EXIT.

;VTMDSO ROUTINE CALLED BY SCNSER WHEN A DATA-SET LINE COMES UP
;CALL U := POINTER TO THE LDB
;RETURN CPOPJ ;ALWAYS
VTMDSO::MOVEI T1,STY.RG ;GET THE RING/CARRIER BIT
IORM T1,LDBREM##(U) ; AND SET IT IN THE STATUS
PJRST VTMSSS ;GO "SET SEND STATUS" AND QUEUE THE LINE
;VTMDSF ROUTINE CALLED BY SCNSER WHEN A DATA-SET LINE HANGS UP
;CALL U := POINTER TO THE LDB
;RETURN CPOPJ ;ALWAYS
VTMDSF::MOVEI T1,STY.RG ;GET THE RING/CARRIER BIT
ANDCAM T1,LDBREM##(U) ; AND CLEAR IT IN THE STATUS WORD
MOVSI T1,LRLDIP## ;GET THE "WE WANT TO DISCONNECT" BIT
IORM T1,LDBREM##(U) ; AND SET IT
PJRST VTMENQ ;QUEUE THE LINE SO THAT IT GETS SENT
;VTMSSS ROUTINE TO "SET SEND STATUS" AND QUEUE A LINE
;CALL U := POINTER TO THE LDB
;RETURN CPOPJ ;ALWAYS
VTMSSS: MOVSI T1,LRLSTS## ;GET THE "PLEASE SEND STATUS BIT"
IORM T1,LDBREM##(U) ; AND SET IT SO STATUS GOES SOON
PJRST VTMENQ ;QUEUE THE LINE SO IT GETS SCANNED

;VTMDAP ROUTINE TO DIS-ASSEMBLE AN INCOMING DAP MESSAGE AND DISPATCH
; ON THE VARIOUS DAP SUB-MESSAGES.
;CALL F := LAT ENTRY (RH(F) = LDB POINTER)
; W := NDB THAT THE LINE IS CONNECTED TO
; P1 & P4 := BYTE POINTER & COUNT TO THE INCOMING MESSAGE
;RETURN CPOPJ ;MESSAGE WAS "BAD" IN ONE WAY OR ANOTHER
; CPOPJ1 ;MESSAGE HAS BEEN PROCESSED.
VTMDAP: MOVE T1,PCBPTR(U) ;GET MESSAGE POINTER (SO WE CAN GET NCT LATER)
PUSH P,U ;PRESERVE THE PCB ADDRESS
MOVE U,F ;THE LDB ADDRESS IS CARRIED IN "U"
;NOW LOOK AT THE NCT BYTE TO SEE IF THIS MESSAGE IS INTERRUPT OR NORMAL
ILDB T1,T1 ;GET THE NCT BYTE
TRNE T1,NCT.IT ; AND SEE IF IT HAS THE INTERRUPT BIT SET
JRST VTMDP1 ;IT'S AN INTERRUPT MSG. LEAVE DRQ ALONE.
LDB T1,LDPDRQ## ;IT'S NORMAL DATA. GET THE DRQ COUNT
SOSGE T1 ; AND COUNT OFF ONE LESS OUTSTANDING DRQ
PJSP T1,VTMDP3 ;IF DRQ WENT NEGATIVE, REMEMBER OUR PC
; FIXUP THE STACK AND MARK THE MSG AS BAD.
DPB T1,LDPDRQ## ;STORE THE UPDATED DRQ
;DROP THROUGH TO DISSECT THE INCOMING MESSAGE.

VTMDP1: JUMPLE P4,UPOPJ## ;IF AT END OF MESSAGE, GIVE GOOD RETURN
;CNT
PUSHJ P,EBI2BI## ;GET THE LENGTH OF THIS SUB-MESSAGE
SUB P4,T1 ; CALCULATE LENGTH OF REMAINDER OF MSG.
SKIPGE P4 ;MAKE SURE MSG LENGTH DOESN'T GO NEGATIVE
PJSP T1,VTMDP3 ;IF SUB MSG LONGER THAN MSG, TOSS MSG AS BAD
PUSH P,P4 ;REMEMBER HOW MUCH IS LEFT IN THE MESSAGE
MOVEI P4,(T1) ; AND SET UP THE LENGTH FOR THIS SUB-MSG
;TYPE
PUSHJ P,EBI2BI## ;GET THE IDC TYPE FIELD
CAIL T1,DC.DAT ;RANGE CHECK IT
CAILE T1,DC.CTL ; SO WE DON'T JUMP OFF INTO THE WEEDS
PJSP T1,VTMDP2 ;IF OUT OF RANGE TYPE, REPORT BAD MESSAGE
PUSHJ P,@TTYNDP(T1) ;CALL THE APPROPRIATE SUB-MSG PROCESSOR
PJSP T1,VTMDP2 ; AND IF HE THINKS THE MSG IS BAD, TOSS IT.
SOJG P4,[IBP P1 ;SKIP TO THE END OF THE SUB-MSG
JRST .] ; SO WE'RE READY TO READ THE NEXT "CNT" FIELD
POP P,P4 ;RECOVER THE LENGTH OF THE UNPROCESSED PART
JRST VTMDP1 ; AND GO DO THE NEXT SUB-MESSAGE
;HERE IF FOR SOME REASON WE THINK THE MESSAGE IS BAD.
;CALL T1 := ADDRESS OF CODE THAT DECIDED IT DIDN'T LIKE THE MSG
VTMDP2: POP P,P4 ;FIXUP THE STACK IF WE HAVE THE LENGTH ON IT
VTMDP3: POP P,U ;GET THE PCB POINTER BACK FOR INCTBD
JRST INCTBD## ;MARK THE MESSAGE AS BAD & RETURN

;VTMEPM ROUTINE TO PROCESS AN INCOMING ECHO-PIPELINE-MARKER.
;CALL U := POINTER TO THE LDB
; P1 & P4 := POINTER TO AND LENGTH OF SUB MESSAGE
;RETURN CPOPJ ;NEVER
; CPOPJ1 ;EPM PROCESSED.
;FCN IF THE EPM SERIAL NUMBER MATCHES THE LAST ONE SENT, THEN
; THERE ARE NO MORE CHARS IN THE "PIPELINE". IN THIS CASE
; WE CAN GO INTO LOCAL ECHO ONLY IF WE HAVE NO INPUT CHARS
; QUEUED FOR THE REMOTE HOST.
VTMEPM: PUSHJ P,BYT2BI## ;GET THE 8 BIT EPM SERIAL NUMBER
LDB T2,LDPEPM## ;GET THE SERIAL NUMBER OF THE LAST EPM SENT
CAIE T1,(T2) ;IF WE HAVEN'T GOTTEN OUR LAST EPM BACK
RETSKP ; THEN THERE ARE STILL CHARS IN THE PIPE
MOVEI T1,STY.DE ;GET THE "REMOTE IS ECHOING" BIT
TDNN T1,LDBREM##(U) ;SEE IF WE ARE ALREADY IN LOCAL ECHO
RETSKP ; IF IN LOCAL ECHO, IGNORE EXTRA EPM
SCNOFF ;MAKE SURE WE DON'T ECHO A CHAR FOR A WHILE
SKIPN LDBTIC##(U) ;MAKE SURE THAT NO CHARS HAVE
SKIPE LDBECC##(U) ; SNUCK IN WHILE WE WEREN'T LOOKING
JRST SONPJ1## ;IF CHARS QUEUED, DON'T ENTER LOCAL ECHO MODE
ANDCAB T1,LDBREM##(U) ;CLEAR REMOTE ECHO (ENABLE LOCAL ECHO)
DPB T1,LDPDST## ;SAVE THE STATUS MESSAGE
MOVSI T1,LRLDST## ;GET THE BIT SAYING A STATUS MSG IS "SAVED"
IORM T1,LDBREM##(U) ; SO THAT NEXT TIME WE START A MESSAGE
; FOR THE REMOTE WE WILL SEND A STATUS
; MESSAGE TELLING HIM WE'RE LOCAL ECHOING
SCNON ;INTERRUPTS OK NOW.
AOS (P) ;GIVE GOOD RETURN
PJRST VTMENQ ;NOW QUEUE THE LINE TO SEND THE STATUS
; *** NOTE *** WHILE IT WOULD BE NICE
; TO BE ABLE TO DELAY SENDING THIS STATUS
; MESSAGE, UNTIL NETMCR GETS SMARTER ABOUT
; TELLING US IF WE SHOULD ECHO OR NOT, WE
; MUST INFORM IT IMMEDIATLY UPON ENTERING
; LOCAL ECHO MODE. IF WE DON'T, PASSWORDS
; WILL ECHO...
;VTMCGB ROUTINE TO PROCESS A "CHARACTER GOBBLER" (^O) REQUEST
;CALL U := POINTER TO THE LDB
; P1 & P4 := POINTER TO, AND LENGTH OF SUB MSG (WE IGNORE IT)
;RETURN CPOPJ ;NEVER
; CPOPJ1 ;OUTPUT STREAM "GOBBLED"
VTMCGB: PUSHJ P,TSETBO## ;SCNSER DOES ALL THE WORK
RETSKP ;GIVE GOOD RETURN

;VTMHST ROUTINE TO PERFORM THE "SET HOST" FUNCTION FOR A LOCAL TERMINAL
;CALL W := ADDRESS OF THE NODE TO "SET HOST" THIS TERMINAL TO
; U := ADDRESS OF THE LDB TO THAT IS DOING THE "SET HOST"
;RETURN CPOPJ ;WITH EITHER THE CONNECT DONE, OR AN
; ; ERROR MESSAGE PRINTED
VTMHST::HRRZ F,LDBDDB##(U) ;GET THE ADDRESS OF THIS GUY'S TTY DDB
SKIPE F ;DON'T DO THE DETACH IF NO DDB
PUSHJ P,TTYDET## ;DETACH THIS GUY
; PJRST VTMCNT ;LET VTMCNT DO THE REST OF THE WORK
;VTMCNT ROUTINE TO PERFORM THE CONNECT FUNCTION FOR A TERMINAL.
;CALL W := ADDRESS OF NDB OF NODE TO CONNECT TO
; U := ADDRESS OF LDB TO CONNECT
;RETURN CPOPJ ;WITH EITHER THE CONNECT SENT, OR
; ; AN ERROR MESSAGE PRINTED.
VTMCNT: PUSHJ P,VTMLOC ;CLEAN UP THE LDBREM WORDS.
PJRST FRELDB## ;AWKWARD TIME FOR LAT/NRT/ETC TO DIE. FREE LDB
POPJ P, ;RETURN WITH NO MORE ADO
MOVE T1,U ;LDB ADDRESS FOR GETSLA
TLO T1,LAT.TY!LAT.VT;REMEMBER THAT THIS IS VTM/LDB-STYLE
MOVEI T2,LAT.CC ;INITIAL STATE IS CONNECT-CONFIRM
PUSHJ P,GETSLA## ;ATTEMPT TO ASSIGN AN SLA
JRST [MOVEI T1,[ASCIZ \No free LAT entries.\]
JRST VTMCN8] ;MAKE LINE LOCAL AND PRINT ERROR
DPB T1,LDPSLA## ;SAVE THE SOURCE LINK ADDRESS
HLRZ T1,NDBNNM(W) ;GET THE NUMBER OF THE NODE TO CONNECT TO
DPB T1,LDPRNN## ; AND SAVE THAT AS THE VTMS REMOTE NODE #
PUSHJ P,VTMXCN ;SEND THE CONNECT.
JRST [MOVE T1,NRTNCE## ;"NETWORK CAPACITY EXCEEDED ERROR
JRST VTMCN8] ;MAKE LINE LOCAL AND PRINT ERROR
;AT THIS POINT WE HAVE SENT THE CONNECT. NOW MAKE THE LINE "REMOTE"
MOVSI T1,LRLVTM## ;GET THE "THIS IS A VTM" BIT
IORM T1,LDBREM##(U) ; AND SET IT SO TYPEIN COMES TO US AND
; DOESN'T GO TO SCNSER
POPJ P, ;EXIT WITH LINE WAITING FOR CONNECT CONFIRM.
;HERE ON ERROR TRYING TO DO THE CONNECT, ERROR MESSAGE IN T1
VTMCN8: PUSHJ P,VTMLOP ;MAKE LINE LOCAL AND PRINT ERROR MESSAGE
PJRST FRELDB## ;AWKWARD TIME FOR LAT/NRT/ETC TO DIE. FREE LDB
POPJ P, ;RETURN WITH NO MORE ADO
POPJ P, ;RETURN WITH LINE LOCAL AND USEABLE

;VTMENQ ROUTINE TO QUEUE A VTM FOR PROCESSING.
;CALL U := ADDR OF THE LDB TO QUEUE
;RETURN CPOPJ ;WITH THE LINE QUEUED
VTMENQ::
IFN PARANOID&P$VTM,< ;IF WE'RE BEING CAREFUL,
TRNN U,-1 ;MAKE SURE THAT WE'VE GOT A LDB POINTER
STOPCD .,STOP,VTMLDB, ;++ NO LDB IN VTMENQ
>
SCNOFF ;NO JOSTLING IN THE WAITING ROOM PLEASE.
MOVSI T1,LRLQED## ;GET THE "LDB ALREADY QUEUED BIT"
TDNE T1,LDBREM##(U) ; AND SEE IF WEVE ALREADY BEEN QUEUED
JRST SONPPJ## ;IF ALREADY QUEUED, WE'RE DONE.
IORM T1,LDBREM##(U) ;MARK THIS LDB AS QUEUED.
MOVE T1,VTMQUE## ;GET THE FIRST QUEUE ENTRY
HRRM T1,LDBVTQ##(U) ;MAKE OUR LDB POINT TO IT.
HRRZM U,VTMQUE## ;MAKE OUR LDB THE HEAD OF THE LIST.
JRST SONPPJ## ;RE-ENABLE INTERRUPTS AND RETURN
;VTMDEQ ROUTINE TO REMOVE A LINE FROM THE VTMQUE.
;CALL U := POINTER TO THE LDB TO DE-QUEUE (CALLED BY VTMLOC ONLY)
;RETURN CPOPJ ;WITH THE LINE DEQUEUED, BUT THE "QUEUED BIT"
; ; STILL ON (SO LINE WON'T GET RE-QUEUED BY
; ; AN INTERRUPT)
VTMDEQ: SCNOFF ;NO INTERRUPTS WHILE THIS IS GOING ON.
MOVSI T1,LRLQED## ;GET THE "THIS VTM IS QUEUED BIT"
TDNN T1,LDBREM##(U) ; AND SEE IF WE THINK IT IS QUEUED
JRST [IORM T1,LDBREM##(U) ;IF NOT, SET BIT TO PREVENT RE-QUEUE
JRST SONPPJ##] ; AND WE'RE DONE
HRRZ T1,VTMQUE## ;GET ADDR OF FIRST LDB IN THE QUEUE
HRLI T1,(MS.SCN) ; USING SCNSER SECTION
CAMN T1,U ; AND SEE IF WE'RE FIRST
JRST [HRRZ T1,LDBVTQ##(U) ;GET POINTER TO THE "NEXT" LDB
HRRZM T1,VTMQUE## ; AND MAKE THAT THE "FIRST"
JRST SONPPJ##] ;EXIT WITH LINE DE-QUEUED.
JRST VTMDE2 ;FIRST DIDN'T MATCH, CHECK FOR EMPTY QUEUE
VTMDE1: MOVE T2,T1 ;REMEMBER THE ADDRESS OF THE "LAST" LDB
HRRZ T1,LDBVTQ##(T1) ;STEP TO THE "NEXT" LDB
HRLI T1,(MS.SCN) ;SCNSER SECTION
CAMN T1,U ;IF THIS LDB IS THE ONE WE WANT,
JRST [HRRZ T1,LDBVTQ##(T1) ;GET THE ADDR OF THE ONE AFTER THAT
HRRM T1,LDBVTQ##(T2) ; AND PUT IT IN OUR PLACE
JRST SONPPJ##] ;EXIT WITH THE LINE DE-QUEUED.
VTMDE2: TRNE T1,-1 ;IF WE'RE NOT AT THE END YET,
JRST VTMDE1 ;KEEP LOOKING
STOPCD .,STOP,VTMQED, ;++ LINE NOT QUEUED THOUGH LRLQED IS SET

;VTMJIF ONCE/JIFFY PROCESSING FOR VTMS.
;CALL PUSHJ P,VTMJIF ;FROM JIFFY CODE IN NETSER
;RETURN CPOPJ ;ALWAYS (WITH VTMQUE PROCESSED)
VTMJIF::SKIPN VTMQUE## ;JUST A QUICKY CHECK (SINCE WE GET HERE A LOT)
POPJ P, ;VTMQUE IS EMPTY.
SCNOFF ;GET THE SCNSER INTERLOCK.
HRRZ U,VTMQUE## ;GET THE NEXT ENTRY
JUMPE U,SONPPJ## ;?? SOME ONE SNUCK IN.
HRLI U,(MS.SCN) ;SCNSER SECTION
HRRZ T1,LDBVTQ##(U) ;GET THE ADDRESS OF THE NEXT ENTRY
HRRZM T1,VTMQUE## ; AND MAKE THAT LDB BE THE NEW "FIRST"
MOVSI T1,LRLQED## ;GET THE "THIS LDB IS QUEUED" BIT
ANDCAB T1,LDBREM##(U) ; AND CLEAR IT SO WE CAN RE-QUEUE LATER.
SCNON ;RE-ENABLE INTERRUPTS
TLNN T1,LRLCON## ;MAKE SURE WE'RE CONNECTED
JRST VTMJIF ;IF NOT CONNECTED YET, DON'T PROCESS
; (THIS HAPPENS WHEN WE RUN OUT OF CHARS
; AND "ZAPBUF" IN SCNSER RE-QUEUES THE
; LINE BEFORE THE CONNECT FINISHES)
TLNE T1,LRLDIP## ;IF WE WANT TO SEND A DISCONNECT-INIT
JRST VTMJI1 ; THEN SEE IF WE ALREADY HAVE
LDB T1,LDPRNN## ;GET THE NUMBER OF THE NODE WE'RE TALKING TO
PUSHJ P,SRCNDB## ;SET W := A POINER TO THE NODES NDB
STOPCD .,STOP,VTMNDB, ;++ NO NDB FOR LDB'S NODE.
PUSHJ P,VTMSCN ;GO DO WHATEVER IS NECESSARY FOR THE VTM
PJRST VTMENQ ; IF NO CORE. REQUEUE LINE, AND WAIT TILL
; NEXT JIFFY.
PUSHJ P,VTMXDQ ;TRY TO SEND DATA-REQUESTS
PJRST VTMENQ ;REQUEUE IF NO CORE
JRST VTMJIF ;LOOP OVER ALL LINES IN VTMQUE.
;HERE SEE IF WE NEED TO SEND A DISCONNECT FOR THIS TERMINAL
VTMJI1: LDB T1,LDPSLA## ;GET THE SOURCE LAT ADDRESS
SKIPN T1 ;MAKE SURE WE HAVE ONE
STOPCD .,STOP,VTMNLA, ;++ NO LAT ADDRESS FOR VIRTUAL TERMINAL?
LDB T2,LATSTA## ;GET OUR CONNECTION STATE
CAIE T2,LAT.OK ;IF WE'RE NOT IN "OK" STATE
JRST VTMJIF ; THEN WE'VE SENT THE DISCONNECT. NEXT TERMINAL
LDB T1,LDPRNN## ;GET THE REMOTE NODE NUMBER
PUSHJ P,SRCNDB## ;SET UP "W" WITH THE NDB ADDRESS
STOPCD .,STOP,VTMNNN, ;++ BUT VTMNWD SHOULD HAVE CAUGHT THIS
MOVEI T1,RSN.OK ;REASON = GOODNIGHT
PUSHJ P,TRMXDC## ;SEND THE DISCONNECT
PJRST VTMENQ ;REQUEUE THE LINE IF NO CORE
JRST VTMJIF ;OTHERWISE GO DO THE NEXT LINE