TITLE NETSER - DEVICE INDEPENDENT NETWORK SERVICE ROUTINES - V1151 SUBTTL D. TODD/DRT/EJW/JBS/DRL 28 JAN 85 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. ; .CPYRT<1974,1986> ;COPYRIGHT (C) 1974,1975,1976,1977,1978,1979,1980,1982,1984,1986 ;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS. ;ALL RIGHTS RESERVED. ; ; XP VNETSER,1151 ;PUT VERSION NUMBER IN GLOB AND LOADER MAP NETSER::ENTRY NETSER ;LOADING IF IN LIBRARY SEARCH MODE Comment @ Loose ends. NETSER problems. o The interface to PSISER with respect to PSINTC (Topology change) is poor. Probably should have a bit in the NDB that indicates whether or not the interrupt has been given. Network device (rdx, cdr, lpt, tsk etc) problems Monitor problems (in routines other than NETSER) o Make COMMON generate the right amount of free core. DN87 problems (-11 code) o LB.IBF gets filled up too easily. Make it use a chunk? Loose ends in general (Programs to write etc...) @ SUBTTL INTERFACE TO AUTCON ; ROUTINE TO SET THE COUNT OF VARIOUS DEVICES IN THE HOST'S NDB. ; CALL: MOVE T1,<.TYXXX/.TYEST>,,NUMBER OF DEVICES ; PUSHJ P,NETDEV ; ; AC USAGE: T1 - T4 ; IFN FTAUTC,< NETDEV::HRRZ T2,T1 ;GET NUMBER OF DEVICES HLRZS T1 ;ISOLATE DEVICE TYPE MOVSI T3,- ;AOBJN POINTER NETDE1: HLRZ T4,OBJTAB##(T3) ;GET A DEVICE TYPE CAME T1,T4 ;MATCH? AOBJN T3,NETDE1 ;TRY ANOTHER JUMPGE T3,CPOPJ## ;RETURN IF NOT AN ANF-10 DEVCE PUSH P,W ;SAVE FROM DESTRUCTION MOVEI W,NETNDB## ;POINT TO OUR NDB DPB T2,NETCNF##(T3) ;UPDATE DEVICE COUNT IN THE NDB JRST WPOPJ## ;RESTORE W AND RETURN > ;END IFN FTAUTC SUBTTL INTERFACE TO COMCON ;ENTRY FROM COMCON WITH A NETWORK ASSIGN COMMAND ; ; ASSIGN NODENAME_DEV:LOGICAL ; ;COMCON HAS ALREADY SCANNED OF THE NODE NAME ; T2=NODE NAME ; T3=DELIMETER ;RETURN ; CPOPJ ;NOT A NETWORK DEVICE. ERROR MESSAGE PRINTED ; CPOPJ1 ;IT IS A NETWORK DEVICE. T2 := THE "TRANSLATED" ; ; NAME OF THE FORM GGGNNU NETASG:: ;ENTRY MOVE P1,T2 ;SAVE THE STATION NAME CAIE T3,"_" ;TERMINATED BY A _ JRST CPOPJ1## ;IF NOT, DON'T CONVERT THE NAME PUSHJ P,COMTYS## ;YES, SKIP THE "_" NETDBJ ;INTERLOCK THIS CODE PUSHJ P,CTXDEV## ;GET THE DEVICE NAME JUMPE T2,NOTENF## ;ILLEGAL ARG LIST MOVE P2,T2 ;SAVE THE DEVICE NAME TRNE T2,505050 ;MUST BE NUMERIC GGGU JRST NOTDEV## ;ERROR RETURN TLNE P2,505050 ;IS LH A NUMBER? JRST NETAS1 ;NO, CONTINUE NORMALLY MOVSS P2,P2 ;FLIP HALVES OF ARGUMENT NETAS0: TRNE P2,77 ;IS RIGHTMOST DIGIT ZERO? JRST NETAS2 ;NO, DONE LSH P2,-6 ;SHIFT RIGHT ONE DIGIT JRST NETAS0 ; AND TRY AGAIN NETAS2: TRO P2,202020 ;MAKE IT ALL DIGITS HRLI P2,(SIXBIT/TTY/); AND MAKE LH SAY TTY ;HERE TO VALIDATE THE STATION NAME NETAS1: MOVE T1,P1 ;COPY THE STATION NAME PUSHJ P,SRCNDB ;DOES THE STATION EXIST JRST [HRRZ T1,NRTUNN ;TYPE AN ERROR PJRST ERRMES##] ;ERROR MESSAGE MOVE T2,P2 ;RESTORE DEVICE NAME HLRZ P1,NDBNNM##(W) ;GET NODE # CAMN P1,JBTLOC## ;LOCAL NODE? JRST CPOPJ1## ;YES, JUST RETURN MOVEI P1,(W) ;SAVE THE NDB POINTER ;HERE TO VALIDATE THE REMOTE DEVICE NAME HLRZ T1,P2 ;GENERIC NAME ONLY FROM THE LEFT HALF CAIN T1,(SIXBIT /TTY/) ;IS IT TERMINAL? JRST NETAST ;YES, ASSIGN IT TRNN P2,505050 ;MUST BE LEFT HALF NUMERIC OR ZEROS PUSHJ P,SRCNDT ;SEARCH THE NDT PJRST NOTDEV## ;NOT A LEGAL DEVICE HLL P2,NDTNAM(W) ;COPY THE GENERIC -10 DEVICE NAME MOVEI W,(P1) ;GET THE NODE POINER BACK HLRZ P1,NDBNNM(W) ;PUT THE NODE NUMBER IN P1 ;HERE TO CONVERT THE DEVICE NAME INTO A NETWORK NAME ;DEVICE MUST BE OF THE FORM(S) GGGU,OR GGG MOVEI T1,(P1) ;CONVERT THE NODE NUMBER TO SIXBIT TRO T1,77700 ;FORCE CONVERSION TO LINE UP S0PSHJ CVTSBT## ;IN UUOCON MOVEI T2,(P2) ;COPY THE UNIT NUMBER IF ANY LSH T2,-14 ;SHIFT THE UNIT NUMBER IF ANY TO LOW ORDER IORI T2,(T1) ;COMBINE THE RIGHT HALF HLL T2,P2 ;AND INSERT THE GENERIC NAME JRST CPOPJ1## ;RETURN WITH T2 := GGGNNU NETAST: ;HERE IF NETWORK TERMINAL BEING ASSIGNED HRLZ T1,P2 ;GET THE REMOTE LINE NUMBER PUSHJ P,CVTOCT## ;CONVERT IT TO OCTAL JRST NOTDEV## ;NON NUMERIC LINE NUMBER HLL T1,NDBNNM(W) ;GET THE NODE NUMBER PUSHJ P,ASGTTY## ;AND TRY TO CONVERT THE PAIR TO "TTYNNN" JRST NOTDEV## ;COULDN'T CONNECT. DEVICE NOT AVAILABLE MOVE T2,T1 ;COPY THE DEVICE NAME JRST CPOPJ1## ;WE SUCCEDED. T2 := DEVICE NAME SUBTTL INTERFACE TO COMCON FOR THE "NODE" COMMAND NODE.A::NETDBJ ;INTERLOCK THIS CODE PUSHJ P,CTEXT1## ;GET THE ARGUMNET SKIPN T1,T2 ;CHECK FOR AN ARG JRST [PUSHJ P,FNDSTA## ;IF NO ARG, GET THE STATION OUR TTY JRST NODEC1] ; IS AT, AND USE THAT ONE PUSHJ P,CVTOCT## ;TRY TO CONVERT THE NUMBER MOVE T1,T2 ; IF WE CAN'T, USE THE NAME ;TYPE OUT A PARTICULAR NODE NAME NODEC1: PUSHJ P,SRCNDB ;FIND THE NODE BLOCK POPJ P, ;NO SUCH NODE, GIVE FAIL RETURN (IF MORE ; NETWORKS, LET THEM TRY). ; PJRST NODEC2 ;TYPE THE INFO NODEC2: PUSHJ P,TYPNDB ;TYPE IT PUSHJ P,INLMES## ;TYPE CR-LF-TAB ASCIZ / / MOVSI P1,- ;GET THE DEVICE TABLE SIZE NODEC4: LDB T1,NETCNF##(P1) ;GET THE NUMBER OF DEVICES JUMPE T1,NODEC5 ;NONE DON'T PRINT HRLZ T2,OBJTAB##(P1) ;GET THE DEVICE NAME PUSHJ P,PRNAME## ;PRINT IT OUT MOVEI T3,"[" ;BRACKET PUSHJ P,COMTYO## ;TYPE LDB T1,NETCNF##(P1) ;GET THE NUMBER OF ENTRIES PUSHJ P,RADX10## ;PRINT PUSHJ P,INLMES## ;BRACKET SPACE ASCIZ /] / NODEC5: AOBJN P1,NODEC4 ;CONTINUE TO THE END PUSHJ P,PCRLF## ;END OF LINE JRST CPOPJ1## ;AND RETURN SUCCESS SUBTTL INTERFACE TO UUOCON FOR THE NODE UUO ;NODE. UUO SUB-FUNCTIONS ; .NDALN==1 ;ASSIGN LOGICAL NAME ; .NDRNN==2 ;RETURN NODE NUMBER ; .NDSSM==3 ;SEND STATION CONTROL MESSAGE ; .NDRBM==4 ;RECEIVE BOOT REQUEST MESSAGE ; .NDRCI==5 ;RETURN CONFIGURATION INFORMATION ; .NDOUT==6 ;DO DOUTPU WITH E-O-R (NOT IMPLEMENTED) ; .NDIN==7 ;DO INPUT WITH E-O-R (NOT IMPLEMENTED) ; .NDTCN==10 ;TERMINAL CONNECT ; .NDTDS==11 ;TERMINAL DIS-CONNECT ; .NDLND==12 ;LIST KNOWN NODES ; .NDNDB==13 ;RETURN VARIOUS NDB FIELDS ; .NDGNF==14 ;GET NEXT UN-GREETED NODE, CLEAR UN-GREETED FLG ;NODE. UUO ERROR CODES ND%IAL==ECOD1## ;ILLEGAL ARGUMENT LIST ND%INN==ECOD2## ;ILLEGAL NODE NAME/NUMBER ND%PRV==ECOD3## ;CALLER NOT PRIVILEGED ND%NNA==ECOD4## ;NODE NOT AVAILABLE ND%NLC==ECOD5## ;NOT LOCKED IN CORE ND%TOE==ECOD6## ;TIME OUT ERROR ND%RNZ==ECOD7## ;RESERVED WORD NOT ZERO ND%NND==ECOD10## ;NOT NETWORK DEVICE ND%IOE==ECOD11## ;IO ERROR ND%NFC==ECOD12## ;NO FREE CORE ND%IAJ==ECOD13## ;IN USE BY ANOTHER JOB (TERMINAL) ND%NMA==ECOD14## ;NO MESSAGE AVAILABLE ND%TNA==ECOD15## ;TERMINAL NOT AVAILABLE ND%NLT==ECOD16## ;NOT A LEGAL TERMINAL ND%ISF==ECOD17## ;ILLEGAL SUB-FUNCTION ND%RBS==ECOD20## ;RECEIVE BUFFER TOO SMALL ND%NUG==ECOD21## ;NO UNGREETED NODES ND%ILN==ECOD22## ;ILLEGAL LINE NUMBER (IN STC MESSAGE) ND%ADC==ECOD23## ;ADDRESS CHECK NODE.U:: ;ENTRY POINT HLRZ T4,T1 ;GET THE FUNCTION IN T4 SKIPE T4 ;NOT ZERO CAILE T4,NUULEN ;CHECK THE LENGTH JRST ND%IAL ;ILLEGAL RETURN 1 HRRI M,(T1) ;GET THE ARG LIST IN M NETDBJ ;INTERLOCK THIS CODE JRST UUOTAB-1(T4) ;JUMP ON THE FUNCTION TYPE UUOTAB: ;NODE UUO FUNCTIONS JRST CPOPJ## ;ASSIGN A DEVICE JRST NODE.2 ;RETURN A NODE NUMBER JRST NODE.3 ;STATION CONTOL MESSAGE JRST NODE.4 ;AUTO RELOAD OF DAS 80 SERIES JRST NODE.5 ;RETURN CONFIG INFO FOR NODE JRST CPOPJ## ;OUTPUT DATA TO NETWORK JRST CPOPJ## ;INPUT DATA FROM NETWORK JRST NODE10 ;CONNECT A TERMINAL JRST NODE11 ;DISCONNECT A TERMINAL JRST NODE12 ;GET COUNT AND NUMBERS OF ALL NODES JRST NODE13 ;GET SELECTED INFORMATION ABOUT A NODE JRST NODE14 ;RETURN/CLEAR UN-GREETED NODE FLAG NUULEN==.-UUOTAB ;LENGTH OF THE TABLE SUBTTL NODE.1 - ASSIGN A REMOTE DEVICE NODE.1: PUSHJ P,SAVE4## ;SAVE THE P'S PUSHJ P,GETWRD## ;GET THE ARGUMENT LIST SIZE JRST ND%ADC ;ADDRESS CHECK CAIE T1,4 ;MUST HAVE FOUR ARGS JRST ECOD1## ;ILLEGAL ARG LIST PUSHJ P,GETWR1## ;GET THE NODE NAME JRST ND%ADC ;ADDRESS CHECK PUSHJ P,SRCNDB ;CHECK IF DEFINED JRST ECOD2## ;NO, ILLEGAL NODE NAME HLRZ T1,NDBNNM(W) ;GET NODE NUMBER CAMN T1,JBTLOC## ;IS IT LOCAL SITE? JRST ECOD2## ;YES, CAN'T ASSIGN LOCAL DEVICE MOVEI P1,(W) ;SAVE THE NODE DATA BLOCK PUSHJ P,GETWR1## ;GET THE PHYSICAL DEVICE NAME JRST ND%ADC ;ADDRESS CHECK SKIPN P2,T1 ;COPY THE NAME JRST ECOD3## ;ZERO IS ILLEGAL HLRZS T1 ;GENERIC NAME ONLY FOR SEARCH PUSHJ P,SRCNDT ;SEARCH THE DEFINED NAME TABLE JRST ECOD3## ;ILLEGAL DEVICE NAME PUSHJ P,GETWR1## ;GET THE LOGICAL NAME JRST ND%ADC ;ADDRESS CHECK MOVE P3,T1 ;COPY THE NAME PUSHJ P,MAKDDB ;MAKE A REMOTE NETWORK DDB JRST ECOD4## ;NO CORE AVAILABLE PUSHJ P,NCSCNT ;CONNECT THE DEVICE JRST [MOVEI T1,10(T1);STEP UP THE ERROR NUMBER PUSHJ P,STOTAC## ;TELL CALLER WHY IT FAILED PJRST RMVNET] ;REMOVE DDB FROM SYSTEM PUSHJ P,LNKDDB ;LINK NEWLY CONNECTED DDB MOVEI T1,ASSCON ;NOW THAT WE'VE ASSIGNED THE DEVICE, WE IORM T1,DEVMOD(F) ; BETTER MARK IT. (OR ELSE UUOCON WILL ZAP IT) PJRST CPOPJ1## ;CONNECT OK EXIT SUBTTL NODE.2 RETURN A NODE NUMBER IN THE AC NODE.2: ;ENTRY PUSHJ P,GETWRD## ;GET THE ARG COUNT JRST ND%ADC ;ADDRESS CHECK CAIE T1,2 ;MUST BE A 2 JRST ND%IAL ;NO ILLEGAL FUNCTION PUSHJ P,GETWR1## ;GET THE NODE NAME JRST ND%ADC ;ADDRESS CHECK PUSHJ P,NODE.S ;FIND CORRECT NDB PJRST ND%INN ;ILLEGAL NODE MOVE T2,T1 ;COPY ARGUMENT HLRZ T1,NDBSNM(W) ;GET THE NAME POINTER MOVE T1,(T1) ;GET THE NAME TLNE T2,-1 ;WANTS A NAME? HLRZ T1,NDBNNM(W) ;NO, GET THE NODE NUMBER PJRST STOTC1## ;RETURN NODE NUMBER IN AC ;SUBROUTINE TO FIND NDB FOR NODE.UUO FUNCTIONS ;CALL T1 = ARGUMENT TO NODE.UUO ;RETURNS CPOPJ IF NOT FOUND ; CPOPJ1 WITH W SET TO NDB, RESPECTS T1 NODE.S::PUSH P,T1 ;SAVE ARGUMENT PUSHJ P,SRCNDB ;SCAN NDB'S PJRST TPOPJ## ;NOPE, GIVE ERROR MOVSI T1,NDB.UP ;DON'T DO THE TRANSLATION TDNN T1,NDBFLG(W) ; UNLESS THE NODE IS UP. JRST TPOPJ## ; IF WE DO, WE GET GARBAGE NAMES PJRST TPOPJ1## ;RETURN WITH W SET UP SUBTTL NODE.3 STATION CONTROL MESSAGES ;FORMAT OF THE UUO ARGS ; XWD TIME,ARG-LIST-LENGTH ; SIXBIT /NODE NAME/ OR NUMBER ; XWD COUNT,ADR OF OUTPUT BUFFER ; XWD COUNT,ADR OF RESPONSE BUFFER NODE.3: PUSHJ P,NTDPRV ; SURE THAT THIS GUY IS PRIVILEDGED PJRST ND%PRV ;USER HAS INSUFFICIENT PRIVILEDGES PUSHJ P,SAVJW## ;WE WILL CLOBBER THESE PUSHJ P,SAVE4## ;WE COPY THE UUO ARGS IN P1 - P4 PUSHJ P,N34SET ;GO READ THE UUO ARGS POPJ P, ; IF BAD ARGLIST, PROPAGATE THE ERROR MOVE T1,P2 ;GET THE SECOND ARG (NODE ID) PUSHJ P,SRCNDB ;GO SET W := NDB POINTER JRST ND%INN ;IF NO NDB, GIVE ILLEGAL NODE ERROR CAIN W,NETNDB## ;IF HE SPECIFIED THE LOCAL NODE, JRST NODE3L ; GO TRY TO SEND MSG TO A FEK HRRZ J,NDBSTC(W) ;SEE IF ANYONE IS USING STATION CONTROL CAMN J,.CPJOB## ;IF WE ARE USING IT, THEN ASSUME A PAGE JRST N34NRD ; FAULT WHILE READING STC AND TRY AGAIN JUMPN J,ND%NNA ;IF SOMEONE ELSE HAS IT, NOT AVAILABLE HRRZ J,NDBICT(W) ;GET MESSAGE ADDR SKIPE J ;IS THERE ONE? PUSHJ P,GIVSTC ; FREE IT, SINCE LOOKING FOR A RESPONSE SETZM NDBICT(W) ;CLEAR THE INCOMING MESSAGE POINTER. ;NOW SEND THE STATION CONTROL MESSAGE MOVEI T1,(P3) ;GET THE ADDRESS OF THE OUTPUT MESSAGE HLRE T2,P3 ;GET ITS LENGTH IN BYTES JUMPLE T2,ND%IAL ;IF GARBAGE LENGTH, GIVE ILLEGAL ARG ERROR ADDI T2,3 ;ROUND UP AND GET THE LENGTH OF THE LSH T2,-2 ;MESSAGE IN WORDS PUSH P,T2 ;SAVE LENGTH IN WORDS FOR LATER HRLI T1,(IFIW) ;SECTION LOCAL ADDRESSING PUSHJ P,ARNGE## ;MAKE SURE ALL THE DATA IS IN CORE. JRST ND%ADC ;ADDRESS CHECK JFCL ;ADDR OK BUT ILLEGAL FOR I/O (IGNORED HERE) HRRZ T1,(P) ;GET THE WORD COUNT BACK ADDI T1,5 ;ACCOUNT FOR A HEADER AND WORD ALIGNMENT PUSHJ P,MKNPCB ;MAKE A "NUMBERED" PCB JRST [POP P,T1 ;IF NO CORE, CLEAN UP THE STACK JRST ND%NFC] ; AND GIVE THE "NO FREE CORE" ERROR PUSH P,P2 ;SAVE THE NODE'S NAME/NUMBER PUSH P,P3 ;SAVE THE OUTPUT BUFFER POINTER MOVE P2,PCBPTR(U) ;GET BYTE POINTER TO THE PCB SETZ T1, ;WE WANT AN NCT OF 0 (NUMBERED MSG) PUSHJ P,NCSWHD ;WRITE THE NCL HEADER ;DLA XMTI 0 ;DLA = 0 MEANS NOT DEVICE CONTROL ;CNT HLRZ T1,(P) ;GET MESSAGE'S BYTE COUNT ADDI T1,1 ; +1 FOR "NC.CTL" TYPE FIELD XMT T1 ;WRITE THE COUNT ;TYP XMTI NC.CTL ;THIS IS A STATION CONTROL MESSAGE ADDM P3,PCBCTR(U) ;THAT'S ALL OF THE "HEADER" UPDATE ITS LENGTH POP P,P3 ;GET THE OUTPUT MESSAGE POINTER BACK ;NOW BLT THE DATA INTO THE PCB MOVEI T1,1(P2) ;GET THE ADDRESS OF FIRST "FULL" FREE WORD HRLI T1,(POINT 8,0) ;MAKE ADDRESS A BYTE POINTER MOVEM T1,PCBPT2(U) ; STORE IT AS "SECONDARY" BUFFER POINTER HLRZM P3,PCBCT2(U) ;SET NUMBER OF BYTES TO WRITE AS SECONDARY SIZE HRLI T1,(P3) ;GET THE USER ADDRESS OF THE DATA IN SRC(BLT) POP P,P2 ;GET THE NODE NUMBER BACK IFE FTXMON,< POP P,T2 ;GET THE LENGTH OF THE DATA IN WORDS ADDI T2,-1(T1) ;GET ADDRESS OF LAST WORD TO FILL WITH DATA EXCTUX ;COPY THE DATA TO THE PCB > IFN FTXMON,< XSFM T2 ;GET PCS HRLZS T2 ;IN LH WHERE IT BELONGS HLR T2,T1 ;FORM USER SOURCE ADDRESS HRRZ T3,T1 ;FORM MONITOR DESTINATION ADDRESS POP P,T1 ;GET THE LENGTH OF THE DATA IN WORDS XBLTUX T1 ;COPY THE DATA TO THE PCB > MOVEI T1,PCV.NC ;SAY THAT DATA IS 8 BIT BYTES (NO CONVERSION) PUSHJ P,NTDWRT ;GIVE THE MESSAGE TO THE NETWORK ;NOW CLAIM OWNERSHIP OF STATION CONTROL AND WAIT FOR A RESPONSE JUMPE P4,CPOPJ1## ;IF NO RESPONSE BUFFER, UUO IS DONE. HLLZ T1,P1 ;LH OF NDBSTC := SECONDS TO WAIT FOR ANSWER SKIPN T1 ;IF USER SPECIFIED A TIME, THEN USE HIS MOVSI T1,10 ; OTHERWISE DEFAULT TO 8 SECONDS MOVE J,.CPJOB## ;GET OUR JOB NUMBER HRRI T1,(J) ;RH OF NDBSTC := JOB TO WAKE UPON ANSWER MOVEM T1,NDBSTC(W) ;STORE NDBSTC SO ICMCTL CAN WAKE US NODE31: MOVEI T1,EV.STC ;GET THE "STATION CONTROL" EVENT WAIT CODE PUSHJ P,[NTSAVE ; RETURN THE "NT" RESOURCE JRST ESLEEP##] ; AND SLEEP UNTIL MSG COMES OR WE TIME OUT MOVE T1,P2 ;WE'VE BEEN AWAKENED. TRACK THE NDB DOWN AGAIN PUSHJ P,SRCNDB ; AS IT MAY HAVE CRASHED. PJRST ND%INN ;IF NDB GONE, GIVE ILLEGAL NODE ERROR SKIPE T1,NDBICT(W) ;SEE IF THERE IS AN INCOMING MESSAGE PJRST N34NRD ;IF RESPONSE, GO READ IT SKIPN T1,NDBSTC(W) ;SEE IF STATION CONTROL STILL ASSIGNED PJRST ND%TOE ;IF NOT, WE MUST HAVE TIMED OUT. MOVEI T1,(T1) ;GET JUST THE JOB NUMBER CAME T1,.CPJOB## ;MAKE SURE WE STILL OWN STATION CONTROL PJRST ND%TOE ;IF NOT, THEN TIME OUT ERROR JRST NODE31 ;IF SO, THEN SPURIOUS WAKE, SLEEP SOME MORE IFE FTKS10, ;THE KS-10 IS CURRENTLY THE ONLY SYSTEM ; THAT CAN DOWN-LINE LOAD ITS FEKS. IFN FTKS10,< ;IF ON A KS-10, ASSEMBLE STC-FEK STUFF ;HERE WHEN A STC MESSAGE FOR THE "LOCAL" NODE IS SEEN. SEE IF IT'S FOR ; ONE OF OUR LINES. IF IT IS, SEND THE STC MESSAGE TO THE FEK. NODE3L: MOVEI T1,(P3) ;GET THE ADDRESS OF THE STC MESSAGE MOVE J,.CPJOB## ;SET UP OUR JOB (SO WE DON'T GET AN LN1) PUSHJ P,UADRCK## ;MAKE SURE IT'S LEGAL AND IN CORE EXCTUX ;GET THE "LINE NUMBER FIELD" JUMPE T1,ND%INN ;DON'T LET STC TO THIS NODE DO ANYTHING PUSHJ P,LN2FEK ;CONVERT LINE NUMBER TO FEK ADDRESS (IN "J") JRST ND%ILN ;GIVE "ILLEGAL LINE NUMBER" IF NO SUCH FEK HRRZ T1,FEKBJN(J) ;GET THE NUMBER OF JOB OWNING STC ON FEK CAMN T1,.CPJOB## ;IF WE OWN THE STC OF THIS FEK, JRST NODFRD ; ASSUME PAGE FAULT WHILE STORING RESPONSE JUMPN T1,ND%NNA ;IF SOMEONE ELSE HAS STC, SAY "NOT AVAIL" ;HERE STC FOR THIS FEK IS FREE. COPY THE MESSAGE AND SEND IT MOVE W,J ;USE "W" AS A FEK POINTER FOR A BIT SKIPE J,FEKICT(W) ;SEE IF THERE ARE ANY STALE INPUT MSGS PUSHJ P,GIVSTC ;IF STALE MSGS, FREE THEM SETZM FEKICT(W) ;CLEAR INCOMING MESSAGE POINTER MOVEI T1,(P3) ;GET USER ADDRESS OF MESSAGE TO SEND HLRE T2,P3 ;GET LENGTH OF THE MESSAGE (BYTES) JUMPLE T2,ND%IAL ;SAY ILLEGAL ARG LIST IF GARBAGE LENGTH ADDI T2,3 ;WE WANT LENGTH IN WORDS. ROUND BYTES UP LSH T2,-2 ; AND DIVIDE BY 4 BYTES PER WORD PUSH P,T2 ;SAVE THE WORD COUNT FOR BLT COMING UP HRLI T1,(IFIW) ;SECTION LOCAL ADDRESSING PUSHJ P,ARNGE## ;MAKE SURE WE DON'T IME. JRST ND%ADC ;ADDRESS CHECK JFCL ;ADDR OK BUT ILLEGAL FOR I/O (IGNORED HERE) HLRE T1,P3 ;GET THE BYTE COUNT AGAIN PUSHJ P,GETSTC ;GET A STC BLOCK TO HOLD THE DATA JRST [POP P,T1 ;IF NO CORE, FIXUP THE STACK JRST ND%NFC] ; AND TELL THE USER IFE FTXMON,< MOVSI T1,(P3) ;SOURCE(BLT) := USER ADDRESS HRRI T1,STCDAT(J) ;DEST(BLT) := STC BLOCK POP P,T2 ;GET THE LENGTH (IN WORDS) BACK ADDI T2,-1(T1) ;GET LAST MONITOR ADDRESS TO FILL EXCTUX ;COPY THE DATA INTO THE STC BLOCK > IFN FTXMON,< XSFM T2 ;GET PCS HRLZS T2 ;IN LH WHERE IT BELONGS HRRI T2,(P3) ;FORM USER SOURCE ADDRESS HRRZI T3,STCDAT(J) ;FORM MONITOR DESTINATION ADDRESS POP P,T1 ;GET THE LENGTH (IN WORDS) BACK XBLTUX T1 ;COPY DATA TO STC BLOCK > ;NOW PUT OUR NODE NUMBER IN THE FIRST BYTE, AND GIVE MSG TO THE FEK HLRZ T1,NETNDB##+NDBNNM ;GET OUR NODE NAME DPB T1,[POINT 8,STCDAT(J),7] ; AND STORE IT AS THE "SNA" MOVE U,J ;SET UP U := STC MESSAGE MOVE J,W ; AND J := FEK -- FOR CALL TO FEK HLRE T1,P1 ;GET THE USERS TIMER VALUE SKIPG T1 ;IF HE DIDN'T SPECIFY A VALUE MOVEI T1,10 ; THEN USE 8 SECONDS MOVSI T1,(T1) ;PUT TIMER IN THE LH HRR T1,.CPJOB## ;GET OUR JOB NUMBER MOVEM T1,FEKBJN(J) ;CLAIM OWNERSHIP OF THE FEK'S STC MOVEI T1,FF.STC ;GET THE "STC" FUNCTION CODE XCT FEKDSP(J) ;CALL THE FEK JRST [SETZM FEKBJN(J);IF THE FEK DOESN'T ACCEPT THE STC, MOVEI J,(U) ; CLEAR STC OWNERSHIP, GET STC IN "J" PUSHJ P,GIVSTC ; FREE THE STC BLOCK JRST ND%ILN] ; AND GIVE ILLEGAL LINE ERROR JUMPE P4,[SETZM FEKBJN(J) ;IF NO RESPONSE WANTED, CLEAR OWNER RETSKP] ; AND GIVE GOOD RETURN ;NOW WE'VE SENT THE MESSAGE. CHECK FOR A RESPONSE. IF NONE, WAIT. NOD3L1: HRRZ T1,FEKBJN(J) ;GET THE OWNER OF THE FEK'S STC CAME T1,.CPJOB## ;MAKE SURE IT'S US. JRST ND%TOE ;IF NOT US, THEN GIVE "TIME OUT ERROR" SKIPE FEKICT(J) ;SEE IF ANY INCOMING MSGS. JRST NODFRD ;IF INCOMING MESSAGE. RETURN IT TO THE USER MOVEI T1,EV.STC ;GET THE "STATION CONTROL" EVENT WAIT CODE PUSH P,J ;SAVE OUR FEK FOR A BIT MOVE J,.CPJOB## ;SET J := JOB NUMBER (FOR ESLEEP) PUSHJ P,[NTSAVE ;RETURN THE "NT" INTERLOCK JRST ESLEEP##] ; AND SLEEP WAITING FOR A RESPONSE POP P,J ;GET OUR FEK ADDRESS BACK JRST NOD3L1 ;UPON AWAKING, SEE IF WE HAVE A MSG. >;END IFN FTKS10 SUBTTL NODE.4 RECEIVE STATION CONTROL BOOT MESSAGES ;FORMAT OF THE UUO ARGS ; EXP 0 ; EXP 0 ; EXP 0 ; XWD COUNT,ADR OR RESPONSE BUFFER NODE.4: PUSHJ P,NTDPRV ; SURE THAT THIS GUY IS PRIVILEDGED PJRST ND%PRV ;USER HAS INSUFFICIENT PRIVILEDGES PUSHJ P,SAVJW## ;WE WILL CLOBBER THESE PUSHJ P,SAVE4## ;WE COPY THE UUO ARGS IN P1 - P4 PUSHJ P,N34SET ;GO READ THE UUO ARGS POPJ P, ; IF BAD ARGLIST, PROPAGATE THE ERROR ;NOW SEARCH FOR AN NDB WITH AN UNCLAIMED INCOMING CONTROL MESSAGE SKIPA W,[EXP NETNDB##];START WITH OUR NDB NODE41: HRRZ W,NDBNNM(W) ;STEP TO THE NEXT NDB JUMPE W,NODE42 ;IF NO MSGS ON NDB'S, CHECK FEKS SKIPN NDBSTC(W) ;IF SOME JOB IS WAITING, OR SKIPN NDBICT(W) ; IF NO STC MESSAGE HAS COME, JRST NODE41 ; THEN GO TRY NEXT NDB N34NRD: HRRZ J,NDBICT(W) ;GET THE ADDRESS OF THE STC MESSAGE JUMPE J,ND%TOE ;IF NONE, THEN PROBABLY A TIME OUT HLL T1,STCBLK(J) ;THE NUMBER OF BYTES IS THE LH(STCBLK) HLLZM T1,STCLNN(J) ; SAVE THE COUNT FOR N34RED PUSHJ P,N34RED ;STORE THE MESSAGE IN THE USERS BUFFER SOS (P) ;PROPAGATE THE ERROR (IF ANY) SETZM NDBSTC(W) ;CLEAR STC OWNERSHIP SETZM NDBICT(W) ;CLEAR (NOW FREED) INCOMING STC MSG RETSKP ;GIVE (POSSIBLY BAD) RETURN IFE FTKS10, ;IF NO MESSAGES FROM FEKS, SAY NO MSG AVAIL IFN FTKS10,< ;THE KS-10 GETS STC MSGS FROM ITS D8K FEKS NODE42: MOVEI J,FEKFST## ;GET THE ADDRESS OF THE FIRST FEK. CAIA ;SKIP INTO THE LOOP NODE43: HRRZ J,FEKBLK(J) ;ADVANCE TO THE NEXT FEK JUMPE J,ND%NMA ;IF NO MORE, SAY "NO MESSAGE AVAILABLE" SKIPN FEKBJN(J) ;IF SOMEONE IS WAITING, OR SKIPN FEKICT(J) ; THERE ISN'T A MESSAGE JRST NODE43 ;GO TRY THE NEXT FEK. ;NODFRD ROUTINE TO RETURN THE STC MESSAGE QUEUED ON FEK ;CALL J := FEK ;RETURN CPOPJ ;ERROR (BUT STC FREED) ; CPOPJ1 ;OK (STC FREED) NODFRD: SKIPN U,FEKICT(J) ;GET U := INCOMING MESSAGE JRST ND%TOE ;IF NONE, ASSUME A TIME OUT ERROR (?) EXCH J,U ;REMEMBER THE FEK, SET J := STC MSG ;NOW REMOVE ANY NODE NUMBER ON THE MESSAGE AND INSERT THE LINE NUMBER ; THIS MEANS COPYING THE MESSAGE DOWN IF THE NODE NUMBER IS EXTENSIBLE HLRZ T1,STCBLK(J) ;GET THE INITIAL LENGTH OF THE MESSAGE MOVE T2,[POINT 8,STCDAT(J)] ;A POINTER TO THE MESSAGE MOVEI T3,1 ;FINAL VALUE OF MESSAGE (START WITH LINE #) MOVE T4,T2 ;"PUTTER" BYTE POINTER FOR COPYING SOJGE T1,[ILDB W,T2 ;GET NEXT BYTE TRNE W,200 ;AND SEE IF IT'S STILL THE NODE NUMBER JRST . ;STILL EXTENSIBLE, KEEP LOOKING JRST .+1] ; END OF NODE NUMBER HRRZ W,STCLNN(J) ;GET THE LINE NUMBER IDPB W,T4 ;STORE AS THE FIRST BYTE ; AOS T3 ;COUNT THE BYTE (DONE ABOVE...) SOJGE T1,[ILDB W,T2 ;FOR ALL THE REST OF THE BYTES, LOAD IDPB W,T4 ; AND STORE IN THE NEW MESSAGE AOJA T3,.] ; COUNT THE BYTE AND LOOP HRLM T3,STCLNN(J) ;STORE THE LENGTH FOR N34RED MOVEI W,NETNDB## ;SET UP "W" := NETNDB TO RETURN OUR NODE # PUSHJ P,N34RED ;STUFF THE MESSAGE IN THE USERS BUFFER SOS (P) ;IF FAIL RETURN, MAKE SURE WE DON'T SKIP SETZM FEKBJN(U) ;CLEAR THE STC OWNER SETZM FEKICT(U) ;CLEAR ANY INCOMING MSG (N34RED FREED IT) RETSKP >; END OF IFN FTKS10 ;N34RED ROUTINE TO COPY STC MESSAGES BACK INTO THE USERS BUFFER ;CALL P1 - P4 := AS SET UP BY N34SET ; J := ADDR OF STC MESSAGE TO COPY ; W := NDB OF NODE WHOS NUMBER WE RETURN AS THE BOOT NODE ;RETURN NOT AT ALL IF ADDRESS CHECK OR PAGE FAULT ; CPOPJ ;IF ERROR, WITH STC BLOCK FREED ; CPOPJ1 ;IF OK, WITH STC BLOCK FREED N34RED: MOVEI T1,(P4) ;GET THE ADDRESS OF THE USER'S INPUT BUFFER HLRZ T2,STCLNN(J) ;GET THE LENGTH OF THE STC MESSAGE (BYTES) HLRZ T3,P4 ;GET THE LENGTH OF THE USER'S BUFFER (BYTES) CAIGE T3,(T2) ;IF THE MESSAGE IS LONGER THAN THE USER'S JRST [PUSHJ P,GIVSTC ;IF STC WON'T FIT, FREE THE MESSAGE PJRST ND%RBS] ; AND GIVE A "RECEIVE BUFFER 2 SMALL" ERROR ADDI T2,3 ;ROUND BYTES UP TO NEXT EVEN WORD LSH T2,-2 ;CONVERT BYTES TO WORDS PUSH P,T2 ;SAVE LENGTH IN WORDS HRLI T1,(IFIW) ;SECTION LOCAL ADDRESSING PUSHJ P,ARNGE## ;RANGE CHECK THE USER'S INPUT BUFFER AREA JRST ND%ADC ;ADDRESS CHECK JRST ND%ADC ;ILLEGAL FOR I/O IFE FTXMON,< POP P,T2 ;GET LENGTH BACK ADDI T2,-1(T1) ;COMPUTE LAST ADDRESS MOVEI T1,(P4) ;GET THE ADDRESS OF THE USER'S BUFFER BACK HRLI T1,STCDAT(J) ;GET THE ADDRESS OF THE STC MESSAGE EXCTXU ;COPY THE STC MESSAGE > IFN FTXMON,< XSFM T3 ;GET PCS HRLZS T3 ;IN LH WHERE IT BELONGS HRRI T3,(P4) ;FORM USER DESTINATION ADDRESS HRRZI T2,STCDAT(J) ;FORM MONITOR SOURCE ADDRESS POP P,T1 ;GET LENGTH IN WORDS BACK XBLTXU T1 ;COPY THE STC MESSAGE > PUSH P,J ;PROTECT STC POINTER FROM DEATH BY PUTWRD HRRI M,1(M) ;SET RH(M) TO THE ADDRESS TO RETURN NODE NUMBER HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER PUSHJ P,PUTWRD## ;RETURN THE NODE NUMBER JRST ND%ADC ;ADDRESS CHECK MOVEI T1,(P4) ;GET THE ADDRESS OF THE USERS INPUT BUFFER HRRZ J,(P) ;RECOVER STC POINTER AGAIN HLL T1,STCLNN(J) ;GET THE NUMBER OF VALID BYTES IN IT HRRI M,2(M) ;SET RH(M) TO ADDRESS OF USERS INPUT BUFFER PUSHJ P,PUTWRD## ;STORE UPDATED "XWD LENGTH,ADDR" FOR THE USER JRST ND%ADC ;ADDRESS CHECK POP P,J ;GET STC POINTER ONCE AGAIN PUSHJ P,GIVSTC ;RETURN THE STC BLOCK RETSKP ;GIVE GOOD RETURN ;N34SET ROUTINE TO SET P1 - P4 TO THE NODE. UUO ARGUMENTS ;CALL M := UUO N34SET: PUSHJ P,GETWRD## ;P1 GETS THE "XWD TIME,ARG-LIST-LENGTH" JRST ND%ADC ;ADDRESS CHECK MOVE P1,T1 HRRZ T1,T1 ;GET JUST THE ARG LIST LENGTH CAIGE T1,4 ;MAKE SURE IT'S LONG ENOUGH PJRST ND%IAL ; IF TOO SHORT, GIVE ILLEGAL ARG LIST PUSHJ P,GETWR1## ;P2 GETS THE NODE NAME JRST ND%ADC ;ADDRESS CHECK MOVE P2,T1 PUSHJ P,GETWR1## ;P3 GETS THE OUTPUT BUFFER POINTER JRST ND%ADC ;ADDRESS CHECK MOVE P3,T1 PUSHJ P,GETWR1## ;P4 GETS THE INPUT BUFFER POINTER JRST ND%ADC ;ADDRESS CHECK MOVE P4,T1 SUBI M,3 ;SET THE UUO POINTER BACK RETSKP ;SKIP RETURN WITH P1 - P4 SET UP SUBTTL NODE.5 RETURN CONFIG INFO FOR NODE ;FORMAT OF THE UUO ARGS ; XWD 0,,COUNT ; SIXBIT /NODE NAME/ OR NUMBER ; 0 RESERVED FOR DATE AND NAME ; BLOCK INFO RETURNED HERE NODE.5: PUSHJ P,SAVE1## ;SAVE P1 FIRST PUSHJ P,GETWRD## ;GET ARGUMENT LIST SIZE JRST ND%ADC ;ADDRESS CHECK SUBI T1,3 ;DEDUCT OVERHEAD CAIG T1,^D1000 ;RIDICULOUS SIZE SKIPG P1,T1 ;ANY ROOM LEFT FOR ANSWER PJRST ND%IAL ;NO, ILLEGAL ARG LIST PUSHJ P,GETWR1## ;GET NODE NAME JRST ND%ADC ;ADDRESS CHECK PUSHJ P,NODE.S ;FIND CORRECT NDB PJRST ND%INN ;ILLEGAL NODE PUSHJ P,GETWR1## ;GET RESERVED WORD JRST ND%ADC ;ADDRESS CHECK JUMPN T1,ND%RNZ ;MUST BE ZERO NODE51: PUSHJ P,GETWR1## ;GET DEVICE TYPE REQUEST JRST ND%ADC ;ADDRESS CHECK MOVSI T2,- ;NUMBER OF KNOWN DEVICES NODE52: LDB T3,[EXP OB%TYP##+OBJTAB##+(T2)] ;GET A TYPE CAIE T3,(T1) ;FOUND REQUEST AOBJN T2,NODE52 ;NO, TRY ANOTHER TYPE SKIPL T2 ;FIND ANY TDZA T2,T2 ;NONE OF REQUESTED TYPE LDB T2,NETCNF##(T2) ;GET NUMBER OF THAT TYPE HRL T1,T2 ;INSERT COUNT FOR USER PUSHJ P,PUTWRD## ;STORE BACK JRST ND%ADC ;ADDRESS CHECK SOJG P1,NODE51 ;DO FOR ALL ARGS PJRST CPOPJ1## ;GIVE GOOD RETURN SUBTTL NODE.6 NETWORK OUTPUT WITH USER CONTROL OF EOR REPEAT 0,< ;SUPERSEDED BY TSK. UUO ;FORMAT OF THE UUO ARGS ; XWD 0,NUMBER OF ARGS ; XWD FLAGS,IO CHANNEL NODE.6: PUSHJ P,SAVE1## ;HAVE TO SAVE FLAGS SOMEWHERE PUSHJ P,N67SET ;SETUP F, T1 MOVE P1,T1 ;SAVE PARAMETER WORD FOR EOR CHECK BELOW HLR M,DEVBUF(F) ;GET ADDRESS OF OUTPUT BUFFER HEADER PUSHJ P,GETWRD## ;GET ADDRESS OF CURRENT BUFFER JRST ND%ADC ;ADDRESS CHECK JUMPL T1,NODE61 ;IF BUFFER NEVER SET UP, JUST DO THE OUTPUT HRR M,T1 ;TO READ LINKAGE WORD OF BUFFER PUSHJ P,GETWRD## ;GET IT JRST ND%ADC ;ADDRESS CHECK JUMPL P1,NODE60 ;SKIP IF USER WANTS EOR TLOA T1,IONER ;DOESN'T, FLAG BUFFER NODE60: TLZ T1,IONER ;DOES, MAKE SURE THIS IS OFF PUSHJ P,PUTWRD## ;PUT BACK IN BUFFER JRST ND%ADC ;ADDRESS CHECK NODE61: PUSHJ P,TOUT## ;DO THE OUTPUT PJRST CPOPJ1## ;SUCCESS, GIVE USER A SKIP RETURN JRST N67IOE ;FAILED, RETURN ERROR STATUS >;REPEAT 0 SUBTTL NODE.7 NETWORK INPUT WITH NOTIFICATION OF END OF RECORD REPEAT 0,< ;SUPERSEDED BY TSK. UUO ;FORMAT OF UUO ARGS ; XWD 0,NUMBER OF ARGS ; XWD 0,IO CHANNEL NODE.7: PUSHJ P,N67SET ;VERIFY IO CHANNEL, SETUP F, T1 PUSHJ P,TIN## ;DO THE INPUT JRST NODE70 ;SUCCESS, CHECK EOR N67IOE: MOVEI T1,11 ;ERROR CODE 11 IS IO ERROR HRL T1,DEVIOS(F) ;AND WE RETURN THE GETSTS INFO TO THE PJRST STOTAC## ; SO THE USER DOESN'T NEED ANOTHER UUO NODE70: HRR M,DEVBUF(F) ;GET ADDRESS OF INPUT BUFFER HEADER PUSHJ P,GETWRD## ;GET IT JRST ND%ADC ;ADDRESS CHECK HRR M,T1 ;GET ADDRESS OF BUFFER LINKAGE WORD PUSHJ P,GETWRD## ;GET THAT JRST ND%ADC ;ADDRESS CHECK TLNE T1,IONER ;NOW, DOES THIS BUFFER NOT MARK THE END OF RECORD? TDZA T1,T1 ;RIGHT, MAKE BIT 0 0 MOVSI T1,400000 ;END OF RECORD, SET BIT 0 PJRST STOTC1## ;RETURN THAT TO USER ;ROUTINE FOR NODE. UUO FUNCTIONS 6 AND 7 TO DO COMMON SETUP. ; M/RH: ADDR OF ARG LIST (SETUP BY UUOCON) ; PUSHJ P,N67SET ; NORMAL RETURN, ; F/ DDB ADDRESS, T1/ FLAGS,,IO CHANNEL ;THIS ROUTINE ABORTS THE UUO IF THE IO CHANNEL IS NOT OPEN OR THE DEVICE ;IS NOT A NETWORK DEVICE. N67SET: PUSHJ P,GETWRD## ;GET ARG LIST LENGTH JRST ND%ADC ;ADDRESS CHECK CAIGE T1,2 ;NEED AT LEAST 2 WORDS PJRST ND%IAL ;TOO SHORT, RETURN LIST LENGTH ERROR PUSHJ P,GETWR1## ;GET FLAGS,,IOCHAN WORD JRST ND%ADC ;ADDRESS CHECK PUSH P,T1 PUSHJ P,SETUF## JRST [POP P,(P) PJRST ND%IAL] POP P,T1 MOVSI T2,DVCNET ;MAKE SURE DEVICE IS A NETWORK DEVICE TDNN T2,DEVCHR(F) ; FOR PARANOIA'S SAKE PJRST ND%NND ;IT ISN'T, ABORT UUO POPJ P, ;RETURN TO DO IO >;REPEAT 0 ;NODE10 (.NDTCN) UUO TO ATTEMPT TO CONNECT REMOTE TERMINAL'S TO THE SYSTEM. ;ARGUMENT BLOCK FORMAT. ; ; 1) XWD 0,LENGTH ;LENGTH ALWAYS = 2 ; 2) XWD NODE,LINE ;NODE AND LINE TO TRY TO CONNECT ; ;RETURNS ; SIXBIT /TTYNNN/ ;THE NAME THE TERMINAL WAS ASSIGNED. ; ;ERRORS ; NDIAL%==1 ;ILLEGAL ARGUMENT LIST ; NDTNA%==2 ;TERMINAL NOT AVAILABLE. ; NODE10: PUSHJ P,GETWRD## ;GET THE ARG-LIST LENGTH JRST ND%ADC ;ADDRESS CHECK CAIE T1,2 ;WE ONLY WANT 1 DATA ARGUMNET JRST ND%IAL ;ILLEGAL ARG LIST (NDIAL%) PUSHJ P,GETWR1## ;GET THE "XWD NODE,LINE" TO CONNECT TO JRST ND%ADC ;ADDRESS CHECK PUSHJ P,ASGTTY## ;ATTEMPT THE CONNECT. PJRST ND%TNA ;TERMINAL NOT AVAILABLE (NDTNA%) PJRST STOTC1## ;RETURN TERMINAL NUMBER IN AC ;NODE11 (.NDTDS) DISCONNECT A REMOTE TERMINAL FROM THE SYSTEM (WITH OPTIONAL ; RECONNECT TO ANOTHER SYSTEM). ; ;NODE. UUO ARGUMENT BLOCK. ; 1) XWD 0,LENGTH ;EITHER 2 OR 3 (3 IMPLIES AUTO RECONNECT) ; 2) SIXBIT /TTYNNN/ ;NAME OF TERMINAL DO DIS/RE-CONNECT ; 3) EXP NODE-NUMBER ;OPTIONAL NODE NUMBER TO RECONNECT TO. ; ;RETURNS ; NOTHING. ON A SUCCESSFUL RETURN, THE AC IS UNCHANGED ; ;ERRORS ; NDIAL%==1 ;ILLEGAL ARGUMENT LIST (LENGTH WRONG) ; NDINN%==2 ;ILLEGAL NODE NUMBER/NAME (CAN'T HAPPEN...) ; NDIAJ%==3 ;THE TERMINAL IS IN USE BY ANOTHER JOB. ; NDNLT%==4 ;USER DID NOT GIVE A LEGAL TERMINAL NAME AS ; ; THE SECOND ARGUMENT. ; NODE11: PUSHJ P,SAVE4## ;WE USE THE P'S FOR TEMPS PUSHJ P,GETWRD## ;GET THE LENGTH OF THE ARG-LIST JRST ND%ADC ;ADDRESS CHECK CAIL T1,2 ;RANGE CHECK THE LENGTH. MUST CAILE T1,3 ; BE BETWEEN 2 AND 3 JRST ND%IAL ;ILLEGAL ARG LIST (NDIAL%) MOVE P2,T1 ;SAVE THE LENGTH FOR A BIT PUSHJ P,GETWR1## ;GET THE TERMINAL NAME JRST ND%ADC ;ADDRESS CHECK MOVE P3,T1 ;SAVE THE NAME MOVEI P4,RSN.OK ;ASSUME THAT THIS IS SIMPLE DISCONNECT. CAIN P2,3 ;BUT IF THIS IS A RE-CONNECT, JRST [PUSHJ P,GETWR1## ;THEN GET NODE NUMBER TO RECONNECT TO. JRST ND%ADC ;ADDRESS CHECK HRLZ P4,T1 ;AND PUT NODE NUMBER IN LH HRRI P4,RSN.RC ;REASON IS "RE-CONNECT" JRST .+1] ;REJOIN MAIN FLOW WITH ALL ARGS READ NOD11A: MOVE T1,P3 ;GET THE TERMINAL NAME BACK PUSHJ P,TTYPHY## ;SET U := LDB, F := DDB(IF ANY) PJRST ND%NLT ;GIVE "NDNLT%" ERROR IF TERMINAL NAME IS BAD JUMPN F,[LDB T1,PJOBN## ;IF WE FOUND A LDB, SEE IF WE GOT A DDB. SKIPE T1 ;IF NO-ONE OWNS IT, WE'RE OK CAMN T1,.CPJOB## ; IF WE OWN IT WE'RE OK CAIA ; WE'RE OK JRST ND%IAJ ; IF WE DON'T OWN IT, GIVE "NDIAJ%" ERROR PUSHJ P,TTYDTC## ; DETACH THE TERMINAL JRST .+1] ; IF WE DO OWN IT, THEN ALL'S OK PUSHJ P,MCRCHK## ;SEE IF IT'S A LEGAL REMOTE TERMINAL. JRST ND%NLT ;IF NOT, THEN RETURN "NDNLT%" LDB T1,LDPRNN## ;GET THE NODE NUMBER THAT IT'S CONNECTED TO PUSHJ P,SRCNDB ;FIND THE NDB STOPCD .,STOP,ANFNNT, ;++ NO NBD FOR TERMINAL MOVE T1,P4 ;GET "XWD NODE,REASON" PUSHJ P,TRMXDC## ;SEND THE DISCONNECT JRST [PUSHJ P,NETSLP ;IF NO CORE, SLEEP FOR A BIT JRST NOD11A] ; AND TRY AGAIN JRST CPOPJ1## ;ALL DONE. GIVE GOOD RETURN ;NODE12 (.NDLND) RETURNS THE NUMBER OF NODES IN THE NETWORK, AND A LIST ; OF THE NODE NUMBERS. ; ;NODE. UUO ARGUMENT BLOCK ; 1) XWD 0,LENGTH ;LENGTH OF ARG BLOCK (INCLUDES THIS WORD) ; 2) EXP RTN-VAL-1 ;FILLED IN WITH NODE NUMBER OF FIRST NODE ; 3) EXP RTN-VAL-2 ;FILLED WITH SECOND NODE NUMBER ; . ; . ; . ; N+1) EXP RTN-VAL-N ;FILLED WITH NUMBER OF N'TH NODE ; ;RETURNS ; IN THE AC, THE NUMBER OF NODES IN THE NETWORK ; IN ARG-LIST(2 THRU N+1) THE NUMBERS OF THE NODES IN THE NETWORK ; ;ERRORS ; NDIAL%==1 ;ARG-LIST LENGTH LESS THAN 1 ; ;NOTE! NO ERROR IS RETURNED IF THE ARGUMENT LIST IS TOO SHORT TO HOLD ; ALL THE NODES. THE EXTRA ARGUMENTS ARE SIMPLY NOT RETURNED. NODE12: PUSHJ P,GETWRD## ;GET THE LENGTH OF THE ARG LIST JRST ND%ADC ;ADDRESS CHECK CAIGE T1,1 ;MAKE SURE IT'S LEGAL JRST ND%IAL ;NDIAL% ILLEGAL ARG LIST MOVE T3,T1 ;SAVE THE ARG-LIST LENGTH FOR A WHILE MOVEI T2,NETNDB## ;GET THE ADDRESS OF THE FIRST DDB SETZ T4, ;WE'VE COUNTED NO NODES YET. NOD12A: JUMPE T2,[MOVE T1,T4 ;IF WE'VE COUNTED ALL THE NODES, JRST STOTC1##] ;COPY THE COUNT AND RETURN IT HLRZ T1,NDBNNM(T2) ;GET THE NUMBER OF THE NODE SOJLE T3,NOD12B ;COUNT DOWN ANOTHER RETURN-VALUE PUSHJ P,PUTWR1## ;RETURN THE NODE NUMBER JRST ND%ADC ;ADDRESS CHECK NOD12B: HRRZ T2,NDBNNM(T2) ;STEP TO THE NEXT NODE AOJA T4,NOD12A ;COUNT THIS ONE AND LOOP OVER ALL NODES ;NODE13 (.NDNDB) RETURN INFORMATION ABOUT AN NDB. ; ;NODE. UUO ARGUMENT LIST ; 1) XWD 0,LENGTH ;LENGTH OF ARG LIST. (INCLUDES THIS WORD) ; 2) EXP NODE NUMBER/NAME;NUMBER OR NAME OF THE NODE IN QUESTION ; 3) EXP SUB-FCN NUMBER ;DESCRIBES WHICH FIELD TO RETURN ; 4) RTN-VALUE-1 ;FIRST RETURN VALUE ; 5) RTN-VALUE-2 ;SECOND RETURN VALUE ; . ; . ; . ; 3+N) N'TH-RETURN-VALUE ;LAST RETURN VALUE ; ;ERRORS ; NDIAL%==1 ;ARG LIST TOO SHORT ; NDINN%==2 ;ILLEGAL NODE NUMBER/NAME ; NDISF%==3 ;ILLEGAL SUB-FUNCTION ; ;VALID FIELDS (ARG #3) ; ND.NNM==1 ;THE NUMBER OF THE SPECIFIED NODE ; ND.SNM==2 ;THE NAME IN 6 OR LESS SIXBIT CHARACTERS ; ND.SID==3 ;THE SOFTWARE ID IN "ASCIZ" ; ND.DAT==4 ;THE SOFTWARE DATE IN "ASCIZ" ; ND.LMA==5 ;THE NCL LAST MESSAGE ASSIGNED ; ND.LMS==6 ;THE NCL LAST MESSAGE SENT ; ND.LAR==7 ;THE NCL LAST ACK RECEIVED ; ND.LAP==10 ;THE NCL LAST ACK PROCESSED ; ND.LMR==11 ;THE NCL LAST MESSAGE RECEIVED ; ND.LMP==12 ;THE NCL LAST MESSAGE PROCESSED ; ND.LAS==13 ;THE NCL LAST ACK SENT ; ND.MOM==14 ;THE MAXIMUM OUTSTANDING MESSAGE COUNTER ; ND.TOP==15 ;THE TOPOLOGY TABLE. THIS IS "NGHMAX" WORDS ; ; OF THE FORM "XWD LEVEL,NODE" ; ND.CNF==16 ;THE CONFIGURATION TABLE. THIS IS VARIABLE ; ; LENGTH OF THE FORM "XWD OBJ,NUMBER" ; ND.CTL==17 ;RETURN STATION CONTROL JOB ; ND.OPR==20 ;RETURN OPR TTY NUMBER ; NODE13: PUSHJ P,SAVE4## ;WE USE THE P'S AS TEMPS PUSHJ P,GETWRD## ;GET THE LENGTH OF THE ARG LIST JRST ND%ADC ;ADDRESS CHECK CAIGE T1,4 ;MAKE SURE THAT IT'S AT LEAST 4 WORDS LONG JRST ND%IAL ;RETURN NDIAL% -- ILLEGAL ARG LIST MOVE P4,T1 ;SAVE THE LENGTH FOR A WHILE SUBI P4,3 ;ADJUST SO P4 = RETURN LOCATIONS FREE PUSHJ P,GETWR1## ;GET THE NODE NUMBER/NAME JRST ND%ADC ;ADDRESS CHECK PUSHJ P,SRCNDB ;SET UP W FROM THE NUMBER/NAME JRST ND%INN ;RETURN NDINN% -- ILLEGAL NODE NUMBER PUSHJ P,GETWR1## ;GET THE SUB-SUB-FUNCTION CODE. JRST ND%ADC ;ADDRESS CHECK CAIL T1,1 ;RANGE CHECK IT CAILE T1,N13LEN ; TO MAKE SURE IT'S VALID JRST ND%ISF ;RETURN NDISF% -- INVALID SUB-FUNCTION XCT N13TBL-1(T1) ;CALL ROUTINE TO GET FIELD SKIPA ;MUST STORE JRST CPOPJ1## ;DON'T N13WD1: PUSHJ P,PUTWR1## ;NON-SKIP MEANS WE SHOULD STORE ARG HERE JRST ND%ADC ;ADDRESS CHECK JRST CPOPJ1## ;ALL DONE. ;N13TBL TABLE OF INSTRUCTIONS TO EXECUTE TO RETURN VARIOUS FIELDS OF AN NDB N13TBL: HLRZ T1,NDBNNM(W) ;(01) GET THE NODE NUMBER FIELD PUSHJ P,N13SNM ;(02) CALL SUBROUTINE TO GET NODE NAME JRST N13SID ;(03) CALL SUBROUTINE TO GET SOFTWARE-ID JRST N13DAT ;(04) CALL SUBROUTINE TO GET SOFTWARE-DATE LDB T1,NDBLMA## ;(05) GET LAST MESSAGE ASSIGNED LDB T1,NDBLMS## ;(06) GET LAST MESSAGE SENT LDB T1,NDBLAR## ;(07) GET LAST ACK RECEIVED LDB T1,NDBLAP## ;(10) GET LAST ACK PROCESSED LDB T1,NDBLMR## ;(11) GET LAST MESSAGE RECEIVED LDB T1,NDBLMP## ;(12) GET LAST MESSAGE PROCESSED LDB T1,NDBLAS## ;(13) GET LAST ACK SENT MOVE T1,NDBMOM(W) ;(14) GET MAXIMUM OUTSTANDING MESSAGE COUNTER JRST N13TOP ;(15) RETURN TOPOLOGY TABLE JRST N13CNF ;(16) RETURN CONFIGURATION TABLE HRRZ T1,NDBSTC(W) ;(17) GET STATION CONTROL JOB NUMBER PUSHJ P,N13OPR ;(20) GET OPR TTY NUMBER N13LEN==.-N13TBL ;DEFINE LENGTH FOR RANGE CHECK ;N13SNM (02) RETURN THE SOFTWARE NAME (UP TO 6 SIXBIT CHARACTERS) N13SNM: HLRZ T1,NDBSNM(W) ;GET ADDRESS OF THE SNM MOVE T1,(T1) ;GET THE SNM POPJ P, ;RETURN AND LET MAIN CODE STORE THE ANSWER. ;N13SID (03) RETURN THE SOFTWARE ID (VERSION INFO) FOR THE NODE. N13SID: HRRZ P1,NDBSID(W) ;GET A POINTER TO THE SID PJRST N13ASZ ;AND GO USE ASCIZ COPY ROUTINE ;N13DAT (04) RETURN THE SOFTWARE DATE FOR THE NODE N13DAT: HLRZ P1,NDBSID(W) ;GET A POINTER TO THE DATE ; PJRST N13ASZ ;AND GO USE THE ASCIZ COPY ROUTINE N13ASZ: SOSGE P4 ;COUNT DOWN NEXT WORD TO RETURN JRST ND%IAL ;IF WE COUNT OUT, THEN LIST WAS TO SHORT SKIPE T1,P1 ;UNLESS POINTER NOT PRESENT, MOVE T1,(P1) ;GET THE NEXT WORD TO RETURN PUSHJ P,PUTWR1## ;STORE THE WORD IN THE ARG LIST JRST ND%ADC ;ADDRESS CHECK MOVEI T2,5 ;COUNT TO SEE ANY CHAR WAS A NULL N13AS1: TLNN T1,774000 ;WAS THIS CHAR A NUL JRST CPOPJ1## ;IF SO, GIVE SKIP RETURN LSH T1,7 ;SHIFT TO NEXT CHAR POSITION SOJG T2,N13AS1 ;LOOP OVER ALL 5 CHARACTERS AOJA P1,N13ASZ ;LOOP OVER ALL WORDS IN NAME ;N13TOP (15) RETURN THE TOPOLOGY TABLE FOR THE PARTICULAR NODE. ; ;THE TABLE IS RETURNED IN THE FORM OF UP TO 16 WORDS OF ; XWD LEVEL,NODE ; WHERE NODE IS THE NEIGHBOR OF THE NODE IN QUESTION, AND LEVEL IS THE ; "COST" OF THE LINK TO GET THERE N13TOP: MOVE P3,[POINT 9,NDBTOP(W)] ;POINTER TO THE TOPOLOGY TABLE MOVEI P2,NGHMAX ;MAX LENGTH OF THE TOPOLOGY TABLE N13TP1: SOSGE P2 ;COUNT DOWN ANOTHER ENTRY JRST N13RZR ;ALL DONE. WRITE TERMINATING ZERO AND RETURN ILDB T1,P3 ;GET THE NEXT ENTRY ILDB T2,P3 ;GET ITS COST JUMPE T1,N13TP1 ;IF NULL, KEEP TRYING SOSGE P4 ;COUNT DOWN THE LENGTH OF THE ARGLIST JRST ND%IAL ;ILLEGAL ARGLIST (TOO SHORT) HRLI T1,(T2) ;PUT COST IN LH OF RETURN VALUE PUSHJ P,PUTWR1## ;STORE THE "XWD LEVEL,NODE" JRST ND%ADC ;ADDRESS CHECK JRST N13TP1 ;LOOP OVER ALL TABLE ENTRIES ;N13CNF (16) RETURN THE CONFIGURATION INFORMATION FOR A NODE. ; ; CONFIGURATION INFORMATION RETURNED AS UP TO "OBJ.MX" WORDS OF THE FORM ; XWD OBJECT-TYPE,NUMBER ; WHERE OBJECT-TYPE IS THE NCL TYPE OF THE DEVICE, AND NUMBER IS THE ; NUMBER OF SAID DEVICES THAT THE NODE POSSESSES. N13CNF: MOVEI P1,OBJ.MX+1 ;MAXIMUM OBJECT TYPE +1 N13CN1: SOJL P1,N13RZR ;COUNT DOWN THROUGH ALL OBJECT TYPES LDB T1,NETCNF##(P1) ;GET THE NUMBER OF THIS TYPE JUMPE T1,N13CN1 ;IF NONE, KEEP TRYING HRLI T1,(P1) ;PUT OBJECT TYPE IN THE LH SOSGE P4 ;COUNT DOWN ANOTHER RETURN VALUE JRST ND%IAL ;ARG LIST TOO SHORT PUSHJ P,PUTWR1## ;RETURN THE VALUE JRST ND%ADC ;ADDRESS CHECK JRST N13CN1 ;LOOP OVER ALL OBJECT TYPES ;N13RZR ROUTINE TO WRITE THE TERMINATING ZERO FOR N13TOP AND N13CNF N13RZR: SOSGE P4 ;COUNT DOWN THE ARGLIST JRST ND%IAL ;ERROR IF LIST TOO SHORT SETZ T1, ;ZERO TO STORE JRST N13WD1 ;AND LET NODE13 STORE IT FOR US. ;N13OPR (20) RETURNS OPR TTY NUMBER OR -1 IF NOT CONNECTED N13OPR: HRRZ T1,NDBOPR(W) ;GET LDB OF OPR LINE FOR THIS NODE SKIPN T1 ;HAVE ONE? SOJA T1,CPOPJ## ;NO--RETURN -1 EXCH U,T1 ;SAVE U, GET LDB ADDRESS SSX U,MS.SCN ;USE SCNSER SECTION LDB U,LDPLNO## ;GET THE LOCAL LINE NUMBER EXCH T1,U ;RESTORE U POPJ P, ;AND RETURN ;NODE14 (.NDGNF) READ/SET THE GREETED NODE FLAG ;NODE. UUO ARGUMENT BLOCK ; 1) XWD 0,LENGTH ;LENGTH MUST BE "2" ; 2) EXP 0!NODE # ;EITHER 0 (RETURN FIRST UN-GREETED NODE) ; ; OR NODE # (SET "GREETED BIT") ;RETURNS ; IN ARG 2 THE NODE # OF THE FIRST "UN-GREETED" NODE) ; ;ERRORS: ; ND%IAL ;ILLEGAL ARG LIST ; ND%NUG ;NO UNGREETED NODES ; ND%INN ;ILLEGAL NODE NUMBER (SET GREETED BIT FCN) ; ND%PRV ;USER NOT PRIVLEGDED ; NODE14: PUSHJ P,NTDPRV ;CHECK PRVS RIGHT AWAY PJRST ND%PRV ;USER DOESN'T HAVE PRVS TO DO THIS PUSHJ P,GETWRD## ;GET ARG LIST LENGTH JRST ND%ADC ;ADDRESS CHECK CAIGE T1,2 ;MAKE SURE ITS LONG ENOUGH PJRST ND%IAL ;IF TO SHORT, GIVE "ILLEGAL ARG LIST" ERROR PUSHJ P,GETWR1## ;GET 0 (RETURN) OR NODE # (SET) JRST ND%ADC ;ADDRESS CHECK JUMPE T1,NOD14A ;IF 0 (RETURN) GO SEARCH NDB'S PUSHJ P,SRCNDB ;GO SEE IF WE CAN FIND AN NDB FOR HIM PJRST ND%INN ;IF NO NDB, GIVE ILLEGAL NODE NUMBER ERROR MOVSI T1,NDB.GF ;GET THE "GREETED FLAG" IORM T1,NDBFLG(W) ; AND SET IT RETSKP ;GIVE GOOD RETURN TO THE UUO. NOD14A: HRRZI W,NETNDB ;GET THE ROOT OF ALL NODES NOD14B: HRRZ W,NDBNNM(W) ;GO TO NEXT NODE (SKIP NETNDB) JUMPE W,ND%NUG ;IF AT END OF LIST, GIVE NO UN-GREETED NODE ERR MOVE T1,NDBFLG(W) ;GET THE FLAGS TLNE T1,NDB.UP ;IF THE NODE IS NOT UP, TLNE T1,NDB.GF ; OR IT'S ALREADY BEEN GREETED JRST NOD14B ;THEN GO TRY THE NEXT NODE HLRZ T1,NDBNNM(W) ;THIS IS OUR NODE, GET THE NUMBER PUSHJ P,PUTWRD## ;STORE IT FOR THE USER JRST ND%ADC ;ADDRESS CHECK RETSKP ;GIVE GOOD RETURN TO UUO SUBTTL NDB INTERFACE ROUTINES ;SUBROUTINE NETOPR -- KEEP NETNDB(NDBOPR) UP TO DATE WITH OPRLDB ;CALL MOVE U,NEW OPR LDB ;RETURN CPOPJ1 NETOPR::HRRM U,NETNDB##+NDBOPR ; STORE THE LDB ADDRESS JRST CPOPJ1## ; SKIP RETURN FOR SCNSER ;SUBROUTINE TO LOAD INTO T1 THE TERMINAL NUMBER OF THE OPR'S ; TERMINAL FOR THE STATION WHOSE NUMBER IS IN T1. STBOPR:: SE1ENT PUSH P,U ;SAVE U HRRZS T1 ;STATION NUMBER IN T1 NETOFF ;PROTECT OURSELF WHEN SCANNING THE NDB'S ; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB") PUSHJ P,SRCND0 ;FIND THE NODE BLOCK (BYPASS 'NT' CHECK) JRST LCLOPR ;NO, USE LOCAL OPR HRRZ U,NDBOPR(W) ;GET THE OPR LDB SKIPN U ;ANY ASSIGNED LCLOPR: MOVE U,OPRLDB## ;NO, USE LOCAL OPR SSX U,MS.SCN ;USE SCNSER SECTION LDB T1,LDPLNO## ;GET NUMBER OF TERMINAL IN U NETON ;INT'S ON AGAIN JRST UPOPJ## ;RESTORE U AND EXIT. ;SUBROUTINE STBSCA - RETURN THE STATION NUMBER ;CALL MOVEI T1,NNM ; PUSHJ P,STBSCA ;RETURN CPOPJ ;NO SUCH STATION ; CPOPJ1 ;STATION VALID T1=NNM STBSCA:: ;ENTRY PUSHJ P,SAVJW## ;SAVE J AND W NETOFF ;PROTECT WHILE LOOKING AT THE NDB'S ; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB") PUSHJ P,SRCND0 ;SEARCH NDB'S (BYPASS THE 'NT' CHECK) JRST NTONPJ ;RETURN INVALID STATION HLRZ T1,NDBNNM(W) ;GET THE STATION NUMBER NETON ;ALL'S CLEAR PJRST CPOPJ1## ;EXIT SUBTTL ERROR MESSAGES. NODERT: XWD [ASCIZ / Assigned/] NRTDNA: XWD [ASCIZ /Device Not Available/] NRTNCE::XWD [ASCIZ /Network Capacity Exceeded/] NRTTNA: XWD [ASCIZ /Task Not Available/] NRTUNT: XWD [ASCIZ /Undefined Network Task/] NRTUNN::XWD [ASCIZ /Undefined Network Node/] NRTUND: XWD [ASCIZ /Undefined Network Device/] SUBTTL TSTNET - FIND OUT IF A DEVICE EXISTS ON THE NETWORK ;SUBROUTINE TSTNET - ASSIGN A DDB FOR THE DEVICE IF IT EXISTS ;CALL MOVE T1,DEVICE NAME ; PUSHJ P,TSTNET ;RETURN CPOPJ ;DEVICE DOES NOT EXIST/NOT AVAILABLE ; CPOPJ1 ;DEVICE EXISTS AND IS AVAILABLE TSTNET:: ;ENTRY FROM UUOCON HLRZ T2,M ;GET THE UUO ANDI T2,777000 ;ONLY THE UUO OP CODE CAIE T2,(OPEN) ;IS IT POPJ P, ;NO, GET THE ASSIGN LATER HLRZ T2,T1 ;GET GENERIC PORTION OF NAME CAIN T2,'TTY' ;IS IT A TTY? POPJ P, ;YES, TTY'S DON'T HAVE STATION NUMBERS IN DDBS TRNE T1,7700 ;IS THERE A STATION NUMBER PUSHJ P,DVSCVT## ;GET THE STATION NUMBER POPJ P, ;NOT A STATION NUMBER PUSH P,T1 ;SAVE THE NAME DPB T1,[POINT 6,T1,23] ;MOVE THE UNIT NUMBER OVER TRZ T1,7777 ;CLEAR THE JUNK PUSHJ P,GENNET ;GO ASSIGN THE DEVICE PJRST TPOPJ## ;NO SUCH DEVICE PJRST TPOPJ1## ;DEVICE ASSIGNED F=DDB ;SUBROUTINE GENNET - TEST FOR A GENERIC NETWORK DEVICE ;CALL MOVE T1,[SIXBIT /DEVNAME/] ; MOVE T2,STATION NUMBER ; PUSHJ P,GENNET ;RETURN POPJ ;NO ON THE NETWORK OR AVAILABLE ; CPOPJ1 ;F=DDB ADDRESS GENNET:: ;ENTRY FROM UUOCON NETDBJ ;INTERLOCK THIS CODE CAMN T2,JBTLOC## ;LOCAL STATION POPJ P, ;YES, RETURN PUSHJ P,SAVT## ;NO, SAVE THE T'S MOVEI T4,(P) ;GET THE STACK ADDRESS CAMG T4,LOCORE## ;RUNNING AT CLOCK LEVEL POPJ P, ;YES, DON'T TRY THE NETWORK PUSHJ P,SAVJW## ;SAVE J AND W PUSHJ P,SAVE3## ; AND THE P'S MOVE P2,T1 ;COPY THE DEVICE NAME MOVEI T1,(T2) ;PUT THE STATION NUMBER IN T1 PUSHJ P,SRCNDB ;DOES THE STATION EXIST POPJ P, ;NO EXIT MOVEI P1,(W) ;SAVE THE NDB POINTER SETZ P3, ;CLEAR THE LOCAL NAME HLRZ T1,P2 ;GET THE GENERIC DEVICE NAME PUSHJ P,SRCNDT ;SEE IF IT EXISTS AT THE STATION POPJ P, ;NO, EXIT PUSHJ P,MAKDDB ;YES, MAKE A DDB POPJ P, ;CAN'T PUSHJ P,NTDCNT ;USE THE "NORMAL" DEVICE CONNECT ROUTINE (WAITS) PJRST RMVNET ;FAILED DISCARD DDB PUSHJ P,LNKDDB ;LINK CONNECTED DDB PJRST CPOPJ1## ;WE WON SUBTTL DDB -- ROUTINES TO MANAGE NETWORK DEVICE DATA BLOCKS ;MAKDDB ROUTINE TO CREATE A NETWORK DDB ;CALL MOVE P1,NDB POINTER ; MOVE P2,DEVICE NAME ; MOVE P3,LOGICAL NAME ; MOVE W,NDT POINTER ; MOVE T2,LENGTH ;MAKDDC ONLY ; PUSHJ P,MAKDDB/MAKDDC ;RETURN CPOPJ ;NO SPACE AVAILABLE ; CPOPJ1 ;F=DDB POINTER,U=PCB ; ;NOTE! THIS ROUTINE DOES NOT ASSIGN AN SLA MAKDDB::MOVEI T2,NETLEN ;GET THE LENGTH OF THE PROTOTYPE DDB MAKDDC::NTDBUG ;VERIFY THE INTERLOCK IFN PARANOID&P$DDB,< ;SOME CONSISTENCY CHECKING CAIL T2,NETLEN ;CAN'T BE SMALLER THAN MINIMUM NETWORK LENGTH CAILE T2,NETLEN+10 ;AND NONE ARE MUCH BIGGER STOPCD .,STOP,ANFUND, ;++ UNREASONABLE NETWORK DDB LENGTH > ;END IFN PARANOID&P$DDB PUSH P,T2 ;SAVE ALLOCATED LENGTH PUSHJ P,GETZWD ;ALLOCATE THE SPACE JRST T2POPJ## ;SPACE NOT AVAILABLE MOVEI F,(T1) ;COPY THE DDB POINTER HRLI T1,NETDDB ;BLT POINTER TO COPY THE PROTOTYPE DDB BLT T1,NETLEN-1(F) ;COPY IT POP P,T2 ;RETRIEVE LENGTH OF NEW DDB DPB T2,NETZWD## ;SET LENGTH OF DDB FOR RMVNET CAIG T2,NETLEN ;IS THIS AN EXTENDED DDB? JRST MAKDD2 ;NO SETZM NETLEN(F) ;YES, CLEAR OUT REMAINDER MOVSI T1,NETLEN(F) ;CONCOCT A HRRI T1,NETLEN+1(F) ; BLT POINTER ADDI T2,(F) ;AND A BLT TERMINATOR BLT T1,-1(T2) ;TO CLEAR DDB EXTENSIONS ;CONTINUED ON NEXT PAGE ;CONTINUED FROM PREVIOUS PAGE MAKDD2: MOVEM P2,DEVNAM(F) ;STORE THE DEVICE NAME MOVEM P3,DEVLOG(F) ;STORE THE LOGICAL NAME HLRZ T1,NDBNNM(P1) ;GET THE NODE NUMBER HRRZM T1,DEVNET(F) ;STORE THE NODE NUMBER DPB T1,PDVSTA## ;STORE AS THE STATION NUMBER TRO T1,77700 ;FORCE A STATION NUMBER ALIGNMENT S0PSHJ CVTSBT## ;CONVERT TO SIXBIT MOVE T2,P2 ;COPY THE DEVICE NAME TRNN T2,7777 ;CHECK FOR GGGU LSH T2,-14 ;YES, SHIFT FOR THE UNIT NUMBER ANDI T2,77 ;ONLY ONE DIGIT IORI T1,(T2) ;INSERT THE DIGIT HRRM T1,DEVNAM(F) ;STORE IN THE DEVNAME ANDI T1,77 ;SAVE LAST DIGIT SKIPN T1 ;IS IT A BLANK IE GENERIC TROA T1,177 ;YES, USE 177 FOR GENERIC SEARCH ANDI T1,7 ;ONLY THREE BITS WORTH (FOR GGGNNU) DPB T1,PUNIT## ;STORE THE UNIT NUMBER MOVSI T1,DVCNET ;GET THE NETWORK OWNERSHIP BIT IORM T1,DEVCHR(F) ;STORE WE OWN IT DPB J,PJOBN## ;STORE THE JOB NUMBER LDB T1,NDTBFZ## ;GET THE DEFAULT BUFFER SIZE DPB T1,PBUFSZ## ;STORE THE BUFFER SIZE LDB T1,NDTTYP## ;GET THE DEVICE TYPE DPB T1,DEYTYP## ;STORE THE DEVICE TYPE LDB T1,NDTSPL## ;GET THE DEFAULT SPOOL BITS DPB T1,DEYSPL## ; AND STORE THEM IN THE NEW DDB MOVE T1,NDTMOD(W) ;GET THE DEVMOD BITS MOVEM T1,DEVMOD(F) ;STORE DEVMOD HRLM W,DEVNET(F) ;LINK THE NDT TO THE DDB JRST CPOPJ1## ;EXIT WITH F=NETDDB, U=PCB, W=NDT ;SUBROUTINE LNKDDB - ADD THE DDB(F) INTO THE DDB CHAIN ;CALL MOVEI F,DDB ; PUSHJ P,LNKDDB ;RETURN CPOPJ LNKDDB::PUSHJ P,SAVE1## ;SAVE P1 PUSH P,F ;SAVE THE DDB POINTER MOVE T1,DEVLOG(F) ;GET THE LOGICAL NAME PUSHJ P,DEVLG## ;CHECK FOR IN USE JRST LNKDD1 ;NO, SETZM DEVLOG(F) ;YES, CLEAR THE LOGICAL NAME MOVE T2,DEVMOD(F) ;GET THE DEV MODE BITS TLNE T2,DVDSK ;IS IT A DSK TRNE T2,ASSPRG ; AND INIT'ED JRST LNKDD1 ;NO IGNORE PUSHJ P,CLRDVL## ;CLEAR LOGICAL NAME TABLE ENTRY PUSHJ P,CLRDDB## ;YES, CLEAR THE DDB LNKDD1: POP P,F ;RESTORE THE DDB POINTER PUSHJ P,SETDVL## ;SET UP THE LOGICAL NAME SKIPN DEVLOG(F) ;WAS IT BEING CLEARED PUSHJ P,ASSCK1## ;YES, RECLAIM SPACE DDBSRL HLRZ T2,NETDDB+DEVSER ;GET THE LINK POINTER HRLM T2,DEVSER(F) ;LINK THIS TO THE PROTOTYPE HRLM F,NETDDB+DEVSER ;AND THE PROTOTYPE DDBSRU POPJ P, ;RETURN ;SUBROUTINE UNLDDB -- ROUTINE TO UNLOAD A NETWORK DDB. THIS ROUTINE ; UNLINKS AND DELETES THE DDB. ;CALL MOVEI F,DDB ; PUSHJ P,UNLDDB ;RETURN CPOPJ UNLDDB:: ;GLOBAL ENTRY POINT NTDBUG ;VERIFY THE INTERLOCK PUSHJ P,UNLKDB ;UNLINK DDB (ALSO WORKS OK IF NOT LINKED!!) PJRST RMVNET ;NO GIVE THE STORAGE BACK TO THE MONITOR ;SUBROUTINE UNLKDB - UNLINK A DDB FROM THE SYSTEM'S LIST ;CALL MOVE F,DDB ;RETURN CPOPJ UNLKDB: MOVEI T2,NETDDB## ;GET THE STARTING DDB UNLDB1: MOVE T1,T2 ;FOLLOW THE DDB CHAIN HLRZ T2,DEVSER(T1) ;NEXT DDB JUMPE T2,CPOPJ## ;WENT AWAY CAIE T2,(F) ;IS THIS THE ONE JRST UNLDB1 ;NO CONTINUE DDBSRL HLRZ T2,DEVSER(F) ;GET THE NEXT DDB HRLM T2,DEVSER(T1) ;REMOVE THE DDB LINKS DDBSRU POPJ P, ;RETURN WITH LINK BROKEN ;RMVNET ROUTINE TO FREE THE STORAGE ASSOCIATED WITH A DDB. ;CALL MOVEI F,DDB ;NOT LINKED OR CONNECTED ; PUSHJ P,RMVNET ;RETURN CPOPJ ;DDB FREED ; RMVNET:: ;HERE TO DELETE A DDB PUSHJ P,CLNNET ;CLEAN OUT THE DDB (FREE RANDOM STUFF) LDB T1,NETZWD## ;GET LENGTH OF THIS PARTICULAR DDB MOVEI T2,(F) ;GET ADDR OF THE DDB PUSHJ P,GIVZWD ;FREE THE DDB SETZ F, ;MAKE SURE F DOESN'T POINT ANYWHERE POPJ P, ;ALL DONE ;CLNNET ROUTINE TO INITIALIZE A DDB. ;CALL MOVEI F,DDB ;MUST NOT BE CONNECTED ; PUSHJ P,CLNNET ;RETURN CPOPJ ;DDB INITIALIZED CLNNET::NTDBUG ;JUST CHECKING... IFN PARANOID&P$DDB,< ;MAKE SURE THAT THIS DDB IS TRULY FREE. SKIPN F ;IS THERE A DDB THERE STOPCD .,STOP,ANFCND ;++ CLNNDB HAS NO DDB LDB T1,NETSLA## ;SHOULDN'T HAVE A LAT ASSIGNED SKIPE T1 ; ALL THE DISCONNECT ROUTINES CLEAR THIS STOPCD .,STOP,ANFCLA ;++ LAT STILL ASSIGNED IN CLNNDB > PUSHJ P,GV2NPD ;WE MUST FREE THE NPD'S PUSH P,U ;SAVE "U" FOR A BIT HRRZ U,DEVPCB(F) ;GET THE POINTER TO QUEUED PCB'S (IF ANY) PUSHJ P,RMVALP ;FREE THEM ALL POP P,U ;RESTORE "U" SETZM DEVDRQ(F) ;CLEAR ANY STALE DATA-REQUESTS SETZB T1,DEVPCB(F) ;CLEAR POINTER TO JUST FREED PCB'S SETZB T2,DEVPBP(F) ; AND CLEAR AUX POINTER TO SUB MSG DMOVEM T1,DEVAXI(F) ;CLEAR INPUT BUFFER POINTERS DMOVEM T1,DEVAXO(F) ; AND OUTPUT TOO. HLLZS DEVNET(F) ;CLEAR NODE NUMBER DPB T1,NETSLA## ;CLEAR SOURCE LINK ADDR DPB T1,NETDLA## ; DESTINATION LINK DPB T1,NETRLN## ; RECORD LENGTH DPB T1,NETDVT## ; AND ATTRIBUTES POPJ P, ;ALL DONE. RESTORE A CLEAN DDB ;ZAPNET ROUTINE TO TAKE CARE OF USELESS NETWORK DDB'S ;CALL MOVEI F,DDB ; PUSHJ P,ZAPNET ;RETURN CPOPJ, F/0 IF DDB ZAPPED, OTHERWISE UNCHANGED ; ;ZAPNET IS CALLABLE FOR ANY NON-TTY DDB IN F, WILL RETURN HARMLESSLY IF ;THE DDB IS NOT NETWORK-ZAPPABLE (I.E., IS NOT A ANF DEVICE, IS UNDER MDA ;CONTROL, IS RESTRICTED, OR IS ASSIGNED/INITED BY A JOB/PROGRAM) ZAPNET::MOVE T1,DEVMOD(F) ;A COLLECTION OF DEVICE FLAGS TRNE T1,ASSCON!ASSPRG;NEVER DISCONNECT A DDB WHICH IS IN USE POPJ P, ;DON'T DISCONNECT THIS DEVICE ZAPNE0: MOVE T1,DEVCHR(F) ;SOME DIFFERENT DEVICE FLAGS IFN FTMDA, ;NEVER DISCONNECT ONE OF QUASAR'S PLAYTHINGS TLNN T1,DVCNET ;NEVER DISCONNECT A NON-ANF-NETWORK DEVICE POPJ P, ;DON'T DISCONNECT THIS DEVICE MOVE T1,DEVSTA(F) ;OTHER ASSORTED DEVICE FLAGS TLNE T1,DEPRAS ;NEVER DISCONNECT A RESTRICTED DEVICE POPJ P, ;DON'T DISCONNECT THIS DEVICE IFN FTDDP,< ;IF DDPS ARE AROUND, LDB T1,PDVTYP## ;GET THE DEVICE TYPE CAIN T1,.TYDDP/.TYEST;IS THIS A DDP DEVICE? PJRST ZAPDDP## ;YES, FIRST CHECK WITH DDPSER ON ZAPABILITY > ;END IFN FTDDP ZAPNE1::NETDBJ ;GET THE NETSER INTERLOCK MOVE S,DEVIOS(F) ;GET THE IO STATUS TLNE S,IOSZAP ;HAVE WE FREED THIS DDB ONCE ALREADY?? STOPCD .,STOP,ANFRDT, ;++ RELEASING DDB TWICE TLNN S,IOSCON ;IS THIS DEVICE CONNECTED? PJRST UNLDDB ;IF NOT CONNECTED, JUST DELETE THE DDB. MOVEI T1,RSN.OK ;NORMAL DISCONNECT REASON PUSHJ P,NTDXDS ;SEND THE DISCONNECT. JRST [PUSHJ P,NETSLP ;IF WE CAN'T, WAIT FOR CORE TO SHOW UP JRST ZAPNET] ;AND TRY AGAIN. MOVSI S,IOSZAP ;SINCE NO-ONE WANTS THIS DEVICE ANY MORE, IORB S,DEVIOS(F) ;INDICATE THAT IT IS FREE TO BE DELETED. PUSHJ P,UNLKDB ;UNLINK THE DDB SO NO-ONE ELSE GETS IT SETZ F, ;INDICATE THAT THE DDB IS GONE, AND POPJ P, ;RETURN. (NTDDSC WILL EVENTUALLY FREE THE DDB) SUBTTL PCB -- ROUTINES TO HANDLE PROTOCOL CONTROL BLOCKS ;SUBROUTINE MK?PCB - BUILD A PROTOCOL DATA BLOCK ;CALL MOVEI F,DDB OR 0 IF AN NCL MESSAGE ; MOVEI W,NDB ; MOVEI T1,BUFFERSIZE ;SIZE OF ASSOCIATED MESSAGE BUFFER ; PUSHJ P,MK?PCB ;RETURN CPOPJ ;NO SPACE AVAILABLE, OR TOO MANY PENDING MSGS ; CPOPJ1 ;U=PCB POINTER ; ;MKUPCB THIS SUBROUTINE IS USED TO GET A PCB FOR AN UNNUMBERED MESSAGE. ; IT DOES NOT DECREMENT, OR CHECK NDBMOM(W) ;MKNPCB THIS SUBROUTINE IS USED TO ALLOCATE A PCB FOR A NUMBERED MESSAGE. ; IT CHECKS TO MAKE SURE THAT NDBMOM(W) IS GREATER THAN ZERO. THIS ; CHECK IS NECESSARY TO ENSURE THAT WE DO NOT SEND MORE THAN 128 MSGS ; TO ANY GIVEN NODE. (IF WE DID THE MSG NUMBERS WOULD WRAP AROUND!) MKNPCB:: ;MAKE NUMBERED PCB SKIPE NTUEFC ;IS THIS AN EMERGENCY? JRST MKNPC1 ;YES - SKIP THIS CHECK PUSH P,T1 ;NO MOVE T1,NDBMOM(W) ;GET NUMBER OF MESSAGES AVAILABLE CAIG T1,5 ;ARE THERE A FEW FREE? JRST TPOPJ## ;NO - SAY WE CAN'T DO IT POP P,T1 ;DO IT MKNPC1: SOSLE NDBMOM(W) ;CHECK ON THE NUMBER OF OUTSTANDING MSGS PUSHJ P,MKUPCB ; IF WE CAN, TRY TO MAKE ANOTHER PCB AOSA NDBMOM(W) ;HERE IF WE CAN'T SEND ANOTHER PCB NOW. JRST [SETZM NTUEFC ;IF WE GOT ONE, CLEAR "EMERGENCY FLAG" RETSKP] ; AND GIVE GOOD RETURN SKIPN NTUEFC ;IF WE CAN'T USE EMERGENCY FREE CORE, POPJ P, ; THEN GIVE BAD RETURN SETZM NTUEFC ;OTHERWIZE CLEAR THE "EMERGENCY" FLAG PJRST PCBEGT ; AND GO GET "EMERGENCY" MEMORY MKUPCB:: ;MAKE UN-NUMBERED PCB IFN PARANOID&P$COR,< ;IF WE'RE BEING CAUTIOUS, SKIPLE T1 ; THEN MAKE SURE THAT THE CALLER CAILE T1,MSGMAW## ; ASKED FOR A POSITIVE, NOT-TOO-LARGE BUFFER STOPCD .,STOP,ANFMRL, ;++ MESSAGE REQUEST TOO LARGE > ;END IFN PARANOID&P$COR ADDI T1,MSGAGW##-1 ;ROUND UP AND ANDCMI T1,MSGAGW##-1 ; TRUNCATE MODULO ALLOCATION GRANULARITY MOVE T2,T1 ;COPY OF REQUESTED SIZE (WORDS) LSH T2,-MSGAGN## ;REDUCE TO ALLOCATION GRANULARITY NETOFF ;NO INTERRUPTS WHILE LOOKING AT FREE-LISTS SKIPG NTFREC##(T2) ;ARE THERE ANY PCB'S ON THIS FREE LIST? JRST MAKPC1 ;NO FREE PCB'S, ALLOCATE A NEW ONE HRRZ U,NTFREF##(T2) ;GET THE FIRST FREE PCB HRRZ T1,PCBBLK(U) ;GET THE NEXT FREE PCB HRRZM T1,NTFREF##(T2) ; AND MAKE THE "NEXT" ONE THE NEW "FIRST" ONE SOSG NTFREC##(T2) ;DECREMENT THE FREE COUNT, IF ZERO, THEN SKIPN NTFREF##(T2) ;MAKE SURE THAT PCB FREE LIST IS NULL SKIPG U ;MAKE SURE THAT WE GOT A VALID PCB STOPCD .,STOP,ANFPCL, ;++ PCB LISTS SCREWED UP NETON ;ALL'S CONSISTENT. INTS BACK ON HLLZS PCBBLK(U) ;MAKE SURE WE DON'T KEEP ANY POINTERS IFN PARANOID&P$COR,< ;IF WE'RE BEING CAUTIOUS, MOVE T1,PCBTAG(U) ;A PCB UNIQUENESS CAME T1,['PCBTAG'] ;DOES ALLEGED PCB LOOK LIKE A PCB? STOPCD .,STOP,ANFPCT ;++ PCB TRASHED MOVE T1,PCBALN(U) ;LENGTH OF DATA BUFFER (WORDS) LSH T2,MSGAGN## ;LENGTH IT SHOULD BE CAME T1,T2 ;IF LENGTHS DIFFERENT STOPCD .,STOP,ANFBLW, ;++ BUFFER LENGTH WRONG MOVE T1,PCBADR(U) ;ADDRESS OF DATA BUFFER PUSH P,T2 ;SAVE LENGTH HLRZ T2,-1(T1) ;GET TOP-END CHECK WORD ADD T1,0(P) ;ADJUST ADDRESS AND MOVE T1,0(T1) ;GET BOTTOM-END CHECK WORD CAMN T1,['NETMEM'] ;IS BOTTOM-END CHECK WORD OK? CAIE T2,'NET' ;IS TOP-END CHECK WORD OK? STOPCD .,STOP,ANFDMU, ;++ DATA BUFFER MESSED UP > ;END IFN PARANOID&P$COR MOVE T1,PCBADR(U) ;DATA BUFFER ADDRESS HRLI T1,(POINT 8,) ;PROTOTYPE BYTE POINTER MOVEM T1,PCBPTR(U) ;RESET PCB BYTE POINTER ; (CAN BE TRASHED BY ETHSER/D8EINT) JRST TPOPJ1## ;GUVE SUCCESS RETURN ;HERE TO ALLOCATE THE PCB FROM MONITOR FREE CORE MAKPC1: NETON ;NOT DIDDLING THE FREE LIST ANYMORE PUSH P,T1 ;SAVE THE BUFFER SIZE MOVEI T2,PCBLEN ;GET THE LENGTH OF A PCB PUSHJ P,GETZWD ;GET A ZERO BLOCK OF FREE CORE JRST TPOPJ ;NO SPACE MOVEI U,(T1) ;COPY THE PCB POINTER MOVE T2,(P) ;GET BUFFER SIZE BACK JUMPE T2,TPOPJ1 ;IF NO BUFFER WANTED, LEAVE NOW PUSHJ P,GETZWD ;GET THE BUFFER PJRST [POP P,T1 ;IF NONE AVAILABLE, CLEAN STACK AND PJRST RMVPCB] ;AND RETURN THE PCB MOVEM T1,PCBADR(U) ;SAVE BUFFER ALLOCATED ADDRESS HRLI T1,(POINT 8) ;MAKE BYTE POINTER TO THE BUFFER AREA MOVEM T1,PCBPTR(U) ;AND SAVE IT AWAY POP P,PCBALN(U) ;REMEMBER BUFFER ALLOCATED LENGTH AOS (P) ;GIVE A GOOD RETURN PJRST CLNPCB ; AND SET UP CACHE INFORMATION ;SUBROUTINE RMVPCB - REMOVE THE PCB FROM FREE CORE ;CALL MOVEI U,PCB ; S0PSHJ RMVPCB ;RETURN CPOPJ RMVPCB: JUMPE U,CPOPJ## ;DON'T FREE A NON-EXISTANT PCB IFN PARANOID&P$COR,< ;IF WE ARE BEING CAUTIOUS, SKIPE PCBAL2(U) ;MAKE SURE THAT THE "SECONDARY" STOPCD .,STOP,ANFSBA, ;++ SECONDARY BUFFER ALLOCATED ("OLD FEATURE") > MOVE T2,PCBALN(U) ;GET THE LENGTH OF THE PRIMARY BUFFER JUMPE T2,ZAPPCB ;IF NO PRIMARY BUFFER, RETURN PCB TO FREE-CORE PUSH P,T2 ;HANG ON TO DATA BUFFER LENGTH IFN PARANOID&P$COR,< ;NOW WE CAN CHECK TO SEE IF SIZE IS REASONABLE MOVE T1,PCBTAG(U) ;A PCB UNIQUENESS CAMN T1,['PCBTAG'] ;DOES PCB STILL LOOK LIKE A PCB? TRNE T2,MSGAGW##-1 ;IS PCB'S DATA BUFFER LENGTH NICELY GRANULAR? STOPCD .,STOP,ANFPCR, ;++ PCB TAG WORD TRASHED WHEN REMOVING LSH T2,-MSGAGN## ;CONVERT LENGTH TO GRANULARITY INDEX CAILE T2,MSGALN## ;IS PCB'S DATA BUFFER A REASONABLE LENGTH? STOPCD .,STOP,ANFMBL, ;++ BUFFER LENGTH WRONG MOVE T1,PCBADR(U) ;ADDRESS OF DATA BUFFER HLRZ T2,-1(T1) ;GET THE TOP-END CHECK WORD ADD T1,0(P) ;ADVANCE BUFFER ADDRESS AND MOVE T1,0(T1) ;GET THE BOTTOM-END CHECK WORD CAMN T1,['NETMEM'] ;IS BOTTOM-END CHECK WORD OK? CAIE T2,'NET' ;IS TOP-END CHECK WORD OK? STOPCD .,STOP,ANFPCM, ;++ PCB MESSAGE CHECK WORDS TRASHED > PUSHJ P,CLNPCB ;REFRESH THE PCB POP P,T2 ;RETRIEVE DATA BUFFER LENGTH LSH T2,-MSGAGN## ;REDUCE TO ALLOCATION GRANULARITY NETOFF ;DISABLE INTERRUPTS WHILE HACKING FREE-LISTS SKIPG NTFREC##(T2) ;SEE IF FREE-LIST IS EMPTY JRST [HRRZM U,NTFREF##(T2) ;IF EMPTY, THEN THIS PCB GOES ON FIRST HRRZM U,NTFREL##(T2) ; AS WELL AS LAST JRST RMVPC1] ;GO TO COMMON CODE TO CLEAN UP HRRZ T1,NTFREL##(T2) ;GET THE ADDRESS OF THE "LAST" PCB IN THE LIST HRRM U,PCBBLK(T1) ; PUT THIS PCB JUST AFTER IT IN THE FREE LIST HRRM U,NTFREL##(T2) ; AND ALSO MAKE THIS THE NEW "LAST" PCB RMVPC1: AOS NTFREC##(T2) ;COUNT THE NEW FREE PCB SETZ U, ;CLEAR "U" TO INDICATE PCB HAS BEEN FREED RMVPC7: NETON ;RE-ENABLE INTERRUPTS POPJ P, ;RETURN WITH PCB NOW ON PROPER FREE LIST ;THIS ROUTINE DOES NOT 'RECYCLE' THE PCB. PCB IS RETURNED TO FREE-CORE ZAPPCB: HLLZS PCBTAG(U) ;CLEAR THE 'UNIQUE' TAG SKIPE PCBCT2(U) ;GET THE DATA LENGTH STOPCD .,STOP,ANFOBS, ;++ OBSOLETE FEATURE ZAPPC2: SKIPG T1,PCBALN(U) ;GET THE DATA BUFFER LENGTH JRST ZAPPC3 ;NONE MOVE T2,PCBADR(U) ;GET THE INPUT POINTER PUSHJ P,GIVZWD ;REMOVE THE SPACE ZAPPC3: MOVEI T2,(U) ;COPY THE ADDRESS MOVEI T1,PCBLEN ;GET THE LENGTH PUSHJ P,GIVZWD ;RETURN THE SPACE SETZ U, ;CLEAR U TO FLAG PCB AS REMOVED POPJ P, ;CLNPCB REFRESH A PCB. ;CALL MOVE U,PCB ; PUSHJ P,CLNPCB ;RETURN CPOPJ ;ALWAYS ;CLOBBERS T1,T2 CLNPCB: SETZM PCBBLK(U) ;CLEAR FLAGS AND LINK FIELDS SETZM PCBFEK(U) ;CLEAR FEK AND NODE NUMBER SETZM PCBCTR(U) ;CLEAR VALID DATA BYTE COUNT SETZM PCBCT2(U) ;CLEAR SECONDARY DATA BYTE COUNT MOVE T1,[SIXBIT /PCBTAG/] ;GET AND SET THE "TAG" MOVEM T1,PCBTAG(U) ; WORD SO WE KNOW IT'S A PCB IFN FTKL10,< ;ONLY NEED WORRY ABOUT CACHE ON A KL PUSHJ P,PCBMRK## ;SET UP THE CACHE INFORMATION IN THE PCB > POPJ P, ;ALL DONE ;"EMERGENCY" PCB MANAGEMENT. Comment @ One of the most persistant problems with NETSER has been that it uses a great deal of free core, and when free core runs low, NETSER tends to crash. What follows it the latest in a continuing series of HACKS to ameloiate the effects of finite free-core. The routines involved are: PCBECK This routine checks to make sure that there is sufficient "emergency" free core available, and that there are message numbers available. If it skips, one may call PCBEGT with out fear. PCBEGT This routine gets an "emergency" numbered pcb. If one is not available, it STOPCD's. Unfortunatly, NETSER is not organized in a fashion that makes using these routines easy. The problem is that very low-level subroutines are the ones that allocate messages (pcbs). Figuring out if it is an "emergency" or not is beyond their limited abilities. What is needed is a way for "middle" level routines to inform lower level ones that there is an emergency. This is currently accomplished by the gross hack of using a global flag. The mechanisims for this are: NTUEFC If this location is non-zero, then the next call to MKNPCB will not fail. It will attempt to use "normal" free-core, but if none is available, it will use emergency free core. EMRGCY This is a macro that currently SETOM's ntuefc. It should be used just before calls to routine such as NCSHDR when it is imperative that they NOT fail. End Comment @ ;ROUTINES TO MANAGE EMERGENCY STORAGE ;PCBECK ROUTINE TO SEE IF EMERGENCY MESSAGES ARE AVAILABLE. ;CALL W := NDB POINTER ;RETURN CPOPJ ;EITHER NO FREE MESSAGE NUMBERS, OR NO CORE ; CPOPJ1 ;THERE ARE FREE MESSAGE NUMBERS, AND ; ; EMERGENCY STORAGE. IN PARTICULAR, A ; ; CALL TO PCBEGT WILL SUCCEED. PCBECK: MOVE T1,NDBMOM(W) ;GET THE COUNT OF FREE MESSAGE NUMBERS, CAIG T1,3 ; AND MAKE SURE IT IS REASONABLY LARGE POPJ P, ;IF NOT ENOUGH FREE NUMBERS GIVE ERROR RETURN MOVE T1,PCBECT ;GET THE COUNT OF "EMERGENCY" PCB'S CAIL T1,2 ; AND IF THERE ARE 2 OR MORE, THEN RETSKP ;GIVE "SUCCESS" RETURN PUSH P,U ;"U" IS IN USE BY NETSCN AT THIS POINT MOVEI T1,MSGMAW## ;IF NOT ENOUGH "EMERGENCY" PCB'S, TRY PUSHJ P,MKUPCB ; TO ALLOCATE THE LARGEST POSSIBLE. PJRST UPOPJ## ;IF NO MORE FREE-CORE, GIVE ERROR RETURN NETOFF ;IF WE GOT ONE, TURN OFF INTERRUPTS HRRZ T1,PCBELS ; AND INSERT THE NEW ONE HRRZ T1,PCBBLK(U) ; ON THE FRONT OF THE "EMERGENCY" HRRM U,PCBELS ; PCB FREE LIST (PCBELS). AOS PCBECT ;COUNT THE NEW "EMEGENCY" PCB NETON ;RE-ENABLE INTERRUPT, AND POP P,U ;GET NETSCN'S "U" BACK JRST PCBECK ;GO SEE IF WE HAVE ENOUGH NOW. ;PCBEGT ROUTINE TO GET AN "EMERGENCY" NUMBERED PCB ;CALL W := NDB POINTER ;(WE NEED TO FIX NDBMOM) ;RETURN CPOPJ1 ;WITH U := "EMERGENCY" PCB ; ; (IF NONE AVAILABLE, WE STOPCD) PCBEGT: NETOFF ;DISABLE INTERRUPTS WHILE HACKING LISTS SOSL NDBMOM(W) ;DECREMENT THE FREE MESSAGE NUMBER COUNTER SOSGE PCBECT ;DECREMENT THE COUNT OF "EMERGENCY" PCB'S STOPCD .,STOP,ANFNFP, ;++ NO FREE PCBS OR NO FREE MESSAGES HRRZ U,PCBELS ;GET THE FIRST FREE PCB, HRRZ T1,PCBBLK(U) ;GET THE ADDRESS OF THE SECOND (IF ANY) HRRM T1,PCBELS ;MAKE THE "SECOND" THE NEW "FIRST" PJRST NTONP1 ;RE-ENABLE INTERRUPTS AND SKIP RETURN. ;ONCE/SECOND CODE FOR PCB MANAGEMENT. ;THIS CODE FREES EXCESS PCBS FROM THE FREE LISTS ONCE/SECOND. ;AT LEAST ONE FREE PCB IS ALWAYS KEPT IN ORDER TO MINIMIZE THE ;CONTENTION ON GENERAL MONITOR FREE CORE. IN PARTICULAR, FOR ;THE MSGMAX-SIZED PCB LIST TWO FREE PCBS ARE KEPT (SINCE ALL ;INPUT OPERATIONS MUST ALMOST-BY-DEFINITION USE THIS SIZE). PCBSEC: MOVE T1,TIME## ;GET SYSTEM TIME (IN JIFFIES) IDIV T1,TICSEC## ;GET SYSTEM TIME (IN SECONDS) IDIVI T1,MSGALN##+1 ;TAKE MOD ALLOCATION TABLE MAXIMA NETOFF ;MAKE SURE NOT INTERRUPTED SKIPG T1,NTFREC##(T2) ;GOT A FREE PCB HERE? PJRST RMVPC7 ;NO, JUST RE-ENABLE AND GO AWAY CAIL T2,MSGALN## ;IS THIS THE MSGMAX-SIZED PCB LIST? SUBI T1,1 ;YES, ALLOW FOR ONE MORE SOJLE T1,RMVPC7 ;ALWAYS KEEP THE "LAST" ONE HRRZ U,NTFREF##(T2) ;GET THE ADDRESS OF THE "FIRST" FREE ONE HRRZ T1,PCBBLK(U) ;GET THE ADDRESS OF THE "NEXT" FREE ONE HRRM T1,NTFREF##(T2) ;MAKE THE "NEXT" THE "FIRST" SOSLE NTFREC##(T2) ;COUNT DOWN THE PCB COUNTER JRST PCBSE3 ;ALL DONE SKIPE NTFREF##(T2) ;THAT WAS THE LAST, BETTER NOT BE ANY MORE STOPCD .,STOP,ANFFCW, ;++ FREE PCB COUNT WRONG SETZM NTFREL##(T2) ;CLEAR POINTER TO LAST PCBSE3: NETON ;NO LONGER PLAYING WITH FREE LISTS HLLZS PCBBLK(U) ;NO STRAY POINTERS PJRST ZAPPCB ;RETURN THE PCB TO FREE CORE ;RMVALP THIS ROUTINE FREES AN ENTIRE CHAIN OF PCB'S ;CALL U := FIRST ONE TO GO ;RETURN CPOPJ RMVALP: PUSHJ P,SAVE1 ;SAVE P1 FOR THE DURATION RMVAL1: JUMPE U,CPOPJ ;ALL DONE IF NO PCB HRRZ P1,PCBBLK(U) ;GET AND KEEP POINTER TO NEXT PCB S0PSHJ RMVPCB ;FREE THIS PCB MOVEI U,(P1) ;CURRENT PCB := NEXT PCB PJRST RMVAL1 ;TAIL-RECURSE SUBTTL NDB -- ROUTINES TO MANAGE NODE DATA BLOCKS ;SUBROUTINE MAKNDB - BUILD A NODE DATA BLOCK (NDB) ;CALL MOVEI J,FEK ; MOVEI T1,NNM ; PUSHJ P,MAKNDB ;RETURN CPOPJ ;NO CORE ; CPOPJ1 ;W=NDB MAKNDB: ;ENTRY NTDBUG ;VERIFY THE INTERLOCK PUSH P,T1 ;SAVE THE NODE NUMBER MOVEI T2,NDBLEN ;LENGTH PUSHJ P,GETZWD ;ALLOCATE PJRST TPOPJ## ;NO SPACE MOVEI W,(T1) ;COPY THE POINTER HRRM J,NDBFEK(W) ;STORE THE FEK POINTER HRRZ T1,NETNDB## ;GET THE START OF THE NDB CHAIN NETOFF ;NEED PROTECTION SINCE 'STBOPR' AND ; OTHER ROUTINES SCAN THE NDB LIST WITH ; OUT FIRST GETTING THE 'NT' INTERLOCK ; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB") HRRM T1,NDBNNM(W) ;LINK THIS NDB TO THE START HRRM W,NETNDB## ;LINK POP P,T1 ;GET THE NODE NUMBER CAIG T1,NODMAX ;RANGE CHECK HRRM W,.GTNDA##(T1) ;STORE ADDRESS IF VALID NETON ;ALL'S CLEAR HRLM T1,NDBNNM(W) ;STORE PJRST CPOPJ1## ;EXIT SUBTTL SUBROUTINE TO RETURN STORAGE DATA BLOCK TO THE MONITOR ;SUBROUTINE RMVNDB - REMOVE A NODE DATA BLOCK NDB ;CALL MOVEI W,NDB ; PUSHJ P,RMVNDB ;RETURN CPOPJ RMVNDB: NTDBUG ;VERIFY THE INTERLOCK PUSHJ P,SAVJW## ;SAVE J AND W PUSHJ P,SAVE1## ;SAVE P1 PUSHJ P,NODEDN ;CALL "NODE DOWN" PUSHJ P,CLNNDB ;CLEAN OUT STUFF HANGING ON THE NDB MOVEI T1,NETNDB## ;GET THE START OF THE NDB CHAIN NETOFF ;TURN OFF THE PI'S SINCE STBOPR ; DOESN'T ALWAYS GET THE 'NT' INTERLOCK ; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB") RMVNT2: HRRZ T2,NDBNNM(T1) ;GET THE NEXT POINTER JUMPE T2,CPOPJ## ;EXIT IF END CAIN T2,(W) ;IS THIS THE BLOCK JRST RMVNT3 ;YES, MOVEI T1,(T2) ;NO, STEP ALONG JRST RMVNT2 ;TRY AGAIN RMVNT3: HRRZ T3,NDBNNM(W) ;GET THE FORWARD LINK HRRM T3,NDBNNM(T1) ;STORE BACKWARD HLRZ T1,NDBNNM(W) ;GET NODE REMOVED CAIG T1,NODMAX ;RANGE CHECK HLLZS .GTNDA##(T1) ;AND CLEAR POINTER NETON ;ALL'S CLEAR MOVEI T1,NDBLEN ;GET THE LENGTH PJRST GIVZWD ;RELEASE THE BLOCK ;CLNNDB CLEAN OUT AN NDB. THIS ROUTINE ZEROS ALL MESSAGE COUNTS ; AND OTHER APPROPRIATE FIELDS AND FREES ALL DATA HANGING OFF OF ; AN NDB. (CALL WHEN SENDING OR RECEIVING STARTS) ;CALL W := NDB ;RETURN CPOPJ CLNNDB: NTDBUG ;VERIFY THE INTERLOCK PUSHJ P,SAVE4## ;THIS ROUTINE CLOBBERS EVERYTHING PUSHJ P,SAVJW## ;THESE TOO PUSH P,U ;AND EVEN THIS IFN PARANOID&P$NDB, ;MAKE SURE WE DON'T DELETE OUR NDB ;HERE TO CHECK FOR STATION CONTROL RESOURCE PUSH P,W ;SAVE NDB POINTER HRRZ J,NDBICT(W) ;GET MESSAGE ADDR SKIPE J ;IS THERE ONE ? PUSHJ P,GIVSTC ;IF SO, FREE THEM SKIPE T1,NDBSTC(W) ;ANYONE USING STATION CONTROL PUSHJ P,EWAKE## ;IF SO, WAKE HIM UP. POP P,W ;GET NDB POINTER BACK ;HERE TO CALL ALL THE NETWORK DEVICES AND INFORM THEM THAT THIS NODE HAS ; GONE AWAY. ALL THE SERVICE ROUTINES WILL BE CALLED ON THEIR "NDPNWD" ; ENTRY POINT. THE INTERFACE FOR A NDPNWD ENTRY SHOULD BEHAVE AS FOLLOWS. ;AT ENTRY ; P1 := NODE NUMBER OF CRASHED NODE. ; P2 := LAT INDEX ('SLA') ; F := LAT ENTRY FOR THIS DEVICE (XWD FLAGS,DDB/LDB) ;RETURN CPOPJ ;ALWAYS. CLNND0: MOVSI P2,-LATLEN## ;MAKE AN AOBJN POINTER FOR ACCESSING THE LAT. HLRZ P1,NDBNNM(W) ;GET THE NUMBER OF THE CRASHED NODE. PUSH P,W ;WE MAY CLOBBER "W". PRESERVE IT FOR NOW. JRST CLNND2 ;SKIP OVER THE ZERO'TH ENTRY (NETDDB) CLNND1: SKIPN T2,NETLAT##(P2) ;GET THE NEXT LAT ENTRY JRST CLNND2 ;THIS ENTRY NOT IN USE LDB F,LATPP2## ;EXTRACT DDB/LDB ADDRESS (INDEX P2) TLNN T2,LAT.TY ;IS THIS A DDB OR LDB SKIPA T1,DEVNET(F) ;DDB, GET NODE NUMBER LDB T1,LDPRNF## ;LDB, GET NODE NUMBER ANDI T1,777 ;MASK OFF LH JUNK CAIE T1,(P1) ;IS THIS DEVICE/TTY DOOMED? JRST CLNND2 ;NO, LEAVE IT ALONE THEN MOVEI T1,NDPNWD ;GET THE "NODE WENT DOWN" FCN CODE PUSHJ P,ICMNDP ;AND CALL THE DISPATCH ROUTINE CLNND2: AOBJN P2,CLNND1 ;LOOP OVER ALL LAT ENTRYS POP P,W ;RECOVER OUR NDB POINTER ;CONTINUED ON NEXT PAGE ;CONTINUED FROM PREVIOUS PAGE ;HERE TO PURGE THE NDB NAME POINTERS MOVEI T1,^D8 ;FOUR WORDS TO REMOVE HLRZ T2,NDBSID(W) ;GE THE SOFTWARE ID POINTER SKIPE T2 ;ASSIGNED PUSHJ P,GIVZWD ;RETURN THE SPACE MOVEI T1,^D8 ;FOUR WORDS TO RETURN HRRZ T2,NDBSID(W) ;GET THE ADDRESS SKIPE T2 ;NOT ASSIGNED PUSHJ P,GIVZWD ;REMOVE THE SPACE ;HERE TO REMOVE THE QUEUES FOR THE NODES HRRZ U,NDBQUE(W) ;GET AND FREE THE PUSHJ P,RMVALP ; THE RIGHT HAND HLRZ U,NDBQUE(W) ;GET AND FREE THE PUSHJ P,RMVALP ; THE LEFT HAND HRLZI T1,(W) ;BUILD A BLT POINTER HRRI T1,1(W) ; TO ZERO THE NDB NETOFF ;COVER OURSELVES WHILE NDB IS SCREWED UP ; (SEE FOOTNOTE AFTER ROUTINE "SRCNDB") MOVE T2,NDBNNM(W) ;SAVE "XWD NODE#,LINK" FOR A WHILE HRRZ T3,NDBFEK(W) ;SAVE THE ADDR OF THE FEK SETZM (W) ;ZAP THE FIRST, AND THEN BLT T1,NDBLEN-1(W) ; THE REST OF THE NDB. MOVEM T3,NDBFEK(W) ;RESTORE THE FEK ADDRESS AND THE MOVEM T2,NDBNNM(W) ; NODE#,,LINK WORD NETON ;ALL IS CONSISTENT NOW MOVEI T1,^D30 ;ONLY ALLOW A MAX OF 30 OUTSTANDING (IE. ; UN-ACKED) MESSAGES MOVEM T1,NDBMOM(W) ;INITIALIZE MAX OUTSTANDING MESSAGES PJRST UPOPJ ;RESTORE U AND RETURN ;ROUTINE TO HANDLE NODE ONLINE EVENTS ;CALL MOVX W,NDB-POINTER ; PUSHJ P,NODEUP ;RETURN CPOPJ ;DOES "ONLINE" PROCESSING ONLY IF NODE WAS NOT ; ; ONLINE BEFORE NODEUP: MOVSI T1,NDB.UP ;GET THE NODE "ONLINE" FLAG TDNE T1,NDBFLG(W) ;SEE IF WE ARE ALREADY ONLINE POPJ P, ; IF ONLINE ALREADY, RETURN IORM T1,NDBFLG(W) ;MARK THE NODE AS ONLINE S0PSHJ ONLNDB ;PRINT THE ONLINE MESSAGE IFN FTPI,< PUSHJ P,PSINTC## ;SIGNAL THE ONLINE EVENT > MOVE T1,[XWD .CSCNO,.ERCSC] ;GET CODE TO TELL DAEMON NODE ONLINE PJRST NODEAM ; AND GO TELL DAEMON ;ROUTINE TO HANDLE NODE OFFLINE EVENTS ;CALL MOVX W,NDBPOINTER ; PUSHJ P,NODEDN ;RETURN CPOPJ ;DOES "OFFLINE" PROCESSING ONLY IF THE ; ;NODE WAS ONLINE. NODEDN: MOVSI T1,NDB.UP ;GET THE "ONLINE" BIT TDNN T1,NDBFLG(W) ;IF WE'RE NOT ONLINE NOW, POPJ P, ; THEN DON'T DO ANY OFFLINE STUFF ANDCAM T1,NDBFLG(W) ;CLEAR THE ONLINE BIT S0PSHJ OFLNDB ;TELL THE OPERATOR IT WENT AWAY IFN FTPI,< PUSHJ P,PSINTC## ;SIGNAL THE OFFLINE EVENT > MOVE T1,[XWD .CSCNF,.ERCSC] ;GET NODE OFF-LINE DAEMON CODE ; PJRST NODEAM ; AND GO TELL DAEMON ;ROUTINE TO CALL DAEMON FOR NODE ON/OFF LINE EVENTS ;CALL MOVX T1,"DAEMON CODE" ; PUSHJ P,NODEAM ;RETURN CPOPJ ;ALWAYS NODEAM: PUSHJ P,SAVJW## ;"J" GETS MASHED BY DAEEIM PUSH P,U ;DON'T WANT TO CLOBBER INCTSK'S PCB SETZ F, ;CLEAR "F" SO AS NOT TO CONFUSE DAEMON HLRZ U,NDBNNM(W) ;GET THE NODE NUMBER IN U PUSHJ P,DAEEIM## ;CALL THE NON-BLOCKING FORM OF DAEMON PJRST UPOPJ## ;CLEAN UP AND RETURN ;SRCNDB ROUTINE TO FIND A NDB GIVEN A NODE NAME OR NUMBER ;CALL MOVE T1,NNM ;NODE NUMBER ;OR MOVE T1,[SIXBIT /NODE NAME/] ;SIXBIT NODE NAME ; PUSHJ P,SRCNDB ;RETURN CPOPJ ;NOT FOUND ; CPOPJ1 ;FOUND W=NDB POINTER SRCNDB::NTDBUG ;VERIFY THE INTERLOCK SRCND0::TLNE T1,-1 ;IF IT'S A NAME, JRST SRCND3 ; GO USE A DIFFERENT LOOP SRCND1: SKIPN T1 ;IF NODE NUMBER IS ZERO, MOVE T1,JBTLOC##+0 ;USE THE LOCAL NODE CAILE T1,NODMAX ;RANGE CHECK POPJ P, ;NOT IN RANGE HRRZ W,.GTNDA##(T1) ;GET NDB ADDRESS CAIE W,0 ;ONLINE AOS (P) ;YES, SKIP POPJ P, ;AND RETURN SRCND3: PUSHJ P,SRCND4 ;FIRST TRY IT AS A "NAME" CAIA ; AND IF THAT SUCCEEDS, JRST CPOPJ1## ; THEN WE'RE DONE. PUSH P,T1 ;OTHERWISE, TRY TO CONVERT PUSHJ P,CVTOCT## ; A SIXBIT NUMBER JRST TPOPJ## ; IF THAT FAILS, GIVE UP PUSHJ P,SRCND1 ;TRY THE NUMBER JRST TPOPJ## ; FAILED JRST TPOPJ1## ; SUCCEEDED. SRCND4: MOVEI W,NETNDB ;GET THE HEAD OF THE CHAIN SRCND5: HLRZ T3,NDBSNM(W) ;GET THE ADDRESS OF THE NAME JUMPE T3,SRCND6 ;IF NO NAME, NO ADDRESS OF NAME CAMN T1,(T3) ; SEE IF THEY MATCH JRST CPOPJ1## ;RETURN SUCCESS IF THEY DO SRCND6: HRRZ W,NDBNNM(W) ;OTHERWISE GO TO THE NEXT JUMPN W,SRCND5 ; AND CHECK THAT POPJ P, ;ERROR RETURN IF NO MORE ;*** FOOTNOTE *** COMMENT \ The entry SRCND0 should only be called under cover of a "NETOFF" macro. One of the fundamental goals in the 7.01 NETSER was to eliminate crashes caused by "stale" pointers to NDB's that had been destroyed. In light of this, the only time that a pointer to an NDB is valid is under the NETSER interlock. Unfortunatly, ocasionally the need arises to look at some field in some NDB at a time when it is not convenient to request the NETSER interlock. Examples of this are translating a node name to a node number, and finding the OPR ldb of a particular remote station. Both of these routines (STBSCA and STBOPR) are called from clock and/or interrupt levels, and hence cannot do a NDTDBJ. Routines like these MUST NETOFF for the period that they possess a valid NDB address. \ SUBTTL NDT -- ROUTINES TO SEARCH THE NDT ;SUBROUTINE SRCNDT - SEARCH THE NETWORK DEVICE TABLE ;CALL HRRZ T1,(SIXBIT /GENERIC NETWORK DEVICE NAME/) ; MOVEI P1,NDB ; PUSHJ P,SRCNDT ;RETURN CPOPJ ;DEVICE NOT FOUND ; CPOPJ1 ;DEVICE FOUND W(RT)=THE NDT POINTER SRCNDT::CAIE T1,'MCR' ;THE "MONITOR COMMAND ROUTINE" ISN'T CAIN T1,'MC ' ; A REAL DEVICE (TOO BAD, MIGHT BE NEAT) POPJ P, ;REJECT MCR: NTDBUG ;VERIFY THE INTERLOCK MOVE W,NDTXWD## ;GET THE SEARCH POINTER SRCNDC: HLRZ T2,NDTNAM(W) ;GET THE -10 DEVICE NAME HRRZ T3,NDTNAM(W) ;GET THE -11 DEVICE NAME CAIE T1,(T2) ;IS IT A -10 DEVICE CAIN T1,(T3) ;OR A -11 DEVICE JRST SRCNDD ;CHECK THE CONFIGURATION ADDI W,NDTLEN-1 ;NO, STEP TO THE NEXT ENTRY AOBJN W,SRCNDC ;AND TRY AGAIN POPJ P, ;DEVICE NOT FOUND SRCNDD: PUSH P,W ;SAVE THE NDT POINTER LDB T1,NDTOBJ## ;GET THE DEVICE TYPE MOVEI W,(P1) ;COPY THE NDB POINTER LDB T1,NETCNF##(T1) ;GET THE CONFIGURATION COUNT JUMPE T1,WPOPJ## ;THAT NODE DOES NOT HAVE ANY PJRST WPOPJ1## ;DEVICE IS OK SUBTTL LAT -- ROUTINES FOR MANIPULATING THE LINK ADDRESS TABLE ;GETSLA ROUTINE TO GET A SOURCE LINK ADDRESS FROM THE LAT TABLE ;CALL: MOVE T1, ; MOVEI T2,LAT.XX ;LAT STATE ; PUSHJ P,GETSLA ;RETURN CPOPJ ;NONE AVAILABLE ; CPOPJ1 ;T1=SLA GETSLA::NTDBUG ;VERIFY THE INTERLOCK PUSH P,T1 ;SAVE LAT ADDRESS AND FLAGS IFN PARANOID&P$LAT,< TLZ T1,777700 ;MASK OUT ALL BUT ADDRESS PUSH P,T2 ;SAVE DESIRED INITIAL STATE CAIL T2,0 ;RANGE CAILE T2,LAT.MX ; CHECK PUSHJ P,NTDSTP ;++ INITIAL LAT STATE ILLEGAL MOVSI T2,-LATLEN## ;PROTOTYPE LAT INDEXER GETSL1: LDB T3,LATPT2## ;GET THIS SLA'S DDB/LDB ADDRESS CAMN T3,T1 ;DOES THIS DDB/LDB ALREADY HAVE A LAT SLOT? STOPCD .,STOP,ANFWLA, ;++ WRONG LAT ASSIGNED AOBJN T2,GETSL1 ;LOOP OVER ALL LAT ENTRIES POP P,T2 ;RETRIEVE INITIAL LAT STATE > ;IFN PARANOID&P$LAT MOVSI T1,-LATLEN## ;GET THE LENGTH FOR THE AOBJN SKIPE NETLAT##(T1) ;LOOK FOR AN AVAILABLE SLOT AOBJN T1,.-1 ;CONTINUE STEPPING JUMPGE T1,TPOPJ## ;NONE AVAILABLE POP P,NETLAT(T1) ;MARK THE SLOT AS IN USE DPB T2,LATSTA## ;SET INITIAL STATE IN LAT ENTRY FOR THIS SLA JRST CPOPJ1 ;T1=SLA ;GIVSLA ROUTINE TO RETURN A LAT ADDRESS ;CALL MOVEI F,DDB ;THIS DOESN'T WORK FOR TERMINAL ; PUSHJ P,GIVSLA ;RETURN THE LAT ENTRY, ZERO NETSLA ;RETURN CPOPJ ;UNLESS WE STOPCD. ; ;NOTE! THIS ROUTINE PRESERVES ALL REGISTERS (ESPECIALLY T1) GIVSLA::NTDBUG ;VERIFY THE NETSER INTERLOCK PUSHJ P,SAVE2## ;SAVE P1, P2 SO WE DON'T CLOBBER THE T'S LDB P2,NETSLA## ;GET THE CURRENT SLA FOR THIS DEVICE HRRZ P1,NETLAT##(P2) ;GET [MOST OF] THE LAT ENTRY. ;IT'S OK TO ONLY LOOK AT 18 BITS HERE . . . CAIE P1,(F) ;MAKE SURE EVERYTHING IS CONSISTENT. STOPCD .,STOP,ANFLAT, ;++ DDB AND LAT DON'T AGREE SETZB P1,NETLAT##(P2) ;FREE THE LAT DPB P1,NETSLA## ;CLEAR THE SLA IN THE DDB DPB P1,NETDLA## ; GET THE DLA SINCE NOT CONNECTED. POPJ P, ;ALL DONE SUBTTL NPD -- ROUTINES TO MANIPULATE NETWORK CONNECT DISCRIPTORS ;GETNPD ROUTINE TO ALLOCATE A NETWORK CONNECTION DESCRIPTOR BLOCK ;CALL MOVEI T1,LENGTH ;LENGTH OF DESIRED NPD (INCLUDES NPDBLK) ; PUSHJ P,GETNPD ;RETURN CPOPJ ;ERROR RETURN. NO CORE ; CPOPJ1 ;WITH J := A POINTER TO THE NPD ; GETNPD:: ;HERE TO ALLOCATE AN NPD MOVEI T2,(T1) ;COPY THE LENGTH FOR GETZWD PUSH P,T1 ;SAVE IT SO WE CAN PUT IT IN NPDBLK PUSHJ P,GETZWD ;ALLOCATE THE STORAGE JRST TPOPJ## ;NO STORAGE. ERROR RETURN POP P,T2 ;GET THE LENGTH BACK MOVEI J,(T1) ;COPY THE NPD POINTER HRLZM T2,NPDBLK(J) ;SAVE THE LENGTH JRST CPOPJ1## ;GOOD RETURN ;GIVNPD ROUTINE TO RETURN A NETWORK CONNECTION DESCRIPTOR BLOCK ;CALL MOVEI J,NPD ADDRESS ; PUSHJ P,GIVNPD ;RETURN CPOPJ ;ALWAYS ; GIVNPD::HLRZ T1,NPDBLK(J) ;GET THE ALLOCATED LENGTH OF THE NPD MOVEI T2,(J) ;GET THE ADDRESS OF THE STORAGE PUSHJ P,GIVZWD ;FREE THE NPD SETZ J, ;INDICATE THAT IT IS GONE POPJ P, ;GIVE A GOOD RETURN ;GV2NPD RETURN BOTH NPD'S OF A TASK ;CALL F := DDB ;RETURN CPOPJ ;ALWAYS GV2NPD::PUSH P,J ;PRESERVE "J" HRRZ J,DEVNPD(F) ;GET THE ADDRESS OF THE FIRST NPD SKIPE J ;IF IT'S NOT NULL, PUSHJ P,GIVNPD ;RETURN IT HLRZ J,DEVNPD(F) ;GET THE ADDRESS OF THE REMOTE NPD SKIPE J ;IF IT'S NOT NULL, PUSHJ P,GIVNPD ;RETURN IT TOO SETZM DEVNPD(F) ;CLEAR THE NPD POINTER JRST JPOPJ## ;RESTORE "J" AND RETURN SUBTTL STC -- ROUTINES TO MANIPULATE STATION CONTROL MESSAGE BLOCKS ;GETSTC ROUTINE TO ALLOCATE A STC (STATION CONTROL MESSAGE) BLOCK ;CALL T1 := NUMBER OF BYTES IN THE STC MESSAGE ; W := POINTER TO THE NDB WE'RE SENDING TO/RECEIVING FROM ;RETURN CPOPJ ;NO CORE ; CPOPJ1 ;STC ALLOCATED. ; ; J := POINTER TO STC BLOCK GETSTC::PUSH P,T1 ;SAVE THE LENGTH (IN BYTES) MOVEI T2,3+<4*STCDAT>(T1) ;SET T2 := LENGTH(BYTES) OF ENTIRE STC LSH T2,-2 ;CHANGE WORDS TO BYTES (ROUNDED UP) PUSHJ P,GETZWD ;GET A BLOCK OF FREE-CORE TO HOLD STC MSG JRST TPOPJ## ; IF NO MORE MEMORY, GIVE ERROR RETURN MOVEI J,(T1) ;MAKE "J" THE STC POINTER POP P,T1 ;GET BACK THE LENGTH OF THE MESSAGE (BYTES) HRLZM T1,STCBLK(J) ;STORE LENGTH IN STC BLOCK RETSKP ;GIVE GOOD RETURN ;GIVSTC ROUTINE TO FREE A STC (STATION CONTROL MESSAGE) BLOCK ;CALL J := POINTER TO THE STC MESSAGE BLOCK ;RETURN CPOPJ ;ALWAYS GIVSTC::MOVEI T2,(J) ;SET T2 := ADDRESS OF STC BLOCK HLRZ T1,STCBLK(J) ;GET THE LENGTH (BYTES) OF THE STC DATA ADDI T1,3+ ;GET THE LENGTH (BYTES) OF STC DATA + STC BLOCK LSH T1,-2 ;SET T1 := LENGTH OF BLOCK (WORDS ROUNDED UP) PJRST GIVZWD ;RETURN THE STORAGE AND RETURN ;FEK2LN ROUTINE TO CONVERT FROM FEK ADDRESS TO STATION CONTROL LINE NUMBER ;CALL J := FEK ;RETURN CPOPJ ;T1 := LINE NUMBER ; ;STOPS IF J /= A VALID FEK ADDRESS FEK2LN: MOVEI T1,1 ;START WITH LINE NUMBER 1 MOVEI T2,FEKFST ;GET THE ADDRESS OF THE FIRST FEK FEK2L1: CAIN T2,(J) ;IF THIS IS THE FEK WE'RE LOOKING FOR POPJ P, ; RETURN WITH T1 := ITS LINE NUMBER HRRZ T2,FEKBLK(T2) ;GET THE ADDRESS OF THE NEXT FEK SKIPN T2 ;IF THERE AREN'T ANY MORE FEKS, THEN STOPCD .,STOP,ANFGFK, ;++ GARBAGE FEK POINTER AOJA T1,FEK2L1 ;INCREMENT THE LINE NUMBER AND CHECK NEXT FEK ;LN2FEK ROUTINE TO CONVERT FROM STATION CONTROL LINE NUMBER TO FEK ADDRESS ;CALL T1 := LINE NUMBER ;RETURN CPOPJ ;NO FEK CORRISPONDS TO THAT LINE ; CPOPJ1 ;J := ADDRESS OF FEK. LN2FEK: MOVEI J,FEKFST ;GET THE ADDRESS OF FEK FOR LINE #1 SOJN T1,[HRRZ J,FEKBLK(J) ;DECREMENT THE LINE NUMBER, GO TO NEXT FEK JUMPE J,CPOPJ ;IF DONE ALL FEKS, GIVE FAIL RETURN JRST .] ;KEEP LOOKING RETSKP ;RETURN WITH J := ADDRESS OF FEK REPEAT 0,< ;USELESS CODE (I THINK) ;STCREJ ROUTINE TO SEND A STATION CONTROL REJECT <13> MESSAGE ;CALL J := POINTER TO STC MESSAGE WITH ; 1ST BYTE := LINE # ; LH(STCNNL) := NODE NUMBER TO SEND REJECT TO ;RETURN CPOPJ WITH STC FREED STCREJ: PUSH P,W ;SAVE W (WE PUT DESTINATION NDB IN IT) PUSH P,J ;SAVE THE STC POINTER HLRZ T1,STCNNL(J) ;GET THE NODE NUMBER PUSHJ P,SRCNDB ; AND LOOK UP THE NDB JRST STCRE1 ;IF NODE NOT THERE, JUST FREE THE STC MSG PUSHJ P,NCMHDR ;WRITE THE MESSAGE HEADER JRST STCRE1 ;IF NO CORE, JUST TOSS THE STC BLOCK ;TYP XMTI NC.CTL ;THIS IS A STATION CONTROL MESSAGE ;LINE LDB T1,[POINT 8,STCDAT(J),7] ;GET THE LINE NUMBER XMT T1 ; AND SEND THAT ;CODE XMTI STC.RJ ;SEND THE REJECT CODE JSP T1,NETWRC ;SEND THE MESSAGE (AND CLOBBER "J") STCRE1: POP P,J ;GET THE STC POINTER BACK PUSHJ P,GIVSTC ;RETURN THE STC BLOCK JRST WPOPJ## ;RESTORE "W" AND RETURN >;END REPEAT 0 ;STCSEC ROUTINE CALLED ONCE/SEC TO DO STATION CONTROL TIMING FUNCTIONS ;CALL W := NDB POINTER ;RETURN CPOPJ ;ALWAYS ;ACTION IF THE "NDBSTC" TIMER GOES OFF, THE JOB OWNING NDBSTC ; IS WOKEN, AND NDBSTC(W) IS CLEARED ; IF THE "NDBICT" TIMER GOES OFF, THE INCOMING MESSAGE IS FREED STCSEC: SKIPN T1,NDBSTC(W) ;IS THE STATION CONTROL DEVICE IN USE? JRST STCSE1 ; IF NOT IN USE, GO TIME OUT BOOT REQUESTS HLRZ T1,T1 ;GET THE TIMER FOR STATION CONTROL USERS SOSLE T1 ;DECREMENT IT, SKIP IF IT COUNT'S OUT JRST [HRLM T1,NDBSTC(W) ;IF NOT COUNTED OUT YET, STORE IT -1 JRST STCSE1] ; BACK AND GO TIME INCOMING MESSAGES HRRZ T1,NDBSTC(W) ;GET THE JOB NUMBER OF THE USER THAT TIMED OUT SKIPE T1 ; IF NO ONE WAS USING IT, DON'T WAKE ANYONE PUSHJ P,EWAKE## ;WAKE THE USER NOW THAT HE'S TIMED OUT SETZM NDBSTC(W) ;CLEAR STC TO SAY THAT NO-ONE IS USING IT. STCSE1: SKIPN T1,NDBICT(W) ;SEE IF ANY BOOT MSGS ARE WAITING JRST STCSE2 ;IF NONE, DON'T LOOK ANY FARTHER HLRZ T1,T1 ;GET THE COUNTER FOR INCOMING STC MSGS SOSLE T1 ;COUNT OFF ONE MORE SECOND. IF NOT TIMED OUT, JRST [HRLM T1,NDBICT(W) ;THEN JUST STORE THE UPDATED COUNT JRST STCSE2] ;BACK AND EXIT PUSH P,J ;IF MESSAGE BEEN HERE TO LONG, FREE IT. SAVE J HRRZ J,NDBICT(W) ;GET A POINTER TO THE STC BLOCK PUSHJ P,GIVSTC ;RETURN THE STC BLOCK POP P,J ;RESTORE "J" SETZM NDBICT(W) ;INDICATE THAT NO STC MESSAGES ARE WAITING STCSE2: POPJ P, ;RETURN. SUBTTL FEK -- ROUTINES TO MANIPULATE FEKS ;CLNFEK THIS ROUTINE CLEANS OUT A FEK. IT RETURNS ALL ; BUFFER SPACE ASSOCIATED WITH A FEK, AND GIVES THE ; OUTPUT MESSAGES TO THE OUTPUT DONE ROUTINE IN NETSCN. ; IN THIS WAY MESSAGES BEING ROUTED THROUGH THE NODE WILL ; GET RE-ROUTED, AND MESSAGES TO THE NODE WILL BE DISCARDED. ;CALL MOVE J,FEK ;GET THE ADDRESS OF THE FEK ; PUSHJ P,CLNFEK ;CLEAN IT OUT ;RETURN CPOPJ ;ALWAYS ;CLOBBERS S,U,T1,T2 NTFONC==:CLNFK2 ;FOR NOW. CLNFEK: ;HERE TO RECYCLE A FEK IFN PARANOID&P$FEK,< ;DON'T REFURBISH NULL FEK HLLZ S,FEKBLK(J) ;GET THE FEK'S FLAGS TLNE S,FK.NUL ;SEE IF THIS IS A NULL FEK STOPCD .,STOP,ANFNUL, ;++ NULL FEK BEING CLEANED > SKIPE U,FEKIAD(J) ;GET THE INPUT PCB, IF THERE WAS ONE S0PSHJ RMVPCB ; THEN FREE THE INPUT BUFFER SETZM FEKIAD(J) ;CLEAR THE INPUT PCB POINTER SKIPG T2,FEKOCT(J) ;ARE THERE ANY OUTPUT PCBS? JRST CLNFK2 ;IF NOT, THEN DON'T FREE ANY. HRRZ U,FEKOAD(J) ;GET THE FIRST OUTPUT PCB SKIPA T1,U ;INITIALIZE WHAT WILL BECOME POINTER TO LAST CLNFK1: HRRZ T1,PCBBLK(T1) ;ADVANCE THE POINTER TOWARDS THE LAST SKIPN T1 ;MAKE SURE WE'VE GOT A PCB STOPCD .,STOP,ANFNPL, ;++ NO PCB'S ON LIST SOJG T2,CLNFK1 ;ADVANCE N-1 TIMES WHERE N = # OF PCB'S ; (EXIT WITH T1 POINTING TO LAST PCB) HRRZ T3,PCBBLK(T1) ;GET THE POINTER TO THE NTH+1 PCB SKIPE T3 ; IF IT ISN'T ZERO, THEN STOPCD .,STOP,ANFPCC, ;++ COUNT OF PCB'S ON LIST IS WRONG NETOFF ;PROTECTION WHEN DIDDLING QUEUES EXCH U,NTQOUT ;PUT THIS LIST ON THE HEAD OF NTQOUT HRRM U,PCBBLK(T1) ;AND SPLICE THE OLD ONE ON THE END NETON ;ALL CLEAR (WASN'T THAT EASY!) CLNFK2: MOVSI S,FK.ONL!FK.NID!FK.STO!FK.STI!FK.OAC!FK.IAC!FK.CPD ANDCAB S,FEKBLK(J) ;IN THE FEK STATUS WORD. SETZM FEKOAD(J) ;CLEAR POINTER TO THE PCB'S SETZM FEKODN(J) ;CLEAR OUTPUT DONE POINTER SETZM FEKOCT(J) ;SET FEK IDLE SETZM FEKHTM(J) ;CLEAR THE HUNG TIMER SETZM FEKNNM(J) ;CLEAR THE NODE NUMBER SETOM FEKBSO(J) ;CLEAR OUTPUT BUSY SETOM FEKBSI(J) ;CLEAR INPUT BUSY POPJ P, ;AND WE ARE DONE SUBTTL ROUTINE TO GENERATE THE NCL PROTOCOL HEADERS ;SUBROUTINE NCSHDR - CREATE ;CALL MOVEI W,NDB ; MOVEI T1,NCT MESSAGE TYPE ; PUSHJ P,NCSHDR ;RETURN CPOPJ ;NO CORE ; CPOPJ1 ;P3=COUNT, P2=CURRENT BYTE POINTER NCSHDR: ;ENTRY NTDBUG ;VERIFY THE INTERLOCK PUSHJ P,SAVE1## ;DON'T CLOBBER P1. MOVE P1,T1 ;COPY THE FLAGS MOVEI T1,^D16 ;MAKE A PCB WITH 16 WDS OF BUFFER TRNE P1,7 ;IS THIS A NUMBERED MESSAGE? JRST [PUSHJ P,MKUPCB ; IF NOT, THEN GET AN 'UN-NUMBERED' PCB POPJ P, ; (EXIT NCSHDR IF NOT AVAILABLE) JRST NCSHD1] ;RETURN TO MAIN FLOW WITH U := PCB PUSHJ P,MKNPCB ;IF IT'S A DATA MESSAGE, GET A NUMBERED PCB POPJ P, ; BUT GIVE ERROR RETURN IF NOT AVAILABLE. NCSHD1: MOVE P2,PCBPTR(U) ;GET BYTE POINTER AOS (P) ;WE WILL SUCCEED, SO GIVE GOOD RETURN MOVE T1,P1 ;GET THE NCT FLAGS BACK FOR NCSWHD ; PJRST NCSWHD ;FILL IN THE HEADER ;NCSWHD ROUTINE TO WRITE THE HEADER OF AN NCS MESSAGE. ;CALL MOVE T1,NCT FLAGS ; MOVE U,POINTER TO VIRGIN PCB ; PUSHJ P,NCSWHD ;RETURN CPOPJ ;ALWAYS ; ; PCB HAS NCT, DNA, SNA, NCA, NCN FILLED IN, ; ; PCBCTR IS UPDATED AND P3 IS ZERO, ; ; P2 HAS THE POINTER TO THE "DLA" BYTE. NCSWHD:: SETZ P3, ;CLEAR THE COUNT FIELD TRO T1,NCT.RH!NCT.SQ ;INSERT THE ADDITIONAL FLAGS PUSH P,T1 ;SAVE THE FLAGS FOR LATER ;NCT PUSHJ P,BI2EBI ;OUTPUT THE FLAGS ;DNA HLRZ T1,NDBNNM(W) ;GET THE DESTINATION NODE ADDRESS HRRM T1,PCBNNM(U) ;STORE IN PCB FOR NETWRT TO USE WHEN SENDING PUSHJ P,BI2EBI ;OUTPUT ;SNA MOVEI T1,NETNDB## ;ADDRESS OF THE NODE DATA BLOCK HLRZ T1,NDBNNM(T1) ;GET THE SOURCE NODE ADDRESS (US) PUSHJ P,BI2EBI ;OUTPUT ;NCA ;REAL MESSAGE NUMBER IS ASSIGNED BY NETWRT MOVEI T1,0 ;DUMMY MESSAGE NUMBER NOW PUSHJ P,DPBBIN ;STORE ;NCN MOVEI T1,0 ;AGAIN PUSHJ P,DPBBIN ;EXIT MOVSI T1,PCB.NM ;GET NUMBERED MESSAGE FLAG POP P,T2 ;GET THE NCT FLAGS BACK TRNN T2,NCT.TP ;NUMBERED MESSGE?? IORM T1,PCBBLK(U) ;YES, SET THE FLAG ADDM P3,PCBCTR(U) ;UPDATE THE CURRENT COUNT SETZ P3, ;CLEAR THE COUNT FIELD POPJ P, SUBTTL UNNUMBERED NCS CONTOL MESSAGES ;SUBROUTINE NCSSTR/NCSSAK - SEND A START/STACK MESSAGE ;CALL MOVEI W,NDB ;WHERE TO SEND THE MESSAGE ; PUSHJ P,NCSSSM ;SEND A START OR A STACK MESSAGE ;RETURN CPOPJ ;CAN'T NO CORE ; CPOPJ1 ;OK NCSSSM: MOVE T1,NDBFLG(W) ;GET THE FLAGS, AND TLNE T1,NDB.SK ; IF WE ARE SUPPOSED TO SEND A STACK JRST NCSSS1 ; THEN SKIP THE SEND-START CODE PUSHJ P,CLNNDB ;CLEAN OUT THE NDB FOR STARTERS MOVEI T1,NCT.ST ;START FLAGS SKIPA NCSSS1: MOVEI T1,NCT.SK ;START ACK FLAGS PUSHJ P,SAVE3## ;SAVE THE P'S IFN PARANOID&P$NDB, ;MAKE SURE WE DON'T SEND OURSELF A START PUSH P,T1 ;SAVE THE FLAGS SETZ F, ;NCS MESSAGE PUSHJ P,NCSHDR ;MAKE A HEADER (U = NEW PCB) PJRST TPOPJ## ;EXIT NO CORE PUSHJ P,NCSOPD ;GET THE ADDM P3,PCBCTR(U) ;UPDATE THE COUNT POP P,T2 ;RESTORE THE FLAGS PUSHJ P,NETWRT ;SEND THE STACK MESSAGE JRST CPOPJ1 ;ALL DONE ;SUBROUTINE NCSNID - SEND A NODE ID MESSAGE ;CALL MOVEI J,FEK ; PUSHJ P,NCSNID ;RETURN CPOPJ ;NO CORE ETC ; CPOPJ1 ;SENT NCSNID: PUSHJ P,SAVE3## ;SAVE THE P'S IFN PARANOID&P$FEK,< ;MAKE SURE WE DON'T SEND THE NULL FEK A NODEID HLLZ T1,FEKBLK(J) ;GET THE FEK'S FLAGS TLNE T1,FK.NUL ;SEE IF IT'S A NULL FEK STOPCD .,STOP,ANFNFI, ;++ SENDING NODE ID TO THE NULL FEK > SETZB W,F ;NO DDB OR NDB MOVEI T1,^D16 ;MESSAGE SIZE PUSHJ P,MKUPCB ;ALLOCATE THE MESSAGE SPACE POPJ P, ;NO SPACE AVAILABLE MOVE P2,PCBPTR(U) ;GET THE BYTE POINTER SETZ P3, ;CURRENT COUNT IS ZERO ;NCT MOVEI T1,NCT.ID!NCT.SQ ;GET ID FLAGS PUSHJ P,BI2EBI ;WRITE THE FLAGS ;NCA MOVEI T1,0 ;NO, ACKS FOR MESSAGE NUMBERS PUSHJ P,BI2EBI ;WRITE ;NCN MOVEI T1,0 ;SAME AS ABOVE PUSHJ P,BI2EBI ;WRITE ;OPD PUSHJ P,NCSOPD ;SEND THE IFN FTENET,< MOVE T1,FEKBLK(J) ;GET FEK FLAGS TLNN T1,FK.ETM ;ETHERNET (MASTER) FEK? JRST NCSNI4 ;NO, END OF NODEID THEN MOVEI T1,NIT.BC ;YES, MARK THIS AS A "BROADCAST" NODEID PUSHJ P,BI2EBI ;AND NCL'IZE IT AOS T1,FEKNIS(J) ;INCREMENT NODEID SERIAL NUMBER PUSHJ P,BI2EBI ;NCL'IZE THE SERIAL NUMBER HLRZ T2,FEKNIT(J) ;GET NEW BROADCAST TIMER INTERVAL HRRM T2,FEKNIT(J) ;AND SET IT FOR ONCE/SECOND CHECKING > ;END IFN FTENET NCSNI4: MOVSI T1,FK.NID ;GET NODE ID FLAG IORM T1,FEKBLK(J) ;SET FLAG NODE ID SENT ADDM P3,PCBCTR(U) ;UPDATE THE COUNT IFN FTCMSR, AOS (P) ;SKIP RETURN IFN FTKL10,< ;ONLY NEED WORRY ABOUT CACHE ON A KL PUSHJ P,PCBMRK## ;SET UP CACHE INFO FOR CALL TO FRCWRT > NETOFF ;NO RACE, "NETWRT" WILL RESTORE PI'S PJRST FRCWRT ;FORCE WRITE THE MESSSAGE ;SUBROUTINE NCSOPD - GENERATE THE OPTIONAL DATA ;CALL MOVEI U,PCB ; PUSHJ P,NCSOPD ;RETURN CPOPJ NCSOPD: ;ENTRY PUSH P,W ;SAVE THE NDB POINTER MOVEI W,NETNDB## ;GET THE NODE DATA BLOCK ;NNM HLRZ T1,NDBNNM(W) ;GET THE NODE NUMBER PUSHJ P,BI2EBI ;WRITE ;SNM HLRZ T1,NDBSNM(W) ;GET THE POINTER TO THE SYSTEM NAME MOVE T1,(T1) ;GET THE NAME PUSHJ P,SX2EAS ;WRITE ;SID HRRZ P1,NDBSID(W) ;SOFTWARE NAME PUSHJ P,AS2EAZ ;WRITE HLRZ P1,NDBSID(W) ;CREATION DATE POP P,W ;RESTORE THE NDB PJRST AS2EAZ ;WRITE ;NCSNAK THIS ROUTINE FIRST SCRAPS ALL UNPROCESSED MESSAGES ON ; LH(NDBQUE(W)). IT THEN SENDS A NAK. ; NOTE NAK'S ARE ONLY SENT AS A RESPONSE TO A REP. ; NOTE REPS ALWAYS ELICIT A NAK RESPONSE NCSNAK: NETOFF ;PROTECT FROM FEK'S HLRZ U,NDBQUE(W) ;GET THE LIST OF PCB'S HRRZS NDBQUE(W) ;SPLICE OUT THE LIST NETON ;ALL CLEAR NOW PUSHJ P,RMVALP ;FREE THE LIST MOVEI T1,NCT.NK ;GET THE NAK NCT PJRST NCSANR ;GO TO COMMON CODE ;NCSREP THIS ROUTINE SENDS A REP MESSAGE (NO OTHER PROCESSING) ;CALL W := NDB ;RETURN CPOPJ FAILED ; CPOPJ1 SENT IT OK NCSREP: MOVEI T1,NCT.RP ;GET REP NCT PJRST NCSANR ;GO TO COMMON CODE ;SUBROUTINE NCSACK - NCSNAK SEND AN ACK MESSAGE ;CALL MOVEI W,NDB ;PUSHJ P,NCSACK/NCSNAK ;RETURN CPOPJ ;ERROR ; CPOPJ1 ;OK NCSACK: MOVEI T1,NCT.AK ;GET THE ACK TYPE ; PJRST NCSANR ;COMMON CODE TO FINISH ACK/NAK/REP NCSANR: ;COMMON CODE FOR ACK-NAK-REP ;CALL WITH T1 := NCT IFN PARANOID&P$NDB, ;MAKE SURE WE AREN'T SENDING IT TO US PUSHJ P,SAVE3## ;SAVE THE P'S PUSH P,F ;SAVE F SETZ F, ;CLEAR F NCS MESSAGE PUSHJ P,NCSHDR ;WRITE THE HEADER JRST FPOPJ ;RESTORE F AND GIVE ERROR EXIT POP P,F ;RESTORE F PJRST NETWSR ;SEND THE MESSAGE SUBTTL NCS NUMBERED CONTROL MESSAGE HEADER ;NCMHDR ROUTINE TO BUILD THE HEADER FOR NUMBERED CONTROL MESSAGES. ;CALL MOVEI W,NDB ; PUSHJ P,NCMHDR ;RETURN CPOPJ ;NO CORE ; CPOPJ1 ;U := PCB, -1(P) := BYTE POINTER TO "CNT" ; ;NOTE!!! ; THIS ROUTINE DOES THE GROSS AND UGLY THING OF MEDDLING WITH THE ; STACK ON A SUCCESSFUL RETURN. SINCE EVERY PLACE THIS ROUTINE WAS ; CALLED IMMEDIATLY DID A "PUSH P,P2" THIS IS FAKED BEFORE NCMHDR ; GIVES A SUCCESSFUL RETURN. (THIS LEAVES THE STACK IN THE CORRECT ; STATE FOR A "JSP T1,NETWRC" TO SEND THE MESSAGE.) ; NCMHDR:: ;HERE TO BUILD A NUMBERED MESSAGE HEADER MOVEI T1,0 ;CONTROL MESSAGE PUSHJ P,NCSHDR ;OUTPUT THE HEADER POPJ P, ;NO CORE, GIVE ERROR RETURN MOVEI T1,0 ;NUMBERED CONTROL MESSGE PUSHJ P,BI2EBI ;DEPOSIT MOVEI P3,2 ;ACCOUNT FOR THE FIRST ADDM P3,PCBCTR(U) ; TWO BYTES SETZ P3, ;CLEAR THE COUNT FIELD IBP P2 ;STEP OVER THE FIELD POP P,T1 ;GET THE RETURN ADDRESS PUSH P,P2 ;SAVE A POINTER TO THE "CNT" FIELD FOR NETWRC JRST 1(T1) ;GIVE SKIP (CPOPJ1) RETURN ;NCSCNT ROUTINE TO SEND A CONNECT CONFIRM MESSAGE. ;CALL MOVE T1,[XWD "ROUTINE TO WRITE SPN","ROUTINE TO WRITE DPN"] ; MOVEI F,DDB ; PUSHJ P,NCSCNC ;RETURN CPOPJ ;SOMETHING WAS WRONG. ERROR CODE IN T1. ; CPOPJ1 ;CONNECT CONFIRM WAS SENT - DEVICE IS CONNECTED NCSCNC::PUSHJ P,NCSCNT ;SEND A "CONNECT" MESSAGE POPJ P, ;HO HUM MOVSI S,IOSCON ;THE "DEVICE IS CONNECTED" FLAG IORB S,DEVIOS(F) ;TELL THE WORLD THE DEVICE IS GOOD NOW JRST CPOPJ1## ;SUCCESSFUL RETURN WITH HAPPY DEVICE ;NCSCNT ROUTINE TO SEND A CONNECT INITIATE MESSAGE. ;CALL MOVE T1,[XWD "ROUTINE TO WRITE SPN","ROUTINE TO WRITE DPN"] ; MOVEI F,DDB ; PUSHJ P,NCSCNT ;RETURN CPOPJ ;SOMETHING WAS WRONG. ERROR CODE IN T1. ; CPOPJ1 ;CONNECT WAS SENT. (BUT NOT CONFIRMED) NCSCNT:: ;HERE TO SEND A CONNECT MESSAGE NTDBUG ;JUST CHECKING... PUSHJ P,SAVE3## ;SAVE THE P'S PUSHJ P,SAVJW## ;WE WILL CLOBBER J(FEK) AND W(NDB) PUSH P,U ;SAVE ANY MESSAGE WE MAY BE READING MOVE P1,T1 ;SAVE ADDRESS TO WRITE "DPN" & "SPN" HRRZ T1,DEVNET(F) ;GET THE NUMBER OF THE NODE THAT OWNS THIS PUSHJ P,SRCNDB ;SET UP W TO POINT TO ITS NDB. JRST [MOVEI T1,NRTUNN-NODERT ;GIVE A NODE-WENT-AWAY ERROR JRST UPOPJ##] ;AND AN ERROR ROUTINE SO CALLER WILL NOTICE. MOVEI T1,MSGMAW## ;BECAUSE CONNECT MSGS MAY BE VERY LONG PUSHJ P,MKNPCB ; WE MUST GET A LARGE PCB JRST [MOVEI T1,NRTNCE-NODERT ;BUT IF WE ARE OUT OF CORE, THEN JRST UPOPJ##] ;GIVE A NODE-CAPACITY-EXCEEDED ERROR MOVE P2,PCBPTR(U) ;GET THE ADDRESS OF THE MESSAGE BUFFER SETZ T1, ;THIS IS A NUMBERED MSG (TYPE 0) PUSHJ P,NCSWHD ;WRITE THE 5 HEADER BYTES XMTI 0 ;NO DLA SIGNIFIES NUMBERED CONTROL PUSH P,P2 ;REMEMBER WHERE THE "CNT" FIELD IS XMT1 T1 ;WRITE TWO GARBAGE XMT1 T1 ; BYTES. (WILL HOLD AN EXTENSIBLE COUNT) ADDM P3,PCBCTR(U) ;UPDATE THE LENGTH OF THE MESSAGE SO FAR SETZ P3, ;RESET P3 SO WE CAN MEASURE THE CONNECT MSG. ;FALL THROUGH TO WRITE THE BODY OF THE CONNECT MESSAGE ;TYP MOVEI T1,NC.CNT ;THIS IS A CONNECT MESSAGE PUSHJ P,BI2EBI ;WRITE THE TYPE ;DLA LDB T1,NETDLA## ;GET THE DLA FROM THE DDB PUSHJ P,BI2EBI ;SLA LDB T1,NETSLA## ;GET THE SLA FROM THE DDB IFN PARANOID&P$LAT,< SKIPN T1 ;JUST A BIT OF PARANOIA AGAIN STOPCD .,STOP,ANFSLA, ;++ NO SLA ON A CONNECT > PUSHJ P,BI2EBI ;DPN(OBJ,PID) PUSHJ P,(P1) ;LET CALLER WRITE THE DEST PROCESS DESCRIPTOR ;SPN(OBJ,PID) MOVS P1,P1 ;SWAP THE HALVES PUSHJ P,(P1) ;LET THE CALLER WRITE THE SOURCE PROCESS DESC. ;MML LDB T1,NETMML## ;GET SERVICE-ROUTINE-SPECIFIED MAX MESSAGE SIZE CAIG T1,0 ;GO WITH IT IF ANYTHING SPECIFIED MOVEI T1,MSGMAD## ;GET OUR LARGEST PERMISSABLE MESSAGE ; (*** SEE FOOTNOTE) PUSHJ P,BI2EBI ;OUTPUT ;FEA(DCM) PUSH P,W ;SAVE THE NDB POINTER FOR A BIT HLRZ W,DEVNET(F) LDB T1,NDTDCM## ;GET THE DEVICE MODES POSSIBLE PUSHJ P,BI2EBI ;WRITE ;FEA(,RLN) MOVEI T1,0 ;RECORD LENGTH IS VARIABLE PUSHJ P,BI2EBI ;WRITE ;FEA(,,DVT) LDB T1,NDTDVT## ;GET THE DEVICE ATTRIBUTES PUSHJ P,BI2EBI ;WRITE ;FEA(,,,DVU) LDB T1,NETDVU## ;GET DEVICE "UNIT" TYPE PUSHJ P,BI2EBI ;WRITE ;FEA(,,,,DVV) LDB T1,NETDVV## ;GET DEVICE "CONTROLLER" TYPE PUSHJ P,BI2EBI ;WRITE ;FALL THROUGH TO FIXUP THE LENGTH AND SEND THE MESSAGE ;CNT (GO BACK AND FILL IT IN) POP P,W ;RESTORE THE NDB POINTER CAILE P3,^D256 ;IS THE MSG LONGER THAN THIS ARBITRARY VALUE STOPCD .,STOP,ANFCIL, ;++ CONNECT INITIATE MESSAGE TOO LONG, ; SOMEONE (TSKSER) SCREWED UP ADDM P3,PCBCTR(U) ;UPDATE THE TOTAL MESSAGE LENGTH POP P,T2 ;GET THE POINTER TO THE TWO BYTE "CNT" BACK LDB T1,[POINT 7,P3,35] ;GET THE LOW 7 BITS TRO T1,200 ; AND MAKE THEM EXTENSIBLE IDPB T1,T2 ;STORE THE FIRST BYTE OF THE COUNT LDB T1,[POINT 7,P3,28] ;GET THE REST OF THE LENGTH IDPB T1,T2 ; AND STORE THAT PUSHJ P,NETWRT ;SEND THE MESSAGE PJRST UPOPJ1## ;GIVE GOOD RETURN ;*** FOOTNOTE *** COMMENT \ Historically, this value was calculated by taking the minimum of all message length's for all nodes in the path between the node we were sending the connect to and ourself. This seems wrong to me. Given a multi-path environment, we may find ourselves using an un-expected path. The result of this is that the sender must calculate the maximum message length based on the current minimum of all nodes in the network. In light of this, my opinion is that the MML field should represent our "local" maximum. It doesn't really matter though since no one uses the field anyway... Matson And I take offense at the above footnote - I tried to believe the silly value in the DDP code in the -87, and look where it got me - into trap service 'cuz the -10 sent some silly number that had no relation with reality. Boo Hiss! Such are the trials and tribulations of life in the small country pits . . . -RDH \ ;NCSDSC ROUTINE TO SEND A DISCONNECT MESSAGE. ;CALL MOVEI F,DDB ; MOVEI T1,"REASON" ; PUSHJ P,NCSDSC ;RETURN CPOPJ ;NO CORE, OR NODE WENT AWAY. ; CPOPJ1 ;DISCONNECT SENT (BUT NOT CONFIRMED!) ; NCSDSC:: ;HERE TO SEND A DISCONNECT MESSAGE NTDBUG ;JUST CHECKING PUSHJ P,SAVE3## ;SAVE THE P'S PUSHJ P,SAVJW## ;WE CLOBBER J(FEK) AND W(NDB) PUSH P,U ;SAVE ANY INPUT MESSAGE WE MAY BE PROCESSING MOVEI P1,(T1) ;SAVE THE REASON IN A SAFE REGISTER IFN PARANOID&P$LAT,< LDB T1,NETSLA## ;JUST A QUICK CHECK TO MAKE SURE THAT THE LAT HRRZ T1,NETLAT##(T1) ; AND THE DDB AGREE WITH RESPECT TO THE SLA ;IT'S OK TO ONLY LOOK AT 18 BITS . . . CAIE T1,(F) ;DOES THE SLA POINT BACK TO THE DDB? STOPCD .,STOP,ANFLDD, ;++ LAT AND DDB DISAGREE > HRRZ T1,DEVNET(F) ;GET THE NODE NUMBER PUSHJ P,SRCNDB ;SET UP "W" WITH THE NDB POINTER STOPCD .,STOP,ANFNWA, ;++ NODE WENT AWAY, DRIVER SHOULD HAVE NOTICED PUSHJ P,NCMHDR ;MAKE A CONTROL MESSAGE HEADER. JRST UPOPJ ; IF NO CORE, GIVE AN ERROR RETURN ;TYP MOVEI T1,NC.DSC ;WE ARE A DISCONNECT MESSAGE PUSHJ P,BI2EBI ;SEND THE DISCONNECT TYPE ;DLA LDB T1,NETDLA## ;GET THE REMOTE'S ADDRESS FOR THIS CONNECTION IFN PARANOID&P$LAT,< SKIPN T1 ;JUST A LITTLE PARANOIA STOPCD .,STOP,ANFDLA, ;++ NO DLA ON CONNECT > PUSHJ P,BI2EBI ;SEND THE DLA ;SLA LDB T1,NETSLA## ;GET OUR ADDRESS FOR THIS CONNECTION PUSHJ P,BI2EBI ;SEND THE SLA ;RSN MOVEI T1,(P1) ;GET THE CALLER SPECIFIED REASON PUSHJ P,BI2EBI ;SEND THE REASON ;CNT JSP T1,NETWRC ;SEND THE MESSAGE PJRST UPOPJ1## ;GIVE A GOOD RETURN ;*** FOOTNOTE *** COMMENT \ Since this routine must be called under the protection of the NETSER interlock, there is no reason that the device driver cannot check to make sure that the node he is attempting to send a disconnect to is still up. The reason for replacing the "UPOPJ" with a STOPCD is to enforce such practices in device drivers \ ;SUBROUTINE NCSNBN - SEND NEIGHBOR NAME MESSAGE ;CALL PUSHJ P,NCSNBN ;RETURN CPOPJ ; CPOPJ1 NCSNBN: ;ENTRY PUSHJ P,SAVE3## ;SAVE THE P'S PUSHJ P,SAVJW## ;SAVE J AND W SETZ F, ;CONTROL MESSAGE PUSHJ P,NCMHDR ;WRITE NUMBERED HEADER (PUSH BYTE PTR ON STK) POPJ P, ;NO CORE MOVEI T1,NC.NBN ;GET HEIGHBOR NAMES PUSHJ P,BI2EBI ;WRITE PUSH P,W ;SAVE THE NDB POINTER MOVEI W,NETNDB## ;GET OUR NDB MOVE T4,[POINT 9,NDBTOP(W)] ;SEARCH THE TOPOLOGY TABLE MOVEI T3,NGHMAX ;GET THE SIZE OF THE NEIGHBORS TABLE NCSNB1: ILDB T1,T4 ;GET THE NODE NUMBER JUMPE T1,[IBP T4 ;IF NO NODE IN THIS SLOT. SKIP USLESS COST JRST NCSNB2] ;AND GO DO NEXT SLOT ;NNM XMT T1 ;SEND THE NODE NUMBER ;LVL ILDB T1,T4 ;GET THE COST XMT T1 ;SEND THE COST NCSNB2: SOJG T3,NCSNB1 ;LOOP OVER ALL NEIGHBORS POP P,W ;RESTORE THE TARGET NODE MOVSI T1,NDB.NB ;GET NEIGHBORS SENT IORM T1,NDBFLG(W) ;SET IT JSP T1,NETWRC ;SEND THE MESSAGE JRST CPOPJ1 ;GIVE GOOD (SKIP) RETURN ;SUBROUTINE SETNBN - SET THE BITS TO SEND NEIGHBORS MESSAGES TO ALL ;CALL PUSHJ P,SETNBN ;RETURN CPOPJ SETNBN: ;ENTRY ON CHANGE OF NEIGHBORS PUSHJ P,SAVJW## ;SAVE J AND W MOVSI T1,NDB.NB ;GET NEIGHBORS BIT MOVEI W,NETNDB ;START OF NDB'S SETNB1: HRRZ W,NDBNNM(W) ;GET THE FIRST NDB LESS OURS JUMPE W,CPOPJ## ;END OF LIST ANDCAM T1,NDBFLG(W) ;CLEAR THE BIT JRST SETNB1 ;CONTINUE ;SUBROUTINE NCSRCF - REQUEST CONFIGURATION MESSAGE ;CALL MOVEI W,NDB ; PUSHJ P,NCSRCF ;RETURN CPOPJ ;NO CORE ; CPOPJ1 ;RETURN NCSRCF: ;ENTRY PUSHJ P,SAVE3## ;SAVE THE P'S IFN PARANOID&P$NDB, ;MAKE SURE WE AREN'T SENDING IT TO US PUSHJ P,SAVJW## ;SAVE J AND W SETZ F, ;CONTROL MESSAGE PUSHJ P,NCMHDR ;WRITE A HEADER (AND PUSH "CNT" POSITION ON STK) POPJ P, ;CAN'T MOVEI T1,NC.RCF ;TYPE REQUEST CONFIGURATION PUSHJ P,BI2EBI ;SEND JSP T1,NETWRC ;SEND THE MESSAGE PJRST CPOPJ1## ;SKIP RETURN ;SUBROUTINE NCSCNF - SEND A CONFIGURATION MESSAGE UPON REQUEST ;CALL MOVEI W,NDB ; PUSHJ P,NCSCNF ;RETURN CPOPJ ; CPOPJ1 NCSCNF: ;ENTERY PUSHJ P,SAVE3## ;SAVE THE P'S IFN PARANOID&P$NDB, ;MAKE SURE WE AREN'T SENDING IT TO THIS NODE PUSHJ P,SAVJW## ;SAVE J W SETZ F, ;CLEAR THE DDB PUSHJ P,NCMHDR ;GET A HEADER (AND PUSH "CNT" POSITION) POPJ P, ;NO CORE AVAILABLE MOVEI W,NETNDB## ;GET OUR NODE DATA BLOCK MOVEI T1,NC.CNF ;CONFIGURATION MESSAGE PUSHJ P,BI2EBI ;SEND ;OBJ MOVSI P1,- ;NUMBER OF DEVICE TYPES NCSCF1: LDB T1,NETCNF##(P1) ;GET THE COUNT JUMPE T1,NCSCF2 ;DON'T HAVE ANY MOVEI T1,(P1) ;GET THE TYPE BACK PUSHJ P,BI2EBI ;SEND THE DEVICE TYPE ;NDV LDB T1,NETCNF##(P1) ;DEVICE COUNT PUSHJ P,BI2EBI ;SEND ;PID MOVEI T1,0 ;ZERO PID PUSHJ P,BI2EBI ;SEND NCSCF2: AOBJN P1,NCSCF1 ;CONTINUE THROUGH THE LIST JSP T1,NETWRC ;SEND THE MESSAGE JRST CPOPJ1## ;GIVE SKIP RETURN ;SUBROUTINE NCSDRQ - SEND A DATA REQUEST ;CALL MOVEI T1,DATA REQUEST COUNT ; MOVEI F,DDB ; PUSHJ P,NCSDRQ ;RETURN CPOPJ ;NO CORE ; CPOPJ1 ;REQUEST SENT NCSDRQ:: ;ENTRY NTDBUG ;VERIFY THE INTERLOCK MOVE S,DEVIOS(F) ;GET THE DEVICE STATUS TLNN S,IOSCON ;ARE WE STILL CONNECTED? JRST CPOPJ1## ;NO, GOOD RETURN, OUTPUT BETTER TRAP ERROR PUSHJ P,SAVE3## ;SAVE THE P'S PUSHJ P,SAVJW## ;SAVE J AND W PUSH P,U ;SAVE U (SELF CONTAINED ROUTINE) MOVEI P1,(T1) ;SAVE THE DRQ COUNT HRRZ T1,DEVNET(F) ;GET THE NODE NUMBER PUSHJ P,SRCNDB ;SET UP W FROM THE NODE NUMBER SKIPA ;NODE WENT AWAY. GIVE ERROR RETURN PUSHJ P,NCMHDR ;WRITE THE HEADER (AND PUSH "CNT" POINTER) JRST UPOPJ## ;RESTORE U AND GIVE ERROR RETURN MOVEI T1,NC.DQR ;DATA REQUEST PUSHJ P,BI2EBI ;WRITE ;DLA LDB T1,NETDLA## ;GET THE DESTINATION LINK ADDRESS IFN PARANOID&P$LAT,< SKIPN T1 ;JUST A BIT OF PARANOIA AGAIN STOPCD .,STOP,ANFDRZ, ;++ SENDING DRQ'S TO DEVICE ZERO > PUSHJ P,BI2EBI ;WRITE ;DQR MOVEI T1,(P1) ;GET THE DQR PUSHJ P,BI2EBI ;WRITE ;CNT JSP T1,NETWRC ;SEND THE MESSAGE (POP "CNT" POINTER OFF STK) PJRST UPOPJ1## ;SKIP EXIT SUBTTL MEMORY CONTROL ROUTINES ;SUBROUTINE GETZWD - GET A BLOCK OF MONITOR FREE CORE AND ZERO ;CALL MOVEI T2,#WORDS ; PUSHJ P,GETZWD ;RETURN CPOPJ ;NO CORE AVAILABLE ; CPOPJ1 ;T1=ADDRESS GETZWD:: IFN PARANOID&P$COR,< ;KEEP A LINKED LIST OF ALL NETWORK CORE ADDI T2,3 ;WE USE 3 EXTRA WORDS IF WE ARE PARANOID > PUSH P,T2 ;SAVE THE NUMBER OF WORDS HLRE T1,FREPTR## ;GET LENGTH OF FREE CORE MAP MOVNS T1 IMULI T1,^D36 ;MAKE #4 WORD BLOCKS (=1/4 FREE CORE TOTAL) JFCL ; CAML T1,%NTCOR ;DON'T USE MORE THAN 1/4 OF FREE CORE PUSHJ P,GETWDS## ;ALOCATE THE SPACE PJRST T2POPJ## ;NO, SPACE AVAILABLE SETZM (T1) ;CLEAR THE FIRST WORD MOVE T2,(P) ;GET THE NUMBER OF WORDS ADDM T2,%NTCOR ;ACCOUNT FOR CORE USED MOVEM T1,(P) ;SAVE THE STARTING ADDRESS ADDI T2,-1(T1) ;POINT TO THE END OF THE LIST HRLI T1,1(T1) ;MAKE A BLT POINTER MOVSS T1 ;FROM,,TO BLT T1,(T2) ;CLEAR THE BLOCK IFN FTCMSR,< MOVE T1,%NTCOR ;IF WE NOW ARE USING MORE CAMLE T1,%NTMAX ; CORE THAN EVER BEFORE MOVEM T1,%NTMAX ; RECORD FOR PRYING EYES > IFN PARANOID&P$COR,< ;NOW LINK IN THE BLOCK AND SET LAST WORD MOVE T1,[SIXBIT /NETMEM/] ;"UNIQUE" PATTERN FOR END WORD MOVEM T1,(T2) ;SO WE CAN SEE IF USER WROTE TOO FAR. MOVE T1,(P) ;GET ADDRESS OF START OF THE BLOCK NETOFF ;WE NEED PROTECTION WHILE HACKING LISTS MOVE T2,%NTMEM ;GET POINTER TO FIRST BLOCK IN THE CHAIN HRLI T2,%NTMEM ;MAKE OUR BACK LINK POINT TO "%NTMEM" MOVEM T2,(T1) ;STORE DOUBLE LINK IN FIRST WORD ANDI T2,-1 ;STRIP OFF IME-INDUCING LH GARBAGE MOVEM T1,%NTMEM ;MAKE THE LIST START WITH US HRLM T1,(T2) ;FIX UP BACKWARD LINK IN NEXT BLOCK NETON ;ALL'S CLEAR MOVE T2,-1(P) ;GET THE CALLER'S PC HRLI T2,'NET' ;GET A "UNIQUE" 18 BIT STRING MOVEM T2,1(T1) ;AND PUT "XWD STRING,PC" IN SECOND WORD ADDI T1,2 ;MAKE POINTER POINT TO THE THIRD WORD MOVEM T1,(P) ;AND GIVE THAT TO THE USER > PJRST TPOPJ1## ;RESTORE THE ADDRESS AND EXIT ;SUBROUTINE GIVZWD - RETURN MONITOR FREE CORE ;CALL MOVEI T1,#WORDS ; MOVEI T2,ADDRESS ; PUSHJ P,GIVZWD ;RETURN CPOPJ GIVZWD:: IFN PARANOID&P$COR,< ;CHECK FOR ILLEGAL MEMORY USAGE ADDI T1,3 ;ACCOUNT FOR CHECK WORDS SUBI T2,2 ;ADJUST POINTER TO BEGINNING OF BLOCK > ;END IFN PARANOID&P$COR PUSH P,T1 ;SAVE THE LENGTH IFN PARANOID&P$COR,< ;CHECK FOR ILLEGAL MEMORY USAGE PUSH P,T2 ;SAVE THE ADDRESS NETOFF ;PROTECTION WHILE HACKING LISTS MOVE T1,(T2) ;GET THE "XWD BACKWARD,FORWARD" LINK WORD HRRZ T3,T1 ;JUST THE ADDRESS FOR IME-LESS INDEXING HLLM T1,(T3) ;SPLICE OUT ONE POINTER MOVS T1,T1 ;SWAP HALVES HRRZ T3,T1 ;JUST THE ADDRESS FOR IME-LESS INDEXING HLRM T1,(T3) ;SPLICE OUT THE OTHER POINTER NETON ;ALL IS CLEAR. WE ARE SPLICED OUT HLRZ T1,1(T2) ;GET THE LEFT OF THE SECOND CHECK WORD CAIE T1,'NET' ;MAKE SURE IT WASN'T CLOBBERED STOPCD .,STOP,ANFWMB, ;++ USER WROTE IN MEMORY BEFORE BLOCK ADD T2,-1(P) ;GET A POINTER TO ONE PAST THE END OF THE BLOCK EXCH T2,-1(T2) ;GET THE LAST CHECK WORD (AND MAKE IT GARBAGE) CAME T2,[SIXBIT /NETMEM/] ;VERIFY THAT HE DIDN'T CLOBBER IT STOPCD .,STOP,ANFWPE, ;++ USER WROTE PAST THE END OF THE BLOCK POP P,T2 ;GET THE ADDRESS BACK > ;END IFN PARANOID&P$COR MOVN T1,0(P) ;"SUB'ABLE" LENGTH ADDB T1,%NTCOR ;REDUCE CORE USED SKIPGE T1 ;CHECK RESULT STOPCD TPOPJ##,DEBUG,CWN,;++CORE ALLOCATION WENT NEGATIVE POP P,T1 ;RESTORE WORD COUNT PJRST GIVWDS## ;RETURN THE CORE ;SUBROUTINE SVEVM - SAVE THE JOB EVM AND RESTORE ON POPJ ;CALL PUSHJ P,SVEVM ;RETURN CPOPJ SVEVM:: JUMPE F,CPOPJ## ;NO EVM IF NO DDB SKIPN DEVEVM(F) ;ANY EVM POPJ P, ;NO RETURN PUSHJ P,RTEVM## ;YES, RETURN THE EVM POP P,(P) ;PUT THE RETURN ON THE END OF THE STACK PUSHJ P,@1(P) ;RETURN TO THE CALLER PJRST RSTEVM## ;NON-SKIP RESTORE EVM AOS (P) ;SKIP RETURN PJRST RSTEVM## ;RESTORE EVM AND EXIT SUBTTL COMMON SUBROUTINES TO CONVERT EXTENSIBLE ASCII/BINARY ;SUBROUTINE EAS2SX CONVERT EXTENSIBLE ASCII TO SIXBIT ;CALL MOVEI P1,[INPUT POINTER] ; PUSHJ P,EAS2SX ;RETURN CPOPJ ;T1=SIXBIT EAS2SX::MOVE T2,[POINT 6,T1] ;GET BYTE POINTER SETZB T1,T4 ;CLEAR OUTPUT EAS2S1: SOJL P4,CPOPJ## ;EXIT IF NO MORE DATA ILDB T3,P1 ;GET THE BYTE TRZN T3,200 ;CONTINUE BIT SETO T4, ;NO, SET FLAG TRNE T3,140 ;MAKE SURE ASCII BEFOR SUBI SUBI T3,40 ;CONVERT TO SIXBIT TRNN T3,177 ;CHECK FOR A BLANK CHARACTER JUMPE T1,EAS2S2 ;AND A LEADING BLANK CAIE T3,'[' ;CHECK TO [XXX,XXX] CAIN T3,']' ;AND EXIT POPJ P, ;IF FOUND CAIN T3,',' ;ALSO A COMMA POPJ P, ;WILL EXIT TLNE T2,(77B5) ;END OF WORD IDPB T3,T2 ;STORE WORD EAS2S2: JUMPGE T4,EAS2S1 ;NO CONTINUE POPJ P, ;RETURN ;SUBROUTINE SX2EAS CONVERT SIXBIT TO EXTENSIBLE ASCII ;CALL MOVE T1,[SIXBIT /.../] ; MOVE P2,[OUTPUT BYTE POINTER] ; PUSHJ P,SX2EAS ;RETURN CPOPJ ;P3 COUNTED UP SX2EAS::SKIPE T2,T1 ;COPY THE SIXBIT NAME SX2EA1: SETZ T1, ;CLEAR THE OUTPUT AC LSHC T1,6 ;GET A SIXBIT CHARACTER ADDI T1,240 ;CONVERT TO ASCII WITH CONTINUE BIT IDPB T1,P2 ;STORE CHARACTER ADDI P3,1 ;COUNT THE CHARACTER JUMPE T2,CLRBT8 ;EXIT AND CLEAR CONTINUE BIT JRST SX2EA1 ;COUNT AND CONTINUE ;SUBROUTINE AS2EAS CONVERT ASCIZ TO EXTENSIBLE ASCII ;CALL MOVE P1,[INPUT BYTE POINTER] ASCII 7 ; MOVE P2,[OUTPUT BYTE POINTER] EXTENSIBLE ASCII 8 ; PUSHJ P,AS2EAS ;RETURN CPOPJ ;P3 UPDATED WITH CHARACTER COUNT AS2EAZ: JUMPE P1,CPOPJ## ;DO NOTHING IF NO POINTER AS2EAS::TLNN P1,-1 ;IS THERE A BYTE POINTER HRLI P1,(POINT 7) ;NO, SUPPLY ONE AS2EA1: ILDB T1,P1 ;GET AN ASCII CHARACTER JUMPE T1,CLRBT8 ;JUMPE IF END TRO T1,200 ;SET HIGH ORDER BIT IDPB T1,P2 ;STORE 8 BIT BYTE AOJA P3,AS2EA1 ;COUNT CHARACTER TRY AGAIN CLRBT8::LDB T1,P2 ;GET LAST STORED CHARACTER BACK TRZ T1,200 ;CLEAR THE CONTINUE BIT DPB T1,P2 ;STORE CHARACTER POPJ P, ;RETURN ;SUBROUTINE EAS2AZ SEE IF ANYTHING FOR EAS2AS TO CONVERT ;CALL MOVE P1,[INTPUT BYTE POINTER] ; PUSHJ P,EAS2AZ ;RETURN 1 NOTHING TO COPY ;RETURN 2 SOMETHING FOR EAS2AS TO DO ;USES T1 & T2 EAS2AZ: JUMPE P4,CPOPJ## ;RETURN IF NOTHING TO COPY MOVE T1,P1 ;COPY BYTE POINTER ILDB T2,T1 ;EXAMINE FIRST CHARACTER JUMPN T2,CPOPJ1## ;SKIP IF SOMETHING TO COPY MOVE P1,T1 ;NO, COPY INCREMENTED BYTE POINTER SOJA P4,CPOPJ## ;ACCOUNT FOR CHARACTER AND GIVE 'NONE' RETURN ;SUBROUTINE EAS2AS CONVERT AN EXTENSIBLE ASCII STRING TO ASCIZ ;CALL MOVE P1,[INPUT BYTE POINTER] ; MOVE P2,[OUTPUT BYTE POINTER] ; PUSHJ P,EAS2AS ;EXIT EAS2AS::HRLI P2,(POINT 7) ;MAKE A BYTE POINTER MOVEI T2,^D37 ;ALLOW A MAX CHARACTER COUNT EAS2A1: SOJL P4,CPOPJ## ;EXIT IF NO MORE ILDB T1,P1 ;GET AN 8 BIT CHARACTER IDPB T1,P2 ;STORE A SEVEN BIT CHARACTER TRNE T1,200 ;IS CONTINUE BIT ON SOJG T2,EAS2A1 ;YES, CONTINUE SETZ T1, ;SET UP A NULL IDPB T1,P2 ;STORE THE NULL POPJ P, ;RETURN ;SUBROUTINE BI2EBI CONVERT A BINARY NUMBER TO EXTENSIBLE BINARY ;CALL MOVE T1,[A BINARY NUMBER] ; MOVE P2,[OUTPUT BYTE POINTER] 8 BIT ; PUSHJ P,BI2EBI,OCT2EBI,DE2EBI ;RETURN CPOPJ ;P3 UPDATED BI2EBI::CAIG T1,177 ;GREATER THAN 177 JRST DPBBIN ;NO OUTPUT LSHC T1,-7 ;SHIFT OFF THE BITS ROT T2,7 ;SAVE IN T2 TRO T2,200 ;SET CONTINUE BIT IDPB T2,P2 ;STORE IN MESSAGE AOJA P3,BI2EBI ;CONTINUE ;SUBROUTINE EBI2BI TO CONVERT EXTENSIBLE BINARY TO BINARY ;CALL MOVE P1,[INPUT BYTE POINTER ; PUSHJ P,EBI2BI ;RETURN CPOPJ ;T1=BINARY NUMBER EBI2BI::SETZB T1,T2 ;INITIALIZE FOR NUMBER-BUILDING LOOP EBI2B1: SOJL P4,CPOPJ## ;EXIT IF THE END OF DATA ILDB T3,P1 ;GET THE NEXT CHARACTER TRZN T3,200 ;IS THE NUMBER EXTENDED JRST EBI2B5 ;NO, ACCUMLATE END OF NUMBER AND EXIT LSH T3,(T2) ;POSITION NEXT "DIGIT" IOR T1,T3 ;AND ACCUMULATE NUMBER ADDI T2,7 ;"ADVANCE" ACCUMULATOR-POSITIONER JRST EBI2B1 ;CONTINUE EBI2B5: LSH T3,(T2) ;POSITION NEXT "DIGIT" IOR T1,T3 ;AND ACCUMLATE NUMBER POPJ P, ;RETURN WITH BINARY IN T1 ;SUBROUTINE BYT2BI READ ONE BYTE FROM THE STREAM ;CALL JUST LIKE THE REST ;RETURN CPOPJ ;T1 = THE 8 BIT BYTE BYT2BI::SOJL P4,CPOPJ## ;EXIT IF END OF MESSAGE ILDB T1,P1 ;GET THE BYTE POPJ P, ; AND RETURN ;SUBROUTINE XX2EAS CONVERT NUMBER TO EXTENSIBLE ASCII ;CALL P2/ OUTPUT BYTE POINTER P3/ COUNTER T1/ NUMBER ; PUSHJ P,OC2EAS/DC2EAS/RX2EAS ;RETURN CPOPJ WITH P2/P3 UPDATED DC2EAS: SKIPA T3,[^D10] ;DECIMAL CONVERSION OC2EAS::MOVEI T3,^D8 ;OCTAL CONVERSION RX2EBI: IDIVI T1,(T3) ;SEPERATE AGAIN HRLM T2,(P) ;STORE THE BYTE SKIPE T1 ;ANY LEFT NOW PUSHJ P,RX2EBI ;YES, TRY AGAIN HLRZ T1,(P) ;GET THE LAST DIGIT BACK ADDI T1,"0" ;NO CONVERT TO ASCII DPBEAS: TRO T1,200 ;SET THE CONTINUE BIT DPBBIN::ADDI P3,1 ;COUNT IDPB T1,P2 ;NO STORE THE DIGIT POPJ P, ;RETURN ;SUBROUTINE EAS2 - CONVERT ASCII TO OCTAL/DECIMAL/RADIX ;CALL P1, P4:= POINTER TO INPUT ; PUSHJ P,EAS20C/EAS2DC/2ASRX ;RETURN CPOPJ; T1:= NUMBER, T2:= TERMINATING CHARACTER EAS2DC::SKIPA T3,[^D10] ;DECIMAL RADIX EAS2OC::MOVEI T3,^D8 ;OCTAL RADIX EAS2RX::SETZB T1,T4 ;ARBITRARY RADIX IN T3 EAS2NN::SOJL P4,CPOPJ## ;COUNT DOWN INPUT ILDB T2,P1 ;NEXT INPUT CHARACTER TRZN T2,200 ;END OF FIELD SETO T4, ;YES CAIL T2,"0" ;VALID ? CAILE T2,"0"(T3) ; DIGIT ? POPJ P, ;NO, END OF NUMBER IMULI T1,(T3) ;ROOM FOR NEXT ADDI T1,-"0"(T2) ;ADD UP NUMBER JUMPE T4,EAS2NN ;LOOP FOR WHOLE NUMBER POPJ P, ;OR UNITL END OF EXTENSIBLE ASCII ;XSKIP ROUTINE TO SKIP OVER AN EXTENSIBLE FIELD ;CALL P1, P4 := POINT TO FIELD ; PUSHJ P,XSKIP ;RETURN CPOPJ ;ALWAYS ; XSKIP:: SOJL P4,CPOPJ## ;COUNT OFF THIS BYTE ILDB T1,P1 ;GET THE BYTE TRNE T1,200 ;EXTENSIBLE JRST XSKIP ;YES. KEEP LOOKING FOR THE END POPJ P, ; NO. ALL DONE ;SKIP1 ROUTINE TO SKIP OVER A 1 BYTE FIELD ;CALL P1, P4 := POINT TO BYTE TO SKIP ; PUSHJ P,SKIP1 ;RETURN CPOPJ ; SKIP1:: SOJL P4,CPOPJ## ;COUNT DOWN THE BYTE IBP P1 ;INCREMENT THE BYTE POINTER POPJ P, ;ALL DONE ;SUBROUTINE PP2EAS - OUTPUT A PPN IN EXTENSIVE ASCII ;CALL MOVE T1,[PPN] ; PUSHJ P,PP2EAS ;RETURN CPOPJ PP2EAS::PUSH P,T1 ;SAVE THE PPN MOVEI T1,"[" ;OPEN BRACKET PUSHJ P,DPBEAS ;OUTPUT HLRZ T1,(P) ;GET THE PROGRAMMER NUMBER PUSHJ P,OC2EAS ;OUTPUT MOVEI T1,"," ;SEPERATOR PUSHJ P,DPBEAS ;OUTPUT POP P,T1 ;RESTORE THE STACK GET PROGRAMMER # HRRZS T1 ;RT HALF PUSHJ P,OC2EAS ;OUTPUT MOVEI T1,"]" ;CLOSING BRACKET PUSHJ P,DPBEAS ;OUTPUT PJRST CLRBT8 ;CLEAR THE LAST BIT ;SUBROUTINE EAS2PP - INPUT A PROCESS ANEM AND UIC ;CALL PUSHJ P,EAS2PP ;RETURN CPOPJ IFN FTTSK,< EAS2PP:: ;ENTRY PUSHJ P,EAS2SX ;GET THE SIXBIT NAME PUSH P,T1 ;SAVE SETZ T2, ;CLEAR THE PPN WORD CAIE T3,'[' ;DOES A PPN FOLLOW PJRST TPOPJ## ;NO EXIT T1=NAME T2=PPN PUSHJ P,EAS2OC ;GET THE PROJECT NUMBER TLNE T1,-1 ;LESS THAN 7 DIGITS ? SETZ T1, ;ILLEGAL SET TO ZERO PUSH P,T1 ;SAVE THE PROJECT NUMBER PUSHJ P,EAS2OC ;GET THE PROGRAMMER NUMBER TLNE T1,-1 ;LESS THAN 7 DIGITS ? SETZ T1, ;ILLEGAL HRL T1,(P) ;GET THE PROGRAMMER NUMBER BACK MOVE T2,T1 ;COPY TO T2 POP P,(P) ;REMOVE SCRATCH FROM THE STACK PJRST TPOPJ## ;EXIT T1=NAME T2=PPN >;END FTTSK SUBTTL NTFSEC - ONCE A SECOND CODE ;CALLED ONCE A SECOND WITH J SET FOR EACH FEK ; NTFSEC::PUSHJ P,SAVJW## ;SAVE J AND W ETC SKIPN T1,FEKBJN(J) ;SEE IF SOME NODE OWNS THE BOOT JRST NTFSE1 ; IF NOT BOOT-STRAPING, GO CHECK REST OF FEK HLRZ T1,T1 ;GET THE TIMER VALUE SOJLE T1,[HRRZ T1,FEKBJN(J) ;IF TIMER RAN OUT, GET JOB NUMBER PUSHJ P,EWAKE## ;WAKE THE USER SETZM FEKBJN(J) ;RELINQUISH OWNERSHIP OF STC JRST NTFSE1] ;AND GO CHECK FOR STALE MESSAGES HRLM T1,FEKBJN(J) ;STORE THE NEW TIMER VALUE NTFSE1: SKIPN T1,FEKICT(J) ;SEE IF THERE ARE ANY INPUT MSGS QUEUED JRST NTFSE2 ; IF NO INPUT STC MSGS, CHECK REST OF FEK HLRZ T1,T1 ;GET JUST THE TIMER VALUE SOJLE T1,[PUSH P,J ;IF THE MESSAGE TIMES OUT, SAVE FEK HRRZ J,FEKICT(J) ;GET J := STC MESSAGE PUSHJ P,GIVSTC ;FREE THE STC MESSAGE POP P,J ;GET THE FEK ADDRESS BACK SETZM FEKICT(J) ;CLEAR THE (NOW FREED) STC MSG POINTER JRST NTFSE2] ;AND CONTINUE WITH OTHER CHECKING HRLM T1,FEKICT(J) ;STORE THE UPDATED COUNTER NTFSE2: HLLZ S,FEKBLK(J) ;SET UP THE FEK'S FLAGS JUMPGE S,CPOPJ ;IF IT'S NOT ONLINE, DON'T CHECK ANY FARTHER TLNN S,FK.NID ;NODE ID SENT PUSHJ P,NCSNID ;NO, SEND IT JFCL ;ERROR NO CORE (SEND NEXT TIME) SKIPG FEKIAD(J) ;IS THERE AN INPUT PCB? PUSHJ P,NETRDD ;IF NO INPUT PCB, TRY TO SET UP READ REQUEST SKIPG FEKOCT(J) ;IS THERE AN OUTPUT PCB BEING SERVICED? POPJ P, ; IF NOT, THEN DON'T DO HUNG CHECK. AOS T1,FEKHTM(J) ;INCREMENT THE TIME THAT THIS PCB HAS TAKEN. CAIG T1,^D5 ;HAS THIS PCB TAKEN MORE THAN 5 SECONDS? POPJ P, ; IF NOT, THEN IT'S POSSIBLY ALL RIGHT ;HERE IF FEK HAS TIMED OUT. (IE. MORE THAN 5 SECONDS TO SEND LAST MESSAGE) MOVEI T1,FF.CRS ;ASK THIS FEK TO "CRASH" ITSELF XCT FEKDSP(J) ;CALL THE FRONT-END SERVICE ROUTINE POPJ P, ;AND RETURN ;NETSEC THIS ROUTINE IS CALLED ONCE A SECOND FROM CLOCK1 NETSEC:: IFN FTMP, ;ONLY DO SECOND STUFF ON THE BOOT CPU SETOM NTQSEC ;SIGNAL THE SECOND POPJ P, ;LET JIFFY CODE CALL NETSCN SUBTTL NETCTC - CALL ON RESET OR ^C^C AND NOT CCON/CON NETCTC:: ;CALLED BY UUOCON NETDBJ ;GET THE INTERLOCK TO DO THIS. PUSHJ P,SAVJW## ;SAVE J AND W ;CHECK FOR REMOTE DIALER IN USE CAMN J,DIALJB ;DOES THIS JOB HAVE THE [NETWORK] DIALER? SETZM DIALDB ;YES, CLEAR THE DIALER ;CLEAR THE STATION CONTROL DEVICE IF THERE MOVEI W,NETNDB## ;GET THE START ON THE NDB CHAIN NETCT1: SKIPN T1,NDBSTC(W) ;IS STATION CONTROL BUSY JRST NETCT2 ;NO, CONTINUE HRRZS T1 ;GET THE JOB NUMBER FOR COMPARE CAIN T1,(J) ;DOES THIS JOB HAVE THE DEVICE SETZM NDBSTC(W) ;YES, CLEAR THE DEVICE NETCT2: HRRZ W,NDBNNM(W) ;GET THE NEXT STATION POINTER JUMPN W,NETCT1 ;CONTINUE UNLESS THE END OF NDB ;HERE TO CHECK FOR STATION CONTROL IN USE ON ANY FEKS IFN FTKS10,< ;ONLY THE KS-10 HAS SMART FEKS... MOVEI W,FEKFST## ;GET THE ADDRESS OF THE FIRST FEK CAIA ;SKIP INTO THE LOOP NETCT3: HRRZ W,FEKBLK(W) ;ADVANCE TO THE NEXT FEK JUMPE W,NETCT4 ;IF NO MORE FEKS, GO CHECK FOR OTHER THINGS SKIPN T1,FEKBJN(W) ;SEE IF THIS FEK'S STC IS IN USE JRST NETCT3 ;IF NO ONE IS USING IT, GO CHECK NEXT FEK HRRZ T1,T1 ;CLEAR OUT THE TIMER VALUE CAIN T1,(J) ;ARE WE THE ONE USING THE STC? SETZM FEKBJN(W) ; IF WE'RE USING IT, RELEASE IT JRST NETCT3 ;GO CHECK THE REST... >;END IFN FTKS10 ;HERE TO CHECK FOR PENDING CONNECT/DISCONNECT MESSAGES NETCT4: PUSHJ P,FNDPDS## ;FIND THE PDB FOR THE JOB PUSH P,F ;SAVE THE DDB POINTER HLRZ F,.PDNET##(W) ;GET THE POSSIBLE DDB POINTER JUMPE F,NETCT5 ;NONE HRRZS .PDNET##(W) ;CLEAR THE POINTER MOVE T1,DEVMOD(F) ;GET DEVICE'S DV??? FLAGS TRNE T1,ASSPRG ;IS DEVICE OPEN/INITED? JRST NETCT5 ;YES, RELEASE SHOULD GET IT LATER TLNE T1,DVTTY ;IS DEVICE A TTY? JRST [PUSHJ P,TTYKIL## ;YES, THEN USE A DIFFERENT JRST NETCT5] ; ROUTINE TO FREE THE DDB MOVE S,DEVIOS(F) ;IF THE DEVICE NEVER GOT CONNECTED TLNN S,IOSCON ;OR IS BEING DISCONNECTED, JRST [MOVSI S,IOSZAP ;THEN SET IOSZAP. THIS CAUSES ALL IORB S,DEVIOS(F) ;RIGHT THINGS TO HAPPEN AS MSGS COME IN JRST NETCT5] ;RETURN TO MAIN LINE PUSHJ P,ZAPNE0 ;IF CONNECTED, SEND A DISCONNECT NETCT5: JRST FPOPJ## ;RESTORE F AND EXIT ;NDBCHK ROUTINE TO VERIFY THAT W DOES NOT POINT AT NETNDB. (THIS ; ROUTINE CHECKS TO MAKE SURE THAT WE AREN'T TALKING TO OURSELF.) ;CALL PUSHJ P,NDBCHK ;RETURN CPOPJ ;OR STOPCD ; NDBCHK: PUSH P,T1 ;SAVE THIS FOR A BIT MOVEI T1,NETNDB## ;GET THE ADDRESS OF NETNDB CAIN T1,(W) ;MAKE SURE RH(W) DOESN'T POINT AT IT STOPCD .,STOP,ANFTLK, ;++ TALKING TO OURSELVES PJRST TPOPJ ;RESTORE T1 AND RETURN ;FRCNLD ROUTINE TO START UP NETLDR ;CALL PUSHJ P,FRCNLD ;RETURN CPOPJ ;STARTS NETLDR ONLY IF NOT DEBUGGING FRCNLD: MOVE T1,STATES## ;BEFORE WE START UP NETLDR, MAKE SURE TRNN T1,ST.DDL ; OPR SAYS IT'S OK. IF NO NETLDR, SKIPGE DEBUGF ; OR WE'RE DEBUGGING THIS MESS POPJ P, ;DON'T RUN NETLDR PUSH P,U ;FIRST WE NEED AN LDB, SO SAVE POSSIBLE PCB PUSH P,W ;WE ALSO MUST SET UP "W" FOR GETLDB SETZ T1, ;SIGNIFY THAT THERE'S NO REMOTE INVOLVED MOVEI T3,ERRDSP## ;SET UP NULL ISR DISPATCH PUSHJ P,GETLDB## ;GET A FREE LDB JRST FRCNL1 ;IF NO FREE LDB'S JUST IGNORE THE REQUEST MOVEI T1,M.AIDL## ;ANF-10 IDLE MAX PUSHJ P,SCNADT## ;START TIMER LOGIC ON LINE MOVEI T1,TTFCXL## ;GET THE ".NETLD" FORCE COMMAND INDEX PUSHJ P,TTFORC## ;FORCE IT ON THE TERMINAL PUSHJ P,FRELDB## ;*** KROCK *** MUST GET THIS ONTO FRCLIN *** FRCNL1: POP P,W ;RESTORE ANY NDB POINTER PJRST UPOPJ## ;RETURN. NETLDR WILL START UP SOON. ;NETWRC ROUTINE TO FINISH OFF A MESSAGE STARTED BY NCMHDR & FRIENDS ;CALL P3 := "CNT" OF THE CONTROL MESSAGE ; (P) := A BYTE POINTER TO THE "CNT" FIELD IN THE MESSAGE ; T1 := RETURN ADDRESS ;RETURN JRST (T1) ;VIA A CPOPJ FROM NETWRT ; NETWRC:: ;HERE TO SEND A CONTROL MESSAGE EXCH T1,(P) ;GET THE POINTER TO "CNT" (SAVE RETURN ADDR) DPB P3,T1 ;STORE THE COUNT ADDM P3,PCBCTR(U) ;UPDATE THE PCB'S LENGTH PJRST NETWRT ;SEND THE MESSAGE SUBTTL NETWRT - SEND A MESSAGE TO THE FRONT END KONTROLLER FEK ;SUBROUTINE NETWRT - SEND A MESSAGE ;CALL MOVEI U,PCB ; PUSHJ P,NETWRT ;CALLED AT INTERRUPT OR UUO LEVEL ;RETURN CPOPJ ;ALWAYS NETWSR: AOS (P) ;SKIP RETURN NETWRT:: ;ENTRY NTDBUG ;VERIFY THE INTERLOCK PUSHJ P,SAVJW## ;SAVE J/W HRRZ T1,PCBNNM(U) ;GET THE NODE NUMBER PUSHJ P,SRCNDB ;SET UP W FROM THE NODE NUMBER S0JRST RMVPCB ;NODE WENT AWAY, DELETE PCB HRRZ J,NDBFEK(W) ;GET THE FEK POINTER IFN FTCMSR,< MOVE T4,PCBPTR(U) ;GET ADDRESS OF MESSAGE HRLI T4,(POINT 8,0,7);POINT TO NCT LDB T1,T4 ; AND GET IT ANDI T1,NCT.TP ;ISOLATE MESSAGE TYPE AOS NCLXTP(T1) ;COUNT IT JUMPN T1,NETWR2 ;WE'RE DONE IF THIS IS UNNUMBERED CONTROL ADD T4,[-] ;POINT TO DLA LDB T1,T4 ; AND GET IT JUMPN T1,NETWR1 ;NON-ZERO MEANS DATA MESSAGE ILDB T1,T4 ;GET THE COUNT BYTE TRNE T1,200 ; AND IF IT'S EXTENSIBLE JRST .-2 ; KEEP READING ILDB T1,T4 ;GET NUMBERED MESSAGE TYPE CAIG T1,NC.MAX ;IN RANGE? AOS NCLXMT(T1) ;YES, COUNT IT JRST NETWR2 ;ALL DONE, OKAY TO SEND ;STILL IFN FTCMSR NETWR1: MOVE T1,PCBCTR(U) ;GET LENGTH OF ENTIRE MESSAGE ADD T1,PCBCT2(U) ;INCLUDING SECONDARY (USER) DATA, IF ANY SUBI T1,6 ;DISCARD PROTOCOL OVERHEAD CAIGE T1,1_ ; IN RANGE OF TABLE? JFFO T1,.+2 ;YES, GET APPROPRIATE RANGE TDZA T1,T1 ;OUT OF RANGE, INCREMENT ENTRY 0 MOVNI T1,-^D36(T2) ;MAKE ASCENDING ENTRIES MEAN LONGER LENGTHS AOS NCLXDL(T1) ; AND RECORD IT > NETWR2: NETOFF ;TURN OF THE PI SYS ;ASSIGN MESAGE NUMBERS HERE ;NCA MOVE T4,PCBPTR(U) ;GET THE OUTPUT POINTER HRLI T4,(POINT 8,0,31) ;POINT TO THE NCA/NCN FIELDS LDB T1,NDBLMP## ;GET THE LAST MESSAGE PROCESSED DPB T1,NDBLAS## ;SAVE AS LAST ACK DPB T1,T4 ;STORE THE ACK NUMBER ; MOVSI T1,NDB.XA ;GET AND CLEAR THE "NEED TO ACK" FLAG ; ANDCAB T1,NDBFLG(W) ; TO SIGNIFY ACK WENT THIS JIFFY ;NCN LDB T1,NDBLMA## ;GET THE LAST MESSAGE NUMBER ASSIGNED SKIPGE PCBBLK(U) ;NUMBERED MESSAGE ADDI T1,1 ;YES, UPATE THE COUNT DPB T1,NDBLMA## ;STORE AS LAST ASSIGNED IDPB T1,T4 ;STORE THIS MESSAGE NUMBER DPB T1,PCBMSN## ;SAVE THE MESSAGE NUMBER OF THIS PCB IFN FTKL10,< ;ONLY NEED WORRY ABOUT CACHE ON A KL PUSHJ P,PCBMRK## ;UPDATE THE CACHE SWEEP SERIAL IN THE PCB > ;DROP THRU INTO FRCWRT ;DROP THRU FROM NETWRT (WITH NETOFF) FRCWRT: ;PCBMRK MUST HAVE BEEN CALLED IFN PARANOID&P$PCB,< ;IF CHECKING PCB'S MOVE T1,[SIXBIT /PCBTAG/] ;GET THE PCB IDENTIFIER, CAME T1,PCBTAG(U) ; AND MAKE SURE WE HAVE A PCB. STOPCD .,STOP,ANFPCV, ;++ PCB NOT VALID > HLLZS PCBBLK(U) ;MAKE SURE WE ONLY GOT 1 PCB SETZ T3, ;CLEAR "CHECK" COUNTER MOVEI T1,FEKOAD-PCBBLK(J) ;GET ADDRESS OF OUTPUT LIST CAIA ;SKIP INTO LOOP FRCWR1: MOVEI T1,(T2) ;COPY THE PCB ADDRESS HRRZ T2,PCBBLK(T1) ;GET ADDRESS OF "NEXT" PCB SKIPE T2 ;IF NO NEXT PCB, SKIP OUT OF LOOP AOJA T3,FRCWR1 ;COUNT THE PCB AND KEEP LOOPING CAME T3,FEKOCT(J) ;MAKE SURE THAT THE COUNT IS RIGHT STOPCD .,STOP,ANFFEK, ;++ FEK BAD, FEKOAD AND FEKOCT IN CONFLICT HRRM U,PCBBLK(T1) ;QUEUE THIS PCB ON THE "END" OF THE LIST AOS T3,FEKOCT(J) ;COUNT THIS PCB. NETON ;QUEUES ARE CONSISTENT. INTS OK NOW MOVEI T1,FF.WRT ;GET "FEKWRT" FUNCTION CODE AND CALL KONTROLLER XCT FEKDSP(J) ; TO SET UP A WRITE REQUEST POPJ P, ;RETURN WITH MESSAGE ON ITS WAY ;ENQPCB THIS ROUTINE IS USED TO INSERT A PCB INTO A QUEUE SUCH ; AS NDBQUE. THE QUEUES ARE MAINTAINED WITH ALL UN-NUMBERED ; MESSAGES FIRST FOLLOWED BY ALL NUMBERED MESSAGES IN ASCENDING ; ORDER. ;CALL T1 := BYTE POINTER TO BEGINNING OF QUEUE ; U := ADDR OF PCB TO ENQUEUE ;RETURN CPOPJ ENQPCB: LDB T2,T1 ;GET ADDRESS OF FIRST PCB ON LIST JUMPE T2,ENQPC3 ;IF EMPTY, THEN PUT THIS FIRST MOVSI T3,PCB.NM ;GET THE "THIS IS A NUMBERED MESSAGE" FLAG TDNE T3,PCBBLK(U) ;IF THIS MSG IS NUMBERED, JRST ENQPC2 ; THEN USE DIFFERENT ROUTINE TDNE T3,PCBBLK(T2) ;IF FIRST MESSAGE IN QUEUE IS NUMBERED, JRST ENQPC3 ; THEN SPLICE THIS IN AT BEGINNING ENQPC1: MOVSI T1,(POINT 18,0,35) ;ELSE BUILD A BYTE POINTER, HRRI T1,(T2) ;AND RECURSE PJRST ENQPCB ;DOWN THE LIST ENQPC2: ;HERE FOR NUMBERED MESSAGES TDNN T3,PCBBLK(T2) ;IF FIRST MESSAGE IS UNNUMBERED, JRST ENQPC1 ;THEN RECURSE ONWARD PUSH P,U ;SAVE U, WE NEED IT FOR A TEMP LDB T3,PCBMSN## ;GET OUR MESSAGE NUMBER MOVE U,T2 ;COPY OTHER POINTER TO MAKE - LDB U,PCBMSN## ; THIS LDB WORK RIGHT SUB T3,U ;COMPARE THE TWO MESSAGE NUMBERS, POP P,U ;GET OUR PCB PTR BACK TRNN T3,200 ;SKIP IF OUR PCB .LT. FIRST. JRST ENQPC1 ;OUR PCB .GT. FIRST, RECURSE ON ENQPC3: HRRM T2,PCBBLK(U) ;HERE TO INSERT PCB. MAKE LINK ONWARD, DPB U,T1 ;AND LINK US IN. POPJ P, ;AND THAT'S ALL ;ENQNDB THIS ROUTINE QUEUES AN NDB FOR SERVICE ON OR ABOUT THE ; NEXT CLOCK TICK. THE QUEUE IS NOT ORDERED, AS ALL NDB'S ; IN THE QUEUE ARE PROCESSED. THE HEAD OF THE QUEUE IS ; CONTAINED IN THE LOCATION "NTQNDB". THE BIT ".NDBNQ" ; INDICATES THAT THE NDB HAS ALREADY BEEN QUEUED. ;CALL W := ADDR OF NDB ;RETURN CPOPJ ENQNDB: NETOFF ;PROTECT OURSELVES FROM FEK'S MOVSI T1,NDB.NQ ;GET THE "THIS NDB IS QUEUED" BIT TDOE T1,NDBFLG(W) ;SEE IF NDB HAS ALREADY BEEN QUEUED JRST NTONPJ ;IF SO, THEN EXIT NOW HRR T1,NTQNDB ;OTHERWISE ENQUEUE THIS ONE BY GETTING MOVEM T1,NDBFLG(W) ;THE CURRENT HEADER AND SAVEING IT HERE HRRZM W,NTQNDB ;AND MAKING THE START OF THE QUEUE US. JRST NTONPJ ;ALL DONE, TURN THE PI'S BACK ON SUBTTL NETHIB/NETWAK - HIBERNATE AND SLEEP ROUTINE FOR .CPJOB ON THE NET ;SUBROUTINE NETHIB - PUT THE JOB IN THE HIBER STATE ;CALL MOVEI F,DDB ; PUSHJ P,NETHIB ;RETURN CPOPJ ;WHEN AWAKEN BY NETWAK NETHIC: SKIPA T1,[EXP EV.NTC] ;CONNECT WAIT (NO ^C ALLOWED) NETHIB::MOVEI T1,EV.NET ;GET REASON FOR EVENT WAKE SKIPN F ;MUST HAVE A DDB STOPCD CPOPJ##,STOP,FFU,;++F FOULED UP NTSAVE ;RETURN 'NT' FOR REST OF THIS ROUTINE LDB J,PJOBN## ;GET THE JOB NUMBER PUSHJ P,FNDPDS## ;GET THE PDB HRLM F,.PDNET##(W) ;STORE THE DDB POINTER IN CASE OF RESET(^C^C) PUSHJ P,ESLEEP## ;WAIT HRRZ W,JBTPDB##(J) ;GET THE PDB BACK HRRZS .PDNET##(W) ;CLEAR THE POINTER POPJ P, ;YES, EXIT TO CALLER ;SUBROUTINE NETWAK - WAKE THE JOB UP PUT TO SLEEP BY NETHIB ;CALL MOVEI F,DDB ; PUSHJ P,NETWAK ;RETURN CPOPJ ;JOB(PC) WILL BE @ NETHIB NETWAK::PUSHJ P,SAVJW## ;SAVE J AND W LDB T1,PJOBN## ;GET THE JOB NUMBER PJRST EWAKE## ;WAKE THE JOB ;SUBROUTINE NETSLP - PUT THE JOB TO SLEEP FOR 2 SECONDS ;CALL MOVEI F,DDB ; PUSHJ P,NETSLP ;RETURN CPOPJ ;AFTER 2 SECOND NETSLP::PUSHJ P,SAVT## ;SAVE THE T'S DON'T KNOW WHO IS CALLING NTSAVE ;RETURN 'NT' FOR REST OF THIS ROUTINE LDB J,PJOBN## ;GET THE JOB NUMBER MOVEI T1,2 ;TWO SECONDS PUSHJ P,SLEEPF## ;SLEEP JFCL ;MAYBE POPJ P, ;RETURN ;*** FOOTNOTE *** COMMENT \ Note that both these routines clobber "J" and "W". In general these routines are called with contents(J) pointing to a FEK, and contents(W) pointing to an NDB. Since these pointers would no longer be valid (the FEK or node might have crashed) these registers are intentionally clobbered. \ ;SUBROUTINE INCTBD - RECORD AND DISCARD A BAD INPUT MESSAGE ;CALL MOVEI U,PCB ; MOVEI J,FEK ; MOVEI T1,. ; PUSHJ P,INCTBD ;USUALLY PJSP T1,INCTBD ;RETURN CPOPJ INCTBP: HRRZ T1,(P) ;GET PC FOR THOSE WHO PUSHJ INCTBD::AOS %NTBAD ;COUNT THIS MESSAGE HRLI U,(T1) ;KEEP PC OF FINDER IN LH OF %NTBLC EXCH U,%NTBLC ;SAVE, GET LAST ONE S0JRST RMVPCB ;FLUSH THE PCB AND RETURN ;SUBROUTINE NETHRU - SEND A ROUTE THROUGH MESSAGE ;CALL MOVEI U,PCB ; MOVE T1,NODE NUMBER OF DESTINATION ; JRST NETHRU ;RETURN CPOPJ NETHRU: ;ENTRY PUSH P,J ;SAVE THE INPUT FEK PUSHJ P,SRCNDB ;FIND THE NODE TO SEND THE MESSAGE JSP T1,[POP P,J ;RESTORE THE INPUT FEK JRST INCTBD] ;ILLEGAL MESSAGE HRRZ J,NDBFEK(W) ;GET THE OUTPUT FEK IFN FTKL10,< PUSHJ P,PCBMRK## ;MSG WAS LOOKED AT, CLEAR VALID BIT > NETOFF PUSHJ P,FRCWRT ;SEND THE MESSAGE JRST JPOPJ## ;RESTORE THE INPUT FEK AND RETURN ;SUBROUTINE NETRDD - SET UP A READ REQUEST TO THE FRONT END ;CALL MOVE J,FEK ; PUSHJ P,NETRDD ;RETURN CPOPJ NETRDD: SETZ W, ;CLEAR THE NODE POINTER SKIPE FEKIAD(J) ;CURSORY CHECK TO SEE IF INPUT BUFFER POSTED POPJ P, ;IF SO, DON'T GO THROUGH THE HAIR IFN FTENET,< MOVE T1,FEKBLK(J) ;GET FEK FLAGS TLNN T1,FK.ETH ;ETHERNET FEK? JRST NETRD1 ;NO, NORMAL DEVICE FEK TLNN T1,FK.ETM ;ETHERNET MASTER FEK? POPJ P, ;NO, SLAVE FEKS DON'T DO INPUT MOVE T1,FEKNIQ(J) ;GET COUNT OF INPUT PCBS ALREADY QUEUED CAIL T1,4 ;GOT PLENTY? POPJ P, ;YES, DON'T QUEUE UP TOO MANY > ;END IFN FTENET ;ALLOCATE AN INPUT PCB NETRD1: MOVEI T1,MSGMAW## ;BUFFER SIZE THAT IS THE LARGEST PCB PUSHJ P,MKUPCB ;GET THE BUFFER SPACE POPJ P, ;IF NO CORE, JUST EXIT (WILL TRY AGAIN LATER) MOVEI T1,MSGMAX## ;GET, AND SET THE NUMBER OF BYTES MOVEM T1,PCBCTR(U) ; AVAILABLE IN THE PCB. ;NOW QUEUE THE INPUT REQUEST NETOFF ;WE MUST WORRY ABOUT RACES AGAIN. SKIPE FEKIAD(J) ;MAKE SURE WE DIDN'T GET BEAT. IF SOMEONE SET JRST [NETON ; A READ REQUEST JUST NOW, TURN INTERRUPTS ON PJRST RMVPCB] ; RETURN THE BUFFER AND EXIT HRRZM U,FEKIAD(J) ;POST THE INPUT BUFFER NETON ;RE-ENABLE INTERRUPTS WITH BUFFER SET UP ;KICK THE FEK (POST READ REQUEST)