*DECK     NVFCUFS 
USETEXT          TEXTSS 
USETEXT          TXTSUSS
USETEXT          TXTAPSS
USETEXT          TXTANVF
USETEXT          TEXTNVF
USETEXT          TXINNVF
PROC  NVFCUFS;
# TITLE NVFCUFS - UPDATE FLOW STATUS.                                  #
  
      BEGIN # NVFCUFS # 
# 
**    NVFCUFS - UPDATE FLOW STATUS. 
* 
*     S. H. FISCHER.         81/11/06.
*     D. G. DEPEW.           81/12/22.
* 
*     THIS PROCEDURE PERFORMS ALL THE CONNECTION(C) LAYER PROCESSING
*     REQUIRED FOR ALL INBOUND, FLOW CONTROL SUPERVISORY MESSAGES.
* 
*     PROC NVFCUFS
* 
*     ENTRY    WCBUF[0] = WORD COUNT WORD FROM ORIGINAL CONNECTION
*                         TRAFFIC QUEUE (*CTQ*) ENTRY.
*             ABHBUF[0] = APPLICATION BLOCK HEADER FOR THE SM (BASED
*                         ARRAY *ABH* IN *TXTAPSS* POINTS HERE).
*             MSGBUF[0] = BODY OF THE SM (BASED ARRAY *APSM* IN 
*                         *TXTAPSS* POINTS HERE).  THE POSSIBLE PFC/SFC 
*                         VALUES ARE:  FC/INIT/R, FC/ACK, FC/NAK, 
*                         FC/BRK, INTR/USR, AND FC/INACT. 
* 
*     EXIT    ANY OF THE FOLLOWING IN VARIOUS COMBINATIONS ACCORDING TO 
*             THE SM RECEIVED AND THE STATE OF THE ACN LIST ENTRY FOR 
*             THE USER IN QUESTION. 
*             - THE STATE OF THE ACN LIST ENTRY HAS BEEN UPDATED. 
*             - AN FC/INIT/N SM HAS BEEN PLACED IN THE OUTGOING TRAFFIC 
*               QUEUE (*OTQ*).
*             - AN FS/RST SM HAS BEEN PLACED IN THE OUTGOING TRAFFIC
*               QUEUE (*OTQ*).
*             - ONE OR MORE ENTRIES IN THE WAITING BLOCK QUEUE (*WBQ*)
*               FOR THE USER IN QUESTION HAVE BEEN TRANSFERRED TO THE 
*               OUTGOING TRAFFIC QUEUE (*OTQ*)
*             - A CR/SWH/R OR CR/TRM/R SM ENQUEUED (IN THE *WBQ*) FOR 
*               THE USER IN QUESTION HAS BEEN TRANSFERRED TO THE
*               OUTGOING TRAFFIC QUEUE (*OTQ*). 
*             - ALL OUTPUT ENQUEUED (IN THE *WBQ*) FOR THE USER IN
*               QUESTION HAS BEEN DISCARDED.
*             - AN INTR/USR ENTRY HAS BEEN PLACED IN THE TERMINAL-TO- 
*               APPLICATION CONNECTION INPUT QUEUE (*TAINPQ*).
*             - THE SM HAS BEEN DISCARDED.
* 
*     NOTE    THE PROCESSING IS DEFINED BY THE NVF/USER C-LAYER STATE 
*             DIAGRAM.
# 
  
  
  
  
# 
****  PROC NVFCUFS - XREF LIST. 
# 
      XREF
        BEGIN 
        PROC ABORT;          # ABORT PROGRAM                           #
        PROC NVFCFCE;        # FIND CONNECTION ENTRY                   #
        PROC MOVE;           # MOVE BLOCK OF MEMORY                    #
        PROC SSCCTR;         # CANCEL TIMER REQUEST                    #
        PROC SSSAWR;         # ACCEPT WORKLIST REQUEST                 #
        PROC SSTAQE;         # ACCEPT QUEUE ENTRY                      #
        PROC SSTATS;         # ALLOCATE TABLE SPACE                    #
        PROC SSTRTS;         # REMOVE TABLE SPACE                      #
        END 
# 
****
# 
  
  
  
  
      ITEM I          I;     # LOOP VARIABLE AND SCRATCH               #
      ITEM NEWACN     B;     # TRUE IF ACN NOT FOUND IN ACN LIST       #
      ITEM AE         I;     # ORD OF MATCHED (OR NEW) ACN LIST ENTRY  #
      ITEM ACNN       I;     # ACN FROM ENTRY WE ARE LOOKING FOR       #
      ITEM RORD       I;     # ORDINAL OF ENTRY LOCATED IN *WBQ*/*IWBQ*#
      ITEM OORD       I;     # ORDINAL OF ENTRY POSITION IN *OTQ*      #
      ITEM SIZ        I;     # SIZE OF ENTRY BEING MOVED TO *OTQ*      #
      ITEM SMID       I;     # INTERNAL SM IDENTIFIER                  #
  
  
  
  
      SWITCH FSSWT:CTQSTAT
                 LLFCACK:    SACK,     # FC/ACK                        #
                 LLFCBRK:    SBRK,     # FC/BRK                        #
                 LLIUSR:     SIUSR,    # INTR/USR                      #
                 LLFCINA:    SINA,     # FC/INACT                      #
                 LLFCINI:    SINIT,    # FC/INIT                       #
                 LLFCNAK:    SNAK,     # FC/NAK                        #
                 LLBIMRK:    SBMRK;    # BI/MARK                       #
  
  
PROC DELDAT;
  
      BEGIN  # DELDAT # 
# 
*     DELDAT - DELETE SYNCHRONOUS BLOCKS. 
* 
*     THIS EMBEDDED PROC FINDS BLOCKS QUEUED FOR THE ACN IN QUESTION IN 
*     THE WAITING BLOCK QUEUE AND DELETES THEM FROM THE QUEUE.
* 
*     PROC DELDAT 
# 
  
      FOR I = 0 WHILE ACN$WBCNT[AE] NQ 0
      DO
        BEGIN 
        FOR RORD = RORD STEP WBQ$ESIZE[RORD]
          WHILE WBQ$ABHACN[RORD] NQ ACNN
        DO
          BEGIN 
          END 
        SIZ = WBQ$ESIZE[RORD];              # SIZE OF ENTRY TO DELETE  #
        SSTRTS( P<WBQ>, RORD, SIZ );        # DELETE ENTRY             #
        ACN$WBCNT[AE] = ACN$WBCNT[AE] - 1;
        END 
  
      END  # DELDAT # 
  
  
  
  
PROC XMITDAT; 
  
      BEGIN  # XMITDAT #
# 
*     XMITDAT - TRANSMIT SYNCHRONOUS BLOCKS.
* 
*     THIS EMBEDDED PROC FINDS BLOCKS QUEUED FOR THE ACN IN QUESTION IN 
*     THE WAITING BLOCK QUEUE AND MOVES THEM TO THE OUTGOING TRAFFIC
*     QUEUE UNTIL THE NUMBER OF UNACKNOWLEDGED SYNCHRONOUS BLOCKS IS
*     EQUAL TO THE APPLICATION BLOCK LIMIT. 
* 
*     PROC XMITDAT
# 
  
  
      FOR I=0 WHILE ACN$WBCNT[AE] NQ 0
        AND ACN$BLCNT[AE] LS ACN$ABL[AE]
      DO
        BEGIN 
        FOR RORD = RORD STEP WBQ$ESIZE[RORD]
          WHILE WBQ$ABHACN[RORD] NQ ACNN
        DO
          BEGIN END 
  
        OORD = OTQLNGTH;
        SIZ = WBQ$ESIZE[RORD];         # SIZE OF ENTRY TO BE MOVED     #
        WBQ$ABN[RORD] = ACN$ABN[AE];   # TRANSFER NEXT ABN             #
        SSTATS( P<OTQ>, SIZ );
        MOVE( SIZ, WBQ[RORD], OTQ[OORD] );
        SSTRTS( P<WBQ>, RORD, SIZ );
  
        IF OORD EQ 0
        THEN
          SSSAWR( WWDF"SACNI"); 
  
        ACN$ABN[AE] = ACN$ABN[AE] + 1;
        ACN$BLCNT[AE] = ACN$BLCNT[AE] + 1;
        ACN$WBCNT[AE] = ACN$WBCNT[AE] - 1;
        END 
  
  
      END  # XMITDAT #
  
  
  
  
PROC XMITSM;
  
      BEGIN  # XMITSM # 
# 
*     XMITSM - TRANSMIT ASYNCHRONOUS SUPERVISORY MESSAGE. 
* 
*     THIS EMBEDDED PROC FINDS AN ASYNCHRONOUS SM (EITHER CR/SWH/R OR 
*     CR/TRM/R) QUEUED FOR THE ACN IN QUESTION IN THE WAITING BLOCK 
*     QUEUE AND MOVES IT TO THE OUTGOING TRAFFIC QUEUE. 
* 
*     PROC XMITSM 
# 
  
  
      IF (ACN$STATE[AE] EQ ACNST"SWTPEND" 
        OR ACN$STATE[AE] EQ ACNST"TRMPEND") 
        AND ACN$BLCNT[AE] EQ 0
      THEN
        BEGIN 
        FOR RORD = RORD  STEP WBQ$ESIZE[RORD] 
          WHILE WBQ$ABHACN[RORD] NQ 0 
          OR WBQ$CRSACN[RORD] NQ ACNN 
        DO
          BEGIN END 
  
        OORD = OTQLNGTH;
        SIZ = WBQ$ESIZE[RORD];       # SIZE OF ENTRY TO BE MOVED     #
        SSTATS( P<OTQ>, SIZ );
        MOVE( SIZ, WBQ[RORD], OTQ[OORD] );
        SSTRTS( P<WBQ>, RORD, SIZ );
        IF OORD EQ 0
        THEN
          SSSAWR( WWDF"SACNI" );
  
        IF ACN$STATE[AE] EQ ACNST"SWTPEND"
        THEN
          ACN$STATE[AE] = ACNST"SWSTART"; 
        ELSE
          ACN$STATE[AE] = ACNST"ENDED"; 
        END 
  
  
      END  # XMITSM # 
  
  
  
  
  
#     MAIN PROCEDURE CODE BEGINS HERE                                  #
  
      IF WCB$SMID[0] EQ CTQSTAT"SBMRK"
      THEN
        BEGIN 
        ACNN = ABHADR[0]; 
        END 
      ELSE
        BEGIN 
        ACNN = FCACN[0];
        END 
      NVFCFCE( ACNN, AE, NEWACN );
  
      SMID = WCB$SMID[0];    # GET INTERNAL SM IDENTIFIER              #
      IF NEWACN 
      THEN
        BEGIN 
        IF SMID NQ CTQSTAT"SINA"
        THEN
          ABORT;
        ELSE
          GOTO ENDTAS;
        END 
  
  
      RORD = 0; 
      GOTO FSSWT[SMID]; 
  
  
  
  
  
LLFCINI:  
      IF ACN$STATE[AE] NQ ACNST"ENDED"
      THEN
        BEGIN 
        ACN$INIT[AE] = TRUE;
        PFCSFC[0] = FCINITN;
        SSTAQE( P<OTQ>, WCBUF, ABHBUF, MSGBUF );
        XMITDAT;             # SEND DATA IF ANY                        #
        XMITSM;              # SEND SM IF ALL BLOCKS ACKED             #
        END 
      GOTO ENDTAS;
  
  
  
  
LLFCINA:  
  
# 
*     IF THE CURRENT STATE OF THE CONNECTION IS TERMINATE PENDING, THEN 
*     THE CONNECTION IS HUNG.  GO AHEAD AND TERMINATE IT. 
# 
  
      IF ACN$STATE[AE] EQ ACNST"TRMPEND" AND
         ACN$CNUM[AE] EQ ABHABN[0]
      THEN
        BEGIN 
        ACN$BLCNT[AE] = 0;   # CLEAR OUTSTANDING BLOCK COUNT           #
        DELDAT;              # DELETE SYNCHRONOUS DATA                 #
        XMITSM;              # SEND CR/TRM/R                           #
        END 
  
      GOTO ENDTAS;
  
  
  
  
LLIUSR: 
      IF INTRCHR[0] GR RIR"UB2" 
      THEN                   # IF THIS IS A USER INTERRUPT             #
        BEGIN 
        IF ACN$STATE[AE] NQ ACNST"SWSTART" AND
           ACN$STATE[AE] NQ ACNST"ENDED"
        THEN                 # IF A SWITCH OR TERM IS NOT IN PROGRESS, #
          BEGIN              # SEND AN INTR/RSP SM                     #
          WCB$WORD[1] = LINTR + 2;
          ABHWORD[1] = LINTR; 
          ABHABT[1] = APPCMD; 
          ABHACT[1] = ACINTR; 
  
          SPMSG0[1] = 0;
          PFCSFC[1] = INTRRSP;
          INTRACN[1] = ACNN;
  
          SSTAQE(P<OTQ>,WCBUF[1],ABH[1],APSM[1]); 
          END 
        END 
  
      ELSE                   # MUST BE A USER BREAK                    #
        BEGIN 
        ACN$BKCNT[AE] = 1;
        DELDAT;              # DELETE SYNCHRONOUS DATA                 #
  
        IF ACN$STATE[AE] EQ ACNST"ACTIVE" OR
           ACN$STATE[AE] EQ ACNST"BRKCMD" 
        THEN
          BEGIN 
          ACN$STATE[AE] = ACNST"BRKOUT";
          SSTAQE( P<TAINPQ>, WCBUF, ABHBUF, MSGBUF ); 
  
          IF ACN$BLKF[AE] 
          THEN
            BEGIN 
            ACN$BLKF[AE] = FALSE; 
  
            FOR RORD=0 STEP IWQ$WC[RORD] WHILE ACNN NQ IWQ$ACN[RORD+1]
            DO
              BEGIN 
              END 
  
            SSTRTS(P<IWBQ>,RORD,IWQ$WC[RORD]);
            END 
          END 
        ELSE
          XMITSM;            # SEND SM IF ONE                          #
        END 
      GOTO ENDTAS;
  
  
  
  
LLBIMRK:  
      IF ACN$STATE[AE] EQ ACNST"CLEARI" 
      THEN                   # IF THE CURRENT ACN STATE IS CLEAR INPUT #
        BEGIN 
        WCB$WORD[1] = LINTR + 2;
        ABHWORD[1] = LINTR; 
        ABHABT[1] = APPCMD; 
        ABHACT[1] = ACINTR; 
  
        SPMSG0[1] = 0;
        PFCSFC[1] = INTRRSP;
        INTRACN[1] = ACNN;
  
        SSTAQE(P<OTQ>,WCBUF[1],ABH[1],APSM[1]); 
  
                             # SET CURRENT ACN STATE BACK TO ACTIVE    #
        ACN$STATE[AE] = ACNST"ACTIVE";
        ACN$BKCNT[AE] = 0;
        END 
  
      ELSE IF ACN$STATE[AE] EQ ACNST"BRKOUT"
      THEN
        BEGIN 
        ACN$BKCNT[AE] = 0;
        END 
  
      GOTO ENDTAS;
  
  
  
  
LLFCACK:  
LLFCNAK:  
      IF ACN$STATE[AE] EQ ACNST"ENDED" OR 
         ACN$STATE[AE] EQ ACNST"SWSTART"
      THEN
        GOTO ENDTAS;
  
      ACN$BLCNT[AE] = ACN$BLCNT[AE] - 1;
      XMITDAT;               # SEND DATA IF ANY                        #
  
# 
*     IF TERMINATION IS PENDING AND THE CR/TRM/R WILL NOW BE SENT OUT 
*     THEN CANCEL THE TIMER REQUEST THAT WAS STARTED UP BECAUSE OF BEING
*     IN THE PENDING STATE. 
# 
  
      IF ACN$STATE[AE] EQ ACNST"TRMPEND" AND
         ACN$BLCNT[AE] EQ 0 
      THEN
        SSCCTR(ACN$CNUM[AE],I); 
  
      XMITSM;                # SEND SM IF ALL BLOCKS ACKED             #
      GOTO ENDTAS;
  
  
  
LLFCBRK:  
      IF ACN$STATE[AE] NQ ACNST"SWSTART" AND
         ACN$STATE[AE] NQ ACNST"ENDED"
      THEN                   # IF A SWITCH OR TERM IS NOT IN PROGRESS  #
        BEGIN                # SEND AN FC/RST SM                       #
        WCB$WORD[1] = LFCRST + 2; 
        ABHWORD[1] = LFCRST;
        ABHABT[1] = APPCMD; 
        ABHACT[1] = ACFC; 
  
        SPMSG0[1] = 0;
        PFCSFC[1] = FCRST;
        FCACN[1] = ACNN;
  
        SSTAQE(P<OTQ>,WCBUF[1],ABH[1],APSM[1]); 
        END 
      GOTO ENDTAS;
  
  
  
ENDTAS: 
      END # NVFCUFS # 
      TERM
