;TITLE SCLINK - Session Control Layer Control for DECnet-36 ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ;OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ;COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1976, 1986. ;ALL RIGHTS RESERVED. SUBTTL V.Brownell & W.Nichols/Tarl SEARCH D36PAR,SCPAR,MACSYM SALL ENTRY SCTL,SCTINI IFN FTOPS10,< .CPYRT<1976,1986> > ;END IFN FTOPS10 IFN FTOPS20,< SEARCH PROLOG TTITLE SCLINK,,< - Session Control Layer for DECnet-36> > IFN FTOPS10,< SEARCH F,S TITLE SCLINK - Session Control Layer Control for DECnet-36 $RELOC > D36SYM ;SET UP D36 SPECIFIC PARAMETERS XRESCD ;Start in extended resident code SUBTTL Table of Contents ; Table of Contents for SCLINK ; ; ; Section Page ; 1. Table of Contents. . . . . . . . . . . . . . . . . . . 2 ; 2. Definitions ; 2.1. Internal References . . . . . . . . . . . . . 3 ; 2.2. External References . . . . . . . . . . . . . 4 ; 2.3. Accumulators. . . . . . . . . . . . . . . . . 6 ; 2.4. Node name/number database . . . . . . . . . . 7 ; 2.5. Loopback node block . . . . . . . . . . . . . 8 ; 3. Macros ; 3.1. Code-Generating ; 3.1.1. IFxSTATE . . . . . . . . . . . . . . 9 ; 3.1.2. NEWSTATE . . . . . . . . . . . . . . 10 ; 4. SCTINI - Session Control Initialization. . . . . . . . 11 ; 5. SCTPSQ - Grant a PSI interrupt . . . . . . . . . . . . 12 ; 6. SCTSTM - Check Active Connect Timers for Expiration. . 13 ; 7. SCTSEC - Once-a-second service for SCLINK. . . . . . . 14 ; 8. SCTRFJ - Request Second Service for a Link . . . . . . 15 ; 9. SCTL's Interlock ; 9.1. Queuing Version . . . . . . . . . . . . . . . 16 ; 9.2. Waiting Version . . . . . . . . . . . . . . . 17 ; 9.3. Flag Version. . . . . . . . . . . . . . . . . 18 ; 10. SCTULK - SCTL's Interlock ; 10.1. Unlock Checks . . . . . . . . . . . . . . . . 19 ; 11. NSP. ; 11.1. Function Dispatch Table . . . . . . . . . . . 20 ; 11.2. Wait Check Tables ; 11.2.1. Definitons . . . . . . . . . . . . . 21 ; 11.3. Wait check tables ; 11.3.1. "Before" NSP. table. . . . . . . . . 22 ; 11.3.2. "After" NSP. table . . . . . . . . . 23 ; 11.3.3. Routines . . . . . . . . . . . . . . 24 ; 11.4. SCTNSF - The Entry to SCLINK from SCMUUO. . . 25 ; 11.5. NSFRE - REset all links . . . . . . . . . . . 31 ; 11.6. NSFEA - Enter Active State. . . . . . . . . . 32 ; 11.7. NSFEP - Enter Passive State . . . . . . . . . 35 ; 11.8. NSFRI - Read Connect Information. . . . . . . 36 ; 11.9. NSFAC - Accept the Connect. . . . . . . . . . 37 ; 11.10. NSFRJ - Reject the Connect. . . . . . . . . . 39 ; 11.11. NSFRC - Read Connect Confirm Information. . . 40 ; 11.12. NSFSD - Synchronous Disconnect. . . . . . . . 41 ; 11.13. NSFAB - Abort and Release . . . . . . . . . . 43 ; 11.14. NSFRD - Read Disconnect Data. . . . . . . . . 44 ; 11.15. NSFRL - Release the Channel . . . . . . . . . 45 ; 11.16. NSFRS - Read the Channel Status . . . . . . . 46 ; 11.17. NSFIS - Send Interrupt Data . . . . . . . . . 47 ; 11.18. NSFIR - Receive Interrupt Data. . . . . . . . 49 ; 11.19. NSFDS - Send Normal Data. . . . . . . . . . . 51 ; 11.20. NSFDR - Receive Normal Data . . . . . . . . . 55 ; 11.21. NSFSQ - Set Quotas and Goals. . . . . . . . . 57 ; 11.22. NSFRQ - Read Quotas and Goals . . . . . . . . 58 ; 11.23. NSFJS - Set Job Quotas and Goals. . . . . . . 59 ; 11.24. NSFJR - Read Job Quotas and Goals . . . . . . 60 ; 11.25. NSFPI - Set PSI Reason Mask . . . . . . . . . 61 ; 12. RETFLW - Return current flow controls. . . . . . . . . 62 ; 13. SNDDRQ - Send Data Requests. . . . . . . . . . . . . . 63 ; 14. RLSLNK - Release a Link. . . . . . . . . . . . . . . . 64 ; 15. LLINKS Calls ; 15.1. Entry Vector Table. . . . . . . . . . . . . . 65 ; 15.2. SCTRIB - Reserve Input Buffer . . . . . . . . 66 ; 15.3. SCTUCG - Uncongestion Call. . . . . . . . . . 67 ; 15.4. SCTLCI - Connect Initiate Call. . . . . . . . 68 ; 15.5. The Vectored Call Entry Point SCTL. . . . . . 71 ; 15.6. SCCCR - Connect Confirmed call from NSP . . . 72 ; 15.7. SCDIR - Disconnect Initiate received call . . 73 ; 15.8. SCDCR - Disconnect Confirm received call. . . 74 ; 15.9. SCODN - Output done call. . . . . . . . . . . 75 ; 15.10. SCSEG - Segment received call . . . . . . . . 76 ; 15.11. SCDRQ - Data request received call. . . . . . 77 ; 15.12. SCNCF - No confidence in port call. . . . . . 78 ; 15.13. SCNRS - No resources call . . . . . . . . . . 79 ; 15.14. SCCLS - Close Completed call. . . . . . . . . 80 ; 15.15. SCNLK - No link call. . . . . . . . . . . . . 81 ; 15.16. SCNCM - No communication call . . . . . . . . 82 ; 15.17. SCNRN - Not in Run State call . . . . . . . . 83 ; 15.18. SCCAK - Got a Connect ACK . . . . . . . . . . 84 ; 16. Subroutines ; 16.1. CHKABO - Check SLABO flag . . . . . . . . . . 85 ; 16.2. CHKPPN - Check self PPN for validity. . . . . 86 ; 16.3. FREMSG - Free a message block . . . . . . . . 87 ; 16.4. CONBUF - Invoke Conservative Buffering. . . . 88 ; 16.5. FNDSLB - Find SLB given a channel number. . . 89 ; 16.6. FNDSBI - Find SLB from SLBid. . . . . . . . . 90 ; 16.7. FRESLB - Deallocate a SLB . . . . . . . . . . 91 ; 16.8. FRECBP - Free Connect Block . . . . . . . . . 92 ; 16.9. CDMCBP - Copy User Data from Message Block. . 93 ; 16.10. CPMSCB - Copy User Data from Message Block. . 94 ; 16.11. FRESJB - Deallocate a SJB . . . . . . . . . . 95 ; 16.12. MAKSLB - Create a SLB, filling in defaults. . 96 ; 16.13. MAKSJB - Create a SJB, filling in defaults. . 98 ; 16.14. SCSSTS/CHKSTS - Set Status & Inform PSISER. . 99 ; 16.15. SCTWKQ - Queue a Link for later call to SCTPSQ 101 ; 16.16. SLBMAT - Pattern match connect to passive SLBs 102 ; 16.17. CDBMAT - Match Two Connect Blocks . . . . . . 103 ; 16.18. STRMAT - Pattern Matcher. . . . . . . . . . . 106 ; 16.19. STPTMR - Stop the Connect Initiate Timer. . . 107 ; 16.20. STRTMR - Start the Connect Initiate Timer . . 108 ; 16.21. TMRREJ - Send a Reject with Reason RSNNRO . . 109 ; 16.22. BLDCTX - Build connect message. . . . . . . . 110 ; 16.23. PRSCTX - Parse a connect message. . . . . . . 114 ; 16.24. CPYS2M - Copy string block to message segment 118 ; 16.25. CPYM2S - Copy message data to string block. . 119 ; 16.26. SCTGSS - Get segment size for a destination . 120 ; 16.27. SCTCSS - Check segment size for a destination 121 ; 17. Node name/number database ; 17.1. Initialize. . . . . . . . . . . . . . . . . . 122 ; 17.2. Lock/unlock database. . . . . . . . . . . . . 123 ; 17.3. Add a node. . . . . . . . . . . . . . . . . . 124 ; 17.4. Address to name . . . . . . . . . . . . . . . 125 ; 17.5. Name to address . . . . . . . . . . . . . . . 126 ; 17.6. Name to NO block. . . . . . . . . . . . . . . 127 ; 17.7. Default area #. . . . . . . . . . . . . . . . 128 ; 17.8. Hash routine. . . . . . . . . . . . . . . . . 129 ; 17.9. Get a bucket. . . . . . . . . . . . . . . . . 130 ; 17.10. SCTANL - Add a loopback node name . . . . . . 131 ; 17.11. SCTN2L - Convert name to loop circ. . . . . . 132 ; 17.12. SCTL2N - Convert loopback circuit . . . . . . 132 ; 17.13. SCTCKL - Check for loopback node. . . . . . . 132 ; 18. Network management ; 18.1. Dispatch. . . . . . . . . . . . . . . . . . . 133 ; 18.2. SET parameter . . . . . . . . . . . . . . . . 134 ; 18.3. CLEAR parameter . . . . . . . . . . . . . . . 134 ; 18.4. READ parameter. . . . . . . . . . . . . . . . 134 ; 18.5. Return list of entity ids . . . . . . . . . . 135 ; 18.6. Map node address to node name . . . . . . . . 136 ; 18.7. Map node name to node address . . . . . . . . 136 ; 18.8. Check loopback node name. . . . . . . . . . . 136 ; 18.9. Event ; 18.9.1. Invalid message. . . . . . . . . . . 137 ; 18.9.2. CSSE event . . . . . . . . . . . . . 138 ; 19. Local SCTL Storage . . . . . . . . . . . . . . . . . . 139 ; 20. End of SCLINK. . . . . . . . . . . . . . . . . . . . . 140 SUBTTL Definitions -- Internal References ;These are the routines and variables in SCLINK that are referenced ; by other modules ;Initialization INTERN SCTINI ;Initialize SCLINK ;Calls from higher layers INTERN SCTPSQ ;Grant PSI to user INTERN SCTWKQ ;Queue a link to SCTPSQ INTERN SCTSEC ;Once-a-second service INTERN SCTLCW ;Process level interlock grabber INTERN SCTNSF ;Session control function entry point IFN FTOPS20 < INTERN SCTLOK ;Session control interlock > ;Calls from LLINKS INTERN SCTRIB ;Reserve input buffer INTERN SCTUCG ;Congestion INTERN SCTLCI ;Connect initiate INTERN SCTL ;LLINKS entry point in general ;Network management INTERN SCLNMX ;NTMAN entry point INTERN SCTLNL ;Loopback node name list INTERN SCTINT ;Incoming timer INTERN SCTOTT ;Outgoing timer INTERN LEVT.0 ;LCG event parameter 0 ;SJB routines INTERN FRESJB ;Free a SJB INTERN MAKSJB ;Allocate a SJB INTERN CHKSJB ;Check an SJB for SLBs ;Node name and address mapping INTERN SCTAND ;Add or delete a node INTERN SCTA2N ;Map a node address to a name INTERN SCTN2A ;Map a node name to an address INTERN SCTNDC ;# of local nodes defined (for JNTMAN) ;Loopback nodes INTERN SCTN2L ;Map node name to loopback node INTERN SCTCKL ;Check for existance of loopback node SUBTTL Definitions -- External References ;These are the external references to the D36COM library of routines. EXT DNGNBF ;GET TOTAL NUMBER OF BUFFERS IN SYSTEM EXT DNGINI ;INITIALIZE FOR INPUT (DGXYBY) EXT DNPINI ;INITIALIZE FOR OUTPUT (DPXYBY) EXT DNPINR ;REINITIALIZE FOR OUTPUT (DPXYBY) EXT DNP1BY ;PUT ONE BYTE IN MESSAGE EXT DNP2BY ;PUT TWO BYTES IN MESSAGE EXT DNPEBY ;PUT AN EXTENSIBLE BYTE IN MESSAGE EXT DNG1BY ;GET ONE BYTE FROM MESSAGE EXT DNG2BY ;GET TWO BYTES FROM MESSAGE EXT DNGEBY ;GET EXTENSIBLE BYTE FROM MESSAGE EXT DNGMSG ;GET DECNET-36 MESSAGE BLOCK EXT DNFMSG ;FREE MESSAGE BLOCK EXT DNMINI ;REUSE A MESSAGE BLOCK EXT DNLENG ;GET THE MESSAGE LENGTH EXT DNSLNG ;FIND THE SEGMENT LENGTH EXT DNGWDS ;GET SOME WORDS EXT DNGWDP ;Get some words in process context EXT DNGWDZ ;GET SOME ZEROED WORDS EXT DNGWZP ;Get som zeroed words in process context EXT DNFWDS ;FREE SOME WORDS EXT DNSWDS ;SMEAR SOME WORDS EXT DNBKBY ;GO BACKWARDS SOME BYTES EXT DNSKBY ;SKIP SOME BYTES EXT DNSMRK ;SET MARK IN MESSAGE EXT DNGMRK ;POSITION AT MARK IN MESSAGE EXT DNLMSS ;LINK MESSAGE SEGMENT INTO MESSAGE BLOCK EXT DNCPYW ;COPY WORDS WITH BLT OR XBLT EXT DNCM2U ;COPY MESSAGE TO USER BUFFER (TOPS-10) EXT DNCU2M ;COPY USER BUFFER TO MESSAGE (TOPS-10) EXT DNCM2B ;COPY MESSAGE TO MONITOR BUFFER EXT DNCB2M ;COPY MONITOR BUFFER TO MESSAGE EXT DNGTIM ;GET CURRENT TIME IN MS EXT DCNTSB ;TOTAL SYSTEM BUFFERS, USED AND UNUSED EXT DCNCON ;NON-ZERO IF SYSTEM IS CONGESTED EXT DCNRSB ;RESERVED BUFFERS, MODIFIED UNDER D36OFF ; TO PROTECT AGAINST SCTRIB CALL FROM LLINKS EXT DCNRHT ;HIGH TIDE FOR DCNRSB EXT DCNRIF ;INPUT RESERVATION FAILURES EXT DCNROF ;OUTPUT RESERVATION FAILURES EXT NTPARM ;Network management parameter processing EXT EVPBYT ;Network management event parameter output EXT EVP2BT ; " " " " " ;Entries into NSP. EXT NSP ;THE MAIN ENTRY TO NSP EXT NSPINI ;INITIALIZATION ROUTINE FOR NSP EXT NSPEVT ;SIGNAL AN NSP-LEVEL EVENT, USING EVENT MACRO ; FROM SCPAR.UNV ;Entry into ROUTER. ;Calls to ROUTER violate the layering. However, it is necessary to ; ask ROUTER for the maximum buffer sizes to a given destination node in order ; to implement 'big buffers' on the NI. EXT RTRGBS ;Get maximum buffer size for a node EXT RTRCBS ;Check maximum buffer size for a node ;Here are some external references to system things. EXT RTN ;RETURN EXT RSKP ;SKIP RETURN EXT EV96.0 ;Determines whether CSSE event 96.0 is logged IFN FTOPS10,< EXT BITTBL ;TABLE OF BIT POSITIONS BITS==BITTBL ;SCLINK USES BITS TABLE >; END IFN FTOPS10 IFN FTOPS20,< EXT ASGVAS ;Assign virtual address space > ;Externals for TOPS10 interlock management IFN FTOPS10,< ;EXTERNAL FOR SMP INTERLOCK BREAKER EXT SCTLOK ;INTERLOCK WORD EXT SCTLKO ;INTERLOCK OWNER WORD > ;External data. EXT %SCHDR ;MAX LENGTH OF HEADERS BELOW SCTL EXT RTRBSZ ;CELL CONTAINING ROUTER'S BUFFER SIZE EXT IBBLK ;DECnet initialization block EXT RTRHOM ;CELL CONTAINING ROUTER'S HOME AREA EXT RTRMXN ;MAXIMUM NODE ADDRESS IN AREA EXT %SCP2Q ;"PHASE II" QUOTA EXT %SCINT ;DEFAULT INCOMING TIMER VALUE EXT %SCOTT ;DEFAULT OUTGOING TIMER VALUE EXT %RTMXN ;MAX-NODES SUBTTL Definitions -- Accumulators ;These are some local AC defintions for Session Control. SL=FREE1 ;SL POINTS TO THE CURRENT SC LINK BLOCK SA=FREE2 ;SA POINTS TO THE ARGUMENT BLOCK PURGE FREE1,FREE2 ;WE DON'T NEED THIS SYMBOL ANYMORE SUBTTL Definitions -- Node name/number database ;Calculate number of buckets in database. SCNHSZ==^D223 ;Hash table size NRNOPB==^D3 ;Nodes per bucket ;The LDAREA macro extracts an area # from a node address DEFINE LDAREA(DST,SRC) < LDB DST,[POINTR(SRC,RN%ARE)] > ;The STAREA macro stores an area # into a node address DEFINE STAREA(SRC,DST) < DPB SRC,[POINTR(DST,RN%ARE)] > ;The LDNOD macro extracts a local node index from a node address DEFINE LDNODE(DST,SRC) < LDB DST,[POINTR(SRC,RN%NOD)] > ;The BEGSTR BU defines a bucket BEGSTR BU WORD NXT ;Pointer to next bucket WORD NO1, ENDSTR ;The BEGSTR NO defines a single node in a bucket BEGSTR NO ;Represents a single node WORD NAM ;Node name WORD ADR ;Node address ENDSTR SUBTTL Definitions -- Loopback node block BEGSTR LN WORD NXT ;PTR TO NEXT LOOPBACK NODE BLOCK WORD NAM ;LOOPBACK NODE NAME WORD CIR ;LOOPBACK CIRCUIT ENDSTR SUBTTL Macros -- Code-Generating -- IFxSTATE ;Use: AC/ One of the .NSSxx state codes ; ;a) IFSTATE AC, ; executed if match found ;b) IFSTATE AC,,LABEL (Go there if match found) DEFINE IFSTATE(AC,STATES,GLABEL),,,N,GE,L)> ;Use: AC/ One of the .NSSxx state codes ; ;a) IFNSTATE AC, ; executed if match NOT found ;b) IFNSTATE AC,,LABEL (Go there if match NOT found) DEFINE IFNSTATE(AC,STATES,GLABEL),,,E,L,GE)> DEFINE IFST1(AC,STATES,GLABEL,MOD1,MOD2,MOD3),< ZZ==0 ZZCNT==0 IRP STATES, ZZCNT==ZZCNT+1> IFE ZZCNT-1,< CAI'MOD1 AC,.NSS'STATES IFNB ,< IFIDN ,, IFDIF ,, >> IFG ZZCNT-1,< ;;IF MORE THAN ONE STATE TESTED MOVX CX,ZZ ROT CX,(AC) IFB ,< SKIP'MOD2 CX > IFNB ,< JUMP'MOD3 CX,GLABEL > > PURGE ZZCNT,ZZ > SUBTTL Macros -- Code-Generating -- NEWSTATE ;NEWSTATE will change the state of the link and call SCSSTS to tell ;PSISER to possibly let the user know about the change. DEFINE NEWSTATE(suffix),< MOVX T1,.NSS'suffix ;;SET UP STATE CALL SCSSTS ;;LET PSISER KNOW ABOUT IT TRACE SC,New State: suffix > SUBTTL SCTCCR - Compute Core Requirements ;SCTCCR computes SCLINK's core requirements. ;Call: ; PUSHJ P,SCTCCR ;Returns: ; T1/ Size of SCLINK core IFN FTOPS10,< SCTCCR::MOVEI T1,SCNHSZ ;HASH TABLE SIZE OPSTR ,IBMXA,+IBBLK ;PLUS NUMBER OF NODES IN AREA ADDI T1,1 ;AND AN EXTRA WORD FOR NODE 0 RET ;AND RETURN >; END IFN FTOPS10 SUBTTL SCTINI - Session Control Initialization ;SCTINI - Session Control Initialization ; ; Call: ; IBBLK filled in ; ; Return: ; RET ;COULDN'T INITIALIZE DUE TO RESOURCE FAILURE ; RETSKP ;INITIALIZED ; ; Uses: T1-T4 ; ; Context: ; Process XSWAPCD SCTINI: TRACE SC, ;Initialize node name/number database, then call NSP to initialize itself ; and ROUTER CALL SCTNIN ;Initialize node name/number database RET ; -failed, return error CALLRET NSPINI ;NSP, you can fly now! XRESCD ;Back to resident code SUBTTL SCTPSQ - Grant a PSI interrupt ;SCTPSQ - Grant a PSI interrupt for user ; ; Call: T1/ SJB Pointer ; ; Return: ; RET ;IF NOTHING IN QUEUE ; RETSKP ;IF FOUND AN SLB QUEUED ; T1+T2/ STRUCTURE PS, SEE SCPAR ; ; Uses: ;Note that this routine is not under the interlock ;Note that if we use T5 or T6 in this routine, we have to save ;them for caller. XRENT SCTPSQ ;Run in extended resident code D36OFF ;#AVOID PROBLEMS WITH SLPSI FLAG DEQUE T4,SJ.PSQ(T1),SL.NXP,SCTPQ1 ;#ANYTHING ON THE PSI Q? SETZRO SLPSI,(T4) ;#NOT ON THE PSI Q ANY MORE D36ON IF1,IFN PS.MOR, MOVE T3,T1 ;GET POINTER TO SJB LOAD T1,SLSST,(T4) ;NO INTERLOCK, DON'T CALL CHKSTS STOR T1,PSSTS,+T1 ;STORE FOR CALLER (IN T2) TMNE QHBEG,+SJ.PSQ(T3) ;MORE SLBS ON PSI Q? TXO T1,PSMOR ;YES, SET THE MORE FLAG FOR CALLER LOAD T3,SLCHN,(T4) ;GET CHANNEL NUMBER STOR T3,PSCHN,+T1 LOAD T3,SLPSM,(T4) ;GET PSI MASK STOR T3,PSPSM,+T1 RETSKP ;SUCCESS RETURN ;Here if DEQUE found nothing SCTPQ1: D36ON RET SUBTTL SCTSTM - Check Active Connect Timers for Expiration ;SCTSTM - Check active connect timers for expiration ; ; Call: ; With nothing special ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCTSTM: SAVEAC ;SAVE THE JOB AND LINK BLOCK POINTERS LOAD SA,QHBEG,+SCTSJQ ;POINT TO THE FIRST SJB TRNA SCTST1: LOAD SA,SJNXT,(SA) ;GET THE NEXT SJB IN LIST JUMPE SA,RTN ;NO MORE, JUST RETURN JE SJCTA,(SA),SCTST1 ;IF THERE ARE NO TIMERS ACTIVE FOR JOB ; JUST LOOK AT THE NEXT GUY LOAD P1,SJCHC,(SA) ;GET THE COUNT OF ENTRIES IN SLB TABLE LOAD P2,SJCHT,(SA) ;POINT TO THE SLB TABLE SCTST2: SKIPN SL,(P2) ;DO WE HAVE AN SLB? JRST SCTST3 ;NO, CHECK THE NEXT ONE JN ,(SL),SCTST3 ;YES, IGNORE IF ALREADY CLOSING LOAD T1,SLSTA,(SL) ;GET THE STATE IFSTATE T1,CR,SCTST4 ;CHECK THE INCOMING CONNECT TIMER IFSTATE T1,CS,SCTST5 ;CHECK THE OUTGOING CONNECT TIMER SCTST3: ADDI P2,1 ;INCREMENT SLB POINTER SOJG P1,SCTST2 ;ANY MORE LEFT? JRST SCTST1 ;NO, CHECK THE NEXT JOB ;Here with a SLB in CR state. Check the incoming timer for expiration. SCTST4: CALL DNGTIM ;GET THE CURRENT TIME OPSTR ,SLCTM,(SL) ;FIND TIME SINCE TIMER STARTED CAMGE T1,SCTINT ;HAS IT EXPIRED? JRST SCTST3 ;NO, LOOK AT NEXT SLB CALL TMRREJ ;YES, SEND REJECT JRST SCTST3 ;ALLOCATION FAILURE, LEAVE TIMER RUNNING CALLRET SCTST6 ;REJECT, STOP TIMERS AND CHECK THE NEXT ONE ;Here with a SLB in CS state. Check the outgoing timer for expiration. SCTST5: CALL DNGTIM ;GET THE CURRENT TIME OPSTR ,SLCTM,(SL) ;FIND TIME SINCE TIMER STARTED CAMGE T1,SCTOTT ;HAS OUTGOING TIMER EXPIRED? JRST SCTST3 ;NO, LOOK AT NEXT SLB MOVX T1,RSNNRO ;YES, GET 'NO RESPONSE FROM OBJECT' REASON CODE STOR T1,SLRSN,(SL) ;STORE REASON FOR INTERESTED CALLER NEWSTATE RJ ;TELL USER LINK IS REJECTED SCTST6: CALL STPTMR ;STOP THE TIMERS JRST SCTST3 ; AND CHECK THE NEXT ONE SUBTTL SCTSEC - Once-a-second service for SCLINK ;SCTSEC - Once-a-second service for Session Control ; ; Once a second the following things are checked: ; connect timers ; slb's that can be freed ; ; Call: ; with nothing, every second ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 XRESCD SCTSEC: IFN FTOPS10 < SEC1 ;RUN ALL OUR JUNK IN SECTION 1 > SAVEAC SETOM SCTJFF ;TELL SCTULK WE NEED SECOND SERVICE CALLRET SCTLCF ;GET INTERLOCK, CALL SCTSES SCTSES: SKIPE SCTCTA ;ARE THERE ANY OUTSTANDING CONNECTS? CALL SCTSTM ;SCAN FOR RUNNING CONNECT TIMERS ;We must not continue processing after getting a no-resources return ;because the procedure which gave that return put the current port ;back on the second-request queue. If we were to continue along that ;queue, we would visit that port over and over forever. SCTSS1:!DEQUE SL,SCTJFQ,SL.JFQ,RTN ;RETURN WHEN Q EMPTY SETZRO SLJFR,(SL) ;NO LONGER ON THE SECOND-REQ Q TMNN SLFSL,(SL) ;SKIP IF SLB NEEDS TO BE FREED Repeat 0,< ;See comment below and at SNDDRQ JRST SCTSS2 ;NO, SEE IF WE NEED DRQ CHECK > Repeat 1,< JRST SCTSS1 ;Should never happen, but if! just loop back > CALL SCTSFR ;YES, GET RID OF IT CALLRET SCTRFJ ;LEAVE, REQUESTING SERVICE AGAIN JRST SCTSS1 ; AND CHECK THE NEXT CHANNEL ;This code to resend DRQ is commented out since it is never used. ; See comment at SNDDRQ for more information Repeat 0,< SCTSS2: OPSTR ,SLDRR,(SL) ;ARE THERE ANY DATA REQUESTS? CALL SCTJDR ;YES, RESEND THE DATA REQUESTS CALLRET SCTRFJ ;LEAVE, REQUESTING SERVICE AGAIN JRST SCTSS1 ;GET NEXT SLB THAT NEEDS SERVICE > ;Here to free an SLB that we are finished with SCTSFR: JN SLBSY,(SL),RTN ;CAN'T FREE IT NOW, TRY LATER CALL FRESLB ;CLEAN UP THAT ONE. RETSKP ;SUCCESS Repeat 0,< ;Here with a SLB that needs to have DRQs resent. SCTJDR: TXZ T2,MBOTH ;ON THE NORMAL SUB-LINK CALL SNDDRQ ;SEND THOSE DATA REQUESTS RET ;CAN'T, LET CALLER HANDLE THIS SETZRO SLDRR,(SL) ;WE SENT THE DATA REQUESTS RETSKP ; AND RETURN > ;End repeat 0 SUBTTL SCTRFJ - Request Second Service for a Link ;SCTRFJ - Request Second Service for a Link ; ; Call: ; SL/ The SLB for which service is requested ; ; Return: ; RET ;ALWAYS WITH ALL TEMP ACS SMASHED ; ; Uses: T1 SCTRFJ: MOVX T1,SLJFR ;GET QUEUED-FOR-SERVICE FLAG TDNE T1,SL.JFR(SL) ;ALREADY QUEUED? RET ;YES, DON'T Q AGAIN IORM T1,SL.JFR(SL) ;NO, WILL BE NOW THOUGH ENDQUE SL,SCTJFQ,SL.JFQ,T1 RET SUBTTL SCTL's Interlock -- Queuing Version ;SCTLCQ - Interlock routine for interrupt level callers ; ; Call: ; T1/ Address of processor to call with the interlock ; MB/ Pointer to Message Block with arguments stored ; or zero if called from SCTJIF ; ; Return: ; RET ;ALWAYS WITH ALL TEMP ACS SMASHED ; ; Uses: T1 ; ;If it could not get the interlock, it queues the message block with its ;arguments. When the interlock is given up, the queue is checked and ;if it has a message on it, it will service it. SCTLCQ: STOR T1,MBPRC,(MB) ;SAVE THE PROCESSING PROCEDURE D36OFF ;GET GLOBAL INTERLOCK FOR ENDQUE BELOW AOSN SCTLOK ;TEST AND SET THE INTERLOCK JRST SCTLQ1 ;GO PROCESS, NOW THAT WE HAVE THE LOCK ;Here when we have to queue the message and dismiss. ENDQUE MB,SCTPRQ,MB.NXT,T1 ;QUEUE THE MESSAGE D36ON ;TURN INTERLOCK OFF RET ;Here to process the message now. SCTLQ1: APRID SCTLKO ;SET THE OWNER OF THE INTERLOCK IFN FTOPS20,< CONSO PI,1B ;AT DTE PI LEVEL? CSKED ;NO, ASSURE WE GET THROUGH THIS QUICKLY >;END IFN FTOPS20 ;MUSTN'T CALL CSKED AT INTERRUPT LEVEL D36ON ;TURN INTERLOCK OFF LOAD T1,MBAR1,(MB) ;GET THE FIRST ARGUMENT LOAD T2,MBAR2,(MB) ; SECOND LOAD T3,MBAR3,(MB) ; THIRD OPSTR ,MBPRC,(MB) ;GET THE PROCESSOR CALLRET SCTULK ;DO THE UNLOCK CHECKS SUBTTL SCTL's Interlock -- Waiting Version ;SCTLCW - Interlock routine for process level callers ; ; Call: ; T1/ Address of processor to call with the interlock ; MB/ Pointer to Message Block with arguments stored ; ; Return: ; RET ;ALWAYS WITH ALL TEMP ACS SMASHED ; ; Uses: T1 ; ;This version of the interlock will spin on SCTLOK until it is freed. ;This is to be called only from process level, thus it will only spin ;if another process or interrupt level user has it on another processor. ;It will not fight with any other process level users on this processor ;since only one can be active on any one processor at any one time. ; ;Note that SCTLOK must be uncached if this is a multiprocessor system. SCTLCW: SAVEAC ;TEMPORARY UNTIL AC-TRASHING BUG FOUND. ;Even though we don't really have to store the routine address in ;the message block here, we do because its a convenient debugging tool. STOR T1,MBPRC,(MB) ;SAVE THE PROCESSING PROCEDURE IFN FTOPS10,< SCTLW1: SKIPGE SCTLOK ;TEST INTERLOCK TO SEE IF WE HAVE A CHANGE AOSE SCTLOK ;TEST AND SET THE INTERLOCK JRST SCTLW1 ;ITS LOCKED, SPIN UNTIL ITS FREED APRID SCTLKO ;SET THE OWNER OF THE INTERLOCK >;END IFN FTOPS10 ; CAN ONLY BE COMPETING WITH ANOTHER ; PROCESSOR ON TOPS10 IFN FTOPS20,< SCTLW1: CSKED ;ASSURE WE GET THROUGH THIS QUICKLY AOSN SCTLOK ;TEST AND SET THE INTERLOCK JRST SCTLW3 ;ITS OK, GO USE IT ECSKED ;NO, UNDO THE CSKED ABOVE. SKIPE INSKED ;IN USE, ARE WE AT SCHEDULAR LEVEL? JRST SCTLW2 ;YES MOVE T1,[MSEC1,,SCTLWB] ;No, set up scheduler test MDISMS ;WAIT FOR COMPETING PROCESS TO FINISH JRST SCTLW1 ;OK, LETS TRY AGAIN ;Must run in section 1 since the data structure used to keep the scheduler ; test routine is currently only 18-bits wide. RESCD SCTLWB: SKIPL SCTLOK ;IS SESSION CONTROL LOCK FREE YET? JRST (T4) ;NO, SLEEP ON JRST 1(T4) ;YES, WAKE UP FORK XRESCD SCTLW2: BUG.(CHK,SCTBWK,SCLINK,SOFT,,,< Cause: The DECnet entry point SCTNSF has been called from scheduler level when the Session Control interlock was locked. Action: All scheduler level routines which call SCTNSF should first check SCTLOK. If SCTLOK is not -1, then the caller should wait for the next scheduler cycle before calling SCTNSF. Inspect the stack to find out who the offender is. >) RET ;LET CALLER WORRY ABOUT NO DECNET ACTION SCTLW3: >;END IFN FTOPS20 ;Here to process the message now. LOAD T1,MBAR1,(MB) ;GET THE FIRST ARGUMENT LOAD T2,MBAR2,(MB) ; SECOND LOAD T3,MBAR3,(MB) ; THIRD OPSTR ,MBPRC,(MB) ;GET THE PROCESSOR CALLRET SCTULK ;DO THE UNLOCK CHECKS SUBTTL SCTL's Interlock -- Flag Version ;SCTLCF - Interlock routine for Flagged Routines ; ; Call: ; T1/ Address of processor to call with the interlock ; SCTJFF or SCTUCF set non-zero for SCTULK ; ; Return: ; RET ;ALWAYS WITH ALL TEMP ACS SMASHED ; ; Uses: T1 ; SCTLCF: ;We have no message block here, so we cannot store any processor ;address. Caller has set a SCTxxF flag instead. ; ;All we have to do here is call the unlocker, for it will check ;the Service flags SCTJFF and SCTUCF. ; IFN FTOPS20,< CONSO PI,1B ;AT DTE PI LEVEL? CSKED ;NO, ASSURE WE GET THROUGH THIS QUICKLY >;END IFN FTOPS20 ;MUSTN'T CALL CSKED AT INTERRUPT LEVEL AOSE SCTLOK ;TEST AND SET THE INTERLOCK IFN FTOPS20,< IFNSK. CONSO PI,1B ;NOT FREE, LEAVE NOW. AT DTE PI LEVEL? ECSKED ;NO, UNDO CSKED FROM ABOVE. RET ;LEAVE. ENDIF. >;END IFN FTOPS20 IFN FTOPS10,< RET ;NOT FREE, LEAVE NOW >;END IFN FTOPS10 APRID SCTLKO ;SET THE OWNER OF THE INTERLOCK CALLRET SCTULK ;AND DO THE UNLOCK CHECKS. SUBTTL SCTULK - SCTL's Interlock -- Unlock Checks ;SCTULK - All interlock routines call SCTULK to unlock ; ; Call: ; No args in registers ; Called with the Session Control Interlock still on ; ; Return: ; RET ;ALWAYS WITH ALL TEMP ACS SMASHED ; ; Uses: T1 ; SCTULK: SAVEAC ;SAVE SOME ACS ;It is OK to have the window between SKIPE SCTJFF and SETZM SCTJFF ;since the worst that can happen is that we lose a second interrupt. ;If we are so close to the next second when we respond to the last one ;that we fall into the window, its just as well not to introduce more ;overhead by closing the window! SCTUL1: SETZ T1, ;LOAD UP A ZERO TO TO TURN FLAG OFF EXCH T1,SCTJFF ;NEED TO DO SKIPE T1 ; CLOCK LEVEL STUFF? CALL SCTSES ;YES, GIVE SECOND SERVICE SETZ T1, ;LOAD UP A ZERO TO TO TURN FLAG OFF EXCH T1,SCTUCF ;NEED TO DEAL WITH SKIPE T1 ; CONGESTION RELIEF? CALL SCIUCG ;YES, DO SO D36OFF ;TURN OF THE INTERRUPTS DEQUE MB,SCTPRQ,MB.NXT,SCTUL2 ;DEQUEUE MSG FROM PROCESS Q D36ON ;UNDO THE D36OFF LOAD T1,MBAR1,(MB) ;GET THE FIRST ARGUMENT LOAD T2,MBAR2,(MB) ; SECOND LOAD T3,MBAR3,(MB) ; THIRD OPSTR ,MBPRC,(MB) ;GET THE PROCESSOR JRST SCTUL1 ;PROCESS THE NEXT ONE SCTUL2: SETOM SCTLKO ;CLEAR THE INTERLOCK OWNER SETOM SCTLOK ;TURN OFF THE INTERLOCK D36ON ;UNDO THE D36OFF IFN FTOPS20,< CONSO PI,1B ;AT DTE PI LEVEL? ECSKED ;NO, UNDO THE CSKED WE DID BEFORE >;END IFN FTOPS20 ;MUSTN'T CALL ECSKED AT INTERRUPT LEVEL RET ; AND RETURN SUBTTL NSP. -- Function Dispatch Table ;Define some macros to set up the dispatch table for the NSP. UUO functions. DEFINE INIDSP(PREFIX,LABEL,START<0>,FSTNAM),< PREFIX''FSTNAM==START %%%CTR==START-1 DEFINE DSP(NAME),< %%%CTR==%%%CTR+1 ;;INCREMENT THE COUNTER IFN <%%%CTR-PREFIX''NAME>,< PRINTX ?Function PREFIX''NAME in SCLINK not in PRINTX ? the same order as in SCPAR.UNV PASS2 END> IFIW > ;;ENTRY POINT FOR INDIRECT CALL DEFINE ENDDSP(MAXNAM),< PREFIX''MAXNAM==%%%CTR> > ;This is the table which is used to find the entry vector to for a specific ;NSP. function. Symbols are also defined in the for .NSFxx for each of the ;function types. NSFNT: ;START OF THE TABLE INIDSP .NSF,NSF,0 DSP RE ;RESET ALL CHANNELS DSP EA ;ENTER ACTIVE STATE DSP EP ;ENTER PASSIVE STATE DSP RI ;READ CONNECT INFORMATION DSP AC ;ACCEPT THE CONNECT DSP RJ ;REJECT THE CONNECT DSP RC ;READ CONNECT CONFIRM INFORMATION DSP SD ;SYNCHRONOUS DISCONNECT DSP AB ;ABORT DSP RD ;READ DISCONNECT DATA DSP RL ;RELEASE THE CHANNEL DSP RS ;READ THE CHANNEL STATUS DSP IS ;SEND INTERRUPT DATA DSP IR ;RECEIVE INTERRUPT DATA DSP DS ;SEND NORMAL DATA DSP DR ;RECEIVE NORMAL DATA DSP SQ ;SET QUOTAS DSP RQ ;READ QUOTAS DSP JS ;SET JOB QUOTAS DSP JR ;READ JOB QUOTAS DSP PI ;SET PSI REASON MASK ENDDSP SUBTTL NSP. -- Wait Check Tables -- Definitons ;The following definitions are for the wait check tables. The tables ;are used to find out if session control should wait for a condition ;when the user has set the NS.WAI bit. Each table is indexed by ;function number and returns in T1 a value which means one of: XP CW.ERR,0 ;GIVE THE USER A UNEXPECTED STATE ERROR XP CW.NWA,1 ;DON'T BOTHER WAITING XP CW.WAI,2 ;WAIT FOR SOME MORE TIME XP CW.SAT,3 ;WAIT FOR SATISFYING COND BEFORE PROCEEDING XP CW.DAT,4 ;WAIT FOR MORE DATA TO BE SENT BEGSTR CF ;SEE CHKFOR, BELOW FIELD IFI,1 ;THE SIGN BIT IS RESERVED FOR IFIW FLG FILLER 11 ;ROOM FOR SOME FUNCTION FLAGS FIELD CHN,1 ;SET IF A CHANNEL IS REQ'D FOR THIS FCN HWORD TST ;LOCAL ADDRESS OF TESTER FUNCTION ENDSTR XP CHNREQ,1 ;CHANNEL REQUIRED FOR FUNCTION XP NOCHAN,0 ;NO CHANNEL REQ'D ;Define some macros to set up the table. DEFINE INITAB(START<0>),< %%%CTR==START-1 DEFINE CHKFOR(func,reqchn,tester),< %%%CTR==%%%CTR+1 IFN <%%%CTR-.NSF'func>,< PRINTX ?NSP. Function .NSF'func in SCLINK not in PRINTX ? the same order as in SCPAR.UNV PASS2 END> ;;The following doubtful format is designed to prevent MACRO from ;;going Polish and thus encountering its bugs. IFIW reqchn,tester ;SEE BEGSTR CF, ABOVE > DEFINE ENDTAB,< PURGE CHKFOR,...TST >> ;CHKSTA checks for one of STATES, returning successfully if in WAISTA ;and the wait bit is off. DEFINE CHKSTA(SUCSTA,WAISTA),<[IFSTATE T2,,NOWAIT IFNB ,< IFSTATE T2,,WAITMORE > JRST BLEWIT] > ;CHKSTE checks for one of STATES, returning an error if in WAISTA ;and the wait bit is off. DEFINE CHKSTE(SUCSTA,WAISTA),<[ IFSTATE T2,,NOWAIT IFNB ,< JE SAWAI,(SA),BLEWIT IFSTATE T2,,WAITMORE > JRST BLEWIT] > ;CHKBIT checks for on of the .NSxxx status bits. ;CONDSTATES are conditional states, in which we will allow a data or ;interrupt read only if there is something queued now, else the state ;is illegal. We don't want the poor user who sets the wait bit to hang ;in DR or DC state forever! DEFINE CHKBIT(BIT,STATES,CONDSTATES),<[ IFB , IFB ,IFNSTATE T2,,BLEWIT IFNB ,IFNSTATE T2,,BLEWIT TXNE T1,NS'BIT JRST NOWAIT IFNB ,IFNSTATE T2,,BLEWIT JRST WAITMORE] > SUBTTL NSP. -- Wait check tables -- "Before" NSP. table ;The following is the wait table which is checked before the NSP. ;function is called. This table is indexed by function type and ;returns CW.xxx as explained above. ;*Note* The macro seems to rely on the address argument not going ; polish. As SCLINK now runs in section 6, this may happen if you ; change anything below, including moving any of the routines (for ; instance NOWAIT) to another psects. Beware! SCTWTB: INITAB CHKFOR RE,NOCHAN,NOWAIT CHKFOR EA,NOCHAN,NOWAIT CHKFOR EP,NOCHAN,NOWAIT IFN FTOPS10, ;SUCCESS STATE,WAITMORE STATE IFN FTOPS20, CHKFOR AC,CHNREQ,CHKSTA(CR) ;SUCCESS STATE,WAITMORE STATE CHKFOR RJ,CHNREQ,CHKSTA(CR) ;SUCCESS STATE,WAITMORE STATE IFN FTOPS10, ;ERROR IF CS STATE AND NS.WAI=0 IFN FTOPS20, CHKFOR SD,CHNREQ,CHKSTA(RN) ;SUCCESS STATE,WAITMORE STATE CHKFOR AB,CHNREQ,CHKSTA(RN) ;SUCCESS STATE,WAITMORE STATE IFN FTOPS10,)> ;SUCCESS STATE,WAITMORE STATE IFN FTOPS20, CHKFOR RL,CHNREQ,NOWAIT CHKFOR RS,CHNREQ,NOWAIT CHKFOR IS,CHNREQ,CHKBIT(IDR,) CHKFOR IR,CHNREQ,CHKBIT(IDA,,) CHKFOR DS,CHNREQ,CHKBIT(NDR,) CHKFOR DR,CHNREQ,CHKBIT(NDA,,) CHKFOR SQ,CHNREQ,NOWAIT CHKFOR RQ,CHNREQ,NOWAIT CHKFOR JS,CHNREQ,NOWAIT CHKFOR JR,CHNREQ,NOWAIT CHKFOR PI,CHNREQ,NOWAIT ENDTAB SUBTTL NSP. -- Wait check tables -- "After" NSP. table ;The following is the wait table which is checked after the NSP. function ;is called. This table is indexed by function type and returns CW.xxx ;*Note* See comment at SCTWTB about changing the table SCTWTA: INITAB CHKFOR RE,NOCHAN,NOWAIT CHKFOR EA,CHNREQ,CHKSTA(RN,CS) ;SUCCESS STATE,WAITMORE STATE CHKFOR EP,CHNREQ,CHKSTA(CR,CW) ;SUCCESS STATE,WAITMORE STATE CHKFOR RI,CHNREQ,NOWAIT CHKFOR AC,CHNREQ,CHKSTA(RN) ;SUCCESS STATE,WAITMORE STATE CHKFOR RJ,CHNREQ,NOWAIT CHKFOR RC,CHNREQ,CHKSTA(RN,CS) ;SUCCESS STATE,WAITMORE STATE CHKFOR SD,CHNREQ,CHKSTA(DC,DS) ;SUCCESS STATE,WAITMORE STATE CHKFOR AB,CHNREQ,CHKSTA(DC,DS) ;SUCCESS STATE,WAITMORE STATE CHKFOR RD,CHNREQ,NOWAIT CHKFOR RL,CHNREQ,NOWAIT CHKFOR RS,CHNREQ,NOWAIT CHKFOR IS,CHNREQ,NOWAIT CHKFOR IR,CHNREQ,NOWAIT CHKFOR DS,CHNREQ,WAITDAT CHKFOR DR,CHNREQ,WAITSAT CHKFOR SQ,CHNREQ,NOWAIT CHKFOR RQ,CHNREQ,NOWAIT CHKFOR JS,CHNREQ,NOWAIT CHKFOR JR,CHNREQ,NOWAIT CHKFOR PI,CHNREQ,NOWAIT ENDTAB SUBTTL NSP. -- Wait check tables -- Routines ;The following routines perform the correct action for the function. They ;are dispatched to by the "before" and "after" tables. ;Don't wait any longer. NOWAIT: MOVX T1,CW.NWA RET ;Error (possibly expected) occured. BLEWIT: MOVX T1,CW.ERR RET ;Wait some more. WAITMO: MOVX T1,CW.WAI RET ;Loop to do it again. WAITSAT: MOVX T1,CW.SAT RET ;Wait if we are to get more data. WAITDAT: MOVX T1,CW.DAT RET SUBTTL NSP. -- SCTNSF - The Entry to SCLINK from SCMUUO ;SCTNSF - Perform a NSP. UUO function ; ; Call: ; T1/ Pointer to Message Block in SA format (See BEGSTR SA in D36PAR) ; ; Return: ; RET ;ALWAYS WITH SJERR CONTAINING A ZERO FOR SUC. ; ; AND A NON-ZERO ERROR CODE FOR FAILURES ; ; Uses: T1-T6 ; ;We return the updated user arguments in the SJB (or error code on a ;failure). ; ;Note: It is assumed that SCJSYS, or whatever equivalent, has range ;and privilege checked all of the user arguments. The arguments are ;all in either the SAB portion of the message block or in internal ;blocks pointed to by the SAB (SACBP and SASBP). XRENT SCTNSF SAVEAC ;SAVE ALMOST ALL ACS SKIPG SA,T1 ;DID HE SUPPLY A MESSAGE BLOCK? SCERR %NEABE,SCTNIE, SETZRO SAERR,(SA) ;INITIALIZE THE ERROR LOCATION LOAD T1,SAAFN,(SA) ;GET THE FUNCTION CAIL T1,.NSFMN ;RANGE CHECK CAILE T1,.NSFMX ; THE FUNCTION CODE SCERR %NEILF,SCTNIE, ;... ;... ;The code on this page and the following page is a series of coroutines. The ;Session Control interlock will only interlock a whole routine (to reduce the ;possibility of interlock screwups). The routines on this page call ;coroutines on the following page (only) via the Session Control interlock. ;We start on this page, not owning the Session Control interlock. The first ;interlocked coroutine called is SCTNIS (Setup). SCTNIS will do what it can, ;then, when it needs to do something outstide of the Session Control ;interlock, it will put the address of one of the labels on this page into ;MBPRC,(SA) and then RET. The RET takes us back to SCTULK (Session Control ;unlock) where we process any Session Control requests which may have been ;queued. Then control returns to this page after the original coroutine call. ;Each of the coroutines on this page has OPSTR ,MBPRC,(SA) after ;its call the the Session Control interlock. ;Control leaves this page either via a coroutine call to an interlocked ;routine on the next page or by a RET to SCTNSF's caller. MOVE MB,SA ;INTERLOCK ROUTINE NEEDS MB SET UP XMOVEI T1,SCTNIS ;INTERLOCKED SETUP ROUTINE CALL SCTLCW ;CALL INTERLOCKED SETUP ROUTINE OPSTR ,MBPRC,(SA) ;CALL COROUTINE CHOSEN BY SCTNIS ;Here to HIBER without the interlock before calling the BEFORE-function ;coroutine (again). SCTNS1: LOAD T1,SASJB,(SA) ;PASS PTR TO SJB IN T1 TO @SAHBA(SA) LOAD T2,SAACH,(SA) ;PASS CHANNEL # IN T2 MOVE T3,SA ;PASS SAB ADDR IN T3 (SIGH) OPSTR ,SAHBA,(SA) ;CALL THE HIBER'ER MOVE MB,SA ;MB MUST BE SET UP FOR INTERLOCK XMOVEI T1,SCTNIB ;CALL THE "BEFORE" INTERLOCKED PROCESS CALL SCTLCW ; AFTER WE GET THE INTERLOCK OPSTR ,MBPRC,(SA) ;CALL COROUTINE CHOSEN BY SCTNIB ;Here to HIBER without the interlock before calling the AFTER-function ;coroutine (again). SCTNS2: LOAD T1,SASJB,(SA) ;PASS PTR TO SJB IN T1 TO @SAHBA(SA) LOAD T2,SAACH,(SA) ;PASS CHANNEL # IN T2 MOVE T3,SA ;PASS SAB ADDR IN T3 (SIGH) OPSTR ,SAHBA,(SA) ;CALL THE HIBER'ER MOVE MB,SA ;MB MUST BE SET UP FOR INTERLOCK XMOVEI T1,SCTNIA ;CALL THE "AFTER" INTERLOCKED PROCESS CALL SCTLCW ; AFTER WE GET THE INTERLOCK OPSTR ,MBPRC,(SA) ;CALL COROUTINE CHOSEN BY SCTNIA ;Here to give up the interlock and call the system schedular to give others ;a chance between segments of a long message. SCTNS3: IFN FTOPS10,< MCALL (RG,MSEC1,INTLVL##) ;ARE WE AT UUO LEVEL? MCALL (RG,MSEC1,SCDCHK##) ;YES, LET OTHER USERS HAVE A CHANCE >; END IFN FTOPS10 MOVE MB,SA ;MB MUST BE SET UP FOR INTERLOCK XMOVEI T1,SCTNIB ;CALL THE "BEFORE" PROCESS AGAIN CALL SCTLCW ; AFTER WE GET THE INTERLOCK OPSTR ,MBPRC,(SA) ;CALL COROUTINE CHOSEN BY SCTNIB ;All of these routines have the interlock. These routines may only go ;back to non-interlocked code by the return address in MBPRC. ;Setup the SLB. SCTNIS: LOAD T1,SAAFN,(SA) ;GET THE FUNCTION CODE SETO SL, ;ASSUME WE HAVE NO SLB (-1 IS 'UNASSIGNED') JE CFCHN,+SCTWTB(T1),SCNIS1 ;IF NO CHANNEL IS REQ'D, ; LEAVE SL AS 'UNASSIGNED' (-1) LOAD T1,SAACH,(SA) ;GET THE CHANNEL NUMBER LOAD T2,SASJB,(SA) ;POINT TO THE JOB BLOCK CALL FNDSLB ;FIND THE CORRESPONDING SLB SCERR %NEBCN,SCTNIE, SETONE SLBSY,(SL) ;NO ONE MAY FREE THIS SLB LOAD T1,SLUID,(SL) ;GET THE SLB'S SERIAL NUMBER STOR T1,SAUID,(SA) ; AND STASH IT IN THE SAB SCNIS1: STOR SL,SASLB,(SA) ;STORE THE SLB POINTER JRST SCNIB1 ;WE ALREADY HAVE THE INTERLOCK ;Do the BEFORE-function state checking and perform the function. SCTNIB: LOAD SL,SASLB,(SA) ;GET POINTER TO LINK BLOCK SCNIB1: JUMPL SL,[SETZB T1,T2 ;NO STATUS IF NO SLB (EA & EP FUNCTS) JRST SCNIB3] ;GO SEE IF WE CAN MAKE ONE LOAD T1,SLUID,(SL) ;IS THIS SLB POINTER OPSTR ,SAUID,(SA) ; STALE ? JRST SCNIB2 ;NO. CONTINUE SETO SL, ;YES. LOSE THIS POINTER. SCERR %NEBCN,SCTNIE, ;FAIL. SCNIB2: LOAD T1,SLSST,(SL) ;GET CURRENT LINK STATUS LOAD T2,NSSTA,+T1 ;PUT JUST THE STATE IN T2 SCNIB3: LOAD T3,SAAFN,(SA) ;GET THE FUNCTION BACK CALL @SCTWTB(T3) ;SEE IF WE SHOULD WAIT A WHILE CALLRET @.+1(T1) ;BRANCH ON SCTWTB'S RETURN CODE IFIW ;CW.ERR - ERROR RETURN TO MONUSER IFIW ;CW.NWA - NO WAIT, GO DO FUNCTION IFIW ;CW.WAI - WAIT IF MONUSER SO REQUESTED ;Here to call the function processor SCNIB4: LOAD T1,SAAFN,(SA) ;GET THE FUNCTION TYPE CALL @NSFNT(T1) ;CALL FUNCTION PROCESSOR JRST SCTNIE ;REPORT THE ERROR IF NEEDED STOR SL,SASLB,(SA) ;SAVE THE POSSIBLY NEW SLB FOR AFTER CHECKING JRST SCNIA1 ;DON'T GET INTERLOCK, WE HAVE IT ;Here when function not yet complete to see if we should wait SCNIB5: TMNN SAWAI,(SA) ;MONUSER ASK US TO WAIT FOR FCN COMPLETION? JRST SCTNIX ;NO, RETURN TO MONUSER NOW XMOVEI T2,SCTNS1 ;YES, DO OUR HIBER STOR T2,MBPRC,(SA) ;STORE COROUTINE ADDRESS RET ;BACK TO NON-INTERLOCKED CODE ;Here to do the AFTER-function checking. SCTNIA: LOAD SL,SASLB,(SA) ;GET POINTER TO LINK BLOCK SCNIA1: JUMPL SL,SCTNX1 ;IF WE DON'T HAVE A SLB, JUST LEAVE ;Note that none of the NSFxx routines call CHKSTS when they change ;a status other than the link state, because they assume that we will ;call CHKSTS from here. CALL CHKSTS ;UPDATE SLB'S LINK STATUS WORD LOAD T1,SLSST,(SL) ;GET CURRENT LINK STATUS LOAD T2,NSSTA,+T1 ;PUT JUST THE STATE IN T2 LOAD T3,SAAFN,(SA) ;GET THE FUNCTION CODE BACK CALL @SCTWTA(T3) ;SEE IF WE SHOULD WAIT A WHILE CALLRET @.+1(T1) ;BRANCH ON ANSWER FROM SCTWTA IFIW ;CW.ERR - ERROR RETURN REQUIRED IFIW ;CW.NWA - FCN COMPLETE, RETURN TO MONUSER IFIW ;CW.WAI - FCN NOT COMPLETE, WAIT IFIW ;CW.SAT - CHECK FOR I/O SATISFIED IFIW ;CW.DAT - BRIEF PAUSE BETWEEN MSG SEGMENTS ;Here if function not yet complete, see if we have to wait SCNIA2: TMNN SAWAI,(SA) ;DID MONUSER ASK TO WAIT FOR FCN TO COMPLETE? JRST SCTNIX ;NO, RETURN TO USER NOW XMOVEI T1,SCTNS2 ;YES, POINT TO HIBER ROUTINE, OUT-OF-INTERLOCK STOR T1,MBPRC,(SA) ;TELL CO-ROUTINE WHERE TO GO TO HIBER RET ; AND RETURN TO TO HIBER ;Here to see if .NSFDR function is complete, wait if so requested SCNIA3: TMNN SAWAI,(SA) ;MONUSER WANT US TO WAIT FOR I/O COMPLETE? JRST SCTNIX ;NO, RETURN TO MONUSER NOW TMNN SASAT,(SA) ;YES, IS THE I/O SATISFIED YET? JRST SCNIB2 ;NO, GO BACK AND TRY AGAIN JRST SCTNIX ;YES, RETURN TO MONUSER NOW ;Here to free the Session Control interlock briefly between message segments ;so that we don't keep the lock too long when sending long messages. SCNIA4: TMNE SASAT,(SA) ;I/O SATISFIED YET? JRST SCTNIX ;YES, RETURN TO CALLER NOW LOAD T1,SLSST,(SL) ;NO, CAN WE SEND ANOTHER SEGMENT TXNE T1,NSNDR ; NOW? (ONLY NORMAL DATA CAN HAVE MULT SEGS) JRST SCNIA5 ;YES TMNN SAWAI,(SA) ;NO, USER WANT TO BLOCK? JRST SCTNIX ;NO, RETURN TO USER NOW JRST SCNIB2 ;YES, GET BEFORE PROCESSOR TO BLOCK SCNIA5: XMOVEI T1,SCTNS3 ;RELEASE INTERLOCK A BIT STOR T1,MBPRC,(SA) ; THEN DO THE NEXT SEGMENT RET ;RETURN FROM THE SCTL INTERLOCK ;Here to exit with the normal return. SCTNIX: SETZRO SAAST,(SA) ;START WITH NO STATUS SO THAT A RESET ; FUNCTION WILL RETURN A ZERO AS STATUS JUMPL SL,SCTNX1 ;IF WE DON'T HAVE AN SLB, PUNT LOAD T1,SLSST,(SL) ;GET CURRENT LINK STATUS STOR T1,SAAST,(SA) ;STORE STATUS FOR USER AS WE LEAVE SETZRO SLBSY,(SL) ;WE'RE DONE WITH SLB NOW, IF NEED BE ; IT MAY BE FREED SCTNX1: XMOVEI T1,RTN ;JUST RETURN WHEN DONE STOR T1,MBPRC,(SA) ;STORE THAT AS THE PROCEDURE RET ;RETURN TO OTHER CO-ROUTINE ;Here to report the Unexpected State errors. We will give the error ;based upon the state that was unexpected. SCTNIU: CALL CHKSTS ;UPDATE SLB'S LINK STATUS WORD LOAD T1,SLSST,(SL) ;GET CURRENT LINK STATUS LOAD T2,NSSTA,+T1 ;GET THE STATE IFSTATE T2,,SCTNIR ;IF WE'RE IN DR OR RJ GIVE REASON ERROR ; MESSAGE ADJBP T2,ERRSBP ;INDEX INTO UNEXPECTED STATE CODE TABLE LDB T1,T2 ;GET THE VALUE OF THE ERROR MESSAGE JUMPE T1,SCTNUE ;JUMP IF UNEXPECTED STATE CALLRET SCTNIE ;REPORT THE ERROR TO USER SCTNUE: SCERR %NEUXS,SCTNIE, ;Here to give the error codes which correspond to the REASON ;codes given by NSP. SCTNIR: LOAD T3,SLRSN,(SL) ;GET THE REASON CODE NSP GAVE US JUMPE T3,SCTNR1 ;IF REASON IS ZERO, WE HAVE TO FIGURE ;OUT ERROR BASED ON STATE CAILE T3,RSNLEN ;IS THE REASON VALUE REASONABLE? JRST SCTNR2 ;NO, CALL IT UNSPECIFIED MOVE T1,ERRRBP ;GET THE REASON ERROR TABLE BYTE POINTER ADJBP T3,T1 ;INDEX TO THE CORRECT MESSAGE LDB T1,T3 ;GET THE VALUE OF THE ERROR MESSAGE JUMPE T1,SCTNR2 ;IF TABLE SAYS ZERO, IT UNSPECIFIED CALLRET SCTNIE ;RETURN THE FAILURE TO THE USER SCTNR1: IFSTATE T2,RJ SCERR %NERBO,SCTNIE, IFSTATE T2,DR SCERR %NEDBO,SCTNIE, SCTNR2: SCERR %NEREJ,SCTNIE, ;Here with an error code in T1. SCTNIE: SKIPN T1 ;IS THERE AN ERROR CODE? BUG.(CHK,SCLNZE,SCLINK,SOFT,,,< Cause: The routine that is supposed to store an error code for the user is zero. This is an illegal value. Action: Find who called SCTNIE with T1/ 0 and correct the caller's behavior. >) STOR T1,SAERR,(SA) ;STORE THE ERROR TYPE SKIPLE SL ;DON'T UPDATE STATUS IF WE HAVE NO SLB CALL CHKSTS ;UPDATE SLB'S LINK STATUS WORD CALLRET SCTNIX ;FREE THE MESSAGE ;The following is the table (indexed by SC state) which contains the ;error code to give (i.e., %NSUDR = Unexpected State: Disconnect ;Received). ERRSTB: BYTE(6) %NEUXS, %NEUCW, %NEUCR, %NEUCS, %NEURJ, %NEURN BYTE(6) %NEUDS, %NEUDC, %NEUCF, %NEULK, %NEUCM, %NEUNR ERRSBP: POINT 6,ERRSTB ;BYTE POINTER TO ERROR MESSAGES ;This table is indexed by reason code, with each cell corresponding to ;the correct error message to give for that reason. A zero in the ;table means "return the Unspecified Reject Reason error code". ;This should only happen when someone gives us a reason that we ;never heard of. ERRRSB: BYTE(6) %NERES, %NEUNN, %NERNS, %NEURO, %NEIOF, %NEOTB BYTE(6) 0, %NEABM, %NEABO, %NEINF, %NELNS, 0 BYTE(6) 0, 0, 0, 0, 0, 0 BYTE(6) 0, 0, 0, 0, 0, 0 BYTE(6) 0, 0, 0, 0, 0, 0 BYTE(6) 0, 0, 0, %NEACR, 0, 0 BYTE(6) 0, %NERNO, %NENUR, 0, %NENLK, %NEDSC BYTE(6) %NEIMG RSNLEN==<.-ERRRSB>*6 ERRRBP: POINT 6,ERRRSB ;BYTE POINTER TO REASON ERROR MESSAGES SUBTTL NSP. -- NSFRE - REset all links ;NSFRE - REset all links ; ; Call: ; SA/ Pointer to Session Control Argument Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;This function is only done by the system when the user does a RESET ;UUO. There are no arguments. NSFRE: SAVEAC SL ;PRESERVE SL FOR SCTNI* LOAD T1,SASJB,(SA) ;GET POINTER TO SJB LOAD P1,SJCHT,(T1) ;GET THE POINTER TO SLB TABLE LOAD P2,SJCHC,(T1) ;GET THE COUNT OF LINKS NSFRE1: SKIPN SL,(P1) ;IS THERE ANYTHING THERE? JRST NSFRE2 ;NO, TRY NEXT LINK SETZRO SLBSY,(SL) ;THIS LINK IS NO LONGER BUSY SETZ MB, ;RESET PASSES NO MSG BLK, NO Q'D INTERLOCKS CALL RLSLNK ;(MB)DO A RELEASE ON THIS LINK NSFRE2: ADDI P1,1 ;POINT TO THE NEXT SLB SOJG P2,NSFRE1 ;DO THE NEXT ONE, IF THERE ARE ANY LEFT RETSKP ;RETURN SUCCESS SUBTTL NSP. -- NSFEA - Enter Active State ;NSFEA - Enter Active State ; ; Call: ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFEA function, the function dependant arguments are: ; ; SAACH/ Returned: zero on failure, channel # on success ; SAAA1/ Ptr to connect-block ; SAAA2/ Segment Size ; SAAA3/ Flow control mode NSFEA: TRACE SC, SETZRO SAACH,(SA) ;ASSUME WE CANNOT ASSIGN A CHANNEL CALL MAKSLB ;MAKE A SLB SCERR %NEALF,RTN, STOR T1,SAACH,(SA) ;STORE CHANNEL NUMBER FOR MONUSER NEWSTATE CS ;INITIAL STATE IS CONNECT SENT ; Get the Object type and if format 0, store both the source (SLSOB) ; and destination (SLDOB) object type into the SLB. LOAD T3,SACBP,(SA) ;GET POINTER TO CONNECT BLOCK XMOVEI T1,CB.SRC(T3) ;GET THE POINTER TO SOURCE PDB LOAD T2,PBFOR,(T1) ;GET THE FORMAT TYPE CAIE T2,FRM.2 ;FORMAT TYPE WITH PPN? IFSKP. CALL CHKPPN ;AND VERIFY THE PPN SCERR %NEPRV,NSFEAC, ELSE. IFN FRM.0, ANDE. T2 ;IF OBJECT TYPE, STORE THE NUMBER LOAD T2,PBOBJ,(T1) ;GET OBJECT TYPE WE CLAIM TO BE IFN FTOPS10,< LOAD T3,SLSJB,(SL) ;GET POINTER TO SJB TMNN SJPRV,(T3) ;ARE WE PRIVED CAIL T2,^D128 ;IS OBJECT TYPE PRIVED? TRNA ;WE ARE O.K. SCERR %NEPRV,NSFEAC, > ; END FTOPS10 STOR T2,SLSOB,(SL) ;SAVE SOURCE OBJ TYPE FOR SYSDPY AND THE LIKE ENDIF. LOAD T3,SACBP,(SA) ;GET POINTER TO CONNECT BLOCK XMOVEI T1,CB.DST(T3) ;GET THE POINTER TO THE DEST PDB LOAD T2,PBFOR,(T1) ;GET THE FORMAT TYPE CAIE T2,FRM.0 ;FORM WITH JUST AN OBJECT TYPE IFSKP. LOAD T2,PBOBJ,(T1) ;GET THE OBJECT TYPE FROM PDB STOR T2,SLDOB,(SL) ;SAVE DEST OBJ TYPE FOR SYSDPY AND THE LIKE ENDIF. LOAD T1,SAKCB,(SA) ;GET USER'S 'KEEP CONNECT BLOCK' FLAG STOR T1,SLKCB,(SL) ;REMEMBER IT JUMPE T1,NSFEA3 ;JUMP IF WE'RE NOT TO KEEP CONNECT BLOCK MOVX T1,CB.LEN ;GET 'CONNECT BLOCK LENGTH' WORDS CALL DNGWDS ;GET NON-ZEROED WORDS SCERR %NEALF,NSFEAC, STOR T1,SLCBP,(SL) ;SAVE POINTER TO SLB'S NEW CB ; FRESLB WILL FREE THIS CB FROM NOW ON MOVE T2,T1 ;DESTINATION IS NEW CB LOAD T1,SACBP,(SA) ;SOURCE IS CONNECT BLOCK FROM SAB MOVX T3,CB.LEN ;LENGTH IS LENGTH OF A CONNECT BLOCK CALL DNCPYW ;COPY SAB'S CB TO SLB'S CB NSFEA3: LOAD P1,SANAG,(SA) ;GET THE NUMBER OF ARGS USER SPECIFIED CAIG P1,.NSAA3 ;DID USER SPECIFY THE FLOW CONTROL MODE? JRST NSFEA4 ;NO LOAD T1,SAAA3,(SA) ;GET THE FLOW CONTROL MODE JUMPLE T1,NSFEA4 ;DIDN'T SPECIFY, USE THE DEFAULT CAIL T1,NSF.C0 ;RANGE CHECK THE CAILE T1,NSF.MX ; FLOW CONTROL MODE SCERR %NEIFM,NSFEAC, SUBI T1,1 ;TRANSLATE FLOW CONTROL MODE INTO THE ; FCM.XX FORM THAT NSP USES STOR T1,SLRFL,(SL) ;STORE THE FLOW CONTROL MODE NSFEA4: SETZ T1, ;NO USER DATA NEEDED CALL DNGMSG ;GET MESSAGE BLOCK SCERR %NEALF,NSFEAC, MOVE MB,T1 ;PUT MESSAGE BLOCK POINTER IN MB MOVX T1,OA.LEN ;LENGTH OF OPEN ARGS CALL DNGWDZ ;GET BLOCK FOR OPEN ARGS SCERR %NEALF,NSFEAD, ;Now fill in the Open block with the arguments. MOVE P1,T1 ;MAKE P1 POINT TO THE ARGUMENT BLOCK STOR SL,OASCB,(P1) ;PUT ID IN OPEN ARG BLOCK OPSTR ,SACBP,(SA) ;GET THE CONNECT BLOCK POINTER SCERR %NENCD,NSFEAE, OPSTR ,CBNUM,(T2) ;Get node number and check for zero IFSKP. ;If it is zero, then its a loopback circuit LOAD T1,CBCIR,(T2) ;Get loopback circuit ID STOR T1,OACIR,(P1) ; and store it LOAD T1,IBADR,+IBBLK ;Get local node number ENDIF. STOR T1,OANOD,(P1) ;PUT DESTINATION NODE ADDRESS IN ARG BLOCK STOR T1,SLDNA,(SL) ; AND STORE AS DESTINATION OF THIS LINK ; LOAD T1,SLDNA,(SL) OPSTR ,OACIR,(P1) ;Loopback? IFSKP. ; -yes MOVE T1,RTRBSZ ; Use default buffer size SUBI T1,%SCHDR ; minus header ELSE. ; -no, CALL SCTGSS ; Get segment size for that destination ENDIF. LOAD T2,SANAG,(SA) ;Get the number of args user specified CAIG T2,.NSAA2 ;Did the user specifiy the segment size? IFSKP. ;Yes, use the supplied value OPSTR ,SAAA2,(SA) ;Get the segment size CAMLE T2,T1 ; is it bigger than the legal max? IFSKP. ; -no smaller, use that value ENDIF. STOR T1,SLSIZ,(SL) ;STORE THE SEGMENT SIZE IN SLB LOAD T1,SLRFL,(SL) ;GET THE FLOW CONTROL MODE BACK STOR T1,OAFLO,(P1) ;PUT IN OPEN ARG BLOCK LOAD T2,SLGOL,(SL) ;GET THE DATA REQUEST GOAL CAIN T1,FCM.MG ;ARE WE IN MESSAGE FLOW CONTROL? CAIL T2,1 ;YES, IS OUR GOAL SET TO LESS THAN ONE? TRNA ;NO, DON'T WORRY ABOUT IT MOVEI T2,1 ;IN MSG FLOW MODE WE GOAL OF AT LEAST 1 STOR T2,SLGOL,(SL) ;REMEMBER THE GOAL WE DECIDED ON STOR T2,OAGOL,(P1) ;TELL LLINKS ABOUT THE GOAL TOO LOAD T1,SLSIZ,(SL) ;GET THE MAXIMUM SEGMENT SIZE STOR T1,OASIZ,(P1) ;THAT TOO MOVE T1,[XCDSEC,,SCTL] ;HE WANT'S OUR ENTRY VECTOR ADDRESS STOR T1,OASCV,(P1) ;GIVE IT TO HIM MOVE T1,P1 ;PASS ARG POINTER IN T1 MOVX T2,OA.LEN ;LENGTH OF THE OPEN ARG BLOCK MOVX T3,NV.OPN ;FUNCTION IS OPEN A PORT MOVE T4,MB ;POINT TO THE MESSAGE BLOCK WE ALLOCATED CALL NSP ;ASK NSP TO OPEN A PORT SKIPG T1 ;Did we get a port? SCERR %NERES,NSFEAD, ;Now we have an open port to NSP, let's try to make it active. STOR T1,SLPID,(SL) ;STORE THE NSPpid MOVE T1,MB ;LET'S REUSE THE MESSAGE BLOCK MOVEI T2,^D200 ;GET ENOUGH ROOM FOR THE CONNECT MESSAGE CALL DNMINI ;MAKE THE MESSAGE BLOCK LIKE NEW SCERR %NEALF,NSFEAD, XMOVEI T1,UD.MSD(MB) ;POINT TO USER DATA PORTION OF MESSAGE CALL DNPINI ;INITIALIZE FOR PUTTING BYTES IN MESSAGE LOAD T1,SACBP,(SA) ;POINT TO THE CONNECT BLOCK CALL BLDCTX ;BUILD THE CONNECT TEXT IN THE MESSAGE SCERR %NECFE,NSFEAD, LOAD T1,SLPID,(SL) ;GET THE NSPpid BACK AGAIN MOVX T3,NV.ACT ;FUNCTION IS ENTER ACTIVE MOVE T4,MB ;POINT TO MB WITH CONNECT DATA CALL NSP ;CALL NSP TO DO THE FUNCTION CALL STRTMR ;START THE CONNECT TIMERS RETSKP ;GIVE A GOOD RETURN ;The following are the error returns that free up things that we have ;allocated before we got the error. ;Free an arg block, a message block and a SLB. Report "illegal function". NSFEAE: MOVE T1,P1 ;POINT TO THE ARGUMENT BLOCK CALL DNFWDS ; AND GO AND FREE UP THE WORDS MOVEI T1,%NEILF ;"Illegal function" JRST NSFEAD ;GO AND FREE MESSAGE BLOCK ;Free a message block and a SLB. NSFEAD: SAVEAC T1 ;SAVE THE ERROR CODE CALL FREMSG ;FREE THE MESSAGE BLOCK POINTED TO BY MB JRST NSFEC1 ;GO AND FREE THE SLB ;Free an SLB. NSFEAC: SAVEAC T1 ;SAVE THE ERROR CODE NSFEC1: SETONE SLFSL,(SL) ;FREE THE SLB AFTER THE "AFTER" PROCESSING SETZRO SAACH,(SA) ;TELL USER THERE'S NO CHANNEL OPEN CALLRET SCTRFJ ;REQUEST SECOND SERVICE TO FREE SLB SUBTTL NSP. -- NSFEP - Enter Passive State ;NSFEP - Enter Passive State ; ; Call: ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFEP function, the function dependant arguments are: ; ; .NSAA1/ Ptr to connect-block NSFEP: TRACE SC, CALL MAKSLB ;MAKE A SLB SCERR %NEALF,RTN, STOR T1,SAACH,(SA) ;STORE THE CHANNEL FOR USER ; Get the Object type and if format 0, store the source (SLSOB) object type ; in the SLB. LOAD T3,SACBP,(SA) ;GET POINTER TO CONNECT BLOCK XMOVEI T1,CB.SRC(T3) ;GET THE POINTER TO THE SOURCE PDB LOAD T2,PBFOR,(T1) ;GET THE FORMAT TYPE IFE. T2 ;IF FRM.0, IT HAS AN OBJECT TYPE LOAD T2,PBOBJ,(T1) ;GET THE OBJECT TYPE FROM THE PDB STOR T2,SLSOB,(SL) ;STORE IT IN THE SLB ENDIF. XMOVEI T1,CB.DST(T3) ;GET THE POINTER TO THE DEST PDB LOAD T2,PBFOR,(T1) ;GET THE FORMAT TYPE CAIE T2,FRM.2 ;FORMAT TYPE WITH PPN? IFSKP. CALL CHKPPN ;AND VERIFY THE PPN SCERR %NEPRV,NSFEPC, ELSE. IFN FRM.0, ANDE. T2 ;IF OBJECT TYPE, STORE THE NUMBER LOAD T3,SLSJB,(SL) ;GET POINTER TO SJB LOAD T2,PBOBJ,(T1) ;GET OBJECT TYPE WE CLAIM TO BE IFN FTOPS20,< MOVE T1,CAPENB ;ARE WE PRIVED TXNN T1,SC%WHL!SC%OPR > ; END FTOPS20 IFN FTOPS10,< TMNN SJPRV,(T3) ;ARE WE PRIVED > ; END FTOPS10 CAIL T2,^D128 ;IS OBJECT TYPE PRIVED? TRNA ;WE ARE O.K. SCERR %NEPRV,NSFEPC, STOR T2,SLSOB,(SL) ;SAVE IT FOR SYSDPY AND THE LIKE ENDIF. ;Now allocate another block for the internal connect block, so that the ;original goes back to SCLINK's caller. NSFEP2: LOAD T1,SAKCB,(SA) ;GET USER'S 'KEEP CONNECT BLOCK' FLAG STOR T1,SLKCB,(SL) ;REMEMBER IT MOVX T1,CB.LEN ;LENGTH OF A INTERNAL CONNECT BLOCK CALL DNGWDS ;GET THE WORDS SCERR %NEALF,NSFEPC, STOR T1,SLCBP,(SL) ;STORE THE POINTER IN THE SLB MOVE T2,T1 ;SET IT UP IN T2 ALSO FOR DNCPYW LOAD T1,SACBP,(SA) ;POINT TO THE CONNECT BLOCK MOVX T3,CB.LEN ;LENGTH OF THE CONNECT BLOCK CALL DNCPYW ;COPY THE WHOLE THING NEWSTATE CW ;NEW STATE IS CONNECT WAIT SETONE SLPAS,(SL) ;Flag that this link is passive RETSKP ;RETURN WITH SUCCESS ;Here to free up the SLB after an error occured. NSFEPC: SAVEAC T1 ;SAVE THE ERROR CODE SETONE SLFSL,(SL) ;SAY THAT WE SHOULD FREE THE SLB CALLRET SCTRFJ ;REQUEST SECOND SERVICE TO FREE SLB SUBTTL NSP. -- NSFRI - Read Connect Information ;NSFRI - Read Connect Information ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFRI function, the function dependant arguments are: ; ; .NSAA1/ Ptr to connect-block ; .NSAA2/ Maximum segment size ; .NSAA3/ Flow control mode ; ;This function can be called in any state. If we were asked to keep the ;connect in the Enter Active or Enter Passive, then .NSFRI will be able to ;return the connect block at any time, and the user data will have been ;updated with the most recently received user data from CC or DI messages. NSFRI: TRACE SC, SETZRO SASBP,(SA) ;ZERO THE ARGUMENTS IN SETZRO SAAA2,(SA) ; CASE WE CAN'T SETZRO SAAA3,(SA) ; GET THE RIGHT ANSWER ;CDMCBP WILL BUILD A CONNECT BLOCK IF NEEDED CALL CDMCBP ;COPY ANY MESSAGE DATA TO CONNECT BLOCK RET ;PROPOGATE ERROR RETURN, CODE IN T1 TMNN SLCBP,(SL) ;ANY DIS/CONNECT DATA TO READ? SCERR %NENCD,RTN, JE SLKCB,(SL),NSFRI1 ;USER WANT US TO KEEP CONNECT BLOCK ;Here if we are to keep connect block, copy it for user MOVX T1,CB.LEN ;YES, LENGTH OF AN INTERNAL CONNECT BLOCK CALL DNGWDS ;GET NON-ZEROED WORDS SCERR %NEALF,RTN, STOR T1,SACBP,(SA) ;STORE THE POINTER FOR SCJSYS MOVE T2,T1 ;SET UP DEST POINTER FOR DNCPYW LOAD T1,SLCBP,(SL) ;GET THE INTERNAL CB POINTED TO IN THE SLB MOVX T3,CB.LEN ;COUNT OF WORDS TO COPY CALL DNCPYW ;COPY CONNECT BLOCK FOR USER JRST NSFRI2 ;CONTINUE ;Here if we are not to keep the connect block, just hand it over NSFRI1: LOAD T1,SLCBP,(SL) ;GET THE INTERNAL CB POINTED TO IN THE SLB SETZRO SLCBP,(SL) ;SCLINK NO LONGER OWNS THE CONNECT BLOCK SKIPN T1 ;DO WE STILL HAVE A CONNECT BLOCK? SCERR %NEWRS,RTN, STOR T1,SACBP,(SA) ;STORE THE POINTER FOR SCMUUO NSFRI2: LOAD P1,SANAG,(SA) ;GET THE NUMBER OF ARGUMENTS CAIG P1,.NSAA2 ;DID HE WANT SOME OTHER ARGUMENTS? RETSKP ;NO, JUST RETURN LOAD T1,SLSIZ,(SL) ;YES, GET IT FROM THE SLB STOR T1,SAAA2,(SA) ;STORE REASON CODE,,SEGMENT SIZE CAIG P1,.NSAA3 ;HOW ABOUT THE FLOW CONTROL OPTION? RETSKP ;NO, JUST RETURN CALL RETFLW ;GET THE RFL,,XFL IN T1 STOR T1,SAAA3,(SA) ; AND STORE IT IN THE ARG BLOCK RETSKP ;RETURN SUCCESS SUBTTL NSP. -- NSFAC - Accept the Connect ;NSFAC - Accept the Connect ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFAC function, the function dependant arguments are: ; ; .NSAA1/ Ptr to user-data (which is the DATA-CTL optional response) ; .NSAA2/ Maximum segment size ; .NSAA3/ Flow control mode NSFAC: TRACE SC, CALL STPTMR ;STOP THE CONNECT INITIATE TIMER AND FIX COUNTS LOAD P1,SANAG,(SA) ;GET THE NUMBER OF ARGS USER SPECIFIED CAIG P1,.NSAA2 ;DID THE USER SPECIFIY THE SEGMENT SIZE? JRST NSFAC1 ;NO LOAD T2,SLSIZ,(SL) ;Get the segment size that we and remote ; decided upon. OPSTR ,SAAA2,(SA) ;Get the segment size user wants CAML T1,T2 ;User's smaller? IFSKP. ; -yes, use the user's value CAIG P1,.NSAA3 ;DID USER SPECIFY THE FLOW CONTROL MODE? JRST NSFAC1 ;NO LOAD T1,SAAA3,(SA) ;GET THE FLOW CONTROL MODE JUMPLE T1,NSFAC1 ;DIDN'T SPECIFY IT, USE THE DEFAULT CAIL T1,NSF.C0 ;RANGE CHECK THE FLOW CAILE T1,NSF.MX ; CONTROL MODE SCERR %NEIFM,RTN, SUBI T1,1 ;TRANSLATE FROM NSP.'S VERSION OF FLOW CONTROL ; VALUE TO NSP'S STOR T1,SLRFL,(SL) ;STORE THE FLOW CONTROL MODE ;Allocate two message blocks, one for the accept arguments and one to ;send out data requests with. NSFAC1: MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL CALL DNGMSG ;GET A MESSAGE BLOCK SCERR %NEALF,RTN, MOVE MB,T1 ;MAKE MB POINT TO THE MESSAGE BLOCK SETZ T1, ;DON'T NEED ANY USER DATA FOR DRQ MB CALL DNGMSG ;GET THE MESSAGE BLOCK JRST [CALL FREMSG ;FREE THE MESSAGE BLOCK WE JUST ALLOCATED SCERR %NEALF,RTN,] ; AND GIVE A FAILURE TO USER MOVE P2,T1 ;SAVE THE POINTER TO THE DRQ MB ;Copy the user's DATA-CTL (in the user data area) from the user area to ;the message block. XMOVEI T1,UD.MSD(MB) ;WE WANT TO WRITE DATA-CTL INTO USER DATA CALL DNPINI ;INITIALIZE THE MSD LOAD T1,SASBP,(SA) ;GET THE POINTER TO SBLOCK CALL CPYS2M ;COPY THE DATA-CTL TO THE MESSAGE ;Now set up the accept argument block for NSP. MOVX T1,AA.LEN ;LENGTH OF THE ACCEPT ARGUMENT BLOCK CALL DNGWDZ ;GET THAT MANY WORDS SCERR %NEALF,NSFACD, LOAD T2,SLSLB,(SL) ;THE SCB ID FOR NEW PORT STOR T2,AASCB,(T1) LOAD T2,SLPID,(SL) ;NSP'S PORT IDENTIFIER STOR T2,AAPID,(T1) LOAD T3,SLRFL,(SL) ;RECEIVE FLOW CONTROL TYPE STOR T3,AAFLO,(T1) LOAD T2,SLGOL,(SL) ;GET THE DATA REQUEST GOAL CAIN T3,FCM.MG ;ARE WE IN MESSAGE FLOW CONTROL? CAIL T2,1 ;YES, IS OUR GOAL SET TO LESS THAN ONE? TRNA ;NO, DON'T WORRY ABOUT IT MOVEI T2,1 ;IN MSG FLOW MODE WE GOAL OF AT LEAST 1 STOR T2,SLGOL,(SL) ;REMEMBER THE GOAL WE DECIDED ON STOR T2,AAGOL,(T1) ;TELL LLINKS ABOUT THE GOAL TOO LOAD T2,SLSIZ,(SL) ;MAX BYTES ALLOWED IN A SEGMENT STOR T2,AASIZ,(T1) MOVE T2,[XCDSEC,,SCTL] ;OUT ENTRY VECTOR ADDRESS STOR T2,AASCV,(T1) ; SO HE KNOWS WHERE TO CALL US MOVX T2,AA.LEN ;LENGTH OF THE ARG BLOCK MOVX T3,NV.ACC ;FUNCTION IS ACCEPT THE CONNECT MOVE T4,MB ;SET UP T4 WITH MB POINTER ;T1 IS SET UP ALREADY WITH ARG BLOCK ADDRESS CALL NSP ;PERFORM THE FUNCTION NEWSTATE RN ;NEWSTATE IS CONNECT INITIATE SETONE SLCCB,(SL) ;HAVE TO CHECK CONNECT BLOCK NOW ;Now let's send the job's input quota worth of DRQs. MOVE MB,P2 ;POINT TO THE MB WE ALLOCATED BEFORE TMNE SLPH2,(SL) ;SHOULD WE BE CONSERVATIVE WITH THIS FELLOW? RETSKP ;YES, WE BETTER LEAVE NICELY LOAD T1,SLINQ,(SL) ;GET THE INPUT QUOTA STOR T1,QACNT,+T2 ; USE THAT AS THE DATA REQUEST COUNT STOR T1,SSRDO,+SL.NSL(SL) ;WE KEEP COUNT OF OUTGOING DATA REQUESTS TXZ T2,MBOTH ;ON THE NORMAL SUBLINK CALL SNDDRM ;SEND THE DATA REQUESTS SCERR %NERES,RTN, RETSKP ;RETURN SUCCESS ;Here on a error. NSFACD: SAVEAC T1 ;SAVE THE ERROR CODE CALLRET FREMSG ;FREE THE MESSAGE BLOCK POINTED TO BY MB SUBTTL NSP. -- NSFRJ - Reject the Connect ;NSFRJ - Reject the Connect ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFRJ function, the function dependant arguments are: ; ; .NSAA1/ Ptr to user-data (which is the DATA-CTL optional response) ; .NSAA2/ Reason code or zero to take default 'rejected by object' NSFRJ: TRACE SC, CALL STPTMR ;STOP THE CONNECT INITIATE TIMER AND FIX COUNTS MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL CALL DNGMSG ;GET A MESSAGE BLOCK SCERR %NEALF,RTN, MOVE MB,T1 ;MAKE MB POINT TO THE MESSAGE BLOCK XMOVEI T1,UD.MSD(MB) ;WE WANT TO WRITE DATA-CTL INTO USER DATA CALL DNPINI ;INITIALIZE THE MSD ;Put in the reason code (RSNRBO - Rejected by object). LOAD T2,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER OFFERED OPSTR ,SAAA2,(SA) ;USER SPECIFY A REASON? CAIGE T2,4 ;YES, SANAG INCLUDE SAAA2? MOVX T1,RSNRBO ;NO, REJECTED BY THE OBJECT CALL DNP2BY ;PUT REASON IN THE MESSAGE ;Copy the user's DATA-CTL (in the user data area) from the user area to the ;message block. LOAD T1,SASBP,(SA) ;GET THE POINTER TO SBLOCK CALL CPYS2M ;COPY THE DATA-CTL TO THE MESSAGE LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP MOVX T3,NV.REJ ;FUNCTION IS REJECT THE CONNECT MOVE T4,MB ;SET UP T4 WITH MB POINTER ;T1 IS SET UP ALREADY WITH ARG BLOCK ADDRESS CALL NSP ;PERFORM THE FUNCTION ;There is no need to change the state of the link here, as we are ;about to forget about the link. The user may possibly clean out ;his database about this link and then get the state change interrupt, ;confusing him. SETONE SLFSL,(SL) ;SAY THAT WE SHOULD FREE THE SLB LATER CALL SCTRFJ ;REQUEST SECOND SERVICE TO FREE SLB RETSKP ;RETURN NICELY SUBTTL NSP. -- NSFRC - Read Connect Confirm Information ;NSFRC - Read Connect Confirm Information ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFRC function, the function dependant arguments are: ; ; .NSAA1/ Ptr to string block to receive data ; .NSAA2/ Segment size ; .NSAA3/ Flow control mode NSFRC: TRACE SC, SETZRO SASBP,(SA) ;ZERO THE ARGUMENTS IN SETZRO SAAA2,(SA) ; CASE WE CAN'T SETZRO SAAA3,(SA) ; GET THE RIGHT ANSWER ;CDMCBP WILL BUILD A CONNECT BLOCK IF NEEDED CALL CDMCBP ;COPY ANY MESSAGE DATA TO CONNECT BLOCK RET ;PROPOGATE ERROR RETURN, CODE IN T1 TMNN SLCBP,(SL) ;DO WE HAVE ANY CONNECT DATA SCERR %NENCD,RTN, MOVX T1,SB.LEN ;GET SOME WORDS FOR THE DATA-CTL FIELD CALL DNGWDS ;GET THEM FROM MEMORY MANAGER SCERR %NEALF,RTN, MOVE P2,T1 ;POINTER TO STRING BLOCK STOR P2,SASBP,(SA) ;PUT POINTER IN ARG BLOCK FOR SCMUUO MOVEI T1,SB.LEN ;LENGTH OF STRING BLOCK IN WORDS STOR T1,SBWDS,(P2) ;STORE LENGTH IN WORDS LOAD P1,SLCBP,(SL) ;GET PTR TO CONNECT BLOCK LOAD T3,CBCCT,(P1) ;LENGTH OF USER DATA STOR T3,SBCNT,(P2) ;STORE IN STRING BLOCK ADDI T3,3 ;ROUND UP ASH T3,-2 ;CONVERT BYTES TO WORDS XMOVEI T1,CB.UDA(P1) ;POINTER TO CONNECT BLOCK'S USER DATA XMOVEI T2,SB.DAT(P2) ;POINTER TO STRING BLOCK'S DATA SECTION CALL DNCPYW ;(T1,T2,T3)COPY USER DATA TO STRING BLOCK JN SLKCB,(SL),NSFRC1 ;JUMP IF WE'RE TO KEEP CONNECT BLOCK MOVE T1,P1 ;POINTER TO CONNECT BLOCK CALL DNFWDS ;DEALLOCATE MSG BLK WHICH HAD CONNECT DATA SETZRO SLCBP,(SL) ; AND REMEMBER WE'VE USED IT NSFRC1: LOAD T1,SLSIZ,(SL) ;GET THE SEGMENT SIZE STOR T1,SAAA2,(SA) ;STORE IT IN THE ARGUMENT WORD CALL RETFLW ;GET THE FLOW CONTROL TYPES STOR T1,SAAA3,(SA) ;STORE IN THE ARG WORD RETSKP ;RETURN SUCCESS SUBTTL NSP. -- NSFSD - Synchronous Disconnect ;NSFSD - Synchronous Disconnect ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFSD function, the function dependant arguments are: ; ; .NSAA1/ Ptr to user-data (which is the optional disconnect data) ; .NSAA2/ Reason code or zero for 'Disconnected by Object' NSFSD: TRACE SC, TMNE SLOTM,(SL) ;IS THERE A PARTIALLY FILLED OUTPUT MESSAGE? SCERR %NEWRS,RTN, MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL CALL DNGMSG ;GET A MESSAGE BLOCK SCERR %NEALF,RTN, MOVE MB,T1 ;MAKE MB POINT TO THE MESSAGE BLOCK ;Copy the user's DATA-CTL (in the user data area) from the user area to the ;message block. XMOVEI T1,UD.MSD(MB) ;WE WANT TO WRITE DATA-CTL INTO USER DATA CALL DNPINI ;INITIALIZE THE MSD LOAD T2,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER OFFERED OPSTR ,SAAA2,(SA) ;USER SPECIFY A REASON? CAIGE T2,4 ;YES, SANAG INCLUDE SAAA2? MOVX T1,RSNDBO ;NO, REASON IS DISCONNECTED BY OBJECT CALL DNP2BY ;PUT REASON (2 BYTES) IN MESSAGE LOAD T1,SASBP,(SA) ;GET THE POINTER TO SBLOCK CALL CPYS2M ;COPY THE DATA-CTL TO THE MESSAGE ;Now call NSP to do the disconnect. LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP MOVX T3,NV.DSC ;FUNCTION IS DISCONNECT MOVE T4,MB ;SET UP T4 WITH MB POINTER CALL NSP ;PERFORM THE FUNCTION NEWSTATE DS ;NEWSTATE IS DISCONNECT SENT RETSKP ;DID OK SUBTTL NSP. -- NSFAB - Abort and Release ;NSFAB - Abort and Release ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFAB function, the function dependant arguments are: ; ; .NSAA1/ Ptr to user-data (which is the optional disconnect data) ; .NSAA2/ Reason code or zero for 'Aborted by Object' NSFAB: TRACE SC, MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL CALL DNGMSG ;GET A MESSAGE BLOCK SCERR %NEALF,RTN, MOVE MB,T1 ;MAKE MB POINT TO THE MESSAGE BLOCK ;Copy the user's DATA-CTL (in the user data area) from the user area to the ;message block. XMOVEI T1,UD.MSD(MB) ;WE WANT TO WRITE DATA-CTL INTO USER DATA CALL DNPINI ;INITIALIZE THE MSD LOAD T2,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER OFFERED OPSTR ,SAAA2,(SA) ;USER SPECIFY A REASON? CAIGE T2,4 ;YES, SANAG INCLUDE SAAA2? MOVX T1,RSNABO ;NO, REASON IS ABORTED BY OBJECT CALL DNP2BY ;PUT THE TWO BYTES OF REASON CODE IN MSG LOAD T1,SASBP,(SA) ;GET THE POINTER TO SBLOCK CALL CPYS2M ;COPY THE DATA-CTL TO THE MESSAGE LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP MOVX T3,NV.ABO ;FUNCTION IS DISCONNECT MOVE T4,MB ;SET UP T4 WITH MB POINTER CALL NSP ;PERFORM THE FUNCTION NEWSTATE DS ;NEWSTATE IS DISCONNECT SENT CALL STPTMR ;STOP THE CI TIMER IN CASE IT'S GOING SETONE SLABO,(SL) ;WE HAVE TO CLOSE WHEN LINK IS FINISHED RETSKP ;RETURN WITH GOODNESS SUBTTL NSP. -- NSFRD - Read Disconnect Data ;NSFRD - Read Disconnect Data ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFRD function, the function dependant arguments are: ; ; .NSAA1/ Ptr to Connect-Block ; .NSAA2/ The Disconnect Reason NSFRD: TRACE SC, SETZRO SASBP,(SA) ;ZERO THE ARGUMENTS IN SETZRO SAAA2,(SA) ; CASE WE CAN'T GET THE RIGHT ANSWER ;CDMCBP WILL BUILD A CONNECT BLOCK IF NEEDED CALL CDMCBP ;COPY ANY MESSAGE DATA TO CONNECT BLOCK RET ;PROPOGATE ERROR RETURN, CODE IN T1 OPSTR ,SLCBP,(SL) ;GET PTR TO DIS/CONNECT BLOCK SCERR %NENCD,RTN, MOVX T1,SB.LEN ;GET SOME WORDS FOR THE DATA-CTL FIELD CALL DNGWDS ;GET THEM FROM MEMORY MANAGER SCERR %NEALF,RTN, MOVE P2,T1 ;POINTER TO STRING BLOCK STOR P2,SASBP,(SA) ;PUT POINTER IN ARG BLOCK FOR SCMUUO MOVEI T1,SB.LEN ;LENGTH OF STRING BLOCK IN WORDS STOR T1,SBWDS,(P2) ;STORE LENGTH IN WORDS LOAD T3,CBCCT,(P1) ;LENGTH OF USER DATA IN CONNECT BLOCK STOR T3,SBCNT,(P2) ;STORE IN STRING BLOCK ADDI T3,3 ;ROUND UP TO NEAREST WORD ASH T3,-2 ;CONVERT BYTES TO WORDS XMOVEI T1,CB.UDA(P1) ;POINTER TO CONNECT BLOCK'S USER DATA XMOVEI T2,SB.DAT(P2) ;POINTER TO STRING BLOCK'S DATA SECTION CALL DNCPYW ;(T1,T2,T3)COPY USER DATA TO STRING BLOCK LOAD T1,SLRSN,(SL) ;GET THE DISCONNECT REASON CODE STOR T1,SAAA2,(SA) ;RETURN THE REASON CODE RETSKP ; AND GIVE THE GOOD RETURN SUBTTL NSP. -- NSFRL - Release the Channel ;NSFRL - Release the Channel ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFRL function, the function dependant arguments are: ; ; .NSAA1/ Ptr to user-data (which is the optional disconnect data) NSFRL: TRACE SC, SETZ MB, ;WE HAVE NO MESSAGE BLOCK, NO Q'D INTERLOCKS CALL RLSLNK ;(MB)RESET THE LINK (DO THE CLOSE) RETSKP ;RETURN SUCCESS SUBTTL NSP. -- NSFRS - Read the Channel Status ;NSFRS - Read the Channel Status ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFRS function, the function dependant arguments are: ; ; .NSAA1/ State ; .NSAA2/ Segment Size ; .NSAA3/ Flow control type NSFRS: TRACE SC, LOAD P1,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER WANTED CAIG P1,.NSAA1 ;DOES HE WANT TO KNOW SEGMENT SIZE? RETSKP ;NO, JUST RETURN LOAD T1,SLSIZ,(SL) ;GET THE MAX SEG SIZE WE'RE USING STOR T1,SAAA1,(SA) ;STORE IT IN SAB ARGUMENT BLOCK CAIG P1,.NSAA2 ;DOES HE WANT TO KNOW FLOW CONTROL TYPE? RETSKP ;NO, JUST RETURN CALL RETFLW ;RETURN THE FLOW CONTROL TYPES STOR T1,SAAA2,(SA) ;STORE IT IN THE ARGUEMENT BLOCK RETSKP ; AND RETURN SUCCESSFULLY SUBTTL NSP. -- NSFIS - Send Interrupt Data ;NSFIS - Send Interrupt Data ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block with user arguments stored ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ; .NSAA1/ Ptr to user-data (which is the interrupt data to be sent) NSFIS: TRACE SC, TMNE SLCCB,(SL) ;SHOULD WE CHECK CONNECT BLOCK? CALL FRECBP ;YES, GET RID OF CONNECT DATA IF WE CAN NSFIS1: OPSTR ,SASBP,(SA) ;POINT TO THE SBLOCK POINTER SCERR %NEABE,RTN, LOAD T1,SBCNT,(P1) ;GET THE COUNT OF BYTES SKIPL T1 ;RANGE CHECK THE LENGTH CAILE T1,^D16 ;IS IT WITHIN THE SPEC? SCERR %NEIDL,RTN, ;... ;... ;Allocate the message block. MOVX T1,^D16 ;GET 16 BYTES (MIGHT AS WELL GO ALL THE WAY ; SINCE THEY'RE IN THE MB ALREADY) CALL DNGMSG ;GET THE MESSAGE BLOCK SCERR %NEALF,NSFIS2, MOVE MB,T1 ;SET UP MB XMOVEI T1,UD.MSD(MB) ;SET UP TO PUT IN BYTES CALL DNPINI ; IN THE USER SEGMENT D36OFF ;INTERLOCK AGAINST SCTRIB CALL FROM LLINKS JE SLOTU,(SL),NSFISO ;JUMP IF THIS WILL BE ONLY OUTPUT BUFFER NOW MOVE T1,DCNRSB ;GET # NOW RESERVED SKIPN DCNCON ;IS SYSTEM CONGESTED? CAML T1,DCNTSB ;NO, IS THERE ROOM FOR ONE MORE? JRST NSFISF ;NO, RETURN FAILURE AOS T1,DCNRSB ;ONE MORE BUFFER RESERVED CAMLE T1,DCNRHT ;NEW HIGH TIDE? MOVEM T1,DCNRHT ;YES, RECORD IT JRST NSFISA ;GOT ROOM, GO ALLOCATE NSFISF: ;NO ROOM FOR THIS LOGICAL LINK SETOM DCNCON ;CALL FOR CHKSTS WHEN CONGESTION FREES D36ON ;END CRITICAL SECTION AOS DCNROF ;INCREMENT OUTPUT RESERVATION FAILURES CALL FREMSG ;RETURN THE MESSAGE BLOCK JRST NSFIS2 ;SUCCEEDED IN SENDING ZERO BYTES (CONGESTION) NSFISO: JN SLINU,(SL),NSFISA ;JUMP IF INPUT BUFF ALLOC, THAT RESERVES 1 OUT MOVE T1,DCNRSB ;GET # ALREADY RESERVED ADDI T1,2 ;WE INTEND TO RESERVE 2 MORE (1 IN + 1 OUT) CAMLE T1,DCNTSB ;WILL THAT FIT IN TOTAL? JRST NSFISF ;NO, RETURN FAILURE MOVEM T1,DCNRSB ;YES, D36OFF MAKES THIS STORE OK CAMLE T1,DCNRHT ;NEW HIGH TIDE? MOVEM T1,DCNRHT ;YES, RECORD IT NSFISA: INCR SLOTU,(SL) ;INCREMENT NUMBER OF OUTPUT BUFFERS IN USE D36ON ;END OF CRITICAL SECTION ;Here to copy the bytes from the user's buffer into the message. MOVE T1,P1 ;POINT TO THE SBLOCK CALL CPYS2I ;(T1)COPY INTERRUPT DATA FROM STRING BLOCK ; TO MESSAGE SETONE ,(MB) ;INTERRUPT MESSAGES ARE ONE SEGMENT ;Update counts INCR SLPKS,(SL) ;# of 'packets' sent LOAD T1,SBCNT,(P1) ;Get # of bytes in string block OPSTRM ,SLBYS,(SL) ; and update count in SLB ;Now send the message to NSP. LOAD T1,SLPID,(SL) ;GET THE NSPpid SETZ T2, ;T2 HAS THE DA STRUCTURE SETONE MBOTH,(MB) ;SEND ON THE OTHER SUB-LINK MOVX T3,NV.SEG ;FUNCTION IS SEND A SEGMENT MOVE T4,MB ;POINT TO THE MESSAGE BLOCK CALL NSP ;SEND INTERRUPT MESSAGE OPSTRM ,SSXDO,+SL.OSL(SL) ;DECR COUNT OF XMT DATA REQUESTS SETZRO SBCNT,(P1) ;TELL ASYNCHRONOUS USER WE SENT THE DATA RETSKP ; AND RETURN SUCCESSFULLY ;Here when DNGMSG or DCNRSB fails due to congestion. NSFIS2: LOAD T1,SLSST,(SL) ;GET LINK STATUS HALF-WORD TXZ T1,NSNDR ! NSIDR ;NEITHER TYPE OF OUTPUT IS OK NOW STOR T1,SLSST,(SL) ;STORE BACK SO WHEN CONGESTION IS FREED RET ; CHKSTS WILL WAKE USER SUBTTL NSP. -- NSFIR - Receive Interrupt Data ;NSFIR - Receive Interrupt Data ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block with user arguments stored ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ; .NSAA1/ Ptr to interrupt data NSFIR: TRACE SC, TMNE SLCCB,(SL) ;SHOULD WE CHECK CONNECT BLOCK? CALL FRECBP ;YES, GET RID OF CONNECT DATA IF WE CAN MOVX T1,SB.LEN ;GET SB TO STORE THE INTERRUPT DATA CALL DNGWDZ ; FROM MEMORY MANAGER SCERR %NEALF,RTN, STOR T1,SASBP,(SA) ;STORE THE POINTER TO STRING BLOCK MOVX T2,SB.LEN ;LENGTH OF STRING BLOCK IN WORDS STOR T2,SBWDS,(T1) ;STORE LENGTH IN WORDS IN STRING BLOCK XMOVEI T1,SL.OSL(SL) ;POINT TO THE OTHER SUB-LINK'S AREA DEQUE MB,SS.INQ(T1),MB.NXT,NSFIR2 ;TRY TO DEQUE A MESSAGE ON INPUT Q MOVE T1,MB ;SET UP FOR DNLENG CALL DNLENG ;FIGURE OUT LENGTH OF MESSAGE OPSTRM ,SLBYR,(SL) ;Update count of bytes received CAILE T1,^D16 ;IS IT TOO LONG? CALLRET SCEIVM ;--INVALID MESSAGE EVENT MOVE P1,T1 ;SAVE THE LENGTH ;Now copy the data into the intermediate buffer. MOVE T1,MB ;POINT TO THE MESSAGE BLOCK CALL DNGINI ;SET UP TO GET IT LOAD T1,SASBP,(SA) ;POINT TO THE INTERNAL STRING BLOCK CALL CPYI2S ;COPY INTERRUPT DATA TO INTERNAL SB CALLRET SCEIVM ;--INVALID MESSAGE EVENT OPSTRM ,SSRDO,+SL.OSL(SL) ;DECREMENT DATA REQUEST COUNT OPSTR ,SLINQ,(SL) ;IS NEW COUNT WITHIN QUOTA? JRST [CALL FREMSG ;NO, CAN'T SEND ANOTHER DRQ, FREE THE MB RETSKP] ;AND RETURN TO SCMUUO OPSTRM ,SSRDO,+SL.OSL(SL) ;WE'RE SENDING OUT ONE DATA REQUEST TXO T2,MBOTH ;PUT IT ON THE OTHER SUB-LINK MOVX T1,1 ;LET'S SEND OUT ONE DATA REQUEST CALL SNDDRM ;SEND THE DATA REQUESTS SCERR %NEALF,RTN, RETSKP ;RETURN SUCCESSFULLY ;Here when there was nothing on the input queue. NSFIR2: RETSKP ;SCTNA? WILL CALL CHKSTS FOR US SUBTTL NSP. -- NSFDS - Send Normal Data ;NSFDS - Send Normal Data ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block with user arguments stored ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For .NSFDS function, the function dependant arguments are: ; ; SAAA1/ Byte count ; SAAA2/ Byte pointer to data ; SAAA3/ Optional second word of byte pointer NSFDS: TRACE SC, SETZRO SASAT,(SA) ;NOT YET SATISFIED THIS REQUEST. TMNE SLCCB,(SL) ;SHOULD WE CHECK CONNECT BLOCK? CALL FRECBP ;YES, GET RID OF CONNECT DATA IF WE CAN ;We only check the data requests here, not the quotas as well, because ;we may have a msg blk already allocated on the output queue. LOAD T1,SLXFL,(SL) ;GET FLOW CONTROL TYPE TMNN SSXDO,+SL.NSL(SL) ;ARE THERE ANY DRQS LEFT? JUMPN T1,RSKP ;NO, RETURN NICELY UNLESS NO FLOW CTL IF1,> ;Fall through to next page ;Fall through from previous page ;Here we get a message block in which to put user's data and calculate ;how much of the user's data will fit. OPSTR ,SAAA1,(SA) ;GET USER'S BYTE COUNT SCERR %NEADE,RTN,
;DON'T ALLOW NEGATIVE COUNT SETZ T1, ;ASSUME NO BYTES IN SAVED MESSAGE LOAD MB,SLOTM,(SL) ;ALREADY HAVE A MESSAGE? JUMPE MB,NSFDS0 ;JUMP IF NOT SETZRO SLOTM,(SL) ;YES, ITS NOT THERE ANY MORE XMOVEI T1,UD.MSD(MB) ;REINITIALIZE FOR PUTTING BYTES INTO CALL DNPINR ; A PARTIALLY FILLED MESSAGE BLOCK MOVE T1,MB ;SEE HOW MANY ARE BYTES ALREADY CALL DNLENG ; IN IT BY GETTING LENGTH ADD P1,T1 ;ADD IN BYTES ALREADY IN MESSAGE NSFDS0: OPSTR ,SLSIZ,(SL) ;SUBTRACT SEGMENT SIZE WE'RE USING ;P1 is now: ; Negative if user data fits in segment with room to spare ; Zero if user data fits in segment exactly ; Positive if user data is too big to fit in segment ;This fact is used throughout the rest of this routine. LOAD P2,SAAA1,(SA) ;ASSUME USER'S BUFFER WILL FIT IN SEGMENT JUMPLE P1,NSFDS1 ;WILL IT FIT? LOAD P2,SLSIZ,(SL) ;NO, SEND ONE SEGMENT'S WORTH SUB P2,T1 ;P2 NOW HAS NUMBER OF BYTES WE'LL COPY NSFDS1: JUMPN MB,NSFDS2 ;JUMP IF WE JUST DEQUEUED A MESSAGE BLOCK ;Get a message block MOVE T1,P2 ;NUMBER OF BYTES WE'LL COPY INTO FIRST SEGMENT TMNN SAEOM,(SA) ;IS THIS SEGMENT AN END OF MESSAGE? LOAD T1,SLSIZ,(SL) ;NO, ALLOCATE A WHOLE SEGMENT'S WORTH SINCE ; USER WILL BE SENDING MORE IN THIS SEG CALL DNGMSG ;(T1)GET MESSAGE BLOCK JRST NSFDS6 ;SUCCEEDED IN SENDING ZERO BYTES (CONGESTION) MOVE MB,T1 ;SET UP MB WITH MESSAGE BLOCK POINTER XMOVEI T1,UD.MSD(MB) ;INITIALIZE FOR PUTTING BYTES CALL DNPINI ; IN USER DATA PART OF MESSAGE BLOCK D36OFF ;INTERLOCK AGAINST SCTRIB CALL FROM LLINKS JE SLOTU,(SL),NSFDSO ;JUMP IF THIS WILL BE ONLY OUTPUT BUFFER NOW MOVE T1,DCNRSB ;GET # NOW RESERVED SKIPN DCNCON ;IS SYSTEM CONGESTED? CAML T1,DCNTSB ;NO, IS THERE ROOM FOR ONE MORE? JRST NSFDSF ;NO, RETURN FAILURE AOS T1,DCNRSB ;ONE MORE BUFFER RESERVED CAMLE T1,DCNRHT ;NEW HIGH TIDE? MOVEM T1,DCNRHT ;YES, RECORD IT JRST NSFDSA ;GOT ROOM, GO ALLOCATE NSFDSF: ;NO ROOM FOR THIS LOGICAL LINK SETOM DCNCON ;CALL FOR CHKSTS WHEN CONGESTION FREES D36ON ;END CRITICAL SECTION AOS DCNROF ;INCREMENT OUTPUT RESERVATION FAILURES CALL FREMSG ;RETURN THE MESSAGE BLOCK JRST NSFDS6 ;SUCCEEDED IN SENDING ZERO BYTES (CONGESTION) NSFDSO: JN SLINU,(SL),NSFDSA ;JUMP IF INPUT BUFF ALLOC, THAT RESERVES 1 OUT MOVE T1,DCNRSB ;GET # ALREADY RESERVED ADDI T1,2 ;WE INTEND TO RESERVE 2 MORE (1 IN + 1 OUT) CAMLE T1,DCNTSB ;WILL THAT FIT IN TOTAL? JRST NSFDSF ;NO, RETURN FAILURE MOVEM T1,DCNRSB ;YES, D36OFF MAKES THIS STORE OK CAMLE T1,DCNRHT ;NEW HIGH TIDE? MOVEM T1,DCNRHT ;YES, RECORD IT NSFDSA: INCR SLOTU,(SL) ;INCREMENT NUMBER OF OUTPUT BUFFERS IN USE D36ON ;END OF CRITICAL SECTION NSFDS2: ;Fall through to next page ;Fall through from previous page ;Message block is now ready to receive data and P2 has the count of ;data to copy into it. MOVE T1,P2 ;PASS # OF BYTES TO COPY TO COPIER LOAD T2,SAAA2,(SA) ;GET BYTE POINTER LOAD T3,SAAA3,(SA) ;GET OPTIONAL SECOND WORD OF BYTE PTR IFN FTOPS10,< MOVE T4,[XCDSEC,,DNCU2M] ;Assume buffer in user space TMNE SAEVA,(SA) ;IS THAT TRUE? > ;Note: SAEVA must be set on TOPS-20 - user mode buffers are not supported MOVE T4,[XCDSEC,,DNCB2M] ; -no, copy from monitor buffer CALL 0(T4) ;COPY BUFFER TO THE MESSAGE BLOCK STOR T2,SAAA2,(SA) ;STORE UPDATED BYTE POINTER STOR T3,SAAA3,(SA) ;OPTIONAL SECOND WORD OF BYTE PTR SUB P2,T1 ;T1 contains count of bytes we didn't copy SKIPLE T1 ;Any bytes not sent? MOVE P1,T1 ;Yes, remember that MOVN T1,P2 ;GET # OF BYTES WE COPIED OPSTRM ,SAAA1,(SA) ;FIX USER'S COUNT OF BYTES TO SEND TMNN SAEOM,(SA) ;IS THIS END OF MESSAGE SKIPL P1 ; OR DID WE GET A WHOLE SEGMENTS WORTH? JRST NSFDS3 ;YES, SEND SEGMENT TO NSP ;Here to save pointer to message so that the user can add data to it ;later. Note that in this case we allocated a whole segment when we ;allocated the message block. SETONE SASAT,(SA) ;WE HAVE SATISFIED THIS NSFDS REQUEST STOR MB,SLOTM,(SL) ;SAVE PTR TO PARTIALLY FILLED OUTPUT MSG RETSKP ;RETURN SUCCESSFULLY ;Send segment to NSP. ;Set the BoM and EoM flags in the message block and remember whether ;or not this segment had EoM for figuring the next segment's BoM. NSFDS3: MOVE T1,SL.EOM(SL) ;GET "LAST SEGMENT'S EOM" WORD MOVX T2,MBBOM ;GET MESSAGE BLOCK'S BOM FLAG TXOE T1,SLEOM ;LAST SEGMENT HAVE EOM? (ASSUME THIS WILL) IORM T2,MB.BOM(MB) ;YES, THIS MUST BE FIRST SEGMENT OF NEXT MSG JUMPG P1,NSFDS4 ;NEVER EOM IF WE'RE SEGMENTING MOVX T2,MBEOM ;GET MESSAGE BLOCK'S EOM FLAG TMNN SAEOM,(SA) ;IS THIS EOM? NSFDS4: TXZA T1,SLEOM ;NO, REMEMBER THAT FOR NEXT SEGMENT IORM T2,MB.EOM(MB) ;YES, MARK MESSAGE BLOCK WITH EOM MOVEM T1,SL.EOM(SL) ;REMEMBER STATE OF EOM FLAG FOR NEXT TIME ;Update counts INCR SLPKS,(SL) ;# of 'packets' sent XMOVEI T1,UD.MSD(MB) ;Point to user MSD CALL DNSLNG ;Get # of bytes in it OPSTRM ,SLBYS,(SL) ; and update bytes sent ;Send the message LOAD T1,SLPID,(SL) ;GET NSPpid SETZ T2, ;DAOTH IS ZERO MOVX T3,NV.SEG ;FUNCTION IS SEND A SEGMENT MOVE T4,MB ;POINT TO MESSAGE BLOCK CALL NSP ;DO SEND ;Determine whether or not to claim that we have satisfied the request MOVX T1,SASAT ;PICK UP SASAT FLAG SKIPG P1 ;MORE DATA TO SEND FOR THIS REQUEST? IORM T1,SA.SAT(SA) ;NO, WE'VE SATISFIED THE REQUEST ;Update DRQs. LOAD T1,SLXFL,(SL) ;GET FLOW CONTROL TYPE WE ARE USING CAIN T1,FCM.SG ;IS IT SEGMENT? JRST NSFDS5 ;YES, DECREMENT DATA REQUEST COUNT SKIPG P1 ;DO WE HAVE ANY MORE SEGMENTS TO SEND LATER? CAIE T1,FCM.MG ;NO, SAEOM MUST BE SET IF WE'RE HERE RETSKP ;MORE SEGS TO GO OR NO FLOW CONTROL NSFDS5: OPSTRM ,SSXDO,+SL.NSL(SL) ;DECR COUNT OF XMT DATA REQUESTS RETSKP ; AND RETURN SUCCESS ;Here when DNGMSG fails due to congestion. We have not yet changed ;SAAA1, so the user will see that we succeeded in sending zero bytes. NSFDS6: LOAD T1,SLSST,(SL) ;GET LINK STATUS HALF-WORD TXZ T1,NSNDR ! NSIDR ;NEITHER TYPE OF OUTPUT IS OK NOW STOR T1,SLSST,(SL) ;STORE BACK SO WHEN CONGESTION IS FREED RETSKP ; CHKSTS WILL WAKE USER SUBTTL NSP. -- NSFDR - Receive Normal Data ;NSFDR - Receive Normal Data ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block with user arguments stored ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING THE ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFDR function, the function dependant arguments are: ; ; SAAA1/ Byte count ; SAAA2/ Byte pointer ; SAAA3/ Optional second word of byte pointer NSFDR: TRACE SC, SETZRO SASAT,(SA) ;NOT YET SATISFIED THIS REQUEST. TMNE SLCCB,(SL) ;SHOULD WE CHECK CONNECT BLOCK? CALL FRECBP ;YES, GET RID OF CONNECT DATA IF WE CAN LOAD T1,SAFLG,(SA) ;GET THE FLAGS TXNN T1,SA%WAI ;IS WAIT OFF TXNN T1,SA%EOM ; AND EOM ON? TRNA ;NO, NO DEADLY EMBRACE PROBLEM SCERR %NEBCF,RTN, XMOVEI P2,SL.NSL(SL) ;POINT TO NORMAL SUBLINK AREA NSFDR1: LOAD MB,QHBEG,+SS.INQ(P2) ;GET THE FIRST THING ON THE INPUT QUEUE JUMPE MB,RSKP ;THERE'S NOTHING THERE, ; SCTNI? WILL CALL CHKSTS ;Here with MB/ The Input Message ; P2/ SL.NSL(SL) ;The SASAT flag is set when a read is satisfied, that is, when we have ;read a message segment containing an End of Message flag. SASAT is ;used to tell whether to wake a user who has requested NS.WAIt. SASAT ;is for internal use only: it has no meaning to the user. We cannot use ;SAEOM for this purpose because SAEOM has meaning when passed from the ;user to us: if it is set, then we must put the next message in one ;buffer, possibly truncating data, if SAEOM is cleared by the user, we ;must keep the overflow and present it to the next read. Also, we ;consider a read satisfied if the user's buffer is filled and the ;user has not asserted SAEOM. MOVE T1,MB ;SET UP FOR CALL TO DNLENG CALL DNLENG ;GET THE LENGTH OF THE MESSAGE MOVE P1,T1 ;P1 HAS LENGTH OF USER'S DATA IN MSG MOVE T1,MB ;GET READY TO READ REST OF BYTES CALL DNGINI ; IN THE MESSAGE ;Note that the following code does not depend on SASAT being initialized MOVE T4,SA.FLG(SA) ;GET USER'S FLAGS BEFORE THEY'RE MODIFIED LOAD T5,MBEOM,(MB) ;GET EOM FLAG FROM MSG BLK, T5 USED BELOW STOR T5,SASAT,(SA) ;READ IS SATISFIED IF THIS IS EOM ; IOR IF BUFFER IS FULL, SEE BELOW LOAD T1,SAAA1,(SA) ;GET THE LENGTH OF THE USER'S BUFFER ; ; SPR 10-34926 ; If there's a negative count here, it should be because we're discarding ; DECnet messages for the user until we see EOM in an incoming message. ; This happens if the user sets the EOM bit in his arg block, but ; the incoming message is too big to fit in his buffer, and it doesn't ; have EOM set itself. We should discard bytes until we see an EOM. ; SCMUUO already checked to make sure that the user didn't give us a ; negative count to begin with. ; SUB T1,P1 ;WILL THIS MESSAGE FIT? JUMPE T1,NSFDR2 ;MSG FITS IN USER BUFFER EXACTLY JUMPG T1,NSFDR3 ;MSG FITS IN USER BUFFER WITH ROOM TO SPARE ;Here if message overfills user buffer LOAD P1,SAAA1,(SA) ;COPY ONLY WHAT FITS IN USER BUFFER SETZ T5, ;BUFFERFUL HAS NO EOM, SINCE IT OVERFLOWED TXNN T4,SAEOM ;USER WANT WHOLE MSG IN 1 READ? SETZB P2,T1 ;NO, LEAVE MSG BLK FOR NEXT READ, COUNT := 0 ;YES, TOSS REST OF MSG, P2 STILL PTS TO NSL ;Here if message fills or overfills user buffer NSFDR2: MOVX T2,SASAT ;SATISFACTION FLAG TXNN T4,SAEOM ;USER WANT WHOLE MSG IN 1 READ? IORM T2,SA.SAT(SA) ;NO, READ IS SATISFIED SINCE BUFFER IS FULL ; WHETHER OR NOT MBEOM IS TRUE ;Here for all messages, note that count is negative if we toss overflow NSFDR3: TXNN T4,SAEOM ;USER WANT WHOLE MSG IN 1 READ? STOR T5,SAEOM,(SA) ;NO, STORE EOM FLAG WE'VE CALC'D HERE STOR T1,SAAA1,(SA) ;STORE # BYTES REMAINING IN USER BFR ;We now have: P1/ Length of data to copy ; P2/ Pointer to NSL if we're to free msg blk, else 0 JUMPLE P1,NSFDRA ;IF COUNT IS NEGATIVE, DON'T COPY ANYTHING ;Update byte count in SLB OPSTRM ,SLBYR,(SL) ;# of bytes received ;Copy the message data into the user's buffer. MOVE T1,P1 ;NUMBER OF BYTES TO COPY FROM MSG TO USER LOAD T2,SAAA2,(SA) ;GET THE BYTE POINTER LOAD T3,SAAA3,(SA) ; AND OPTIONAL SECOND WORD OF BPTR IFN FTOPS10,< MOVE T4,[XCDSEC,,DNCM2U] ;ASSUME BUFFER IN USER SPACE TMNE SAEVA,(SA) ;IS THAT TRUE? > ;Note: SAEVA must be set on TOPS-20 - buffer can never be in user space MOVE T4,[XCDSEC,,DNCM2B] ;No, copy to monitor buffer CALL 0(T4) ;COPY MESSAGE BLOCK TO BUFFER CALLRET SCEIVM ;--INVALID MESSAGE EVENT STOR T2,SAAA2,(SA) ;STORE THE UPDATED BYTE POINTER STOR T3,SAAA3,(SA) ; AND OPTIONAL SECOND WORD OF BPTR NSFDRA: JUMPE P2,RSKP ;IF THERE'S NO PTR, WE HAVE MORE TO READ ; FROM THIS MSG, SO DON'T DEQUE MSG ; OR SEND OUT DATA REQUESTS YET DEQUE MB,SS.INQ(P2),MB.NXT,NSFDRB ;DEQUE MSG WE WERE PEEKING AT ;Here we unreserve an appropriate number of buffers, but we don't ;reserve any again to correspond to the data requests we send, that is ;done by a call to SCTRIB from LLINKS when a message arrives. NSFDRB: D36OFF ;PROTECT THIS CODE FROM LLINKS CALL TO SCTRIB OPSTRM ,SLINU,(SL) ;ONE LESS INPUT BUFFER USED MOVX T2,-1 ;ASSUME WE'RE NOT FREEING LAST INPUT BUFFER JUMPG T1,NSFDR4 ;JUMP IF THAT'S TRUE MOVX T2,-2 ;WE ARE FREEING LAST INPUT, ASSUME NO OUTPUT TMNE SLOTU,(SL) ;ANY OUTPUT BUFFERS RESERVED? MOVX T2,0 ;YES, LEAVE AN INPUT BUFFER RESERVED NSFDR4: ADDB T2,DCNRSB ;ADJUST THE RESERVED BUFFER COUNT D36ON ;END OF CRITICAL SECTION LOAD T1,SLINQ,(SL) ;GET THE INPUT QUOTA OPSTRM ,SSRDO,+SL.NSL(SL) ;ONE LESS REC DATA REQUEST SUB T1,T2 ;HOW MANY REQUESTS SHOULD WE SEND NOW? JUMPL T1,[CALL FREMSG ;IF WE DON'T HAVE ENOUGH QUOTA, CAN'T SEND ; ANOTHER DRQ, SO FREE MESSAGE BLOCK RETSKP] ;AND RETURN TO MONITOR USER OPSTRM ,SSRDO,+SL.NSL(SL) ;UPDATE RECEIVE DRQ COUNT ;Send the data requests to NSP. TXZ T2,MBOTH ;(T1,T2)ON THE NORMAL SUB-LINK CALL SNDDRM ;SEND DATA REQUESTS USING MESSAGE BLOCK ; WE CURRENTLY HAVE SCERR %NEALF,RTN, RETSKP ;RETURN SUCCESSFULLY SUBTTL NSP. -- NSFSQ - Set Quotas and Goals ;NSFSQ - Set Quotas and Goals ;Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block with user arguments stored ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6, P1 & MB ; ;For the .NSFSQ function, the function dependant arguments are: ; .NSAA1/ Link Quota, input + output ; .NSAA2/ % Input ; .NSAA3/ Input Goal NSFSQ: TRACE SC, LOAD T1,SLSTA,(SL) ;GET LINK STATE IFSTATE T1,,RSKP ;LEAVE QUIETLY IF IN TERMINAL STATE LOAD P1,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER SUPPLIED CAIG P1,.NSAA1 ;DID HE GIVE THE TOTAL QUOTA? SCERR %NEWNA,RTN, LOAD T1,SLINQ,(SL) ;GET THE OLD QUOTA OPSTR ,SLOTQ,(SL) ;TOTAL OF INPUT + OUTPUT QUOTA OPSTR ,SAAA1,(SA) ;USER SUPPLY A NEW QUOTA? STOR T1,SAAA1,(SA) ;NO, STORE OLD QUOTA TOTAL AS DEFAULT MOVEI T2,0 ;NO VALUE OFFERED YET CAILE P1,.NSAA2 ;DID HE GIVE THE % INPUT? LOAD T2,SAAA2,(SA) ;GET HIS VALUE CAILE T2,^D100 ; AND 100 SCERR %NEPIO,RTN, JUMPG T2,NSFSQ1 ;USER OFFER A VALUE? MOVEI T2,^D50 ;NO, ASSUME HALF INPUT & HALF OUTPUT STOR T2,SAAA2,(SA) ;REMEMBER PERCENTAGE WE DECIDED ON NSFSQ1: SETZB T1,MB ;DON'T NEED ANY USER DATA CAIG P1,.NSAA3 ;USER SPECIFY AN INPUT GOAL? IFSKP. ;Yes, apply default if necessary LOAD T2,SASJB,(SA) ;Get pointer to SJB LOAD T1,SJGOL,(T2) ;Get job goal for default OPSTR ,SAAA3,(SA) ;Verify supplied value STOR T1,SAAA3,(SA) ;Apply default CALL DNGMSG ;GET MESSAGE BLOCK IN CASE WE NEED IT SCERR %NEALF,RTN, MOVE MB,T1 ;SAVE POINTER TO MSG BLK ENDIF. ;No more error returns now LOAD T1,SAAA1,(SA) ;GET THE LINK QUOTA LOAD T2,SAAA2,(SA) ;GET PERCENTAGE VERIFIED ABOVE IMUL T1,T2 ;MULTIPY LINK QUOTA BY % INPUT IDIVI T1,^D100 ;DIVIDE BY 100. TO FIND INPUT QUOTA STOR T1,SLINQ,(SL) ;STORE THE INPUT QUOTA IN THE SLB LOAD T2,SAAA1,(SA) ;GET THE LINK QUOTA BACK SUB T2,T1 ;SUBTRACT TO FIND THE OUTPUT QUOTA STOR T2,SLOTQ,(SL) ;STORE THE OUTPUT QUOTA IN THE SLB CAIG P1,.NSAA3 ;WAS THE GOAL SPECIFIED? RETSKP ;USE DEFAULT THAT'S THERE ALREADY ;WE ONLY GOT MSG BLK IF WE HAVE A GOAL LOAD T1,SLRFL,(SL) ;GET THE FLOW CONTROL TYPE LOAD T2,SAAA3,(SA) ;GET THE INPUT GOAL CAIN T1,FCM.MG ;ARE WE IN MESSAGE FLOW CONTROL? CAIL T2,1 ;YES, IS OUR GOAL SET TO LESS THAN ONE? TRNA ;NO, DON'T WORRY ABOUT IT MOVEI T2,1 ;IN MSG FLOW MODE WE GOAL OF AT LEAST 1 STOR T2,SLGOL,(SL) ;REMEMBER THE GOAL WE DECIDED ON ;Notify NSP of the change in the goal. LOAD T1,SLPID,(SL) ;GET THE NSPpid ;T2 CARRIED DOWN FROM ABOVE IFE. T1 ;IS THERE ONE ? MOVE T1,MB ;NO. DON'T TELL NSP CALL DNFMSG ; SINCE THERE IS NO PLACE RETSKP ; TO PUT IT YET. ENDIF. MOVX T3,NV.GOL ;FUNCTION IS SET GOAL MOVE T4,MB ;NSP TAKES MB POINTER IN T4 CALL NSP ;(T1,T2,T3,T4)PERFORM THE SET GOAL RETSKP ;RETURN SUCCESS SUBTTL NSP. -- NSFRQ - Read Quotas and Goals ;NSFRQ - Read Quotas and Goals ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block with user arguments stored ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFRQ function, the function dependant arguments are: ; ; .NSAA1/ Link Quota ; .NSAA2/ % Input ; .NSAA3/ Input Goal NSFRQ: TRACE SC, LOAD T1,SLINQ,(SL) ;GET THE INPUT QUOTA LOAD T2,SLOTQ,(SL) ; AND THE OUTPUT QUOTA ADD T1,T2 ;TOTAL THEM UP STOR T1,SAAA1,(SA) ;STORE IN ARG BLOCK WERE THE LINK QUOTA GOES LOAD P1,SANAG,(SA) ;GET THE NUMBER OF ARGUMENTS USER SUPPLIED CAIG P1,.NSAA2 ;DOES HE WANT THE %INPUT? RETSKP ;NO, JUST GIVE GOOD RETURN LOAD T2,SLINQ,(SL) ;Get the input quota IMULI T2,^D100 ;Multiply by 100 to get % input IDIV T2,T1 ; as an integer between 0 and 100. STOR T2,SAAA2,(SA) ;Store it in argument block CAIG P1,.NSAA3 ;DOES HE WANT THE INPUT GOAL? RETSKP ;NO, JUST RETURN LOAD T1,SLGOL,(SL) ;GET THE GOAL STOR T1,SAAA3,(SA) ;PUT IT IN THE ARG BLOCK RETSKP ; AND RETURN SUBTTL NSP. -- NSFJS - Set Job Quotas and Goals ;NSFJS - Set Job Quotas and Goals ; ; Call: ; Never Happens: serviced in SCMUUO ; ; Return: ; ; Uses: Nothing ; ;This function is performed entirely by SCMUUO or equivalent. NSFJS: SCERR %NEILF,RTN, SUBTTL NSP. -- NSFJR - Read Job Quotas and Goals ;NSFJR - Read Job Quotas and Goals ; ; Call: ; Never Happens: serviced in SCMUUO ; ; Return: ; ; Uses: Nothing ; ;This function is performed entirely by SCMUUO or equivalent. NSFJR: SCERR %NEILF,RTN, SUBTTL NSP. -- NSFPI - Set PSI Reason Mask ;NSFPI - Set PSI Reason Mask ; ; Call: ; SL/ Pointer to Session Control Link Block ; SA/ Pointer to Session Control Arg Block with user arguments stored ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ALL IS WELL ; ; Uses: T1-T6 ; ;For the .NSFPI function, the function dependent arguments are: ; ; .NSAA1/ XWD 0,reason mask NSFPI: TRACE SC, LOAD T1,SAAA1,(SA) ;GET .NSAA1 ARGUMENT STOR T1,SLPSM,(SL) ;STORE THE PSI MASK FOR SCTPSI TMNE ,(SL) ;PSI ALREADY PENDING OR LINK CLOSING? RETSKP ;YES, AVOID RACE ;T1 HOLDS OLD STATUS (0),,NEW MASK LOAD T2,SLCHN,(SL) ;THE LINK NUMBER LOAD T5,SLSST,(SL) ;T5 PASSES STATUS CHANGES (CURRENT STATUS) HRL T2,T5 ;T2 HOLDS NEW STATUS,,CHN NUMBER LOAD T3,SLSJB,(SL) ;@SLWKA NEEDS T3 SET UP WITH PTR TO SJB MOVE T4,SL ;'LINK IDENTIFIER' TO PASS TO SCTWKQ OPSTR ,SLWKA,(SL) ;IS THERE A WAKE ROUTINE? CALL 0(T6) ;(T1,T2,T3,T4,T5)YES, CALL WAKE ROUTINE RETSKP ;RETURN SUCCESSFULLY SUBTTL RETFLW - Return current flow controls ;RETFLW - Return Receive Flow Mode,,Transmit Flow Control ; ; Call: ; SL/ Pointer to Session Control Line Block ; ; Return: ; RET ;ALWAYS, WITH T1 CONTAINING RFL,,XFL ; ; Uses: T1,T2 RETFLW: LOAD T1,SLRFL,(SL) ;GET THE RECEIVE FLOW CONTROL LOAD T2,SLXFL,(SL) ;GET THE TRANSMIT FLOW CONTROL TYPE ADDI T1,1 ;TRANSLATE TO USER'S VALUE HRLI T1,1(T2) ;BUILD RFL,XFL ;TRANSLATE THAT ALSO RET ; AND RETURN SUBTTL SNDDRQ - Send Data Requests ;SNDDRQ - Send some data requests to NSP ; ; Call: ; T1/ Number of Data Requests to Send ; T2/ MBOTH set to the correct value ; (for SNDDRM: ; MB/ Pointer to Message Block) ; ; Return: ; RET ;ON ALLOCATION FAILURE ; RETSKP ;ON SUCCESS ; ; Uses: T1-T6 ;The SNDDRQ code is commented out since there are no callers of it. ; All callers come in at the SNDDRM entry point Repeat 0,< SNDDRQ: SAVEAC ;GET OUR OWN COPY OF MB AND SAVE SOME PEAS DMOVE P1,T1 ;PRESERVE THE ARGUMENTS SETZ T1, ;DON'T NEED ANY USER DATA CALL DNGMSG ;GET A MESSAGE BLOCK RET ;COULDN'T ALLOCATE, JUST RETURN MOVE MB,T1 ;POINT TO THE NEW MESSAGE BLOCK CALLRET SNDDRX ;JOIN COMMON CODE > ;This is the alternate entry for those guys which already have a message ;block. SNDDRM: DMOVE P1,T1 ;SAVE THE COUNT AND MBOTH MOVE T1,MB ;POINT TO THE MESSAGE BLOCK MOVEI T2,0 ;NO USER DATA NEEDED CALL DNMINI ;RE-INITIALIZE THE MESSAGE BLOCK RET ;COULDN'T DO IT SNDDRX: SETZ T2, ;BUILD THE DATA REQUEST ARG BLOCK (QA) IN T2 STOR P1,QACNT,+T2 ; USE THAT AS THE DATA REQUEST COUNT MOVX T1,MBOTH ;GET THE "OTHER" SUBLINK FLAG TXNE P2,MBOTH ;CALLER WANT IT SET IN MESSAGE BLOCK? IORM T1,MB.OTH(MB) ;YES, IT WAS CLEARED BY DNMINI LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP MOVX T3,NV.DRQ ;FUNCTION IS SEND DATA REQUESTS MOVE T4,MB ;POINT TO MESSAGE BLOCK CALL NSP ;CALL NSP AND RETURN EVENTUALLY RETSKP ;RETURN SUCCESS SUBTTL RLSLNK - Release a Link ;RLSLNK - Release a Link ; ; Call: ; MB/ Ptr to msg blk or zero if LLINKS will not have to queue NV.CLS call ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6,MB,MS RLSLNK: JN ,(SL),RLSLN1 ;IGNORE IF LINK ALREADY BEING CLOSED SKIPN EV96.0 ;Shall we log the CSSE event? IFSKP. ; -yes, unfortunately EVENT(LCG,CSE,Link close) ;Log "link close" event for CSSE ENDIF. CALL STPTMR ;STOP THE CI TIMER, IF IT'S GOING JN SLPID,(SL),RLSLN2 ;JUMP IF WE HAVE A PID FROM NSP SETONE SLFSL,(SL) ;WE HAVEN'T TOLD NSP ABOUT ; THIS LINK YET, DON'T CALL HIM NOW CALL SCTRFJ ;REQUEST SECOND SERVICE, SLFSL WILL ; TELL IT TO FREE THE SLB RLSLN1: SKIPN MB ;DID WE HAVE A MSG BLK? RET ;NO, ONLY RETURN CALLRET FREMSG ;YES, FREE IT AND RETURN RLSLN2: LOAD T1,SLPID,(SL) ;GET THE NSPpid FROM SLB LOAD T2,SLSLB,(SL) ;GET THIS PORT'S SLBid MOVX T3,NV.CLS ;CLOSE FUNCTION FOR NSP MOVE T4,MB ;NSP WANTS MSG BLK PTR IN T4 (ZERO IF RESET) CALL NSP ;CALL NSP TO CLOSE THE PORT SETONE SLLBC,(SL) ;LINK IS BEING CLOSED RET ;ONLY RETURN SUBTTL LLINKS Calls -- Entry Vector Table ;See procedure SCTL for a description of the calling sequence used to ;call SCTL. ;The offsets SV.xxx into this table are defined in D36PAR. DEFINE SV(NAM),< IFN .-SCFNT-SV.'NAM,< PRINTX ?SCFNT table (NAM) not in same order PRINTX ? as SV.'NAM in D36PAR.UNV PASS2 END> IFIW > ;These are the function codes for the calls to Session Control from ;NSP. SCFNT: SV CCR ;CONNECT CONFIRMED CALL SV DIR ;DISCONNECT INITIATE RECEIVED CALL SV DCR ;DISCONNECT CONFIRM RECEIVED CALL SV OND ;OUTPUT NOT DONE CALL SV ODN ;OUTPUT DONE CALL SV SEG ;SEGMENT RECEIVED CALL SV DRQ ;DATA REQUEST RECEIVED CALL SV NCF ;NO CONFIDENCE IN PORT CALL SV NRS ;NO RESOURCES CALL SV CLS ;CLOSE COMPLETED CALL SV NLK ;NO LINK CALL SV NCM ;NO COMMUNICATION CALL SV NRN ;NOT IN RUN STATE SV CAK ;GOT A CONNECT ACK SV.MAX==.-SCFNT-1 ;THE HIGHEST RECOGNIZED ENTRY OFFSET ;The Connect Initiate call does not go ;through the vectored interface, since ;it must go to a single routine ;capable of sorting out which Session ;Control will handle the incoming ;message. the connect initiate call ;goes to the global label SCTLCI. PURGE SV SUBTTL LLINKS Calls -- SCTRIB - Reserve Input Buffer ;SCTRIB - Reserve Input Buffer ; ;Call: T1/ Pointer to SLB ; CALL SCTRIB ; Error Return: no input buffer has been reserved ; Normal Return: one input buffer has been reserved ;Changes T1,T2,T3,T4 ;This routine and all others which reference DCNRSB must run under ;D36OFF because this routine is called from LLINKS without the SCLINK ;interlock. This routine is only called from LLINKS. It is here in ;SCLINK so that all references to the reserved buffer counter will be ;together in one module. ;The scheme here is that we want to count the buffers which are ;actually in use, plus those which are required to be reserved in ;order to prevent a deadlock. We must be sure that no logical link is ;put in the position of being having a allowed to read a message while ;being stuck not allowed to send a message. If both ends of a link ;were to be in that state, they would be in a deadly embrace. ; ;So whenever we want to commit a buffer for output (by sending it) or ;for input (by ACKing it), we must check first if we have room in the ;system pool to reserve it. If we reserve a buffer for one direction, ;then we must assure that at least one is reserved for the other ;direction. ; ;The handling of DCNRSB in SCLINK preserves the above guarantees. ;This routine is called from LLINKS when it receives a message and ;there are Session Control data requests for that message. If this ;routine returns failure, LLINKS will keep the message, unACKed, and ;will try to send it to Session Control again when the memory manager ;tells LLINKS that congestion has been relieved. XRESCD SCTRIB: OPSTR ,SLSLB,(T1) ;IS THIS A LEGIT SLB POINTER? BUG.(CHK,SCLRIB,SCLINK,SOFT,,<>,< Cause: LLINKS has called SCTRIB for permission to send a message to SCLINK and has passed an invalid SLB address in T1. The data structures for this logical link are inconsistent. Action: Find out what is in LLINK's ELSCB and why its not an SLB pointer. Data: ADDR - The bad SLB pointer >,RTN) D36OFF ;INTERLOCK AGAINST SCTRIB CALL FROM LLINKS JE SLINU,(T1),SCTRB1 ;JUMP IF THIS WILL BE ONLY INPUT BUFFER NOW MOVE T2,DCNRSB ;GET # NOW RESERVED SKIPN DCNCON ;IS THE SYSTEM CONGESTED? CAML T2,DCNTSB ;NO, CAN WE FIT ONE MORE? JRST SCTRB3 ;NO ROOM FOR THIS LINK AOS T2,DCNRSB ;ONE MORE BUFFER RESERVED JRST SCTRB2 ;SUCCESS SCTRB1: JN SLOTU,(T1),SCTRB4 ;JUMP IF OUTPUT BUFF ALLOC, THAT RESERVES 1 IN MOVE T2,DCNRSB ;GET # ALREADY RESERVED ADDI T2,2 ;WE INTEND TO RESERVE 2 MORE (1 IN + 1 OUT) CAMLE T2,DCNTSB ;ENOUGH ROOM IN TOTAL SYSTEM BUFFERS? JRST SCTRB3 ;NO, NO ROOM FOR THIS LINK MOVEM T2,DCNRSB ;YES, D36OFF MAKES THIS STORE OK SCTRB2: CAMLE T2,DCNRHT ;NEW HIGH TIDE? MOVEM T2,DCNRHT ;YES, RECORD IT SCTRB4: INCR SLINU,(T1) ;UPDATE INPUT_BUFFERS_IN_USE COUNT D36ON ;END OF CRITICAL SECTION RETSKP ;GOT ROOM, SUCCESS RETURN SCTRB3: SETOM DCNCON ;CALL FOR CHKSTS WHEN CONGESTION FREES D36ON ;END OF CRITICAL SECTION AOS DCNRIF ;INCREMENT INPUT RESERVATION FAILURES RET ;FAIL RETURN SUBTTL LLINKS Calls -- SCTUCG - Uncongestion Call ;SCTUCG - LLINKS calls this routine when memory manager announces ; that congestion is relieved. ; ; Call: ; No arguments ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 XRESCD SCTUCG: SAVEAC TRACE SC,Session Control told of congestion relief SETOM SCTUCF ;NO MESSAGE BLOCK TO QUEUE HERE CALLRET SCTLCF ;GET THE INTERLOCK, FLAG IF FAIL ;When NSFDS (data send) and NSFIS (interrupt send) fail to get a ;message block, they will both turn off both NSNDR (normal data ;requests available) and NSIDR (interrupt data requests available). ;Presumably this will only happen if the system is congested. Later, ;when the system congestion is relieved, we must tell the stalled ;links that we again have message blocks available. Since the NSxDR ;flags in the status half-word have been turned off, this call to ;CHKSTS will turn them back on again if appropriate and this will ;trigger CHKSTS to call the wake routine. SCIUCG: LOAD SL,QHBEG,+SCTASQ ;PTR TO FIRST SLB ON ALL SLBs Q SCIUC1: JUMPE SL,RTN ;RETURN WHEN NO MORE SLBs TO VISIT CALL CHKSTS ;SEE IF THIS SLB NEEDS WAKING LOAD SL,SLASQ,(SL) ;STEP TO NEXT SLB ON ALL SLBs Q JRST SCIUC1 ;LOOP OVER ALL SLBs IN SYSTEM SUBTTL LLINKS Calls -- SCTLCI - Connect Initiate Call ;SCTLCI - Connect Initiate Call ; ; Call: ; T1/ NSPpid for port just created ; T2/ Connect Call arguments (see BEGSTR IA in D36PAR) ; T4/ Pointer to Message Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 XRESCD SCTLCI: SAVEAC TRACE SC,Connect Initiate call MOVE MB,T4 ;SET UP THE MESSAGE BLOCK POINTER STOR T1,MBAR1,(MB) ;STORE THE FIRST ARGUMENT STOR T2,MBAR2,(MB) ; AND THE SECOND ONE XMOVEI T1,SCTLC1 ;PROCESSOR TO CALL WHEN WE CALLRET SCTLCQ ; GET THE INTERLOCK ;Now try to find a matching SLB for the incoming connect. SCTLC1: TRACE SC,Processing Connect Initiate MOVE T1,MB ;POINT TO THE INCOMING MESSAGE BLOCK CALL DNGINI ;SET UP MS FOR DNGxBY ROUTINES MOVX T1,CB.LEN ;WE HAVE TO GET A CONNECT BLOCK CALL DNGWDZ ; TO FILL IN AND COMPARE WITH PASSIVE SLBS JRST SCTCIR ;RESOURCE FAILURE MOVE P1,T1 ;SAVE POINTER TO INCOMING CONNECT BLOCK CALL PRSCTX ;PARSE THE INCOMING CONNECT DATA IN CB JRST [ MOVE T1,P1 ;PTR TO NEW CONNECT BLK CALL DNFWDS ;FREE NEW CONNECT BLK CALLRET SCEIVM] ;--INVALID MESSAGE EVENT MOVE T1,P1 ;GET THE INCOMING CONNECT BLOCK POINTER BACK CALL SLBMAT ;FIND PASSIVE SLB TO MATCH NEW SLB JRST [ EXCH T1,P1 ;Get pointer to new connect block and save ; return code CALL DNFWDS ;Free the connect blk JUMPN P1,SCTCIT ;Return 'object too busy' CALLRET SCTCIN] ; otherwise unrecognized object error ;We have found matching SLB, lets set some parameters in the SLB and ;go into CR state. LOAD T1,SLCBP,(SL) ;POINT TO PASSIVE CB CALL DNFWDS ;FREE THAT UP SETZRO SLCBP,(SL) ;LOSE PTR TO PASSIVE CB WE JUST FREED LOAD T1,MBSRC,(MB) ;GET SOURCE NODE ADDRESS STOR T1,SLDNA,(SL) ; AND STORE AS DESTINATION OF THIS LINK STOR T1,CBNUM,(P1) ; and store in connect block SCTLC2: STOR P1,SLCBP,(SL) ;PUT PTR TO ACTIVE CONNECT BLK IN SLB ; FOR .NSFRI FUNCTION XMOVEI T1,CB.SRC(P1) ;Point to source PDB LOAD T1,PBOBJ,(T1) ;Get remote object type STOR T1,SLDOB,(SL) ; and store as destination PDB in SLB LOAD T1,MBAR1,(MB) ;GET THE NSPpid STOR T1,SLPID,(SL) ;STORE IT IN THE SLB LOAD T2,MBAR2,(MB) ;GET THE CONNECT CALL ARGUMENTS LOAD T1,IAFLO,+T2 ;GET FLOW CONTROL TYPE FROM ARGUMENTS STOR T1,SLXFL,(SL) ; AND STORE IT IN SLB LOAD T1,SLDNA,(SL) ;Get destination address LOAD T2,IASIZ,+T2 ;Get segment size specified by remote CALL SCTCSS ;Check what segment size we should use STOR T1,SLSIZ,(SL) ; and store the segment size ROUTER calculated NEWSTATE CR ;CALL SCSSTS TO PUT US IN .NSSCR STATE ; AND WAKE THE USER TMNE MBPH2,(MB) ;IS THIS CONNECT FROM A PHASE II GUY? CALL CONBUF ;YES, SET UP FOR CONSERVATIVE BUFFERING CALL STRTMR ;START CONNECT TIMERS & FIX TIMER COUNTS CALLRET FREMSG ;DEALLOCATE CI MESSAGE, & RETURN TO NSP ;Here when we could not get enough resources to accept the Connect. SCTCIR: MOVX P2,RSNRES ;NO RESOURCES ERROR CODE JRST SCTCFN ;TO COMMON REJECT CODE SCTCIT: MOVX P2,RSNOTB ;Object too busy code JRST SCTCFN ; to common rejet code SCTCIN: MOVX P2,RSNURO ;UNRECOGNIZED OBJECT REASON CODE SCTCFN: TRACE SC,Rejecting Connect Initiate call LOAD P1,MBAR1,(MB) ;SAVE THE NSPpid MOVE T1,MB ;SET UP FOR DNMINI CALL MOVEI T2,3 ;LENGTH OF USER DATA NEEDED CALL DNMINI ;RE-INITIALIZE THE MESSAGE BLOCK WE'RE USING RET ; Will never happen - but if, just return XMOVEI T1,UD.MSD(MB) ;POINT TO THE USER MSD CALL DNPINI ;INITIALIZE FOR PUTTING BYTES MOVE T1,P2 ;GET REASON CODE CALL DNP2BY ;PLACE IT IN THE MESSAGE SETZ T1, ;NO DATA-CTL NEEDED CALL DNP1BY ;PLACE IT IN MOVE T1,P1 ;SET UP THE NSPpid MOVX T3,NV.REJ ;REJECT THE CONNECT MOVE T4,MB ;SET UP POINTER TO MESSAGE BLOCK CALLRET NSP ;INFORM NSP OF FAILURE SUBTTL LLINKS Calls -- The Vectored Call Entry Point SCTL ;SCTL - Here for all calls from NSP except Connect Initiate ; ; Call: ; T1/ SLBid ; T2/ Function specific argument ; T3/ Function Code (SV.xxx) ; T4/ Pointer to message block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 XRESCD SCTL: SAVEAC ;SAVE SOME ACS MOVE MB,T4 ;SET UP MESSAGE BLOCK STOR T1,MBAR1,(MB) ;STORE THE SLBid STOR T2,MBAR2,(MB) ;STORE THE FUNCTION SPECIFIC ARGUMENT STOR T3,MBAR3,(MB) ;STORE THE FUNCTION CODE XMOVEI T1,SCTL1 ;ADDRESS OF PROCESSOR TO CALL AFTER WE CALLRET SCTLCQ ; GET THE INTERLOCK SCTL1: CALL FNDSBI ;FIND THE SLB FROM THE SLBid CALLRET FREMSG ;NO SUCH SLBid, IGNORE THIS MSG CALLRET @SCFNT(T3) ;DISPATCH BY FUNCTION TYPE SUBTTL LLINKS Calls -- SCCCR - Connect Confirmed call from NSP ;SCCCR - Connect Confirmed call from NSP ; ; Call: ; T2/ Connect Initiate arguments (see BEGSTR IA in D36PAR) ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCCCR: TRACE SC,Connect confirmed call SAVEAC P1 ;SAVE A PEA MOVE P1,T2 ;SAVE ARGUMENT FROM NSP CALL STPTMR ;STOP CI TIMER & DECREMENT TIMER COUNTS LOAD T1,IAFLO,+P1 ;GET FLOW CONTROL TYPE STOR T1,SLXFL,(SL) ;STORE TRANSMIT FLOW TYPE IN SLB ;We have to cater for a VMS crock here. Assuming that the buffer size ; is 576 bytes, VMS announces 561 bytes while TOPS-20 would pick 559 bytes. ; The reason is that VMS never uses the piggy-back field while we do do. ; ;Now, if we are an endnode and we try to connect to a remote node and we run ; with big buffers, we will probably suggest 1450 bytes. If the remote is ; not on the same NI and is a VAX it will return 561 bytes and we will accept ; that.... so we make a special test for if the remote buffer size is equal ; to our executor buffer size - %schdr + 2 LOAD T1,IASIZ,+P1 ;GET MAX BYTES ALLOWED IN MESSAGE SEGMENT MOVE T2,RTRBSZ ;Get router buffer size SUBI T2,<%SCHDR-2> ;Get 'VMS size' CAMN T1,T2 ;Equal? SUBI T1,2 ; -yes, fudge for VMS STOR T1,SLSIZ,(SL) ;STORE THAT TMNE MBPH2,(MB) ;WAS CC FROM A PHASE II NODE? CALL CONBUF ;YES, USE CONSERVATIVE BUFFERING STOR MB,SLCDM,(SL) ;SAVE CONNECT MSG FOR "NSFRC" NEWSTATE RN ;SET NEW STATE TO CONNECT RECEIVED SETONE SLCCB,(SL) ;HAVE TO CHECK CONNECT BLOCK NOW ;Now let's send the job's input quota worth of DRQs. TMNE SLPH2,(SL) ;SHOULD WE BE CONSERVATIVE WITH THIS FELLOW? RET ;LEAVE QUIETLY MOVEI T1,0 ;DON'T NEED ANY USER DATA CALL DNGMSG ;GET A NEW MESSAGE BLOCK RET ; - resource error MOVE MB,T1 ;POINT TO THE NEW MSG BLK SETZRO MBOTH,(MB) ;SEND OUT ON THE NORMAL SUBLINK SETZ T2, ;BUILD THE DATA REQUEST ARG BLOCK (QA) IN T2 LOAD T1,SLINQ,(SL) ;GET THE INPUT QUOTA STOR T1,QACNT,+T2 ; USE THAT AS THE DATA REQUEST COUNT STOR T1,SSRDO,+SL.NSL(SL) ;WE KEEP COUNT OF OUTGOING DATA REQUESTS LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP MOVX T3,NV.DRQ ;FUNCTION IS SEND DATA REQUESTS MOVE T4,MB ;POINT TO MESSAGE BLOCK CALLRET NSP ;CALL NSP AND RETURN EVENTUALLY SUBTTL LLINKS Calls -- SCDIR - Disconnect Initiate received call ;SCDIR - Disconnect Initiate received call from NSP ; ; Call: ; T2/ Reason Code ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T2 SCDIR: TRACE SC,Disconnect Initiate received call SAVEAC P1 ;SAVE A PEA STOR T2,SLRSN,(SL) ;ALSO STORE THE REASON FOR ERROR CODE ; PROCESSING LOAD P1,SLSTA,(SL) ;GET THE STATE OF LINK IFSTATE P1,CS ;IF WE WERE IN CONNECT SENT STATE, CALL STPTMR ; STOP CI TIMERS & ADJUST TIMER CNTRS OPSTR ,SLCDM,(SL) ;ANY CONNECT DATA STILL THERE? CALL DNFMSG ;YES, FREE IT NOW STOR MB,SLCDM,(SL) ;STORE DISCONNECT MESSAGE SETONE SLCCB,(SL) ;HAVE TO CHECK CONNECT BLOCK NOW IFNSTATE P1,CS,SCDIR1 ;IF WE WERE IN CONNECT SENT, NEWSTATE RJ ; SET THE STATE TO RJ RET ; AND RETURN ;We differentiate between RJ and DR states here so that the user can ;tell from the state whether or not the link has ever been open. SCDIR1: NEWSTATE DR ;WE GOT INTO RN STATE, SO GO INTO DR STATE RET ;RETURN SUBTTL LLINKS Calls -- SCDCR - Disconnect Confirm received call ;SCDCR - Disconnect Confirm received call from NSP ; ; Call: ; T2/ Reason Code ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T2 SCDCR: TRACE SC,Disconnect Confirm received call SAVEAC P1 ;A DC is normally received in response to our sending out a DI. In ;this case, there will be no interesting reason code and the link will ;not be in CS state, etc. Phase II nodes, or those not yet updated to ;Phase III fully, will reject a CI with a DC instead of a DI and in ;this case the only reason code we get is on that DC message. STOR T2,SLRSN,(SL) ;ALSO STORE THE REASON FOR ERROR CODE ; PROCESSING OPSTR ,SLCDM,(SL) ;ANY CONNECT DATA STILL THERE? CALL DNFMSG ;(T1) YES, FREE IT NOW SETZRO SLCDM,(SL) ;NO DISCONNECT MESSAGE FROM A DC LOAD P1,SLSTA,(SL) ;GET THE STATE OF LINK IFNSTATE P1,CS,SCDCR1 ;IF WE WERE IN CONNECT SENT STATE, CALL STPTMR ; STOP CI TIMERS & ADJUST TIMER CNTRS NEWSTATE RJ ;GO INTO REJECT STATE CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY ;Here if link was not in CS state SCDCR1: NEWSTATE DC ;GO INTO DISCONNECT CONFIRM STATE CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY SUBTTL LLINKS Calls -- SCODN - Output done call ;SCODN - Output done call from NSP ;SCOND - Output not done call from NSP ; ; Call: ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T2 SCOND:! SCODN: TRACE SC,Output done call D36OFF ;PROTECT THIS CODE FROM LLINKS CALL TO SCTRIB OPSTRM ,SLOTU,(SL) ;DECREMENT OUTPUT BUFFERS IN USE MOVX T2,-1 ;ASSUME WE'RE NOT FREEING LAST OUTPUT BUFFER JUMPG T1,SCODN1 ;JUMP IF THAT'S TRUE MOVX T2,-2 ;WE ARE FREEING LAST OUTPUT, ASSUME NO INPUT TMNE SLINU,(SL) ;ANY INPUT BUFFERS ALLOCATED? MOVX T2,0 ;YES, LEAVE AN OUTPUT BUFFER RESERVED SCODN1: ADDB T2,DCNRSB ;ADJUST THE RESERVED BUFFER COUNT D36ON ;END OF CRITICAL SECTION CALL FREMSG ;FREE THE MESSAGE BLOCK CALLRET CHKSTS ;GENERATE PSI INTERRUPT "OUTPUT-OK" SUBTTL LLINKS Calls -- SCSEG - Segment received call ;SCSEG - Segment received call from NSP ; ; Call: ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCSEG: TRACE SC,Segment Received Call XMOVEI T4,SL.NSL(SL) ;ASSUME IT'S ON THE NORMAL SUBLINK TMNE MBOTH,(MB) ;IS IT THE OTHER SUBLINK? XMOVEI T4,SL.OSL(SL) ;YES, POINT TO OTHER AREA ENDQUE MB,SS.INQ(T4),MB.NXT,T1 ;QUEUE THE MESSAGE INCR SLPKR,(SL) ;Increment # of packets received CALLRET CHKSTS ;SEE IF THE USER NEEDS WAKING ;Note: The count of input buffers used is incremented when the data ;requests are sent out in NSFxR, so we don't have to incr now. SUBTTL LLINKS Calls -- SCDRQ - Data request received call ;SCDRQ - Data request received call from NSP ; ; Call: ; T2/ DATA REQUEST call's arguments (see BEGSTR QA in D36PAR) ; SL/ Pointer to Session Control Link Block ; MB/ Pointer to the Message Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCDRQ: TRACE SC,Data Request Received Call XMOVEI T4,SL.NSL(SL) ;ASSUME IT CAME FROM NORMAL SUBLINK TMNE MBOTH,(MB) ;DID IT? XMOVEI T4,SL.OSL(SL) ;NO, MUST BE FROM INTERRUPT SUBLINK LOADE T1,QACNT,+T2 ;GET THE DATA REQUEST COUNT LOADE T3,SSXDO,(T4) ;GET # OF DRQS WE HAVE NOW OUTSTANDING ADD T3,T1 ;NEW COUNT OF DATA REQUESTS STOR T3,SSXDO,(T4) ;STORE THE NEW DATA REQUEST COUNT CALL CHKSTS ;SET THE STATUS, POSSIBLY GENERATING PSI CALLRET FREMSG ;FREE THE MESSAGE BLOCK SUBTTL LLINKS Calls -- SCNCF - No confidence in port call ;SCNCF - No confidence in port call from NSP ; ; Call: ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCNCF: TRACE SC,No confidence in port call NEWSTATE CF ;NEW STATE IS NO CONFIDENCE CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY SUBTTL LLINKS Calls -- SCNRS - No resources call ;SCNRS - No resources call from NSP ; ; Call: ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCNRS: TRACE SC,No resources call NEWSTATE NR ;SET THE NEW STATE TO "NO RESOURCES" CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY SUBTTL LLINKS Calls -- SCCLS - Close Completed call ;SCCLS - Close Completed call from NSP ; ; Call: ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCCLS: TRACE SC,Close Completed call SETONE SLFSL,(SL) ;FREE THE SLB ON NEXT TICK CALL SCTRFJ ;REQUEST SECOND SERVICE FOR THIS LINK CALLRET FREMSG ;FREE THE MESSAGE BLOCK SUBTTL LLINKS Calls -- SCNLK - No link call ;SCNLK - No link call from NSP ; ; Call: ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCNLK: TRACE SC,No Link call NEWSTATE LK ;NEW STATE IS NO-LINK CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY SUBTTL LLINKS Calls -- SCNCM - No communication call ;SCNCM - No communication call from NSP ; ; Call: ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCNCM: TRACE SC,No communication call NEWSTATE CM ;NEW STATE IS NO COMMUNICATION CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY SUBTTL LLINKS Calls -- SCNRN - Not in Run State call ;SCNRN - Not in Run State call from NSP ; ; Call: ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 SCNRN: TRACE SC,Not in Run State call ;NO NEW STATE TO GO INTO HERE CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY SUBTTL LLINKS Calls -- SCCAK - Got a Connect ACK ;SCCAK - Got a Connect ACK from NSP ; ; Call: ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1 ; ;NSP will call us here to report a connect ACK. Using this call, we ;can determine that the CI has made it to the remote, while the remote ;user hasn't yet accepted the connect. Maybe someday we'll figure out ;what to do with this. SCCAK: TRACE SC,Got a Connect ACK CALLRET FREMSG SUBTTL Subroutines -- CHKABO - Check SLABO flag ;CHKABO - Check SLABO flag, close port if need be ; ; Call: ; MB/ Pointer to a message block ; SL/ Pointer to Session Control Link Block ; ; Return: ; RET ;ALWAYS, MESSAGE BLOCK FREED ; ; Uses: T1-T6 ; CHKABO: TMNN SLABO,(SL) ;ARE WE TRYING TO CLOSE AFTER AN ABORT? CALLRET FREMSG ;NO, FREE MSG BLK AND LEAVE TMNE ,(SL) ;YES, HAVE WE ALREADY CLOSED LINK? CALLRET FREMSG ;YES, FREE MSG BLK AND LEAVE CALLRET RLSLNK ;(MB)RELEASE THE LINK AND RETURN SUBTTL Subroutines -- CHKPPN - Check self PPN for validity ;CHKPPN - Check PPN in self port block ; ; Call: ; T1/ Pointer to Port Block ; SL/ Pointer to SLB ; Return ; RET ;INVALID PPN AND NO PRIVS TO FAKE IT ; RETSKP ;VALID CHKPPN: IFN FTOPS10,< LOAD T2,SLSJB,(SL) ;GET POINTER TO SJB JN SJPRV,(T2),RSKP ;IF PRIVED, ALWAYS VALID IFN , MOVE T1,PB.USR(T1) ;GET PPN WE CLAIM TO BE LOAD T2,SJJOB,(T2) ;GET JOB OUR JOB NUMBER CAME T1,JBTPPN##(T2) ;COMPARE OUR PPN WITH PPN WE CLAIM TO BE RET ;THAT'S NOT YOU. FAIL. RETSKP ;THAT'S YOU ALRIGHT. SUCCEED. > ;END IFN FTOPS10 IFN FTOPS20,< RETSKP ;SUCCEED UNTIL WE DECIDE TO CHECK > ;END IFN FTOPS20 SUBTTL Subroutines -- FREMSG - Free a message block ;FREMSG - Free a message block ; ; Call: ; MB/ Pointer to Message Block ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 FREMSG: MOVE T1,MB ;POINT TO THE MESSAGE BLOCK TRASH MB, ;CATCH A BUG CALLRET DNFMSG ;FREE THE MESSAGE BLOCK SUBTTL Subroutines -- CONBUF - Invoke Conservative Buffering ;CONBUF - Invoke Conservative Buffering ; ; Call: ; SL/ Pointer to SLB ; ; Return: ; RET ;ALWAYS ; ; Uses: T1,T2 ;If we do support Phase II, then this routine will have to be updated ;to reserve a small number of buffers (eg, 1 in + 1 out) at open time, ;and then the rest of the 'reserve' routines will have to test for ;Phase II and promise never to release this link's reservations, and ;always to use the existing reservation when reallocating. CONBUF: BUG.(INF,SCLCBN,SCLINK,SOFT,,,< Cause: Conservative buffering is not yet implemented. We should never have a logical link open to a phase II node. >) SETONE SLPH2,(SL) ;MARK LINK AS A PHASE II LINK MOVX T1,FCM.SG ;DO SEGMENT FLOW CONTROL ONLY STOR T1,SLRFL,(SL) ;SET THE RECEIVE FLOW CONTROL TYPE SETZRO SLGOL,(SL) ;SET THE GOAL TO ZERO MOVX T1,SCTP2Q ;GET THE PHASE II QUOTA STOR T1,SLINQ,(SL) ;STORE THAT AS THE INPUT QUOTA STOR T1,SLOTQ,(SL) ; AND AS THE OUTPUT QUOTA RET ;ONLY RETURN SUBTTL Subroutines -- FNDSLB - Find SLB given a channel number ;FNDSLB - Find a SLB from a channel number ; ; Call: ; T1/ Channel # ; T2/ Pointer to Session Control Job Block ; ; Return: ; RET ;COUDLN'T GET IT ; RETSKP ;FOUND IT OK, SL POINTS TO IT ; ; Uses: T1,T2,T4,SL FNDSLB: JUMPLE T1,RTN ;IF NEGATIVE OR ZERO, RETURN FAILURE OPSTR ,SJCHC,(T2) ;DO A QUICKIE RANGE CHECK RET ;OUT OF BOUNDS SOJ T1, ;OUR OFFSET IS ZERO, WHILE USER'S IS ONE LOAD T4,SJCHT,(T2) ;GET POINTER TO SLB TABLE ADD T4,T1 ;FIND ENTRY FOR THIS CHANNEL SKIPN SL,(T4) ;GET THE POINTER TO IT RET ;NO THERE, GIVE BAD RETURN OPSTR ,SLSLB,(SL) ;MAKE SURE IT POINTS TO AN SLB BUG.(CHK,SCLSPF,SCLINK,SOFT,,<,>,< Cause: The DECnet data structures for this link are inconsistent. If this happens more than once, submit a SPR. Data: CHAN - The DECnet channel number SJBPTR - Pointer to the SJB >,RTN) TMNE ,(SL) ;IS IT SCHEDULED FOR DESTRUCTION? RET ;YES, DON'T LET ON THAT ITS HERE RETSKP ;RETURN WITH SUCCESS SUBTTL Subroutines -- FNDSBI - Find SLB from SLBid ;FNDSBI - Find SLB from a SLBid ; ; Call: ; T1/ SLBid ; ; Return: ; RET ;FAILED ; RETSKP ;SUCCESS WITH SL POINTING TO SLB ; ; Uses: T1 FNDSBI: TMNE SLFSL,(T1) ;SLB SCHEDULED FOR DESTRUCTION? RET ;YES, TELL CALLER IT DOESN'T EXIST SKIPE SL,T1 ;EASY ISN'T IT? AOS (P) ;WE'RE OK RET ;BLEW IT SUBTTL Subroutines -- FRESLB - Deallocate a SLB ;FRESLB - Deallocate a SLB ; ; Call: ; SL/ Pointer to SLB ; ; Return: ; RET ;ALWAYS ; ; Uses: T1-T6 FRESLB: SAVEAC OPSTR ,SLSJB,(SL) ;LOAD UP THE JOB BLK POINTER BUG.(CHK,SCLSLB,SCLINK,SOFT,,<>,< Cause: There is no Session Control Job Block (SJB) for this Session Control Link Block (SLB). This error could have happened at any time during the life of the link after it was actively transferring data. Data: SLBPTR/ pointer to the SLB that lacked a SJB pointer >,RTN) LOAD T1,SLCHN,(SL) ;GET THE CHANNEL NUMBER OF LINK LOAD T4,SJCHT,(P2) ;GET POINTER TO SLB TABLE IN THE SJB ADDI T4,-1(T1) ;FIND THE ENTRY FOR THIS CHANNEL CAME SL,(T4) ;MAKE SURE THERE'S ONE THERE BUG.(CHK,SCLTFS,SCLINK,SOFT,,<>,< Cause: The channel table entry didn't point to the correct SLB. There is an internal inconsistency in the DECnet data structures for this link. Action: Submit a SPR if this happens more than once. Data: SLBPTR - Pointer to the bad SLB >,RTN) SETZM (T4) ;ZERO CHANNEL TABLE ENTRY XMOVEI P1,SS.INQ+SL.NSL(SL) ;POINT TO NORMAL SUBLINK'S INPUT Q CALL CLNQUE ;GET RID OF ALL MESSAGES ON THE QUEUE XMOVEI P1,SS.INQ+SL.OSL(SL) ;SAME F