Trailing-Edge
-
PDP-10 Archives
-
tops10_704_monitoranf_bb-x140c-sb
-
10,7/mon/sclink.mac
There are 20 other files named sclink.mac in the archive. Click here to see a list.
;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,1988.
;ALL RIGHTS RESERVED.
SUBTTL V.Brownell & W.Nichols/Tarl
SEARCH D36PAR,SCPAR,MACSYM
SALL
ENTRY SCTL,SCTINI
IFN FTOPS10,<
.CPYRT<1976,1988>
> ;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 ; " " " " "
EXT TIMBAS ;Fractions of a second for time computation
;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.
IFN FTOPS20,<
SCNHSZ==^D223 ;Hash table size
>; END IFN FTOPS20
IFN FTOPS10,<
SCNHSZ==^D509 ;Hash table size (largest prime less than 512)
MAPBAS==777,,000000 ;Base Pseudo address used in pseudo map
>; END IFN FTOPS10
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,<NO.LEN * NRNOPB>
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,<OP,CC,RJ>
; executed if match found
;b) IFSTATE AC,<OP,CC,RJ>,LABEL (Go there if match found)
DEFINE IFSTATE(AC,STATES,GLABEL),<IFST1(AC,<STATES>,<GLABEL>,N,GE,L)>
;Use: AC/ One of the .NSSxx state codes
;
;a) IFNSTATE AC,<OP,CC,RJ>
; executed if match NOT found
;b) IFNSTATE AC,<OP,CC,RJ>,LABEL (Go there if match NOT found)
DEFINE IFNSTATE(AC,STATES,GLABEL),<IFST1(AC,<STATES>,<GLABEL>,E,L,GE)>
DEFINE IFST1(AC,STATES,GLABEL,MOD1,MOD2,MOD3),<
ZZ==0
ZZCNT==0
IRP STATES,<ZZ==ZZ ! 1B<.NSS'STATES>
ZZCNT==ZZCNT+1>
IFE ZZCNT-1,<
CAI'MOD1 AC,.NSS'STATES
IFNB <GLABEL>,<
IFIDN <GLABEL>,<RTN>,<RET>
IFDIF <GLABEL>,<RTN>,<JRST GLABEL>
>>
IFG ZZCNT-1,< ;;IF MORE THAN ONE STATE TESTED
MOVX CX,ZZ
ROT CX,(AC)
IFB <GLABEL>,< SKIP'MOD2 CX >
IFNB <GLABEL>,< 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::OPSTR <MOVE T1,>,IBMXA,+IBBLK ;NUMBER OF NODES IN AREA
ADDI T1,1 ;AND AN EXTRA WORD FOR NODE 0
ADD T1,SCTMPS ;AND SIZE OF PSEUDO MAP
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,<Initializing Session Control>
;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,<PRINTX SCTPSQ needs PSMOR to be in T1>
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 <SA,SL,P1,P2> ;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 <SLFSL,SLLBC>,(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 <SUB T1,>,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 <SUB T1,>,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 <MB,MS,T5,T6,SL,SA,P1,P2>
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 <SKIPE T1,>,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<DLSCHN+^D20> ;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 <CALL @>,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 <MB,SA> ;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,<SCTNSF call from sched without lock>,,<
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 <CALL @>,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<DLSCHN+^D20> ;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<DLSCHN+^D20> ;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 <MB,MS,SL> ;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 <CALL @>,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<DLSCHN+^D20> ;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<MN>),<
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 <LABEL''NAME & 777777>> ;;ENTRY POINT FOR INDIRECT CALL
DEFINE ENDDSP(MAXNAM<MX>),<
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,<SUCSTA>,NOWAIT
IFNB <WAISTA>,< IFSTATE T2,<WAISTA>,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,<SUCSTA>,NOWAIT
IFNB <WAISTA>,< JE SAWAI,(SA),BLEWIT
IFSTATE T2,<WAISTA>,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 <STATES>,<PRINTX ?No STATE(s) declared for CHKBIT macro>
IFB <CONDSTATES>,IFNSTATE T2,<STATES>,BLEWIT
IFNB <CONDSTATES>,IFNSTATE T2,<STATES,CONDSTATES>,BLEWIT
TXNE T1,NS'BIT
JRST NOWAIT
IFNB <CONDSTATES>,IFNSTATE T2,<STATES>,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,<CHKFOR RI,CHNREQ,CHKSTE(CR,CW)> ;SUCCESS STATE,WAITMORE STATE
IFN FTOPS20,<CHKFOR RI,CHNREQ,NOWAIT>
CHKFOR AC,CHNREQ,CHKSTA(CR) ;SUCCESS STATE,WAITMORE STATE
CHKFOR RJ,CHNREQ,CHKSTA(CR) ;SUCCESS STATE,WAITMORE STATE
IFN FTOPS10,<CHKFOR RC,CHNREQ,CHKSTE(RN,CS)> ;ERROR IF CS STATE AND NS.WAI=0
IFN FTOPS20,<CHKFOR RC,CHNREQ,NOWAIT>
CHKFOR SD,CHNREQ,CHKSTA(RN) ;SUCCESS STATE,WAITMORE STATE
CHKFOR AB,CHNREQ,CHKSTA(RN) ;SUCCESS STATE,WAITMORE STATE
IFN FTOPS10,<CHKFOR RD,CHNREQ,CHKSTA(<DR,RJ>)> ;SUCCESS STATE,WAITMORE STATE
IFN FTOPS20,<CHKFOR RD,CHNREQ,NOWAIT>
CHKFOR RL,CHNREQ,NOWAIT
CHKFOR RS,CHNREQ,NOWAIT
CHKFOR IS,CHNREQ,CHKBIT(IDR,<CS,RN>)
CHKFOR IR,CHNREQ,CHKBIT(IDA,<CS,RN,DS>,<DR,DC>)
CHKFOR DS,CHNREQ,CHKBIT(NDR,<CS,RN>)
CHKFOR DR,CHNREQ,CHKBIT(NDA,<CS,RN,DS>,<DR,DC>)
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 <MB,MS,SL,SA,T5,T6,P1,P2> ;SAVE ALMOST ALL ACS
SKIPG SA,T1 ;DID HE SUPPLY A MESSAGE BLOCK?
SCERR %NEABE,SCTNIE,<No argument block>
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,<Illegal function>
;...
;...
;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 <CALLRET @>,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 <CALLRET @>,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 <CALL @>,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 <CALLRET @>,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 <CALL @>,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 <CALLRET @>,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 <CALLRET @>,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,<Bad Channel Number>
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 <CAMN T1,>,SAUID,(SA) ; STALE ?
JRST SCNIB2 ;NO. CONTINUE
SETO SL, ;YES. LOSE THIS POINTER.
SCERR %NEBCN,SCTNIE,<Bad Channel Number> ;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 <SCTNIU&777777> ;CW.ERR - ERROR RETURN TO MONUSER
IFIW <SCNIB4&777777> ;CW.NWA - NO WAIT, GO DO FUNCTION
IFIW <SCNIB5&777777> ;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 <SCTNIU&777777> ;CW.ERR - ERROR RETURN REQUIRED
IFIW <SCTNIX&777777> ;CW.NWA - FCN COMPLETE, RETURN TO MONUSER
IFIW <SCNIA2&777777> ;CW.WAI - FCN NOT COMPLETE, WAIT
IFIW <SCNIA3&777777> ;CW.SAT - CHECK FOR I/O SATISFIED
IFIW <SCNIA4&777777> ;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,<DR,RJ>,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,<Unexpected State: Unspecified>
;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,<Rejected by Object>
IFSTATE T2,DR
SCERR %NEDBO,SCTNIE,<Disconnected by Object>
SCTNR2: SCERR %NEREJ,SCTNIE,<Unspecified Reject Reason>
;Here with an error code in T1.
SCTNIE: SKIPN T1 ;IS THERE AN ERROR CODE?
BUG.(CHK,SCLNZE,SCLINK,SOFT,<Passing zero error code to SCMUUO>,,<
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,<Performing Enter Active (.NSFEA)>
SETZRO SAACH,(SA) ;ASSUME WE CANNOT ASSIGN A CHANNEL
CALL MAKSLB ;MAKE A SLB
SCERR %NEALF,RTN,<Allocation failure>
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,<No privs to use bad PPN>
ELSE.
IFN FRM.0,<PRINTX ?FRM.0 MUST BE EQUAL TO 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,<No privs for this object type>
> ; 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,<Allocation failure>
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,<Illegal flow control mode>
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,<Allocation failure>
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,<Allocation failure>
;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 <SKIPN T2,>,SACBP,(SA) ;GET THE CONNECT BLOCK POINTER
SCERR %NENCD,NSFEAE,<No connect block>
OPSTR <SKIPE T1,>,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 <SKIPN>,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 <SKIPLE T2,>,SAAA2,(SA) ;Get the segment size
CAMLE T2,T1 ; is it bigger than the legal max?
IFSKP. <MOVE T1,T2> ; -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,<Resource error>
;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,<Allocation failure>
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,<Connect Block format error>
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,<Performing Enter Passive (.NSFEP)>
CALL MAKSLB ;MAKE A SLB
SCERR %NEALF,RTN,<Allocation failure>
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,<No privs to use bad PPN>
ELSE.
IFN FRM.0,<PRINTX ?FRM.0 MUST BE EQUAL TO 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,<No privs for this object type>
STOR T2,SLDOB,(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,<Allocation failure>
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,<Performing Read Connect Info (.NSFRI)>
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,<No dis/connect data to read>
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,<Allocation Failure>
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,<Function called in wrong state>
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,<Performing Accept Connect (.NSFAC)>
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 <SKIPLE T1,>,SAAA2,(SA) ;Get the segment size user wants
CAML T1,T2 ;User's smaller?
IFSKP. <STOR T1,SLSIZ,(SL)> ; -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,<Illegal flow control mode>
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,<Allocation failure>
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,<Allocation failure>] ; 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,<Allocation failure>
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,<Failed to get memory>
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,<Performing Reject the Connect (.NSFRJ)>
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,<Allocation failure>
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 <SKIPLE T1,>,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,<Performing Read Connect Confirm Data (.NSFRC)>
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,<No dis/connect data to read>
MOVX T1,SB.LEN ;GET SOME WORDS FOR THE DATA-CTL FIELD
CALL DNGWDS ;GET THEM FROM MEMORY MANAGER
SCERR %NEALF,RTN,<Allocation failure>
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,<Performing Synchronous Disconnect (.NSFSD)>
TMNE SLOTM,(SL) ;IS THERE A PARTIALLY FILLED OUTPUT MESSAGE?
SCERR %NEWRS,RTN,<Function called in wrong state>
MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL
CALL DNGMSG ;GET A MESSAGE BLOCK
SCERR %NEALF,RTN,<Allocation failure>
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 <SKIPLE T1,>,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,<Performing Abort and Release (.NSFAB)>
MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL
CALL DNGMSG ;GET A MESSAGE BLOCK
SCERR %NEALF,RTN,<Allocation failure>
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 <SKIPLE T1,>,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,<Performing Read Disconnect Data (.NSFRD)>
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 <SKIPN P1,>,SLCBP,(SL) ;GET PTR TO DIS/CONNECT BLOCK
SCERR %NENCD,RTN,<No dis/connect data to read>
MOVX T1,SB.LEN ;GET SOME WORDS FOR THE DATA-CTL FIELD
CALL DNGWDS ;GET THEM FROM MEMORY MANAGER
SCERR %NEALF,RTN,<Allocation failure>
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,<Performing Release (.NSFRL)>
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,<Performing Read Status (.NSFRS)>
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,<Sending Interrupt Data (.NSFIS)>
TMNE SLCCB,(SL) ;SHOULD WE CHECK CONNECT BLOCK?
CALL FRECBP ;YES, GET RID OF CONNECT DATA IF WE CAN
NSFIS1: OPSTR <SKIPN P1,>,SASBP,(SA) ;POINT TO THE SBLOCK POINTER
SCERR %NEABE,RTN,<No Sblock supplied>
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,<Interrupt data too long>
;...
;...
;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,<Allocation failure>
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 <MBBOM,MBEOM>,(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 <ADDM T1,>,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 <SOS>,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,<Receiving Interrupt Data (.NSFIR)>
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,<Allocation failure>
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 <ADDM T1,>,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 <SOS T1,>,SSRDO,+SL.OSL(SL) ;DECREMENT DATA REQUEST COUNT
OPSTR <CAML T1,>,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 <AOS>,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,<Allocation Failure>
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,<Sending Normal Data (.NSFDS)>
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,<IFN FCM.NO,<PRINTX ?NSFDS expects FCM.NO to be zero; it isn't>>
;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 <SKIPGE P1,>,SAAA1,(SA) ;GET USER'S BYTE COUNT
SCERR %NEADE,RTN,<Address Error> ;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 <SUB P1,>,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 <ADDM T1,>,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 <ADDM T1,>,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 <SOS>,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,<Receiving Normal Data (.NSFDR)>
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,<Bad Combination of NS.xxx Flags>
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 <ADDM P1,>,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 <SOS T1,>,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 <SOS T2,>,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 <ADDM T1,>,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,<Allocation Failure>
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,<Performing Set Link Quota (.NSFSQ)>
LOAD T1,SLSTA,(SL) ;GET LINK STATE
IFSTATE T1,<DC,LK,CM,CF,NR>,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,<Wrong number of arguments>
LOAD T1,SLINQ,(SL) ;GET THE OLD QUOTA
OPSTR <ADD T1,>,SLOTQ,(SL) ;TOTAL OF INPUT + OUTPUT QUOTA
OPSTR <SKIPG>,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,<Percentage input out of bounds>
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 <SKIPGE>,SAAA3,(SA) ;Verify supplied value
STOR T1,SAAA3,(SA) ;Apply default
CALL DNGMSG ;GET MESSAGE BLOCK IN CASE WE NEED IT
SCERR %NEALF,RTN,<Allocation failure>
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,<Performing Read Link Quota (.NSFRQ)>
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,<Illegal function - handled in SCMUUO>
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,<Illegal function - handled by SCMUUO>
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,<Performing Set PSI Mask (.NSFPI)>
LOAD T1,SAAA1,(SA) ;GET .NSAA1 ARGUMENT
STOR T1,SLPSM,(SL) ;STORE THE PSI MASK FOR SCTPSI
TMNE <SLPSI,SLLBC,SLFSL>,(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 <SKIPE T6,>,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 <MB,P1,P2> ;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 <SLFSL,SLLBC>,(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 <SC'NAM&777777>>
;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 <CAME T1,>,SLSLB,(T1) ;IS THIS A LEGIT SLB POINTER?
BUG.(CHK,SCLRIB,SCLINK,SOFT,<Bad SCTRIB call from LLINKS>,<<T1,ADDR>>,<
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 <MB,SL,SA,MS,P1,P2>
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 <MB,SL,SA,MS,P1,P2>
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,SLSOB,(SL) ; and store as source 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 <MB,MS,SA,SL> ;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 <SKIPE T1,>,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 <SKIPE T1,>,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 <SOS T1,>,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 <SLFSL,SLLBC>,(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 <PB.USR-PB.GRP>,<PRINTX PBUSR and PBGRP must be in same word>
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,<Phase-II buffering not implemented>,,<
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 <CAMLE T1,>,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 <CAME SL,>,SLSLB,(SL) ;MAKE SURE IT POINTS TO AN SLB
BUG.(CHK,SCLSPF,SCLINK,SOFT,<SLB self pointers messed up in FNDSLB>,<<T1,CHAN>,<T2,SJBPTR>>,<
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 <SLFSL,SLLBC>,(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 <P1,P2>
OPSTR <SKIPN P2,>,SLSJB,(SL) ;LOAD UP THE JOB BLK POINTER
BUG.(CHK,SCLSLB,SCLINK,SOFT,<SLB bad at FRESLB>,<<SL,SLBPTR>>,<
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,<Tried to free wrong SLB>,<<SL,SLBPTR>>,<
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 FOR OTHER SUBLINK'S INPUT Q
CALL CLNQUE
OPSTR <SKIPE T1,>,SLOTM,(SL) ;IF WE HAVE A PART FILLED OUTPUT MSG
CALL DNFMSG ; THEN FREE IT
OPSTR <SKIPE T1,>,SLCBP,(SL) ;IF WE HAVE AN INTERNAL CONNECT BLK
CALL DNFWDS ; THEN FREE IT
OPSTR <SKIPE T1,>,SLCDM,(SL) ;IF WE HAVE A DISCONNECT MSG BLK
CALL DNFMSG ; THEN FREE IT
;Here we remove any buffer reservations attached to this SLB.
D36OFF ;#KEEP LLINKS (SCTRIB CALL) OUT OF THIS
LOAD T1,SLOTU,(SL) ;#GET OUTPUT BUFFERS IN USE
LOAD T2,SLINU,(SL) ;#GET INPUT BUFFERS IN USE
SKIPG T3,T1 ;#ANY INPUT BUFFERS RESERVED?
JUMPE T2,FRESL1 ;#NO, NO RESERVATIONS IF NEITHER IN USE
ADD T3,T2 ;#GET TOTAL BUFFERS WHICH WERE IN USE
SKIPE T1 ;#WERE THERE ANY INPUTS IN USE?
SKIPN T2 ;#YES, ANY OUTPUTS?
AOS T3 ;#NO OR NO, ONE MORE WAS RESERVED FOR
MOVNS T3 ;# OTHER DIRECTION
ADDM T3,DCNRSB ;#UPDATE RESERVED BUFFER COUNT
FRESL1: D36ON ;#END CRITICAL SECTION
;Here we remove this SLB from the PSQ if it had a PSI waiting.
TMNN SLPSI,(SL) ;ON THE PSI Q?
JRST FRESL2 ;NO, NO WORRY NOW
D36OFF ;#PSI Q DOESN'T RESPECT SCT INTERLOCK
RMVQUE SL,SJ.PSQ(P2),SL.NXP,T1 ;#REMOVE SLB FROM PSI Q
D36ON ;#FINISHED WITH THE CRITICAL SECTION
FRESL2:
;Here we remove the SLB from the second request Q if need be
RMVQUE SL,SCTJFQ,SL.JFQ,T1 ;THIS IS INTERLOCKED
;Here we remove the SLB from the All SBLs Queue
RMVQUE SL,SCTASQ,SL.ASQ,T1 ;THIS IS INTERLOCKED
;Here we clean out the SLB's serial number
SETZRO SLUID,(SL)
;Here we free up the SLB's memory
MOVE T1,SL ;SET UP FOR CALL TO DNFWDS
SETZ SL, ;JUST FOR KICKS
CALLRET DNFWDS ;FREE THE WORDS AND RETURN
;Routine to clean out a queue of message blks pointed to by P1.
CLNQUE: DEQUE T1,(P1),MB.NXT,RTN ;GET NEXT MB, RETURN IF Q IS EMPTY
CALL DNFMSG ;FREE MESSAGE POINTED TO BY T1
JRST CLNQUE ;LOOP FOR NEXT ONE
SUBTTL Subroutines -- FRECBP - Free Connect Block
;FRECBP - Free Connect Block
;
; Call:
; SL/ Pointer to SLB
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T2
;We try to free up connect data blocks in decending order of importance.
;First, we try to get rid of a message blocks which interrupt level may have
;left for process level by copying them to connect blocks. (Interrupt level
;can't copy for fear of failing to get a connect block from free memory.)
;Whether or not we can get rid of the resulting connect block, we have freed a
;quota-controlled message block.
;Then we try to free any connect block which may be waiting, subject to the
;user's request that we keep it.
FRECBP: SETZRO SLCCB,(SL) ;DON'T NEED TO CHECK CONNECT BLK ANY MORE
TMNN SLCDM,(SL) ;ANY WAITING DIS/CONNECT DATA MESSAGE?
JRST FRECB1 ;NO
CALL CDMCBP ;YES, FREE UP MESSAGE BY COPYING IT TO CBP
JFCL ;COULDN'T WE'LL TRY AGAIN NEXT TIME
FRECB1: TMNN SLCBP,(SL) ;IS THERE A CONNECT BLOCK?
RET ;NONE THERE, LEAVE NOW
TMNE SLKCB,(SL) ;USER WANT US TO KEEP CONNECT BLOCK?
RET ;YES, DON'T RELEASE IT.
LOAD T2,SLSTA,(SL) ;GET LINK'S STATE
IFNSTATE T2,RN,RTN ;IF NOT RUN STATE, MIGHT BE DISCON DATA
LOAD T1,SLCBP,(SL) ;GET POINTER TO CONNECT BLOCK
CALL DNFWDS ;(T1) FREE THE BLOCK
SETZRO SLCBP,(SL) ;REMEMBER WE'VE LOST IT
RET ;THAT'S ALL
SUBTTL Subroutines -- CDMCBP - Copy User Data from Message Block
;CDMCBP - Copy User Data from @SLCDM to @SLCBP
;
; Call:
; SL/ Pointer to SLB
;
; Return:
; RET ;IF INVALID MESSAGE, EVENT ALREADY CALLED
; RETSKP ;ON SUCCESS
;
; Uses: T1-T2
CDMCBP: SAVEAC <MB,MS>
OPSTR <SKIPN MB,>,SLCDM,(SL) ;ANY DISCONNECT MESSAGE?
RETSKP ;NO, NOTHING TO COPY
TMNE SLCBP,(SL) ;YES, IS THERE A CONNECT BLOCK
JRST CDMCB1 ;YES, ONE OF THEM TOO, COPY THE GOODS NOW
MOVEI T1,CB.LEN ;NO, ALLOCATE ONE FIRST
CALL DNGWDZ ;GET A ZEROED BLOCK
SCERR %NEALF,RTN,<Allocation failure>
STOR T1,SLCBP,(SL) ;STORE CONNECT BLOCK POINTER IN SLB
CDMCB1: MOVE T1,MB ;POINT TO THE MESSAGE BLOCK
CALL DNGINI ;SET UP TO GET SOME BYTES OUT
SETZRO SLCDM,(SL) ;REMEMBER WE FREED IT
CALL CPMSCB ;COPY USER DATA TO CONNECT BLOCK
RETSKP ;INVALID MESSAGE, WE'VE DONE BEST WE CAN
CALL FREMSG ;DONE WITH THE DISCONNECT MESSAGE NOW
RETSKP ;SUCCESS RETURN
SUBTTL Subroutines -- CPMSCB - Copy User Data from Message Block
;CPMSCB - Copy User Data from Message Block to Existing Connect Block
;
; Call:
; SL/ Pointer to SLB, SLCBP points to Connect Block
; MB/ Pointer to Message Block
; MS/ Set up for D36COM message block routines to copy user data
;
; Return:
; RET ;IF INVALID MESSAGE, EVENT ALREADY CALLED
; RETSKP ;ON SUCCESS
;
; Uses: T1-T2
CPMSCB: CALL DNG1BY ;GET FIRST BYTE = LENGTH OF USER DATA
SETZ T1, ;ZERO LENGTH IF NO LENGTH BYTE PRESENT
CAIG T1,^D16 ;LONGER THAN ARCHITECTURAL LIMIT OF 16?
JRST CPMSC1 ;NO, ITS OK
MOVEI T1,^D16 ;YES, TOO LONG, TRUNCATE TO 16 BYTES
CALL CPMSC1 ; COPY WHAT WE CAN BEFORE SCEIVM FREES MSG
RET ; OOPS, INVALID MESSAGE EVENT ALREADY GIVEN
CALLRET SCEIVM ; GIVE INVALID MESSAGE EVENT
CPMSC1: LOAD T4,SLCBP,(SL) ;T4 POINTS TO CONNECT BLOCK
STOR T1,CBCCT,(T4) ;STORE LENGTH OF USER DIS/CONNECT DATA
JUMPE T1,RSKP ;SUCCESS NOW IF NO USER DATA
MOVX T2,<<POINT 8,>!1B12> ;2-WORD BYTE POINT PTR TO CONNECT BLOCK'S
XMOVEI T3,CB.UDA(T4) ; USER-CONNECT-DATA BLOCK
CALL DNCM2B ;(T1,T2,T3,MS)COPY MSG BLK TO MONITOR BUFFER
CALLRET SCEIVM ;TOO SHORT, GIVE INVALID MESSAGE EVENT
RETSKP ;JUST RIGHT, SUCCESS
SUBTTL Subroutines -- FRESJB - Deallocate a SJB
;FRESJB - Deallocate a SJB
;
; Call:
; T1/ Pointer to SJB
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T2
XRENT FRESJB
SAVEAC <P1,T5,T6>
SKIPN P1,T1 ;POINTER TO SJB
RET ;JUST CHECKING
CALL CHKSJB ;SEE IF THERE ARE ANY SLBs
BUG.(CHK,SCLTFJ,SCLINK,SOFT,<Freeing SJB with SLB entries existing>,<<P1,SJBPTR>>,<
Cause: FRESJB was called to free up a SJB. However, there are still active
links in use for this SJB. This should never happen, and there is
an internal inconsistency in the DECnet data structures. Submit a
SPR if this happens more than once.
Data: SJBPTR - Pointer to the SJB
>)
D36OFF ;#PROTECT THE SMP
RMVQUE P1,SCTSJQ,SJ.NXT,T1 ;#REMOVE SJB FROM LIST OF SJBS
D36ON ;#END OF CRITICAL SECTION
MOVE T1,P1 ;SET UP TO FREE SOME WORDS
CALLRET DNFWDS ;FREE THE WORDS THE SJB IS USING
SUBTTL Subroutines -- CHKSJB - Check an SJB for SLBs
;CHKSJB - Check an SJB for SLBs
;
; Call:
; T1/ Pointer to SJB
;
; Return:
; RET ;There are SLBs associated with this SJB
; RETSKP ;No SLBs associated with this SJB
;
; Uses: T1-T2
XRENT CHKSJB
LOAD T2,SJCHC,(T1) ;GET COUNT OF SLB SLOTS
LOAD T1,SJCHT,(T1) ;AND ADDRESS OF SLB TABLE
CHKSJ1: SOJL T2,RSKP ;IF NONE LEFT, RETURN
SKIPE (T1) ;IS THERE AN SLB ADDRESS IN THIS SLOT?
RET ;YES, RETURN
AOJA T1,CHKSJ1 ;NO, CHECK NEXT ONE
SUBTTL Subroutines -- MAKSLB - Create a SLB, filling in defaults
;MAKSLB - Create a SLB, filling in defaults
;
; Call:
; T1/ Channel #
; SA/ Pointer to argument block from SCTNSF caller
;
; Return:
; RET ;ON FAILURE DUE TO ALLOCATION
; RETSKP ;SUCCESS WITH SL SET UP WITH THE SLB POINTER
; ; AND T1 CONTAINING THE CHANNEL NUMBER
;
; Uses: T1-T6
CHTFAC==2 ;FACTOR BY WHICH NEW CHT IS LARGER THAN OLD
MAKSLB: SAVEAC <P1,P2> ;CHT POINTER, SJB POINTER
MAKSL1: LOAD P2,SASJB,(SA) ;GET POINTER TO SJB
LOAD P1,SJCHT,(P2) ;GET POINTER TO THE SLB TABLE
LOAD T3,SJCHC,(P2) ; AND THE COUNT OF ENTRIES IN THE TABLE
MAKSL2: SKIPN (P1) ;IS THERE A FREE ENTRY?
JRST MAKSL3 ;YES, GO USE IT
SOSE T3 ;ARE ANY MORE ENTRIES LEFT?
AOJA P1,MAKSL2 ;YES, LOOK AT THE NEXT ONE
;Here when we have to expand the SLB table in the SJB. We will try to make
;it twice as large as it is currently.
LOAD T1,SJCHC,(P2) ;GET THE CURRENT SIZE OF SLB TABLE
IMULI T1,CHTFAC ;CALC NEW, LARGER SIZE
;WE'LL STORE SIZE LATER, AFTER COPY
CALL DNGWDZ ;GET THAT MANY WORDS
RET ;ALLOCATION FAILURE
MOVE T2,T1 ;SET UP DEST POINTER FOR DNCPYW
OPSTRM <EXCH T1,>,SJCHT,(P2) ;STORE NEW CHT PTR, LOAD OLD CHT PTR
LOAD T3,SJCHC,(P2) ;GET THE OLD COUNT
PUSH P,T1 ;SAVE POINTER TO OLD CHT
CALL DNCPYW ;COPY THE OLD WORDS
POP P,T4 ;RESTORE POINTER TO OLD CHT FOR DEALLOCATION
LOAD T2,SJCHC,(P2) ;GET OLD CHT LENGTH
IMULI T2,CHTFAC ;CALC NEW LENGTH AGAIN
STOR T2,SJCHC,(P2) ;STORE NEW CHT LENGTH
;Deallocate the old block if it was outside of the SJB.
XMOVEI T2,SJ.SLT(P2) ;POINT TO THE SLB TABLE IN THE SJB
CAME T2,T4 ;IS THE SLB TABLE IN THE SLB?
JRST [MOVE T1,T4 ;NO, JUST FREE THE BLOCK
CALL DNFWDS ;FREE THE WORDS
JRST MAKSL1] ;MAKE THE NEW ENTRY UP
MOVE T1,T2 ;ZERO THE
ADDI T2,SLT.LN-1 ; ENTRIES IN THE SJB
SETZ T3, ; JUST TO BE SAFE
CALL DNSWDS ;SMEAR THEM
JRST MAKSL1 ; AND GO INTO THE OTHER CODE
;Here to make the new SLB.
MAKSL3: MOVX T1,SL.LEN ;LENGTH OF A SLB
CALL DNGWDZ ;GET THAT MANY WORDS
RET ;ALLOCATION FAILURE
MOVE SL,T1 ;SET UP SL WITH THE POINTER
STOR SL,SLSLB,(SL) ;STORE POINTER TO OURSELVES FOR CHECKING
STOR P2,SLSJB,(SL) ; AND POINTER TO SJB
;Initialize some of the variables.
SETONE SSOTH,+SL.OSL(SL) ;SET "OTHER SUBLINK" BIT IN OTHER SUBLINK
LOAD T1,IBFCM,+IBBLK ;Get default flow control from IB block
STOR T1,SLXFL,(SL) ;SET THE TRANSMIT FLOW CONTROL TO SEGMENT
STOR T1,SLRFL,(SL) ; AND THE RECEIVE FLOW TYPE
SETZRO SLGOL,(SL) ;START THE GOAL AT ZERO
MOVX T1,1
STOR T1,SSXDO,+SL.OSL(SL) ;SET XMT DRQS ON OTHER SUBLINK TO ONE
STOR T1,SSRDO,+SL.OSL(SL) ; ALONG WITH THE RCV DRQS
LOAD T1,SJGOL,(P2) ;GET THE JOB'S GOAL
STOR T1,SLGOL,(SL) ;STORE IT
LOAD T1,SJINQ,(P2) ;GET THE JOB'S INPUT QUOTA
STOR T1,SLINQ,(SL) ;STORE IT IN THE SLB
LOAD T1,SJOTQ,(P2) ;SAME FOR THE OUTPUT QUOTA
STOR T1,SLOTQ,(SL) ;STORE THAT IN THE SLB ALSO
MOVE T1,RTRBSZ ;Get executor bytes size
SUBI T1,%SCHDR ; and subtract size of headers below SC
STOR T1,SLSIZ,(SL) ;SET THAT UP ALSO
SETZRO SLRSN,(SL) ;ZERO THE REASON FIELD
LOAD T1,SAWKA,(SA) ;GET ADDRESS OF WAKEUP ROUTINE
STOR T1,SLWKA,(SL) ;STORE IN THE SLB
SETZRO SLPSM,(SL) ;START WITH PSI MASK DISABLED
SETONE <SLBSY,SLEOM>,(SL) ;INITIALLY THE SLB IS BUSY, SEE SCTNIA
; SLEOM INITIALLY TRUE FOR FIRST BOM
IFN FTOPS10,<
MOVE T1,SYSUTM## ;GET MILLISECONDS OF UPTIME
>;End of IFN FTOPS10
IFN FTOPS20,<
MOVE T1,TODCLK ;SET UP THE
>
STOR T1,SLUID,(SL) ; SLB'S SERIAL NUMBER
;After all errors have been avoided, store pointer in SLB table
ENDQUE SL,SCTASQ,SL.ASQ,T1 ;PUT NEW SLB ON ALL SLB QUEUE
MOVEM SL,(P1) ;SAVE POINTER TO US IN SLB TABLE
OPSTR <SUB P1,>,SJCHT,(P2) ;CALC NEW CHANNEL NUMBER
AOS T1,P1 ;MAKE CHANNEL NUMBERS START AT ONE
STOR P1,SLCHN,(SL) ;STORE IT IN THE SLB
RETSKP ; AND RETURN CHANNEL # TO USER IN T1
SUBTTL Subroutines -- MAKSJB - Create a SJB, filling in defaults
;MAKSJB - Create a SJB, filling in defaults
;
; Call, PC in section 1 if KL paging:
; T1/ DECnet "PDB" word (See PD Structure in D36PAR)
;
; Return:
; RET ;ON ALLOCATION FAILURE
; RETSKP ;OK, WITH T1 SET UP WITH SJB POINTER
;
; Uses: T1-T6
XRENT MAKSJB
SAVEAC <P1,P2,T5,T6>
MOVE P1,T1 ;SAVE THE ARGUMENT
MOVX T1,SJ.LEN ;GET THE LENGTH OF A SJB
CALL DNGWDZ ;GET THAT MANY WORDS
RET ;ALLOCATION FAILURE
MOVE P2,T1 ;SET UP THE SJB POINTER IN P2
D36OFF ;INTERLOCK FOR SMP
ENDQUE P2,SCTSJQ,SJ.NXT,T1 ;PUT IT ON THE QUEUE OF SJB'S
D36ON ;END CRITICAL SECTION
MOVX T1,SLT.LN ;LENGTH OF VIRGINAL SLB TABLE
STOR T1,SJCHC,(P2) ;STORE THAT IN THE COUNT
XMOVEI T1,SJ.SLT(P2) ;MAKE THE SLB TABLE POINTER POINT
STOR T1,SJCHT,(P2) ; TO THE VIRGIN TABLE IN THE SJB
LOAD T1,PDGOL,+P1 ;GET THE JOB'S GOAL
STOR T1,SJGOL,(P2) ;STORE IN THE SJB
LOAD T1,PDDQT,+P1 ;GET THE DEFAULT QUOTA
OPSTR <IMUL T1,>,PDIPR,+P1 ;MULT BY INPUT % = INPUT QUOTA * 100
IDIVI T1,^D100 ; AND DIVIDE BY 100 TO FIND INPUT QUOTA
SKIPG T1 ;ASSURE INPUT
MOVEI T1,1 ; GETS AT LEAST ONE
STOR T1,SJINQ,(P2) ;STORE THE INPUT QUOTA IN SJB
LOAD T2,PDDQT,+P1 ;GET THE TOTAL QUOTA BACK
SUB T2,T1 ;SUBTRACT INPUT QUOTA
SKIPG T2 ;ASSURE OUTPUT
MOVEI T2,1 ; GETS AT LEAST ONE
STOR T2,SJOTQ,(P2) ;TO GET THE OUTPUT QUOTA
MOVE T1,P2 ;RETURN SJB POINTER IN T1
RETSKP ;RETURN SUCCESS
SUBTTL Subroutines -- SCSSTS/CHKSTS - Set Status & Inform PSISER
;SCSSTS/CHKSTS - Set Status & Inform PSISER
;
; Call:
; T1/ New State ;FOR SCSSTS ONLY, NO ARGS FOR CHKSTS
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
;
;NSFDS and NSFIS use the NSNDR and NSIDR bits to determine whether they
;should send a msg, so CHKSTS is the repository of quota information.
SCSSTS: STOR T1,SLSTA,(SL) ;STORE NEW STATE (NOT PART OF SLSST)
CHKSTS: ;ALTERNATE ENTRY TO CHECK BITS ONLY
;Now build a new status word from the data contained in the SLB. The
;new status gets built in T6.
LOAD T6,SLSTA,(SL) ;GET STATE FOR STATUS HALF-WORD
MOVE T4,T6 ;SAVE THE STATE FOR LATER
;Check for input available
TMNE QHBEG,+SL.NSL+SS.INQ(SL) ;ANY NORMAL INPUT DATA AVAILABLE?
TXO T6,NSNDA ;YES, SET NORMAL DATA AVAILABLE
TMNE QHBEG,+SL.OSL+SS.INQ(SL) ;ANY OTHER INPUT DATA AVAILABLE?
TXO T6,NSIDA ;YES, SET INTERRUPT DATA AVAILABLE
;Check for output quota
IFNSTATE T4,<RN>,CHKST4 ;IF WE'RE NOT RUNNING, DON'T ALLOW SENDS
D36OFF ;PROTECT FROM SCTRIB CALL FROM LLINKS
LOAD T2,SLOTU,(SL) ;GET # OUTPUT BUFFERS CURRENTLY IN USE
TMNE SLOTM,(SL) ;Is there an output message being filled?
SOS T2 ;Yes, allow output to continue
SKIPE DCNCON ;WE ARE CONGESTED,
JUMPG T2,CHKST3 ; ALLOW ONLY 1 OUTPUT/LINK
OPSTR <CAML T2,>,SLOTQ,(SL) ;ARE WE WITHIN THE QUOTA?
JRST CHKST3 ;NO, DON'T ALLOW SENDS
MOVEI T1,1 ;ASSUME WE'RE ALREADY USING AN OUTPUT BUFFER
JUMPG T2,CHKST1 ;JUMP IF THAT'S TRUE
MOVEI T1,2 ;WE HAVE NO OUTPUT NOW, ASSUME NO INPUT
TMNE SLINU,(SL) ;ANY INPUT BUFFERS ALLOCATED?
JRST CHKST2 ;YES, AN OUTPUT BUFFER ALREADY RESERVED
CHKST1: MOVE T2,DCNTSB ;GET TOTAL SYSTEM BUFFERS
SUB T2,DCNRSB ;SUBTRACT THOSE ALREADY USED
CAMGE T2,T1 ;ENOUGH ROOM FOR A NEW REQUEST?
JRST CHKST3 ;NO, DON'T ALLOW OUTPUT
;Check for output data requests
CHKST2: LOAD T1,SLXFL,(SL) ;GET THE TRANSMIT FLOW CONTROL OPTION
TMNN SSXDO,+SL.NSL(SL) ;NORMAL DATA REQUESTS AVAILABLE?
CAIN T1,FCM.NO ;NO, PUNT UNLESS NO FLOW CONTROL
TXO T6,NSNDR ;YES, SET NORMAL DATA REQUESTED
TMNE SSXDO,+SL.OSL(SL) ;OTHER DATA REQUESTS AVAILABLE?
TXO T6,NSIDR ;YES, SET INTERRUPT DATA REQUESTED
CHKST3: D36ON ;END CRITICAL SECTION
CHKST4:
;Fall through with new status in T6
;From previous page with new status in T6
;Note that NSFPI calls the wake routine also, and any argument changes
;must be reflected there too.
LOAD T5,SLSST,(SL) ;GET OLD STATUS
STOR T6,SLSST,(SL) ;STORE NEW STATUS
SKIPN T2,T5 ;COPY OLD STATUS
RET ;FIRST CHANGE IS NEVER "INTERESTING"
TXZ T5,^-NSSTS ;LEAVE ONLY THE STATUS BITS
IOR T5,T6 ;BITS (NEW ! OLD) + NEW STATE
XOR T5,T2 ;REVEAL INTERESTING CHANGES AS ONES IN T5
JUMPE T5,RTN ;LEAVE NOW IF NO INTERESTING CHANGES
;SLPSI is no longer in the following test incase we are e blocked at PSI level.
;SCTWKQ won't signal twice.
TMNE <SLLBC,SLFSL>,(SL) ;PSI PENDING OR LINK CLOSING?
RET ;YES, AVOID RACE
;Here if the status has changed in an interesting way
;Pick up the args for the caller's wake routine
LOAD T1,SLPSM,(SL) ;THE PSI MASK FOR THIS LINK
HRL T1,T2 ;T1 HOLDS OLD STATUS,,MASK
LOAD T2,SLCHN,(SL) ;THE LINK NUMBER
HRL T2,T6 ;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 <SKIPE T6,>,SLWKA,(SL) ;IS THERE A WAKE ROUTINE?
CALLRET 0(T6) ;(T1,T2,T3,T4,T5)YES, CALL WAKE ROUTINE
RET ;NO, JUST RETURN
SUBTTL Subroutines -- SCTWKQ - Queue a Link for later call to SCTPSQ
;SCTWKQ - Queue a Link for later call to SCTPSQ
;
; Call: T1/ Link Identifier (SLB ptr) from @SLWKA call above
;
; Return:
; RET ;Only return
;T1 = 0 on return if SLB already queued for PSI, non-zero altered
;This routine is only called by the routine whose address is in SAWKA.
XRENT SCTWKQ ;Entry point
LOAD T3,SLSJB,(T1) ;LOAD UP SJB POINTER FOR ENDQUE BELOW
MOVX T2,SLPSI ;GET THE "QUEUED ON PSQ" FLAG
D36OFF ;#THE DEQUE ROUTINE IS NOT INTERLOCKED
TDNE T2,SL.PSI(T1) ;#IS THIS SLB ALREADY QUEUED?
JRST [SETZ T1,
JRST SCTWKX]
IORM T2,SL.PSI(T1) ;#WELL, IT IS QUEUED NOW
ENDQUE T1,SJ.PSQ(T3),SL.NXP,T2 ;#QUEUE SLB FOR SCTPSQ
SCTWKX: D36ON ;#INTERRUPTS BACK ON AGAIN
RET ;ALL DONE
SUBTTL Subroutines -- SLBMAT - Pattern match connect to passive SLBs
;SLBMAT - Pattern match a connect over all passive SLBs
;
; Call:
; T1/ Pointer to internal connect block (see BEGSTR CB in SCPAR)
;
; Return:
; RET ;COULND'T FIND MATCHING PASSIVE SLB
; RETSKP ;FOUND ONE, POINTER TO IT IN SL
;
; Uses: T1-T6
SLBMAT: SAVEAC <P1,P2>
MOVE P1,T1 ;SAVE THE POINTER TO THE CONNECT BLOCK
SETZ P2, ;No matches so far (used to distinguish
; between 'no such object' and 'object too
; busy'
LOAD SL,QHBEG,+SCTASQ ;GET PTR TO FIRST SLB ON ALL SLBs QUEUE
SLBMA1: JUMPE SL,[MOVE T1,P2 ;If no more SLB's, load return code
RET] ; and fail return
JN <SLFSL,SLLBC>,(SL),SLBMA2 ;IF LINK IS BEING CLOSED, IGNORE IT
;We try to match the connect no matter wait the link state is.
; If we get a success return we check if the state is CW. If so, all is well.
; If not, we know that we had an 'object too busy' reject instead of a
; 'no such object'.
CALL SLBMAS ;COMPARE SLB WITH RECEIVED CONNECT BLK
JRST SLBMA2 ;NO MATCH
LOAD T1,SLSTA,(SL) ;GET THE SLB'S STATE
IFSTATE T1,CW,RSKP ;IF IT'S IN CONNECT WAIT, THEN MATCH
TMNE SLPAS,(SL) ;Was this a passive task?
SETO P2, ; -yes, flag 'object too busy'
SLBMA2: LOAD SL,SLASQ,(SL) ;STEP TO NEXT SLB ON ALL SLBs Q
JRST SLBMA1 ;AND TRY IT
;Check a SLB
SLBMAS: SAVEAC <T3,T4> ;SAVE T3 AND T4 FOR A WHILE
MOVE T2,P1 ;POINT TO THE INCOMING CONNECT BLOCK
LOAD T1,SLCBP,(SL) ;POINT TO THE SLB'S CONNECT BLOCK
JUMPN T1,CDBMAT ;If there is a connect block, then go
; and check it out. CDBMAT returns +1 or +2.
;No connect block - link is not in CW state. Check if the object numbers
; match.
XMOVEI T2,CB.DST(T2) ;Point to the dest pb source
LOAD T2,PBOBJ,(T2) ;Get dest obj number
OPSTR <CAME T2,>,SLDOB,(SL) ;The same object numbers?
RET ; -no, return failure
RETSKP ;-yes, return success
SUBTTL Subroutines -- CDBMAT - Match Two Connect Blocks
;CDBMAT - Match two internal connect blocks
;
; Call:
; T1/ Pointer to passive SLB's connect block
; T2/ Pointer to incoming connect block
;
; Return:
; RET ;THEY DON'T MATCH
; RETSKP ;FOUND A MATCH
;
; Uses: T1-T6
CDBMAT: SAVEAC <P1,P2> ;SAVE SOME PEAS
DMOVE P1,T1 ;SAVE THE POINTERS TO THE CONNECT BLOCKS
;Try to match the destination end names with each other.
XMOVEI T5,CB.DST(P1) ;POINT TO THE DEST PB PATTERN (PASSIVE)
XMOVEI T6,CB.DST(P2) ;POINT TO THE DEST PB SOURCE
CALL CDBMTP ;COMPARE THE DEST END NAME DESCRIPTOR
RET ;NOW GIVE ERROR RETURN
;Both of the end descriptors have matched. Now let's try to match the
;remainder of the fields in the connect data. First:
;RQSTRID
LOAD T1,CBUCT,(P1) ;GET THE PASSIVE RQSTRID COUNT
XMOVEI T2,CB.UID(P1) ;POINT TO THE WORD ALIGNED RQSTRID STRING
LOAD T3,CBUCT,(P2) ;GET THE SOURCE RQSTRID COUNT
XMOVEI T4,CB.UID(P2) ;POINT TO THE WORD ALIGNED STRING
CALL STRMAT ;TRY TO MATCH THE STRING
RET ;A MISMATCH
;PASSWRD
LOAD T1,CBPCT,(P1) ;GET THE PASSIVE PASSWRD COUNT
XMOVEI T2,CB.PSW(P1) ;POINT TO THE WORD ALIGNED PASSWRD STRING
LOAD T3,CBPCT,(P2) ;GET THE SOURCE STRING COUNT
XMOVEI T4,CB.PSW(P2) ;POINT TO THE WORD ALIGNED STRING
CALL STRMAT ;TRY TO MATCH THEM
RET ;MISMATCH
;ACCOUNT
LOAD T1,CBACT,(P1) ;GET THE PASSIVE ACCOUNT COUNT
XMOVEI T2,CB.ACC(P1) ;POINT TO THE WORD ALIGNED ACCOUNT STRING
LOAD T3,CBACT,(P2) ;GET THE SOURCE STRING COUNT
XMOVEI T4,CB.ACC(P2) ;POINT TO THE WORD ALIGNED STRING
CALL STRMAT ;TRY TO MATCH THEM
RET ;MISMATCH
;USRDATA
LOAD T1,CBCCT,(P1) ;GET THE PASSIVE USER CONNECT DATA COUNT
XMOVEI T2,CB.UDA(P1) ;POINT TO THE WORD ALIGNED USER DATA STRING
LOAD T3,CBCCT,(P2) ;GET THE SOURCE STRING COUNT
XMOVEI T4,CB.UDA(P2) ;POINT TO THE WORD ALIGNED STRING
CALLRET STRMAT ;TRY TO MATCH THE STRINGS AND RETURN
;CDBMTP - Subroutine to match process descriptor blocks
;
;Call:
; T5/ Pointer to the passive (or pattern) connect block
; T6/ Pointer to the source (or incoming) connect block
CDBMTP: LOAD T1,PBOBJ,(T5) ;GET THE PASSIVE GUY'S OBJECT TYPE
OPSTR <CAME T1,>,PBOBJ,(T6) ;MUST BE THE SAME AS THE SOURCE'S
RET ;MISMATCH
;Get the format type, do a range check and dispatch.
LOAD T1,PBFOR,(T5) ;GET THE PASSIVE FORMAT TYPE
OPSTR <CAME T1,>,PBFOR,(T6) ;DOES IT MATCH?
RET ;NO, WE HAVE A MISMATCH
CAIL T1,FRM.0 ;RANGE CHECK THE
CAILE T1,FRM.MX ; FORMAT TYPE
RETSKP ; - should never happen, just RSKP
CALLRET @.+1(T1) ;DISPATCH ON FORMAT TYPE
IFIW <RSKP&777777> ;FORMAT TYPE 0
IFIW <CDBMP1&777777> ;FORMAT TYPE 1
IFIW <CDBMP2&777777> ;FORMAT TYPE 2
;Here to match format 1s. We already matched the object type, so just match
;the NAME field.
CDBMP1: LOAD T1,PBNCT,(T5) ;GET THE PASSIVE COUNT
XMOVEI T2,PB.NAM(T5) ;POINT TO THE WORD ALIGNED STRING
LOAD T3,PBNCT,(T6) ;GET THE SOURCE STRING COUNT
XMOVEI T4,PB.NAM(T6) ;POINT TO THE WORD ALIGNED STRING
CALLRET STRMAT ;TRY TO MATCH THE STRING
;Here to match format 2s. We have already matched the object type. Compare
;the GRPCODE and USRCODE fields, allowing zeroes in either field to act as
;wildcards.
CDBMP2:
IFN <PB.USR-PB.GRP>,<
IF2,<PRINTX ?GRPCODE and USRCODE must be in the same word>>
MOVE T1,PB.USR(T5) ;GET THE PASSIVE USRCODE AND GRPCODE
MOVE T2,PB.USR(T6) ; AND THE SOURCE ONE
TLNE T1,-1 ;A ZERO IN THE LEFT OF PASSIVE
TLNN T2,-1 ; OR LEFT OF SOURCE?
HLL T1,T2 ;YES, MAKE BOTH THE SAME
TRNE T1,-1 ;A ZERO IN THE RIGHT OF PASSIVE
TRNN T2,-1 ; OR RIGHT OF SOURCE?
HRR T1,T2 ;YES, MAKE BOTH THE SAME
CAME T1,T2 ;ARE THEY THE SAME?
RET ;MISMATCH
;Now try to match the DESCRPT fields.
LOAD T1,PBNCT,(T5) ;GET THE PASSIVE COUNT
XMOVEI T2,PB.NAM(T5) ;POINT TO THE WORD ALIGNED STRING
LOAD T3,PBNCT,(T6) ;GET THE SOURCE STRING COUNT
XMOVEI T4,PB.NAM(T6) ;POINT TO THE WORD ALIGNED STRING
CALLRET STRMAT ;TRY TO MATCH THE STRING
SUBTTL Subroutines -- STRMAT - Pattern Matcher
;STRMAT - Routine to perform a pattern match
;
; Call:
; T1/ Length of pattern
; T2/ Pointer to start of word aligned pattern string (not a BP)
; T3/ Length of source string
; T4/ Pointer to start of word aligned source string (not a BP)
;
; Return:
; RET ;FAILURE TO MATCH OR TOO MANY "*"S IN PATTERN
; RETSKP ;PATTERN MATCHED STRING
;
; Uses: T1-T6
;
;The special "pattern-matching" characters are:
;
; ? Match the next source character.
; * Match zero or more next source characters.
; ^V (Control-V) Treat the next pattern character as
; a normal character even if it is a "?" or a "*".
;
;Note: This routine uses four words of stack for every "*" contained
;within the pattern. Also note that we are assuming one word byte
;pointers. This is the same algorithm that TSKSER (in TOPS-10) uses.
;Also note that a null pattern will match anything.
P0==SL ;WE NEED ONE MORE AC
STRMAX==^D4 ;MAXIMUM LEVEL OF RECURSION
STRMAT: JUMPE T1,RSKP ;NULL PATTERN MATCHES EVERYTHING
SAVEAC <P0,P1,P2,P3>
MOVE P1,T2 ;KEEP WORD ALIGNED POINTER TO PATTERN IN P1
MOVE P2,T4 ; TO SOURCE STRING IN P2
SETZ P3, ;USE P3 AS A RECURSION COUNTER
MOVX T2,<POINT 8,(P1)> ;SET UP INDEXED BYTE POINTER TO PATTERN
MOVX T4,<POINT 8,(P2)> ; TO SOURCE STRING ALSO
MOVE P0,P ;SAVE THE STACK POINTER
ADJSP P0,4 ;THIS IS ZERO LEVEL
STRMT1: ADJSP P,4 ;SAVE THE
DMOVEM T1,-3(P) ; SOURCE AND
DMOVEM T3,-1(P) ; PATTERN DESCRIPTORS
AOJ P3, ;INCREMENT THE RECURSION COUNTER
CAILE P3,STRMAX ;ARE WE TOO FAR DOWN?
JRST STRMTF ;WE FAILED
STRMT2: SOJL T1,[SOJL T3,STRMTS ;IF BOTH STRINGS ARE NULL, RETURN SUCCESS
JRST STRMT3] ;IF SOURCE STRING TOO LONG, BACK UP
ILDB T5,T2 ;GET THE NEXT PATTERN CHARACTER
CAIN T5,"*" ;SEE IF IT'S A STAR
JRST STRMT1 ;IT IS, GO RECURSE
CAIN T5,"?" ;SEE IF IT'S A WILDCARD CHARACTER
JRST [SOJL T3,STRMTF ;IF SO, COUNT ONE SOURCE CHAR, FAIL IF NONE
IBP T4 ;SKIP OVER NEXT SOURCE CHAR
JRST STRMT2] ; AND CONTINUE MATCHING WITH NEXT CHARACTER
CAIN T5,"V"-100 ;IS IT A ^V?
JRST [SOJL T1,STRMTF ;IF SO, COUNT OFF ON PATTERN CHARACTER
ILDB T5,T2 ;GET THE NEXT "QUOTED" CHARACTER
JRST .+1] ; AND CONTINUE WITH THE MATCH
SOJL T3,STRMTF ;COUNT OFF SOURCE CHARACTER, FAIL IF NONE
ILDB T6,T4 ;GET THE NEXT SOURCE CHARACTER
CAIL T6,"A"+40 ;IS IT
CAILE T6,"Z"+40 ; LOWER CASE?
CAIA ;NO
SUBI T6,40 ;YES, MAKE UPPER CASE
CAIL T5,"A"+40 ;IS IT
CAILE T5,"Z"+40 ; LOWER CASE?
CAIA ;NO
SUBI T5,40 ;YES, MAKE UPPER CASE
XORI T5,(T6) ;COMPARE THE CHARACTERS
TRNN T5,177 ; BUT ONLY LOOK AT LOW 7 BITS
JRST STRMT2 ;IF THEY MATCH, COMPARE NEXT CHARACTERS
;Here when characters don't match.
STRMT3: CAMN P,P0 ;ARE WE AT LEVEL ZERO?
JRST STRMTF ;NO, MATCH FAILED
DMOVE T1,-3(P) ; PATTERN AND THE
DMOVE T3,-1(P) ; SOURCE
SOJL T3,STRMTF ;WE ARE PROCESSING A "*", EAT ONE MORE
IBP T4 ; SOURCE CHARACTER
DMOVEM T3,-1(P) ;REMEMBER THE UPDATED SOURCE
JRST STRMT2 ;NO TRY TO COMPARE AGAIN
;STRMTF on failure, STRMTS on success
STRMTF: SETO T6, ;WHEN T6 IS NON-ZERO, WE FAILED
TRNA ;MERGE WITH OTHER SUCCESS
STRMTS: SETZ T6, ;SIGNAL SUCCESS
ASH P3,2 ;MULTIPLY RECURSION COUNTER BY FOUR
MOVNS P3 ;NEGATE IT
ADJSP P,(P3) ;GO BACK TO TOP LEVEL
ADJSP P0,-4 ;BACK TO TOP LEVEL FROM ZERO LEVEL
IFN FTDEBUG <
CAME P,P0 ;I GET PARANOID ABOUT STACKS
BUG.(CHK,SCLSMS,SCLINK,SOFT,<STRMAT messed up the stack pointer>,,<
Cause: This BUG is for debugging purposes only and will not be present in
a production monitor.
>,RTN)
>
JUMPN T6,RTN ;GIVE BAD RETURN ON FAILURE
RETSKP ; AND GIVE SUCCESS RETURN
SUBTTL Subroutines -- STPTMR - Stop the Connect Initiate Timer
;STPTMR - Stop the Connect Initiate Timer, adjusting timer counts
;
; Call:
; SL/ Pointer to the SLB
;
; Return:
; RET ;ALWAYS
;
; Uses: T1,T2
;
;This is called even when the CI timer isn't running.
STPTMR: JE SLCTM,(SL),RTN ;IF TIMER ISN'T GOING, JUST RETURN
SETZRO SLCTM,(SL) ;ZERO THE CONNECT TIMER
SOSGE SCTCTA ;DECREMENT THE GLOBAL TIMER COUNT
SETZM SCTCTA ; - went negative, should never happen, fix
LOAD T2,SLSJB,(SL) ;POINT TO THE SJB
OPSTRM <SOS T1,>,SJCTA,(T2) ;DECREMENT THE JOB'S TIMER COUNT
JUMPGE T1,RTN ;RETURN IF COUNT IS OK
SETZRO SJCTA,(T2) ; -should never happen, fix
RET
SUBTTL Subroutines -- STRTMR - Start the Connect Initiate Timer
;STRTMR - Start the Connect Initiate Timer, adjusting all timer counts
;
; Call:
; SL/ Pointer to SLB
;
; Return:
; RET ;ALWAYS
;
; Uses: T1,T2
;
;It is illegal to start a CI timer that has already been started.
STRTMR: CALL DNGTIM ;GET THE CURRENT TIME
STOR T1,SLCTM,(SL) ;STORE THE CURRENT TIME
AOS SCTCTA ;INCREMENT THE GLOBAL TIMER COUNT
LOAD T1,SLSJB,(SL) ;GET POINTER TO SJB
INCR SJCTA,(T1) ;INCREMENT THE JOB'S TIMER COUNT
RET ;RETURN
SUBTTL Subroutines -- TMRREJ - Send a Reject with Reason RSNNRO
;TMRREJ - Reject a Connect with reason RSNNRO
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ON ALLOCATION FAILURE - TRY AGAIN LATER
; RETSKP ;ON SUCCESS - STOP THE TIMER
;
; Uses: T1-T6
TMRREJ: SAVEAC <MB,MS> ;SAVE SOME ACS
TRACE SC,<Rejecting connect due to lack of response from object>
MOVX T1,2 ;WE NEED ONLY TWO BYTES
CALL DNGMSG ;GET A MESSAGE BLOCK
RET ;COULDN'T GET IT, TRY AGAIN LATER
MOVE MB,T1 ;POINT TO THE MESSAGE BLOCK
XMOVEI T1,UD.MSD(MB) ;POINT TO THE USER DATA AREA
CALL DNPINI ;INITIALIZE TO PUT BYTES IN MESSAGE
MOVX T1,RSNNRO ;REASON IS "NO RESPONSE FROM OBJECT"
STOR T1,SLRSN,(SL) ;TELL USER THAT REASON AND
CALL DNP2BY ; PUT IT IN MESSAGE TOO
LOAD T1,SLPID,(SL) ;GET THE NSPpid
MOVX T3,NV.REJ ;FUNCTION IS REJECT
MOVE T4,MB ;POINT TO THE MESSAGE BLOCK
CALL NSP ;CALL NSP TO REJECT THE CONNECT
NEWSTATE LK ;GO INTO NO LINK STATE
SETZRO SLPID,(SL) ;NSP HAS FORGOTTEN THIS LINK DUE TO REJECT
RETSKP ;RETURN SUCCESS
SUBTTL Subroutines -- BLDCTX - Build connect message
;BLDCTX - Build the connect message from an internal connect block
;
; Call:
; T1/ Pointer to the internal connect block (See BEGSTR CB in SCPRM)
;
; Return:
; RET ;RANGE CHECKING FOUND ILLEGAL CONNECT INFO
; RETSKP ;EVERYTHING'S ALRIGHT
;
; Uses: T1-T6
;
;Note: We are assuming that DNPINI has already been called and that we can
;just do DNPxBYs to dump bytes into the message.
BLDCTX: SAVEAC <P1,P2> ;SAVE TWO PEAS
MOVE P1,T1 ;SAVE THE POINTER TO THE CONNECT BLOCK
XMOVEI P2,CB.DST(P1) ;BUILD THE
CALL BLDCTP ; DESTINATION END USER NAME
RET ;BAD FORMAT
XMOVEI P2,CB.SRC(P1) ;BUILD THE
CALL BLDCTP ; SOURCE END USER NAME
RET ;BAD FORMAT
;Here to build the MENUVER word.
SETZB T3,T4 ;BUILD MENUVER IN T4, FLAG FOR MNRPA IN T3
OPSTR <IOR T3,>,CBUCT,(P1) ;ANY RQSTRID?
OPSTR <IOR T3,>,CBPCT,(P1) ;ANY PASSWRD?
OPSTR <IOR T3,>,CBACT,(P1) ;ANY ACCOUNT?
SKIPE T3 ;SHOULD WE SAY THOSE FIELDS ARE INCLUDED?
TXO T4,MNRPA ;YES, SET BIT
TMNE CBCCT,(P1) ;ANY USRDATA?
TXO T4,MNUSR ;YES, SET THE BIT TO INDICATE THIS
MOVX T1,SC.VER ;GET THE VERSION OF SESSION CONTROL
STOR T1,MNVER,+T4 ;STORE IT IN THE VERSION FIELD
MOVE T1,T4 ;PUT IT IN T1 FOR DNPEBY
CALL DNPEBY ;PLACE THE MENUVER EXTENSIBLE BYTE IN MESSAGE
TXNN T4,MNRPA ;WAS RQSTRID, PASSWRD OR ACCOUNT SET?
JRST BLDCT1 ;NO, DON'T INCLUDE THEM
;Now put in the User ID, Password, etc.
LOAD T1,CBUCT,(P1) ;GET THE RQSTRID BYTE COUNT
XMOVEI T2,CB.UID(P1) ;POINT TO THE STRING
CALL PUTSTR ;PUT THE STRING IN THE MESSAGE
LOAD T1,CBPCT,(P1) ;GET THE PASSWRD BYTE COUNT
XMOVEI T2,CB.PSW(P1) ;POINT TO THE PASSWORD
CALL PUTSTR ;PUT IT IN THE MESSAGE
LOAD T1,CBACT,(P1) ;GET THE ACCOUNT BYTE COUNT
XMOVEI T2,CB.ACC(P1) ;POINT TO THE ACCOUNT STRING
CALL PUTSTR ;PUT IT IN THE MESSAGE
BLDCT1: TXNN T4,MNUSR ;IS THERE ANY USRDATA?
RETSKP ;NO, JUST RETURN
LOAD T1,CBCCT,(P1) ;GET THE USRDATA BYTE COUNT
XMOVEI T2,CB.UDA(P1) ;POINT TO THE ACCOUNT STRING
CALL PUTSTR ;PUT IT IN THE MESSAGE
RETSKP ; AND RETURN
;BLDCTP - Subroutine for BLDCTX to build end user name from process block
;
; Call:
; P2/ Pointing to the process descriptor block
BLDCTP: LOAD T1,PBFOR,(P2) ;GET THE FORMAT TYPE
CAIL T1,FRM.0 ;DO SOME
CAILE T1,FRM.MX ; RANGE CHECKING
RET ;BAD CONNECT BLOCK
MOVE T4,T1 ;SEMI-PRESERVE THE FORMAT
CALL DNP1BY ;PLACE THE BYTE IN THE MESSAGE
CALL @[IFIW <BLDCP1&777777> ;DISPATCH BY THE FORMAT TYPE
IFIW <BLDCP2&777777> ;
IFIW <BLDCP4&777777>](T4) ;
RET ;ERROR RETURN
RETSKP ;SUCCESS RETURN
;Here to process a end user name format 0. This just consists
;of a non-zero one byte object type.
BLDCP1: OPSTR <SKIPN T1,>,PBOBJ,(P2) ;MUST HAVE AN OBJECT TYPE
RET ;DIDN'T - ILLEGAL CONNECT BLOCK
CALL DNP1BY ;PLACE THE OBJECT TYPE IN
RETSKP ; AND WE'RE DONE
;Here to process a end user name format 1. This format is a
;zero object type followed by a I-16 name field.
BLDCP2: JN PBOBJ,(P2),RTN ;OBJECT TYPE MUST BE ZERO
SETZ T1, ;GET A ZERO FOR THE OBJECT TYPE
CALL DNP1BY ;STORE OBJECT TYPE IN MESSAGE
MOVX T3,^D16 ;MAX LENGTH NAME IS 16 BYTES
BLDCP3: LOAD T1,PBNCT,(P2) ;GET THE COUNT OF NAME BYTES
CAMLE T1,T3 ;RANGE CHECK THE LENGTH
MOVE T1,T3 ;OOPS, OVERFLOWED, USE MAXIMUM ALLOWED LENGTH
XMOVEI T2,PB.NAM(P2) ;POINT TO THE STRING
CALL PUTSTR ;PLACE THE STRING IN THE MESSAGE
RETSKP ;RETURN SUCCESS
;Here to process a end user name format 2. This format is a zero
;object type followed by GRPCODE (1B), USRCODE (1B) and DESCRPT (I-12).
BLDCP4: JN PBOBJ,(P2),RTN ;OBJECT TYPE MUST BE ZERO
SETZ T1, ;GET A ZERO FOR THE OBJECT TYPE
CALL DNP1BY ;STORE OBJECT TYPE IN MESSAGE
LOAD T1,PBGRP,(P2) ;GET THE GROUP CODE
CALL DNP2BY ;PLACE IT IN THE MESSAGE
LOAD T1,PBUSR,(P2) ;GET THE USER CODE
CALL DNP2BY ;PLACE IT IN THE MESSAGE
MOVX T3,^D12 ;MAXIMUM LENGTH FOR THIS GUY IS 12 BYTES
JRST BLDCP3 ;MERGE WITH THE COMMON CODE
;PUTSTR - Subroutine to put a string from an internal block into a message
;
; Call:
; T1/ Length of the string
; T2/ Pointer to word aligned start of string
PUTSTR: SAVEAC <P1,P2,T4> ;THIS IS A REALLY LOCAL ROUTINE
MOVE P1,T2 ;PUT THE POINTER IN P1
MOVE T4,T1 ;PRESERVE THE LENGTH FOR A WHILE
CALL DNP1BY ;PLACE THE IMAGE COUNT IN THE STRING
MOVX P2,<POINT 8,(P1)> ;BYTE POINTER TO 8 BIT STRING
SOJGE T4,[ILDB T1,P2 ;GET THE BYTE FROM CONNECT BLOCK
CALL DNP1BY ;PLACE THE BYTE IN THE MESSAGE
JRST .] ;KEEP GOING UNTIL DONE
RET ; AND THEN RETURN
SUBTTL Subroutines -- PRSCTX - Parse a connect message
;PRSCTX - Parse a connect message into an internal connect block
;
; Call:
; T1/ Pointer to internal connect block (See BEGSTR CB in SCPRM)
; MB/ Pointer to the Message Block
; MS/ Pointer to the current MSD
;
; Return:
; RET ;ON MESSAGE FORMAT ERROR AFTER REPORTING EVENT
; RETSKP ;SUCESS, INTERNAL CONNECT BLOCK IS FILLED
;
; Uses: T1-T6
;
;Note: We are assuming that DNGINI has already been called and that we can
;just do DNGxBYs to get bytes from the message.
PRSCTX: SAVEAC <P1,P2> ;SAVE A COUPLE OF PEAS
MOVE P1,T1 ;PRESERVE THE POINTER TO THE CONNECT BLOCK
XMOVEI P2,CB.DST(P1) ;POINT TO THE DESTINATION PROCESS BLOCK
CALL PRSCTP ;PARSE DSTNAME PORTION OF MESSAGE
RET ;OOPS
XMOVEI P2,CB.SRC(P1) ;POINT TO THE SOURCE PROCESS BLOCK
CALL PRSCTP ;PARSE SRCNAME PORTION OF MESSAGE
RET ;COULDN'T DO IT
;Here to look at the MENUVER field and see what to parse.
CALL DNG1BY ;GET MENUVER
RET ;ERROR, CALLER WILL CALLRET SCEIVM
MOVE P2,T1 ;PRESERVE IT
LOAD T1,MNVER,+P2 ;GET THE VERSION NUMBER
CAIGE T1,SC.VER ;Same or greater than ours?
RET ; - error, caller will SCEIVM
TXNN P2,MNRPA ;ARE RQSTRID, PASSWRD AND ACCOUNT COMING?
JRST PRSCT1 ;NO, CHECK FOR USRDATA
;Now read the RQSTRID, PASSWRD and the ACCOUNT.
CALL DNG1BY ;GET THE LENGTH OF THE RQSTRID
RET ;ERROR, CALLER WILL CALLRET SCEIVM
CAILE T1,^D39 ;IS LENGTH OK?
RET ;ERROR, CALLER WILL CALLRET SCEIVM
STOR T1,CBUCT,(P1) ;STORE THE BYTE COUNT
XMOVEI T2,CB.UID(P1) ;PUT THE TEXT HERE
CALL GETSTR ;DO IT
RET ;Error - Caller will handle
CALL DNG1BY ;GET THE LENGTH OF THE PASSWRD
RET ;ERROR, CALLER WILL CALLRET SCEIVM
CAILE T1,^D39 ;IS LENGTH OK?
RET ;ERROR, CALLER WILL CALLRET SCEIVM
STOR T1,CBPCT,(P1) ;STORE THE BYTE COUNT
XMOVEI T2,CB.PSW(P1) ;STORE THE TEXT IN
CALL GETSTR ; THE CONNECT BLOCK
RET ;Error - Caller will handle
CALL DNG1BY ;GET THE LENGTH OF THE ACCOUNT STRING
RET ;ERROR, CALLER WILL CALLRET SCEIVM
CAILE T1,^D39 ;IS LENGTH OK?
RET ;ERROR, CALLER WILL CALLRET SCEIVM
STOR T1,CBACT,(P1) ;STORE THE BYTE COUNT
XMOVEI T2,CB.ACC(P1) ;STORE THE ACCOUNT STRING
CALL GETSTR ; IN THE CONNECT BLOCK
RET ;Error - Caller will handle
;Now check for the USRDATA field.
PRSCT1: TXNN P2,MNUSR ;IS THERE ANY USER TEXT?
RETSKP ;NO, WE'RE DONE
CALL DNG1BY ;GET THE LENGTH OF THE USRDATA
RET ;ERROR, CALLER WILL CALLRET SCEIVM
CAILE T1,^D16 ;IS LENGTH OK?
RET ;ERROR, CALLER WILL CALLRET SCEIVM
STOR T1,CBCCT,(P1) ;STORE THE BYTE COUNT
XMOVEI T2,CB.UDA(P1) ;PUT THE TEXT HERE
CALL GETSTR ;DO IT
RET ;Error - Caller will handle
RETSKP ;RETURN SUCCESS
;PRSCTP - Subroutine for PRSCTX to parse end user name portion of message
;
; Call:
; P2/ Pointing to the process descriptor block
PRSCTP: CALL DNG1BY ;GET THE FORMAT TYPE
RET ;ERROR, CALLER WILL RET TO CALLRET SCEIVM
CAIL T1,FRM.0 ;RANGE CHECK
CAILE T1,FRM.MX ; THE FORMAT
RET ;ERROR, CALLER WILL RET TO CALLRET SCEIVM
STOR T1,PBFOR,(P2) ;STORE IT IN THE PD BLOCK
MOVE T4,T1 ;SORT OF PRESERVE THE FORMAT
CALL DNG1BY ;GET THE OBJECT TYPE
RET ;ERROR, CALLER WILL RET TO CALLRET SCEIVM
JRST @.+1(T4) ;DISPATCH BY FORMAT TYPE
IFIW <PRSCP1&777777> ;FORMAT TYPE 0
IFIW <PRSCP2&777777> ;FORMAT TYPE 1
IFIW <PRSCP3&777777> ;FORMAT TYPE 2
;Here to parse the end user name format 0.
PRSCP1: SKIPN T1 ;IS THERE A NON-ZERO OBJECT TYPE?
RET ;ERROR, CALLER WILL RET TO CALLRET SCEIVM
STOR T1,PBOBJ,(P2) ;YES, STORE IT
RETSKP ; AND WE'RE DONE
;Here to parse the end user name format 1.
PRSCP2: CALL DNG1BY ;GET THE IMAGE COUNT
SETZ T1, ;ASSUME NO TEXT IF NO COUNT FIELD
CAILE T1,^D16 ;IS IT OF ACCEPTABLE LENGTH?
RET ;ERROR, CALLER WILL RET TO CALLRET SCEIVM
STOR T1,PBNCT,(P2) ;STORE THE COUNT OF BYTES IN NAME
JUMPE T1,RSKP ;SUCCESS NOW IF NO STRING TO GET
XMOVEI T2,PB.NAM(P2) ;POINT TO WERE TO PUT THE STRING
CALL GETSTR ;GET THE STRING INTO THE PB
RET ;Error - Caller will handle
RETSKP ; AND WE'RE DONE
;Here to parse the end user name format 2.
PRSCP3: CALL DNG2BY ;GET THE GRPCODE
RET ;ERROR, CALLER RETS TO CALLRET SCEIVM
STOR T1,PBGRP,(P2) ;STORE IT IN THE PB
CALL DNG2BY ;GET THE USRCODE
RET ;ERROR, CALLER RETS TO CALLRET SCEIVM
STOR T1,PBUSR,(P2) ;STORE IT IN THE PB
CALL DNG1BY ;GET THE IMAGE LENGTH
SETZ T1, ;NO LENGTH FIELD, ASSUME ZERO LENGTH
CAILE T1,^D14 ;IS LENGTH OK?
RET ;ERROR, CALLER RETS TO CALLRET SCEIVM
STOR T1,PBNCT,(P2) ;STORE THE BYTE COUNT
JUMPE T1,RSKP ;SUCCESS NOW IF NO MORE STRING
XMOVEI T2,PB.NAM(P2) ;POINT TO THE NAME AREA IN THE PB
CALL GETSTR ;PLACE THE STRING IN THE PB
RET ;Error - Caller will handle
RETSKP ; AND RETURN SUCCESSFULLY
;GETSTR - Get a string from the message and place it in the connect block
;
; T1/ Byte count
; T2/ Pointer to the string area in the internal connect block
GETSTR: SAVEAC <P1,P2,FREE0>
DMOVE P1,T1 ;SAVE THE BYTE COUNT AND POINTER
MOVX FREE0,<POINT 8,(P2)> ;BYTE POINTER USING FULLWORD IN P2
SOJGE P1,[CALL DNG1BY ;GET THE BYTE
RET ;Return the error
IDPB T1,FREE0 ;STORE IN CONNECT BLOCK
JRST .] ; AND CONTINUE UNTIL WE RUN OUT
RETSKP ;RETURN
;GETSTP performs the same function but takes the data from a string.
;
; Call:
; T1/ Count
; T2/ Fullword Pointer
; T3/ String Block Address (word aligned)
;
; Return:
; RET ;WITH STRING IN BLOCK
GETSTP: SAVEAC <P1,P2> ;SAVE FOR BYTE POINTERS
DMOVE P1,[POINT 8,0(T2)
POINT 8,0(T3)];BYTE POINTERS FOR FULL WORD POINTERS
SOJGE T1,[ILDB T4,P1 ;GET A BYTE FROM STRING
IDPB T4,P2 ;PLACE IT IN THE STRING BLOCK
JRST .] ; AND CONTINUE UNTIL DONE
RET ;RETURN TO SENDER
SUBTTL Subroutines -- CPYS2M - Copy string block to message segment
;CPYS2M - Copy string block to message segment
;
; Call:
; T1/ Pointer to SBLOCK to copy into message
; MS/ Pointer to current message segment
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
;
;Note: CPYS2I is identical except that it doesn't put a image count into
;the message (used for interrupt data).
CPYS2M: SAVEAC P1 ;SAVE A PEA
SKIPE P1,T1 ;SAVE STRING BLOCK POINTER
LOAD T1,SBCNT,(P1) ;GET COUNT OF BYTES IN STRING
CALL DNP1BY ;PUT IMAGE COUNT IN THE MESSAGE
JUMPE P1,RTN ;IF NO STRING BLOCK, RETURN NOW
CPYS21: LOAD T1,SBCNT,(P1) ;GET THE BYTE COUNT AGAIN
MOVX T2,<<POINT 8,>!1B12> ;MAKE UP 2-WORD BYTE POINTER
XMOVEI T3,SB.DAT(P1) ;POINT TO THE DATA
CALLRET DNCB2M ;COPY STRING TO THE MESSAGE
;Here to copy interrupt data into the message block.
CPYS2I: SAVEAC P1 ;SAVE A PEA
JUMPE T1,RTN ;IF THERE'S NO DATA TO COPY, JUST RETURN
MOVE P1,T1 ;PRESERVE POINTER TO THE SBLOCK
CALLRET CPYS21 ;MERGE WITH OTHER CODE
SUBTTL Subroutines -- CPYM2S - Copy message data to string block
;CPYM2S - Copy message data to string block
;
; Call:
; T1/ Pointer to String Block to copy into
; MS/ Pointer to current message segment
; MB/ Pointer to current message block
;
; Return:
; RET ;ON A FAILURE
; RETSKP ;SUCCESSFUL
;
; Uses: T1-T6
;
;Note: CPYI2S performs the same function, expcept it gets the data
;length from the remaining length of the message (used for interrupt
;data).
CPYM2S: SAVEAC <P1,P2> ;SAVE A PEA
MOVE P1,T1 ;SAVE STRING BLOCK POINTER
MOVE T1,MB ;POINT TO MESSAGE BLOCK
CALL DNLENG ;GET LENGTH OF THE MESSAGE
SOS P2,T1 ;SAVE LENGTH OF DATA IN MSG
CALL DNG1BY ;GET THE IMAGE COUNT
JRST [SETZ T1, ;IF THERE WAS NO COUNT
STOR T1,SBCNT,(P1) ; WE SHOULD RETURN A ZERO AS
RETSKP] ; BYTE COUNT IN SBLOCK
CAMLE T1,P2 ;THAT LENGTH LOOK OK?
RET ;NO, CALLER WILL CALLRET SCEIVM
CPYM21: STOR T1,SBCNT,(P1) ;STORE THE REAL COUNT
JUMPE T1,RSKP ;IF NOTHING THERE, JUST RETURN
MOVX T2,<<POINT 8,>!1B12> ;MAKE UP 2-WORD BYTE POINTER
XMOVEI T3,SB.DAT(P1) ;POINT TO THE TEXT PORTION
CALLRET DNCM2B ;COPY IT TO BUFFER AND RETURN
;Here to copy interrupt data from a message block to a string block.
CPYI2S: SAVEAC P1 ;SAVE A PEA
MOVE P1,T1 ;SAVE SBLOCK POINTER
MOVE T1,MB ;POINT TO MESSAGE BLOCK
CALL DNLENG ;GET LENGTH OF THE MESSAGE
CAILE T1,^D16 ;LEGAL INTERRUPT MSG?
RET ;NO, CALLER WILL CALLRET SCEIVM
CALLRET CPYM21 ;MERGE WITH OTHER CODE
SUBTTL Subroutines -- SCTGSS - Get segment size for a destination
;SCTGSS - get the segment size we are willing to use to a specific destination.
; Used to implement 'big buffers on the NI'.
;
; Call:
; T1/ 16-bit destination node address
; CALL SCTGSS
;
; Return:
; RET always with T1/ segment size to use
SCTGSS: CALL RTRGBS ;Get ROUTER buffer size
SUBI T1,%SCHDR ; and subtract max headers below SC
RET
SUBTTL Subroutines -- SCTCSS - Check segment size for a destination
;SCTCSS - check the segment size for a specific destination.
; Used to implement 'big buffers on the NI'
;
; Call:
; T1/ 16-bit destination node address
; T2/ the segment size the remote is willing to use
; CALL SCTCSS
;
; Return:
; RET with T1/ the segment size to use
SCTCSS: ADDI T2,%SCHDR ;Get the right value for ROUTER to compare with
CALL RTRCBS ;Ask ROUTER for value
SUBI T1,%SCHDR ; and remove header length
RET
SUBTTL Node name/number database -- Initialize
;SCTNIN - Initialize node database
; CALL SCTNIN
;
; Return:
; RET Failed to initialize
; RETSKP Success.
XSWAPCD
SCTNIN:
;The node name/number database use swappable extended section memory.
; ASGVAS is used to allocate space.
;
;At initialization time (below) the hash table and the address table
; are allocated. The layout of these are:
;
; HSHTAB ADRTAB
; ! !
; ------------------------------
; ! SCNHSZ ! RTRMXN+1 !
; ------------------------------
;
;As needed, space for the node name buckets are allocated, 1 page at
; a time. QHBUCK points to the head of free buckets:
;
; QHBUCK ---) BUNXT ---) BUNXT ---) 0
;
IFN FTOPS20,<
MOVEI T1,SCNHSZ ;Hash table size
OPSTR <ADD T1,>,IBMXA,+IBBLK ;Add max # of nodes in area
AOJ T1, ; and an extra word to offset from 0
BLCAL.(<@[MSEC1,,ASGVAS]>,<[0],T1>) ;Get unlocked extended virtual mem
BUG.(CHK,SCLVAS,SCLINK,SOFT,<Couldnt get memory>,,<
Cause: SCLINK called ASGVAS to assign virtual address space for the node
name/address database. Since the requested memory is non-resident,
this should always succeed. However, ASGVAS gave a fail return.
>,RTN) ; and return error
>; END IFN FTOPS20
IFN FTOPS10,<
CALL SCTCCR ;Get amount of core allocated
SUBI T1,1 ;Less one for XBLT count
MOVE T2,DCNVFF## ;Get starting address of core
XMOVEI T3,1(T2) ;Plus one for XBLT
SETZM (T2) ;Zero first word
CALL XBLTA## ;Zero the remainder
MOVE T1,DCNVFF## ;Get location of assigned core
>; END IFN FTOPS10
;Success return from ASGVAS, T1 has address of first location
IFN FTOPS20,<
MOVEM T1,HSHTAB ;Save hash table address
ADDI T1,SCNHSZ ;Add hash table size
>; END IFN FTOPS20
MOVEM T1,ADRTAB ;Save node address table address
IFN FTOPS10,<
OPSTR <ADD T1,>,IBMXA,+IBBLK ;Compute end of address table
ADDI T1,1 ;...
MOVEM T1,SCTMAP ;Set up pseudo map
ADD T1,SCTMPS ;Add size of pseudo map
MOVEM T1,DCNVFF## ;Update DECnet first free address
IFN FTMP,<
SNCALL (UPMM##,MCSEC1) ;Get MM for GETPHP
>; END IFN FTMP
MOVEI T3,1 ;Number of pages to allocate
SNCALL (GETPHP##,MCSEC1) ;Get a physical page
IFN FTMP,<
SNCALL (DWNMM##,MCSEC1) ;Give back MM
>; END IFN FTMP
MOVE T2,SCTMAP ;Get address of pseudo map
MOVEM T1,(T2) ;Store first entry
AOS SCTMPF ;Increment pseudo map first free
MOVX T1,MAPBAS ;Set up pseudo address of hash table
MOVEM T1,HSHTAB ;...
>; END IFN FTOPS10
;No buckets yet
SETZM QHBUCK ;Clear bucket header
;Unlock the node database
IFN FTOPS20,< UNLOCK NODLOK>
;Insert executor node name and address into database
LOAD T1,IBNAM,+IBBLK ;Get sixbit executor name
LOAD T2,IBADR,+IBBLK ; and executor address
CALLRET SCTAND ;Insert them into database and return
SUBTTL Node name/number database -- Lock/unlock database
;LOKNOD - Lock/unlock node database
;
;This is a coroutine (like a SAVEAC) that locks the node database
;
; Call: JSP CX,LOKNOD
;
; Return: forwards a +1 or +2 return
;
; Must be called in process context, without already having the lock.
LOKNOD:
IFN FTOPS10,<JRST (CX)>
IFN FTOPS20,<
PUSH P,CX ;Save PC for a little while
LOCK NODLOK ;Lock the database, wait if necessary
NOINT ;No user interrupts while we have lock
CSKED ;Go CSKED since we have a system resource
POP P,CX ;Retrieve PC
CALL 0(CX) ;Call processing routine
IFNSK. ; +1 return
UNLOCK NODLOK ; Unlock,
OKINT ; allow interrupts
ECSKED ; and exit critical section
RET ; and pass on +1 return
ELSE. ; +2 return
UNLOCK NODLOK ; Unlock
OKINT ; allow interrupts
ECSKED ; and exit critical section
RETSKP ; and pass on +2 return
ENDIF.
;Can never get here
> ;END IFN FTOPS20
SUBTTL Node name/number database -- Add a node
;SCTAND - Add a node name to the database
;
; Call: T1/ node name (in sixbit). Zero to clear
; T2/ Node address. If area # is not present, it will be
; to local area.
; CALL SCTAND
;
; Return:
; RET Name already taken, or node address out of range
; RETSKP Node name and address added to the database
XSWAPCD
SCTAND: SAVEAC <T6,P1,P2>
JSP CX,LOKNOD ;Lock node database
DMOVE P1,T1 ;Save node name and address in P1,P2
CALL CHKADR ;Check address, and default area if needed
RET ; -bad address, pass on error code
;P2 now contains a node address with area #, T6 is non-zero if area = home area
;Delete option?
JUMPE P1,SCTDND ;Go delete a node
;Check if the node already exists in the database
CALL NAM2NO ;Map node name to NO pointer
JRST SCTAN1 ; -no, go check address before adding node
;Here to change a node, T1 points to NO block
;
;Are we changing executor (not allowed unless changing to same..)
LOAD T2,NOADR,(T1) ;Get node address
OPSTR <CAME T2,>,IBADR,+IBBLK ;Executor?
IFSKP. ; -yes,
LOAD T2,NONAM,(T1) ; Get node name
OPSTR <CAME T2,>,IBNAM,+IBBLK ; Same as before?
RNMXER (NF.CWS) ; -no, not allowed, component in wrong st.
RETSKP ; -yes, say its ok
ENDIF.
;Is the node number we are replacing in the local area. If so, delete pointer
; from ADRTAB
LDAREA T3,T2 ;Get old area number
CAME T3,RTRHOM ;IS it local area?
IFSKP. ; -yes, must delete old pointer in ADRTAB
LDNODE T3,T2 ; Get local node index
ADD T3,ADRTAB ; and add in ADRTAB base address
SETZM (T3) ; and clear the link
SOS SCTNDC ; and one less local node
ENDIF.
;Now write the new node address into the tables
STOR P2,NOADR,(T1) ;Store new node address
;If we are adding to local area, update ADRTAB
SKIPN T6 ;Home area?
IFSKP. ; -yes,
LDNODE T2,P2 ; Get new local node index
ADD T2,ADRTAB ; and add address table address
IFN FTOPS10,<
CALL UMPBUC ; Compute unmapped address
>; END IFN FTOPS10
MOVEM T1,(T2) ; and store NO pointer in address table
AOS SCTNDC ; Increment # of local nodes defined
ENDIF.
;All done, return
RETSKP
;SCTAN1 - node name is not in database
SCTAN1: SKIPN T6 ;Home area?
IFSKP. ; -yes,
LDNODE T2,P2 ; Get node index
ADD T2,ADRTAB ; and get pointer into address table
SKIPE (T2) ; Entry non-zero?
RNMXER (NF.CWS) ; -yes, not allowed
ENDIF.
;Find the hash index for this node name
CALL HSHNAM ;Get the hash index
ADD T1,HSHTAB ; and make address of hash table entry
IFN FTOPS10,<
CALL MAPBUC ; Map entry
>; END IFN FTOPS10
SKIPN (T1) ;Is there a hash chain already?
JRST SCTAN2 ; -no, go add a hash chain
;There is a hash chain, search buckets for an empty slot, or end of chain
MOVE T1,(T1) ;Point to first bucket
DO. ;LOOP over buckets
IFN FTOPS10,<
CALL MAPBUC ; Map unmapped bucket
>; END IFN FTOPS10
XMOVEI T2,BU.NO1(T1) ; Point to first NO block in bucket
MOVX T3,NRNOPB ; # of NO blocks/bucket
DO. ; LOOP over NO blocks
OPSTR <SKIPE>,NONAM,(T2) ;Is node name clear?
IFSKP. ; -yes,
STOR P1,NONAM,(T2) ; store name
STOR P2,NOADR,(T2) ; and address
JRST SCTAN3 ; Go join common code to update ADRTAB
ENDIF.
ADDI T2,NO.LEN ; Move to next NO block
SOJG T3,TOP. ; And loop back if more to do
ENDDO.
OPSTR <SKIPN T2,>,BUNXT,(T1) ;Go to next bucket, if any
EXIT. ; -no, exit with T1/ last bucket
MOVE T1,T2 ; -yes, bucket pointer in T1
LOOP. ; and loop back
ENDDO.
;Come here of there are no more buckets, T1 points to last one
;SCTAN2 - add a hash chain, T1 has address of hash entry
SCTAN2: ASSUME BU.NXT,EQ,0
MOVE T4,T1 ;"Save" bucket pointer in T4
IFN FTOPS10,<
CALL UMPBUC ;Compute unmapped address
EXCH T1,T4 ;Save in T4
>; END IFN FTOPS10
CALL GETBUC ; and get a bucket
RNMXER (NF.RES) ; -failed (!!)
XMOVEI T2,BU.NO1(T1) ;Point to first NO block in bucket
STOR P1,NONAM,(T2) ; and store node name
STOR P2,NOADR,(T2) ; and node address
IFN FTOPS10,<
CALL UMPBUC ;Compute unmapped bucket address
EXCH T1,T4 ;Save unmapped address, get original bucket
CALL MAPBUC ;Map original bucket
EXCH T1,T4 ;Swap around again
>; END IFN FTOPS10
STOR T1,BUNXT,(T4) ;Link new bucket into chain
IFN FTOPS10,<
CALL MAPBUC ;Map new bucket again
>; END IFN FTOPS10
; JRST SCTAN3 ;Go join common code to update ADRTAB
;SCTAN3 - update address table with a new node. NO pointer in T2
SCTAN3: JUMPE T6,RSKP ;No more to do if not home area
LDNODE T1,P2 ;Get local node index
ADD T1,ADRTAB ; and add address table address
IFN FTOPS10,<
EXCH T1,T2 ;Get mapped bucket address
CALL UMPBUC ;Compute unmapped bucket address
EXCH T1,T2 ;...
>; END IFN FTOPS10
MOVEM T2,(T1) ;Store NO pointer
AOS SCTNDC ;Increment # of local nodes known
RETSKP ; and done
;SCTDND - delete a node
SCTDND: OPSTR <CAMN P2,>,IBADR,+IBBLK ;Deleting executor?
RNMXER (NF.CWS) ; -not allowed
MOVE T1,P2 ;Get node address
CALL LSCTA2N ; and map it to a name, use locked entry point
RETSKP ; -not found, no more to do
;If home area, clear pointer from ADRTAB to NO block
SKIPN T6 ;Home area?
IFSKP. ; -yes,
LDNODE T1,P2 ; Get local node index
ADD T1,ADRTAB ; and add address table address
SETZM (T1) ; and clear entry
SOS SCTNDC ; Decrement # of local nodes
ENDIF.
;Now clear node name in NO block
SETZRO NONAM,(T2) ;Clear
SETZRO NOADR,(T2) ; Might as well clear address too
RETSKP ; and done
SUBTTL Node name/number database -- Address to name
;SCTA2N - Do node address to name mapping
;
; Call: T1/ Node address. If an area # is not present, it will be
; defaulted to local area.
; CALL SCTA2N
;
; Return:
; RET The address does not have a name set
; RETSKP Node name in sixbit returned in T1, NO pointer in T2
XNENT SCTA2N
JSP CX,LOKNOD ;Lock node database
LSCTA2N: ;Entry point if already locked
SAVEAC <T6,P1,P2>
MOVE P2,T1 ;P2 has node address
CALL CHKADR ;Check address, and default area if needed
RET ; -bad address, pass on error code
;P2 now has node address with area #, T6 is non-zero if area = home area
JUMPE T6,SCTA21 ;If not local area, do it the cumbersome way..
;Verify that the node address is in range
LDNODE T1,P2 ;Get local node index
CAMLE T1,RTRMXN ;Compare with max nodes in area
RNMXER (NF.IPV) ; -bad address
;Get NO pointer from ADRTAB
ADD T1,ADRTAB ;Add address of ADRTAB
SKIPN T2,(T1) ;Is there a NO pointer
RNMXER (NF.URC) ; -no, node is not known
IFN FTOPS10,<
MOVE T1,T2 ;Get unmapped bucket address
CALL MAPBUC ;Map unmapped bucket
MOVE T2,T1 ;Get mapped address
>; END IFN FTOPS10
IFN FTDEBUG <
;Do a sanity check
OPSTR <CAME P2,>,NOADR,(T2) ;Node addresses match?
BUG.(CHK,SCLA2N,SCLINK,SOFT,<Node database inconsistent>,<<T1,NOD>>,<
Cause: The node database SCLA2N failed an internal consistency check.
Data: NOD - NO pointer in ADRTAB
>,RTN)
>
LOAD T1,NONAM,(T2) ;Get node name
RETSKP ; and return with T1 and T2
;SCTA21 - map non-local node address
SCTA21:
;T6 can be reused, not needed as flag any more
; Use T6 as hash table index
SETZ T6, ;Start at index 0
DO. ;LOOP over hash table
CAIL T6,SCNHSZ ; Done all of table?
RNMXER (NF.URC) ; -yes, no match
MOVE T1,T6 ; Move hash index to T1
ADD T1,HSHTAB ; And make hash table address
IFN FTOPS10,<
CALL MAPBUC ; Map entry
>; END IFN FTOPS10
SKIPN T1,(T1) ; Is there a hash bucket chain?
AOJA T6,TOP. ; -no, loop back to next index
DO. ; LOOP over hash bucket chain
IFN FTOPS10,<
CALL MAPBUC ; Map unmapped bucket
>; END IFN FTOPS10
XMOVEI T2,BU.NO1(T1) ; Pointer to first NO block for this bucket
MOVX T3,NRNOPB ; and # of NO blocks in this bucket
DO. ; LOOP over NO blocks in bucket
OPSTR <CAME P2,>,NOADR,(T2) ;Node addresses match?
IFSKP. ; -yes,
LOAD T1,NONAM,(T2) ; Get node name
RETSKP ; and return (T1 and T2)
ENDIF.
ADDI T2,NO.LEN ; -no match, go to next NO block
SOJG T3,TOP. ; -if there is any
ENDDO.
OPSTR <SKIPE T1,>,BUNXT,(T1) ;Move to next bucket
LOOP. ; and loop back
ENDDO.
AOJA T6,TOP. ; and move to next hash table entry
ENDDO.
;Will never get here
SUBTTL Node name/number database -- Name to address
;SCTN2A - Do node name to address mapping
;
; Call: T1/ Node name (in sixbit).
; CALL SCTN2A
;
; Return:
; RET No such name
; RETSKP Node address returned in T1
RESCD
SCTN2A: TOXSWAPCD
JSP CX,LOKNOD ;Lock node database
LSCTN2A: ; Already locked entry point
SAVEAC <T6,P1,P2>
MOVE P1,T1 ;P1 contains node name
CALL NAM2NO ;Map node name to NO block
RNMXER (NF.URC) ; -node name not in database
LOAD T1,NOADR,(T1) ;Get node address
RETSKP ; and return it successfully
SUBTTL Node name/number database -- Name to NO block
;NAM2NO - map a node name to NO block
;
; Call: P1/ node name (in sixbit)
; CALL NAM2NO
;
; Return:
; RET Node name not in database
; RETSKP T1/ NO pointer
NAM2NO: CALL HSHNAM ;Get a hash value from name
ADD T1,HSHTAB ;Get pointer to hash table entry
IFN FTOPS10,<
CALL MAPBUC ; Map entry
>; END IFN FTOPS10
SKIPN T2,(T1) ;Get pointer to first bucket
RET ; -none, return error
;Hash table entry (in T1) has address of first bucket in chain
DO. ;LOOP over hash chain
IFN FTOPS10,<
MOVE T1,T2 ; Get unmapped bucket address
CALL MAPBUC ; Map unmapped bucket
MOVE T2,T1 ; Get mapped bucket address
>; END IFN FTOPS10
XMOVEI T1,BU.NO1(T2) ; Point to first NO block in bucket
MOVX T3,NRNOPB ; # of nodes/bucket
DO. ; LOOP over NO blocks
OPSTR <CAMN P1,>,NONAM,(T1) ;Node name matches?
RETSKP ; -yes, return with T1 setup
;No match, go to next NO block in bucket
ADDI T1,NO.LEN ; Move T1
SOJG T3,TOP. ; and do next NO block
ENDDO.
;Come here when one bucket is exhausted, go to next if there is any
OPSTR <SKIPE T2,>,BUNXT,(T2) ;Move to next
LOOP. ; -yes, loop and do next bucket
RET ; -no more in this chain, fail return
ENDDO.
;Will never get here
SUBTTL Node name/number database -- Default area #
;CHKADR - check node address, and default area
;
; Call: P2/ node address
; CALL CHKADR
;
; Return:
; RET Bad node address
; RETSKP P2/ node address with area #, T6 non-zero if home area
CHKADR: TXNE P2,RN%ARE ;Is there an area #?
IFSKP. ; -no, default it
MOVE T1,RTRHOM ; Get ROUTER home area
STAREA T1,P2 ; and store it
ELSE.
LDAREA T1,P2 ; Get area # if there is one
ENDIF.
SETZ T6, ;Assume not home area
CAME T1,RTRHOM ;Is it?
RETSKP ; -yes, all done
SETO T6, ;It is home area
LDNODE T1,P2 ;Get local node index
OPSTR <CAMLE T1,>,IBMXA,+IBBLK ;In range?
RNMXER (NF.IPV) ; -no, return failure
RETSKP ;-yes, all ok
SUBTTL Node name/number database -- Hash routine
; Call: T1/ Node name (in sixbit)
; CALL HSHNAM
;
; Return:
; RET Index into hash table in T1 [0..SCNHSZ-1]
;
; Note:
; May not touch T4....
XSWAPCD
HSHNAM: MOVM T1,P1 ;We know first character is alphanumeric..
IDIVI T1,SCNHSZ ;Divide by table size (prime #)
MOVE T1,T2 ;Use the modulo value
RET
SUBTTL Node name/number database -- Get a bucket
;GETBUC - get a bucket off free bucket list
;
; Call: CALL GETBUC
;
; Return:
; RET No bucket available (!!)
; RETSKP T1 contains address of bucket
XSWAPCD
GETBUC:
IFN FTOPS10,<
SAVEAC <T4,J> ;Save T4 and J
MOVE J,.CPJOB## ;Get our job number
>; END IFN FTOPS10
D36OFF ;Lock out other jobs
SKIPE T1,QHBUCK ;Get first free bucket
IFSKP. ; -none, get more space
IFN FTOPS20,<
D36ON ; Release interlock
BLCAL.(<@[MSEC1,,ASGVAS]>,<[0],[PGSIZ]>) ;Get one page for buckets
RNMXER(NF.RES) ; None, give error
MOVX T2,<PGSIZ/BU.LEN> ; Get # of buckets per page
D36OFF ; Get interlock
>; END IFN FTOPS20
IFN FTOPS10,<
GETBU1: MOVE T4,SCTMPF ; Any room in pseudo page map?
CAMGE T4,SCTMPS ; ...
JRST GETBU2 ; Yes, continue
CALL EXPMAP ; Expand it
JRST [D36ON ; Unsuccessful, release interlock
RNMXER (NF.RES)] ;And give error return
JRST GETBU1 ; And try again
GETBU2: AOS SCTMPF ; Update first free
D36ON ; Release interlock
PUSH P,T4 ; Save index into pseudo map
IFN FTMP,<
SNCALL (UPMM##,MCSEC1) ;Get MM for GETPHP
>; END IFN FTMP
MOVEI T3,1 ;Number of pages to allocate
SNCALL (GETPHP##,MCSEC1) ;Get a physical page
IFN FTMP,<
SNCALL (DWNMM##,MCSEC1) ;Give back MM
>; END IFN FTMP
MOVEI T2,<PAGSIZ##/BU.LEN> ;Get bucket count
POP P,T4 ; Restore pseudo map index
D36OFF ; Get interlock
ADD T4,SCTMAP ; Compute address of first free
MOVEM T1,(T4) ; Store physical address in pseudo map
SUB T4,SCTMAP ; Compute pseudo address
LSH T4,P2WLSH## ; ...
ADDX T4,MAPBAS ; ...
MOVE T1,T4 ; ...
>; END IFN FTOPS10
MOVE T4,QHBUCK ; Save pointer to current list
MOVEM T1,QHBUCK ; Save pointer to first bucket
MOVE T3,T1 ; Get bucket pointer into right AC for loop
DO. ; LOOP over buckets
SOJLE T2,ENDLP. ; Exit if all buckets linked
MOVE T1,T3 ; Copy pointer of current bucket
IFN FTOPS10,<
CALL MAPBUC ; Map unmapped bucket
>; END IFN FTOPS10
ADDI T3,BU.LEN ; and move to next bucket
STOR T3,BUNXT,(T1) ; Link new bucket into old
LOOP. ; and loop
ENDDO.
IFN FTOPS10,<
MOVE T1,T3 ;Get unmapped address
CALL MAPBUC ;Map unmapped bucket address
MOVE T3,T1 ;Get mapped address
>; END IFN FTOPS10
STOR T4,BUNXT,(T3) ; Link previous list onto end of new list
MOVE T1,QHBUCK ; Get bucket header again (now non-zero)
ENDIF.
IFN FTOPS10,<
CALL MAPBUC ;Map unmapped bucket
>; END IFN FTOPS10
LOAD T2,BUNXT,(T1) ;Get link to next free bucket
MOVEM T2,QHBUCK ; and make that the new first bucket
SETZRO BUNXT,(T1) ;Clear link to next word
D36ON
RETSKP
SUBTTL Node name/number database -- Expand pseudo map
;EXPMAP - Expand pseudo map
;
;Call: CALL EXPMAP
;
;Return: RET if unable to expand map
; RETSKP on success
IFN FTOPS10,<
EXPMAP: MOVE T1,SCTMPS ;Get size of map
ADDI T1,^D20 ;Expand by 20 words
CALL DNGWDZ ;...
RET ;Can't return
MOVE T3,T1 ;Get address of new map
MOVE T2,SCTMAP ;Get address of old map
MOVE T1,SCTMPS ;Get size of old map
MOVEM T3,SCTMAP ;Store address of new map
CALL XBLTA## ;Copy old map into new map
MOVEI T1,^D20 ;Update size of new map
ADDM T1,SCTMPS ;...
RETSKP ;And return
>; END IFN FTOPS10
SUBTTL Node name/number database -- Map a bucket
;MAPBUC - Map an unmapped bucket
;
;Call: T1/ Unmapped address of bucket
; CALL MAPBUC
;
;Return: RET with T1/ Virtual address of bucket
XSWAPCD
IFN FTOPS10,<
MAPBUC: SAVEAC <T2> ;Save T2
MOVE T2,T1 ;Copy unmapped address
SUBX T2,MAPBAS ;Convert to map slot number
LSH T2,W2PLSH## ;...
ADD T2,SCTMAP ;Add address of map
MOVE T2,(T2) ;Get physical address
HRLI T2,(<PM.DCD>B2+PM.WRT+PM.PUB) ;Get mapping info
EXCH T2,.UPMP+.UMTMP ;Map in temp slot
ANDI T1,PG.BDY## ;Compute virtual address
IORI T1,.TEMP ;...
; CAME T2,.UPMP+.UMTMP ;Mapping change?
CLRPT .TEMP ;Yes, flush previous mapping
RET ;And return
>; END IFN FTOPS10
SUBTTL Node name/number database -- Compute bucket's unmapped address
;UMPBUC - Compute unmapped address of bucket
;
;Call: T1/ Mapped address of bucket
; CALL UMPBUC
;
;Return: RET with T1/ Unmapped address of bucket
IFN FTOPS10,<
UMPBUC: SAVEAC <T2,T3,T4> ;Save T2-T4
MOVE T2,.UPMP+.UMTMP ;Get mapping information
TXZ T2,PM.NAD ;Mask off non-address bits
MOVE T3,SCTMPS ;Get size of pseudo page map
MOVE T4,SCTMAP ;And address
UMPBU1: SOSGE T3 ;Adjust and check count
BUG. (CHK,SCLPMI,SCLINK,SOFT,<Node database pseudo page map inconsistent>,,,RTN)
CAME T2,(T4) ;Found the correct entry?
AOJA T4,UMPBU1 ;No, loop back
SUB T4,SCTMAP ;Compute pseudo map slot
LSH T4,P2WLSH## ;Make into pseudo address
ADDX T4,MAPBAS ;Compute unmapped address
ANDI T1,PG.BDY## ;...
IOR T1,T4 ;...
RET ;And return
>; END IFN FTOPS10
SUBTTL Node name/number database -- SCTMOV - SET MEMORY OFFLINE support
;SCTMOV - Called on SET MEMORY OFFLINE to move any affected pages
;
; Call:
; P1/ First affected page number
; P2/ Last affected page number
;
; Return:
; RET always
IFN FTOPS10,<
IFN FTLOCK,<
SCTMOV::SAVEAC <P3,P4> ;Save P3-P4
MOVE P3,SCTMPS ;Get size of pseudo map
MOVE P4,SCTMAP ;And address of pseudo map
SCTMO1: JUMPE P3,RTN ;Exit when finished checking
MOVE T1,(P4) ;Get next physical page in pseudo map
JUMPE T1,SCTMO2 ;Skip entry if zero
CAML T1,P1 ;In range being set offline?
CAMLE T1,P2 ;...
JRST SCTMO2 ;No, skip this entry
SNCALL (MOVPAG##,MCSEC1) ;Ask LOKCON to move the page
MOVEM T1,(P4) ;Store new page number
SCTMO2: AOJ P4, ;Bump pointer into pseudo map
SOJA P3,SCTMO1 ;And loop back for entire map
>; END IFN FTLOCK
>; END IFN FTOPS10
SUBTTL Node name/number database -- SCTANL - Add a loopback node name
;SCTANL - Add a loopback node name to table
;
; Call
; T1/ Node name (in sixbit). Zero to clear.
; T2/ Circuit id
;
; Return:
; RET ;NAME ALREADY TAKEN
; RETSKP ;LOOPBACK NODE CREATED
XSWAPCD
SCTANL: JSP CX,LOKNOD ;Lock node database
SAVEAC <P1,P2> ;STORAGE SPACE
DMOVE P1,T1 ;SAVE ARGUMENTS
JUMPE T1,SCTAL5 ;CLEARING?
CALL LSCTN2A ;FIND OUT IF THIS NAME ALREADY EXISTS, locked
IFNSK. ; -no,
MOVE T1,P1 ; maybe loopback node name?
CALL LSCTCKL ; so check that
RNMXER (NF.NRM) ; -yes, return "name already taken"
ENDIF.
MOVE T1,SCTLNL ;GET POINTER TO LIST OF LOOPBACK NODES
SCTAL1: JUMPE T1,SCTAL2 ;IF END OF LIST, ADD IT IN
OPSTR <CAMN P2,>,LNCIR,(T1) ;MAKE SURE CIRCUIT ID DOESN'T MATCH
RNMXER (NF.NRM) ;CIRCUIT ALREADY HAS A LOOPBACK NODE
LOAD T1,LNNXT,(T1) ;GET POINTER TO NEXT LOOPBACK NODE
JRST SCTAL1 ;AND LOOP
SCTAL2: MOVX T1,LN.LST ;GET SIZE OF BLOCK WE NEED
CALL DNGWDP ;ALLOCATE IT
RNMXER (NF.RES) ;OUT OF RESOURCES
STOR P1,LNNAM,(T1) ;SAVE LOOPBACK NAME
STOR P2,LNCIR,(T1) ;SAVE CIRCUIT ID
MOVE T2,SCTLNL ;#GET POINTER TO HEAD OF LIST
STOR T2,LNNXT,(T1) ;#STORE AS NEXT
MOVEM T1,SCTLNL ;#AND STORE POINTER TO THIS AS HEAD
RETSKP ;AND RETURN SUCCESS
SCTAL5: MOVE T1,T2 ;Get circuit ID
MOVE T2,SCTLNL ;GET POINTER TO LOOPBACK NODE LIST
MOVE T3,[MSEC1,,SCTLNL] ;PLACE TO BACK UP TO
SCTAL6: SKIPN T2 ;Skip if there is such circuit
RNMXER (NF.URC) ; -no such circuit
OPSTR <CAMN T1,>,LNCIR,(T2) ;Is this the circuit we are interested in?
JRST SCTAL7 ;YES
MOVE T3,T2 ;SAVE POINTER TO THIS BLOCK
LOAD T2,LNNXT,(T2) ;LOOK AT NEXT loop node
JRST SCTAL6 ;AND LOOP
SCTAL7: LOAD T1,LNNXT,(T2) ;GET POINTER TO NEXT BLOCK
STOR T1,LNNXT,(T3) ;SAVE IN PREDECESSOR, DELINKING THIS BLOCK
MOVE T1,T2 ;POINTER TO THIS BLOCK
CALL DNFWDS ;RETURN THE CORE
RETSKP ;AND DONE
SUBTTL Node name/number database -- SCTN2L - Convert name to loop circ
;SCTN2L - Convert name to loopback circuit
;
; Call
; T1/ Node name (in sixbit).
; Return:
; RET ;NO SUCH LOOPBACK NODE
; RETSKP, T1/ Circuit ID
RESCD
SCTN2L: TOXSWAPCD
JSP CX,LOKNOD ;Lock node database
MOVE T2,SCTLNL ;GET POINTER TO HEAD OF LOOPBACK NODE LIST
DO.
SKIPN T2 ;Skip if another node
RNMXER (NF.URC) ; -no such name
OPSTR <CAME T1,>,LNNAM,(T2) ;IS THIS THE NODE WE WANT?
IFSKP. ; -yes,
LOAD T1,LNCIR,(T2) ; Get circuit ID
RETSKP
ENDIF.
LOAD T2,LNNXT,(T2) ;NOPE, TRY FOR THE NEXT
LOOP.
ENDDO.
;Can never get here
SUBTTL Node name/number database -- SCTL2N - Convert loopback circuit
;SCTL2N - Check for existance of a loopback node name associated with a
;circuit.
;
; Call:
; T1/ circuit id (LI format)
;
; Return:
; RET No loopback name associated with circuit
; RETSKP T1/ sixbit loopback node name
XSWAPCD
SCTL2N: JSP CX,LOKNOD ;Lock node database
MOVE T2,SCTLNL ;Get pointer to header of loopback node list
DO. ;LOOP over list
SKIPN T2 ; More items in list?
RNMXER (NF.URC) ; -no, end of list, no such name
OPSTR <CAME T1,>,LNCIR,(T2) ;Circuits match?
IFSKP. ; -yes,
LOAD T1,LNNAM,(T2) ; Get loopback node name
RETSKP ; and return
ENDIF.
LOAD T2,LNNXT,(T2) ; -no, go to next loopback node
LOOP. ; and loop back
ENDDO.
;Will never get here
SUBTTL Node name/number database -- SCTCKL - Check for loopback node
;SCTCKL - Check for existance of loopback node. Meant to be used with SCTN2A,
; and thus has a reversed return sequence to indicate existance.
;
;Call
; T1/ Node name (in sixbit).
;Return
; RET ;NODE EXISTS
; RETSKP ;NODE DOESN'T EXIST
XSWAPCD
SCTCKL: JSP CX,LOKNOD ;Lock node database
LSCTCKL: ;Entry point if already locked
MOVE T2,SCTLNL ;GET POINTER TO HEAD OF LOOPBACK NODE LIST
DO. ;LOOP through list
JUMPE T2,RSKP ; Skip return at end of list
OPSTR <CAMN T1,>,LNNAM,(T2) ;IS THIS THE NODE WE WANT?
RET ;YES, DECLARE THAT IT EXISTS
LOAD T2,LNNXT,(T2) ;GET POINTER TO NEXT
LOOP. ;Do next node
ENDDO.
;Can never get here
SUBTTL Network management -- Dispatch
;SCLNMX is the entry point for all network management calls to SCLINK.
;
; Call:
; T1/ function code
; T2/ NF block address
;
; Return:
; RET Network management error code in T1
; RETSKP Operation succeded
XSWAPCD ;All of network management is swappable
;Define dispatch table
NMXFNT:
INIDSP NF.,NMX,0
DSP SET ;SET parameter
DSP CLR ;CLEAR parameter
DSP RED ;READ parameter
DSP COU ;SHOW counters
DSP SZC ;SHOW and ZERO counters
DSP RET ;Return list of entity ids
DSP A2N ;Map Node address to Node name
DSP N2A ;Map Node name to node address
DSP CET ;Check entity Id
DSP CKL ;Check loopback node
ENDDSP
ASSUME NF.CKL,EQ,NF.MAX ;Verify our dispatch table
;Network management parameter table
NODPAR:
PARAMETER(^D500,<PANRD!PADRC>,,,0,<CALL SET500>,JFCL,<CALL CLR500>,<Name>)
PARAMETER(^D501,PADRC,,,,<CALL SET501>,<CALL RED501>,<CALL CLR501>,<Circuit>)
PARAMETER(^D502,<PANRD!PADRC>,,,0,<CALL SET502>,JFCL,<CALL CLR502>,<Address>)
PARAMETER(^D510,,^D65535*TIMBAS,^D1000,%SCINT,<MOVEM T2,SCTINT>,<MOVE T2,SCTINT>,<MOVEM T2,SCTINT>,<Incoming timer>)
PARAMETER(^D511,,^D65535*TIMBAS,^D1000,%SCOTT,<MOVEM T2,SCTOTT>,<MOVE T2,SCTOTT>,<MOVEM T2,SCTOTT>,<Outgoing timer>)
NRNPAR==.-NODPAR
CIRPAR:
PARAMETER(^D400,PANST!PANCL,,,,JFCL,<CALL RED400>,JFCL,<Loopback name>)
NRCPAR==.-CIRPAR
XSWAPCD
SCLNMX: CAIL T1,NF.SET ;Range check
CAILE T1,NF.MAX ; the function code
RNMXER (NF.UFO) ;"Unrecognized function or option"
SAVEAC <P1,P2> ;Save preserved ACs
MOVE P1,T2 ;Put NF block in P1
JRST @NMXFNT(T1) ;Go to processing routine
;Unsupported function codes come here
;Session control does not maintain any counters
NMXCOU:
NMXSZC:
;Check entity ID should never be called
NMXCET:
RNMXER (NF.MPE) ;"Management program error"
SUBTTL Network management -- SET parameter
SUBTTL Network management -- CLEAR parameter
SUBTTL Network management -- READ parameter
;NMXSET - SET a network management paramater
;
; Call:
; T1/ function code
; P1/ NF block
; NFEID/ entity ID
; NFPRM/ parameter #
; NFETY/ entity type
; NFBFF/ zero
; NFBUF/ parameter value
NMXSET:
NMXCLR:
NMXRED:
MOVE P2,T1 ;Save function code
LOAD T1,NFETY,(P1) ;Get entity type
CAIE T1,.NTNOD ;NODE?
IFSKP. ; -yes,
XMOVEI T1,NODPAR ; Load node table
MOVEI T2,NRNPAR ; and its length
ELSE. ; -not NODE
CAIE T1,.NTCKT ; Is it circuit?
IFSKP. ; -yes,
XMOVEI T1,CIRPAR ; Load circuit table
MOVEI T2,NRCPAR ; and its length
ELSE. ; -neither NODE nor CIRCUIT
RNMXER (NF.URC) ; -so return error
ENDIF.
ENDIF.
MOVE T3,P2 ;Retrieve function code
CALLRET NTPARM ;Call NTPARM to do more work
;RED400 - READ circuit parameter 400
; Call:
; P1/ points to NF block
; NFEID/ circuit ID (LI format)
;
; Return:
; RET No loopback name associated with circuit
; RETSKP T1/ 0 and T2/ loopback name (sixbit)
RED400: SAVEAC <T3,T4> ;This coroutine may not touch T3 and T4
LOAD T1,NFEID,(P1) ;Get circuit ID
CALL SCTL2N ;Convert loopback circuit to name
RNMXND ; -not there, return 'no data'
MOVE T2,T1 ;Put it in T2
RNMXOK ; and return success
;SET500 - set node parameter 500 (NAME)
;CLR500 - read " " " "
;
; Call:
; NFEID/ Node address
; T2/ sixbit node name in SET case, 0 in CLEAR
;
SET500:
CLR500: SAVEAC <T3,T4> ;Must be preserved
MOVE T1,T2 ;Move node name into place
LOAD T2,NFEID,(P1) ; and node address
CALL SCTAND ;Insert/remove into table
RNMXER () ;Pass error code back up
RNMXOK ;Success return
;SET501 - set node parameter 501 (CIRCUIT)
;
; Call:
; NFEID/ node name
; T2/ circuit ID
;
SET501: SAVEAC <T3,T4> ;Must be preserved
LOAD T1,NFEID,(P1) ;Get loopback node name
CALL SCTANL ;Add loopback node name
RNMXER (NF.NRM) ; -error
RNMXOK ;Return success
;CLR501 - clear parameter 501 (CIRCUIT)
;
; Call:
; NFEID/ node name
; T2/ zero
;
CLR501: SAVEAC <T3,T4>
LOAD T1,NFEID,(P1) ;Get loopback node name to clear
XCALL (MSEC1,SCTN2L) ;Convert it to loopback circuit
RNMXND ; -not there, return 'no data'
MOVE T2,T1 ;Get circuit ID into T2
SETZ T1, ; and clear loopback node name
CALL SCTANL ;Clear loopback node name
RET ; -pass on error code
RNMXOK ;Return success
;RED501 - read parameter 501 (CIRCUIT)
;
; Call:
; NFEID/ loopback node name
;
RED501: SAVEAC <T3,T4> ;Must be preserved
LOAD T1,NFEID,(P1) ;Get node name
XCALL (MSEC1,SCTN2L) ;Convert to circuit
RNMXER (NF.NRM) ; -error
MOVE T2,T1 ;Result to T2
RNMXOK ; and return success
;SET502 - set node parameter 502 (ADDRESS)
;
; Call:
; NFEID/ node name
; T2/ node address on SET
;
SET502: SAVEAC <T3,T4>
LOAD T1,NFEID,(P1) ;Get node name
CALL SCTAND ;Add node name
RNMXER () ; Pass on error code
RNMXOK ;Return success
;CLR502 - clear node parameter 502 (ADDRESS)
;
; Call:
; NFEID/ node name
; T2/ 0
;
CLR502: SAVEAC <T3,T4> ;Must be preserved
LOAD T1,NFEID,(P1) ;Get node name
XCALL (MSEC1,SCTN2A) ;Map it to a node address
IFSKP. ; -ok,
MOVE T2,T1 ; Move node address to T2
SETZ T1, ; Clear node name to indicate clear
CALL SCTAND ; Clear
RNMXER () ; Pass on error code
ENDIF.
RNMXOK ;Return success
SUBTTL Network management -- Return list of entity ids
;NMXRET - return list of entity IDs
;
; SCLINK maintains two entity types: KNOWN NODES and LOOP NODES.
; The KNOWN nodes fall into two categories: home area and not home
; area. The arguments to NMXRET are different in each case.
;
; Common parameters are:
; P1/ address of NF block
; NFSEL/ .NTKNO or .NTLOP
; NFEID/ if NFSEL is .NTKNO then NFEID has area #
NMXRET: LOADE T1,NFSEL,(P1) ;Get selector
CAXN T1,.NTLOP ;Is it LOOP nodes?
JRST RETLOP ; -yes, go return LOOP nodes
CAXE T1,.NTKNO ;then it should be KNOWN nodes
RNMXER (NF.MPE) ; -no, management program error
LOAD T1,NFEID,(P1) ;Get area number
CAME T1,RTRHOM ;Is it local area
JRST RETOAR ; -no, return other area
; JRST RETHAR ;-yes, return home area
;RETHAR - return home area
;
; SCLINK is handed a buffer that is indexed by local node number
; The local node number is filled in if the node is KNOWN, i.e. in
; session controls node database.
;
; Call:
; NFBFF/ set
; NFUBF/ clear
; NFBUF/ buffer address
; NFBLN/ buffer length
;
; Return:
; RET/ error occurred
; RETSKP/ succeeded
RETHAR:
;Do a couple of sanity checks
LOAD T1,NFBFF,(P1) ;Get buffer flag
LOAD T2,NFUBF,(P1) ; and user flag
SKIPE T1 ;Verify buffer flag is set
SKIPE T2 ; and user buffer flag is clear
RNMXER (NF.MPE) ; otherwise "management program error"
;P2 will contain buffer address
LOAD P2,NFBUF,(P1)
;Loop from node 1 to node NFBLN, checking ADRTAB along the way
JSP CX,LOKNOD ;Lock database
LOAD T1,NFBLN,(P1) ;T1 has node index
LOAD T2,IBMXA,+IBBLK ;Get the Maximum Nodes in Area
CAMLE T1,T2 ;Is Max Area .LE. Buffer Length??
MOVE T1,T2 ;If so use Max area as index
DO. ;LOOP
MOVE T2,ADRTAB ; Get address of address table
ADD T2,T1 ; and add in current local node index
SKIPN T3,(T2) ; Is any pointer there?
IFSKP. ; -yes, that node is KNOWN
IFN FTOPS10,<
EXCH T1,T3 ;Map bucket
CALL MAPBUC ;...
EXCH T1,T3 ;...
>; END IFN FTOPS10
LOAD T3,NOADR,(T3) ; Get node address (now 16-bit format)
MOVE T4,T1 ; Get local node index
ADD T4,P2 ; and add destination buffer address
MOVEM T3,(T4) ; and store the node address
ENDIF.
SOJG T1,TOP. ; Loop back if more nodes to do
ENDDO. ; -no, all nodes done, return successfully
RETSKP
;RETOAR - return list of KNOWN nodes in areas other than home area
;
; RETOAR will write directly to a user buffer. Each node within the given
; area should be written in NICE format, i.e. 16-bit node address in two
; bytes followed by a zero byte to indicate no node name following.
;
; Since the node name/number database is organized in a way that makes
; the search for a single node number outside home area very expensive,
; another measure is taken to speed up the processing.
;
; RETOAR will process the entire area in one pass through the database,
; setting a bit in a temporary table if a specific node is there.
;
; Call:
; NFEID/ area #
; NFUBF/ set
; NFBPT/ user byte pointer
; NFBLN/ # of user bytes
;
; Return:
; RET Some error occurred
; RETSKP Success with
; NFBLN/ # of bytes written
RETOAR: SAVEAC <T5,T6> ;Need these two also
;Verify user buffer bit is set
TMNN NFUBF,(P1) ;Is it set?
RNMXER (NF.MPE) ; -no, "management program error"
;Allocate a temporary buffer to store the bit mask of KNOWN nodes in
MOVX T1,<<RN%NOD+^D36>/^D36> ;Room for all nodes in an area
CALL DNGWZP ;Get zeroed space
RNMXER (NF.RES) ; "resource failure"
MOVE P2,T1 ;Keep bit mask address in P2
;Lock node database so it doesnt change under our feet
IFN FTOPS20,<
S1XCT <LOCK NODLOK>
> ;END IFN FTOPS20
;Now go through the entire node name/number database, and check for all nodes
; in the specified area
SETZ T6, ;T6 is hash table index
DO. ;LOOP over hash table
CAIL T6,SCNHSZ ; Done all of table?
EXIT. ; -yes, pass 1 done
MOVE T1,T6 ; Hash index to T1
ADD T1,HSHTAB ; and make hash table address
IFN FTOPS10,<
CALL MAPBUC ; Map entry
>; END IFN FTOPS10
SKIPN T1,(T1) ; Is there a bucket chain?
AOJA T6,TOP. ; -no, go to next hash index
DO. ; LOOP over hash bucket chain
IFN FTOPS10,<
CALL MAPBUC ; Map bucket
>; END IFN FTOPS10
XMOVEI T2,BU.NO1(T1) ; Pointer to first NO block in this bucket
MOVX T3,NRNOPB ; and # of NO blocks per bucket
DO. ; LOOP over bucket
LOAD T4,NOADR,(T2) ; Get node address
LDAREA T5,T4 ; and extract area number
OPSTR <CAME T5,>,NFEID,(P1) ;Do areas match?
IFSKP. ; -yes, found a KNOWN node
LDNODE T5,T4 ; Get the local node index
CALL INSNOD ; and set the corresponding bit
ENDIF.
ADDI T2,NO.LEN ; Go to next NO block
SOJG T3,TOP. ; -if there is any!
ENDDO.
OPSTR <SKIPE T1,>,BUNXT,(T1) ;Move to next bucket
LOOP. ; and loop back
ENDDO.
AOJA T6,TOP. ; and go to next hash index
ENDDO.
;Come here after 1st pass.
; The node database can now be unlocked
IFN FTOPS20,< UNLOCK NODLOK>
;The bit table has now been set up.
;
;Loop over all entries in the bit table and write corresponding node number
; to the user buffer
LOAD T1,IBMXA,+IBBLK ;Get maximum # of nodes in an area
ADDI T1,^D35 ;One bit
IDIVI T1,^D36 ; per node
MOVE T6,T1 ; gives word count in T6
SETZ T1, ;Begin at word 0
DO. ;LOOP over all words
MOVE T2,T1 ; Move index to T2
ADD T2,P2 ; and make bit table address
MOVE T3,(T2) ; Get contents of that word
JFFO T3,RETOA1 ; Find first bit set
;Come here if no bit was set, go to next word
AOJ T1, ; Increment index
CAMGE T1,T6 ; Done all?
LOOP. ; -no, loop back
EXIT. ; -yes, exit loop
RETOA1: ;Come here if some bit was set, bit # in T4
TDZ T3,BITS(T4) ; Clear bit in word
MOVEM T3,(T2) ; and write it back to bit mask
MOVE T3,T1 ; Get index
IMULI T3,^D36 ; and make into
ADD T3,T4 ; node number
CALL WRTNOD ; in order to write it to user space
IFNSK.
MOVE T1,P2 ;Get the buffer address
CALL DNFWDS ;Return space
RNMXER (NF.RES) ;And return a "Resource Error"
ENDIF.
LOOP. ; Loop back with old T1 to take care of
; next set bit in word, if any.
ENDDO.
;At this point, release the temporary buffer and return successfully
MOVE T1,P2 ;Get buffer address
CALL DNFWDS ;Return space
RETSKP ;Done successfully
;INSNOD - insert a node in bit table
;
; T5/ local node index
; P2/ bit mask address
;
;No ACs may be touched
INSNOD: SAVEAC <T1,T2>
MOVE T1,T5 ;Local node index to T1
IDIVI T1,^D36 ;Word index to T1, bit number to T2
ADD T1,P2 ;Make buffer word address
MOVE T2,BITS(T2) ;Get bit mask for node index
IORM T2,(T1) ; and OR in the node
RET ;Done
;WRTNOD - write a node to user buffer
;
; T3/ local node index
; P1/ NF block
; CALL WRTNOD
; +1 return if no more user space available
; +2 return if all is OK
;
;No ACs may be touched
WRTNOD: SAVEAC <T1,T2>
LOAD T1,NFBLN,(P1) ;Is there room
SUBI T1,3 ; for 3 more bytes
SKIPGE T1 ; ?
RET ; -no, return +1 to indicate that
STOR T1,NFBLN,(P1) ;Store new updated count
LOAD T1,NFEID,(P1) ;Get area number
STAREA T1,T3 ; and put it into node number
TOSWAPCD ;Transfer into section 1 to do PXCT
LOAD T1,NFBPT,(P1) ;Get user byte pointer
LDB T2,[POINT 8,T3,35] ;Get 1st byte
XCTBU [IDPB T2,T1] ;Give it to him
LDB T2,[POINT 8,T3,27] ;Get 2nd byte
XCTBU [IDPB T2,T1] ;Give it to him
SETZ T2, ;And a zero length of node name
XCTBU [IDPB T2,T1] ;Give it to him
TOXSWAPCD ;Exit section 1 after PXCT
STOR T1,NFBPT,(P1) ;Save the updated Byte Pointer
RETSKP ;All done
;RETLOP - return list of LOOP nodes
;
; Call:
; NFBFF/ set
; NFUBF/ clear
; NFBUF/ buffer address
; NFBLN/ # of words in buffer
;
; Return:
; RET Some error occurred
; RETSKP Succes with
; NFBLN/ # of words written
; buffer contains sixbit loop node names
RETLOP:
JSP CX,LOKNOD ;Lock node database
;Sanity checks
LOAD T1,NFBFF,(P1) ;Get buffer flag
LOAD T2,NFUBF,(P1) ; and user buffer flag
SKIPE T1 ;Verify buffer flag is set
SKIPE T2 ; and user buffer flag is clear
RNMXER (NF.MPE) ; otherwise "management program error"
;Step through list of loopback nodes
LOAD P2,NFBUF,(P1) ;Buffer address to P2
SETZ T1, ;No loop nodes found yet
MOVE T2,SCTLNL ;Get pointer to head of loopback nodes
DO. ;LOOP over chain
SKIPN T2 ; Is there any more LOOP nodes?
EXIT. ; -no, done
LOAD T3,LNNAM,(T2) ; -yes, get loopback node name
MOVE T4,T1 ; Get count word of nodes found
ADD T4,P2 ; and add in destination address
MOVEM T3,(T4) ; Store the loopback name
AOJ T1, ; One more loopback node found
LOAD T2,LNNXT,(T2) ; Go to next loopback node
LOOP. ; and loop back
ENDDO.
;Come here when there are no more loopback nodes
STOR T1,NFBLN,(P1) ;Store # of loopback nodes returned
RETSKP ; and return successfully
SUBTTL Network management -- Map node address to node name
;NMXA2N - convert from node address to node name
;
; Call:
; T1/ function code
; P1/ NF block
; NFEID/ Entity ID (node address in 16-bit format)
; NFETY/ .NTNOD
; NFBUF/ zero
;
; Return:
; RET Network management error code in T1
; RETSKP NFBUF/ Sixbit node name
SUBTTL Network management -- Map node name to node address
;NMXN2A - convert node name to node number
;
; Call:
; T1/ function code
; P1/ NF block
; NFEID/ entity ID (sixbit node name)
; NFETY/ .NTNOD
; NFBUF/ zero
;
; Return:
; RET Network management error code in T1
; RETSKP NFBUF/ 16-bit node address
NMXN2A:
NMXA2N: LOAD T2,NFETY,(P1) ;Get entity type
LOAD T3,NFBUF,(P1) ; and buffer word
CAIN T2,.NTNOD ;Verify that it is a node
SKIPE T3 ; and that buffer word is zero
RNMXER (NF.MPE) ; "Management program error"
CAIE T1,NF.A2N ;Is it address to name?
IFSKP. ; -yes
LOAD T1,NFEID,(P1) ;Get 16-bit node address
XCALL (MSEC1,SCTA2N) ;Convert it
RNMXER (NF.URC) ; "Unrecognized component"
ELSE. ; -no
LOAD T1,NFEID,(P1) ;Get sixbit node name
XCALL (MSEC1,SCTN2A) ;Convert it
RNMXER (NF.URC) ; "Unrecognized component"
ENDIF.
STOR T1,NFBUF,(P1) ;Store node name/address
RETSKP
SUBTTL Network management -- Check loopback node name
;NMXCKL - Check loopback node name
;
; Call:
; P1/ NF block address
; NFETY/ .NTNOD
; NFEID/ sixbit node name
;
; Return:
; RET Node is not a loopback node
; RETSKP Node is a loopback node
NMXCKL: LOAD T1,NFETY,(P1) ;Get entity type
CAIE T1,.NTNOD ;Verify that it is a node
RNMXER (NF.MPE) ; otherwise "management program error"
LOAD T1,NFEID,(P1) ;Get entity ID
CALL SCTCKL ;Check if it is a loopback node
RETSKP ; SCTCKL returns "wrong way" (to be fixed)
RNMXER (NF.URC) ; -no, return "unrecognized component"
XRESCD
SUBTTL Network management -- Event -- Invalid message
;SCEIVM - Report Invalid Message Event
;
; Call:
; MB/ Pointer to Message Block (which will be freed)
;
; Return:
; RET ;ALWAYS (WITH AN ERROR CODE IN T1)
;
; Uses: T1-T6
SCEIVM: EVENT(NSP,MSG,Invalid Msg in SCTL) ;BAD MESSAGE EVENT TYPE
CALL FREMSG ;MUSTN'T FREE UNTIL AFTER EVENT MACRO
SCERR %NEIMF,RTN,<Illegal message format detected>
;T1 set up with error code by SCERR macro, which also returns via RTN
SUBTTL Network management -- Event -- CSSE event
;LEVT.0 - parameter 0 for CSSE event
XRESCD
LEVT.0:
;Fall through to LEP.0
; CALLRET LEP.0 ;Parameter 0 (all data)
;LEP.0 - LCG event paramater 0
; CM-6
; DU-2 destination object type
; DU-2 destination node address
; DU-2 packets sent
; DU-2 packets received
; DU-2 bytes sent
; DU-2 bytes received
LEP.0: SETZ T1, ;Parameter #0
CALL EVP2BT ; and output
MOVEI T1,306 ;CM-6
CALL EVPBYT
MOVEI T1,002 ;DU-2
CALL EVPBYT ; and output
LOAD T1,SLDOB,(SL) ;Get destination object #
CALL EVP2BT ; and output
MOVEI T1,002 ;DU-2
CALL EVPBYT ; and output
LOAD T1,SLDNA,(SL) ;Get destination node address
CALL EVP2BT ; and output
MOVEI T1,002 ;DU-2
CALL EVPBYT ; and output
LOAD T1,SLPKS,(SL) ;Get # of packets sent
CALL EVP2BT ; and output
MOVEI T1,002 ;DU-2
CALL EVPBYT ; and output
LOAD T1,SLPKR,(SL) ;Get # of packets received
CALL EVP2BT ; and output
MOVEI T1,002 ;DU-2
CALL EVPBYT ; and output
LOAD T1,SLBYS,(SL) ;Get # of bytes sent
CALL EVP2BT ; and output
MOVEI T1,002 ;DU-2
CALL EVPBYT ; and output
LOAD T1,SLBYR,(SL) ;Get # of bytes received
CALLRET EVP2BT ; and output and return
SUBTTL Local SCTL Storage
RESDT ;IMPURE STORAGE (non-zeroed on boot)
IFN FTOPS20,< ;TOPS10 HAS THESE IN COMMON
;Schedular level routines do "SKIPL SCTLOK/RET" before proceeding
SCTLOK: EXP -1 ;SCTL INTERLOCK, USED BY SCTLCQ & SCTLCW
SCTLKO: EXP 0 ;INTERLOCK OWNER
>
SCTJFF: BLOCK 1 ;NON-ZERO: SCTULK SHOULD CALL SECOND SERVICE
SCTUCF: BLOCK 1 ;NON-ZERO: SCTULK SHOULD CALL SCIUCG
SCTCTA: BLOCK 1 ;GLOBAL COUNT OF CI TIMERS ACTIVE
SCTSJQ: BLOCK QH.LEN ;QUEUE OF ALL SJBS
SWAPVR
IFN FTOPS10,<
SCTCOR::BLOCK 1 ;30-bit address of core for name/address map
SCTMPF: BLOCK 1 ;First free name/address pseudo page map slot
SCTMPS: EXP <<SCNHSZ+777>/PAGSIZ##>+^D20 ;Size of name/address pseudo page map
SCTMAP: BLOCK 1 ;Address of Name/address psuedo page map
>; END IFN FTOPS10
HSHTAB: BLOCK 1 ;30-bit address of node name hash table
ADRTAB: BLOCK 1 ;30-bit address of node number table
QHBUCK: BLOCK 1 ;30-bit address of first free bucket
SCTNDC: BLOCK 1 ;# of local nodes known by SCLINK (for JNTMAN)
RESDT
NODLOK: BLOCK 1 ;Lock word for node database
SCTLNL: BLOCK 1 ;LOOPBACK NODE LIST
SCTP2Q: %SCP2Q ;PHASE II QUOTA
SCTINT: %SCINT ;INCOMING TIMER EXPIRATION VALUE
SCTOTT: %SCOTT ;OUTGOING TIMER EXPIRATION VALUE
SCTJFQ: BLOCK QH.LEN ;QUEUE OF SLBS NEEDING SECOND SERVICE
SCTPRQ: BLOCK QH.LEN ;SCTL TRANSACTION QUEUE HEADER
STRCNT: BLOCK 1 ;RECURSION COUNT FOR PATTERN MATCHER
SCTASQ: BLOCK QH.LEN ;ALL-SLBs QUEUE HEADER
XRESCD ;BACK TO PURE STORAGE
SUBTTL End of SCLINK
IFN FTOPS10, .XCMSY ;XCREF THE MACSYM SYMBOLS
IFN FTOPS20, TNXEND ;TOPS-20 ENDING
IFN FTOPS10,<
RESDT
SCTLOW::!
XRESCD
>; END IFN FTOPS10
END