*DECK FFSITIH 
USETEXT TEXTFFS                      # FS  SYSTEM DEFINITIONS         # 
      PROC FFSITIH (CCT$, EVENT); 
*CALL COPYRITE
# TITLE FFSITIH - TCP INDICATION PROCESSOR.                           # 
  
      BEGIN  # FFSITIH #
  
# 
**    FFSITIH - TCP INDICATION PROCESSOR. 
* 
*     CMP  02/88
* 
*     'FFSITIH' PROCESSES INDICATIONS RECEIVED ON A TCP CONNECTION. 
* 
*     ENTRY (CCT$)       = CONNECTION CONTROL TABLE ENTRY NUMBER. 
*           (EVENT)      = EVENT GENERATED BY THE INDICATION HEADER.
*           (DN$T$IDENT) = INDEX INTO PRIMITIVE TABLE OF INDICATION.
* 
*            THE INDICATION AND ANY DATA ARE POINTED TO BY THE DATA 
*            POINTER IN THE INDICATION COMMON BLOCK PASSED TO THE 
*            TCP LAYER. 
* 
*     DESCRIPTION.
* 
* 
*     RETURN. 
# 
  
      ITEM CCT$       U;             # CONNECTION TABLE ENTRY NUMBER  # 
      ITEM EVENT      U;             # EVENT GENERATED IN FFSLTIP     # 
  
      XREF
        BEGIN 
        PROC ABORT;                  # NOS ABORT MACRO                # 
        PROC FFSLNLH;                # NAM REQUEST PROCESSOR          # 
        PROC FFSMATS;                # ALLOCATE TABLE SPACE           # 
        PROC FFSUCLR;                # CLEAR MEMORY UTILITY           # 
        FUNC INT I;                  # FORTRAN INT FUNCTION           # 
        PROC MESSAGE;                # NOS MESSAGE MACRO              # 
        PROC NETUCAS;                # COPY ASCII STRING              # 
        END 
  
      ARRAY BADTCP [00:00] S(4);     # BAD TCP INDICATION             # 
        BEGIN 
        ITEM BADTP   C(00,00,30) =
          [" FFSITIH - BAD TCP INDICATION "]; 
        ITEM BADZB0  U(03,00,60) = [0]; 
        END 
  
      ITEM I         U; 
  
  
      SWITCH NDICATION : TCI$ID      # TCP INDICATION SWITCH          # 
        INVALID   : TCI$A,
        INVALID   : TCI$AC, 
        INVALID   : TCI$ACC,
        INVALID   : TCI$CS, 
        INVALID   : TCI$D,
        INVALID   : TCI$OS, 
        INVALID   : TCI$PC, 
        INVALID   : TCI$S,
        INVALID   : TCI$SD, 
        ABORTIT   : TCI$ABI,
        CONNECT   : TCI$CI, 
        CLOSE$SAP : TCI$CSI,
        DISCNFIRM : TCI$DC, 
        DISCNNECT : TCI$DI, 
        ERROR     : TCI$EI, 
        FLOW      : TCI$FCI,
        DATA      : TCI$R,
        INVALID   : TCI$UDI,
        INVALID   : TCI$END;
  
  
                                                         CONTROL EJECT; 
  
# 
*     CASE INDICATION OF
# 
  
      GOTO NDICATION [DN$T$IDENT];
  
ABORTIT:  
  
# 
*     NOTE:- IF THE VERSION NO. IS NOT SET TO "DGWVERSION" IN THE TCPOS 
*            HEADER, NO ABORT INDICATIONS WILL BE RETURNED TO THE 
*            USER. INSTEAD HE WILL RECEIVE A CON/CB ON THAT CONNECTION. 
*            THIS IMPLEMENTATION OF THE GATEWAY DEPENDS ON ABORT
*            INDICATIONS BEING RETURNED.
*            THE CODE WILL ABORT IF AN INDICATION IS FOUND ON OTHER THAN
*            VERSION NO. "DGWVERSION".
# 
  
      P<GW$HEADER>     = IND$ADDR[INAMTCP$];
      I = DGWVERSION; 
      IF I NQ X"10" 
      THEN
        BEGIN 
        MESSAGE(BADTCP, 0); 
        ABORT;
        END 
      ELSE
        BEGIN 
# 
*       CLEAR OUT TCP FIELDS IN CCT ENTRY.
*       INDICATION ALREADY SET - PASS FURTHER PARAMETERS. 
# 
  
        ACN$DIPFIU[CCT$] = IP$FIUSTAT"NONE";
        ACN$DIPNET[CCT$] = 0; 
        ACN$DIPHST[CCT$] = 0; 
        IF EPTFLAG EQ FTPC$ 
        THEN
          BEGIN                      # CLIENT CONN. - CLEAR SRCE PORT # 
          ACN$STCPRT[CCT$] = 0; 
          ACN$STCPIU[CCT$] = FALSE; 
          END 
        ELSE
          BEGIN                      # SERVER CONN. - CLEAR DEST PORT # 
          ACN$DTCPRT[CCT$] = 0; 
          ACN$DTCPIU[CCT$] = FALSE; 
          END 
  
        ACN$TCEPID[CCT$] = 0; 
        ACN$TURGNT[CCT$] = FALSE; 
        IND$CTYPE[ITCPCM$] = CCT$;
        END 
      GOTO END$CASE;
  
CONNECT:  
  
# 
*     UNPACK SOURCE AND DESTINATION ADDRESSES INTO CCT ENTRY. 
# 
  
      P<GW$HEADER>     = IND$ADDR[INAMTCP$];
      P<GW$TCP$SAD>    = LOC(GW$TCI$SRC); 
      P<GW$TCP$DAD>    = LOC(GW$TCI$DES); 
        P<GW$IP$SAD>   = LOC(GW$TSAD$AD); 
        P<GW$IP$DAD>   = LOC(GW$TDAD$AD); 
      ACN$SIPFIU[CCT$] = GW$ISAD$FU;
      ACN$SIPNET[CCT$] = GW$ISAD$NW;
      ACN$SIPHST[CCT$] = GW$ISAD$HS;
      ACN$STCPIU[CCT$] = GW$TSAD$PI;
      ACN$STCPRT[CCT$] = GW$TSAD$PT;
      ACN$DIPFIU[CCT$] = GW$IDAD$FU;
      ACN$DIPNET[CCT$] = GW$IDAD$NW;
      ACN$DIPHST[CCT$] = GW$IDAD$HS;
      ACN$DTCPIU[CCT$] = GW$TDAD$PI;
      ACN$DTCPRT[CCT$] = GW$TDAD$PT;
  
# 
*     PERFORM MAXIMUM ALLOCATE NOW - THEN NEVER NEED TO WORRY AGAIN.
*     SET UP ALLOCATE HEADER. 
*     CALL FFSLNLH TO SEND THE BLOCK. 
# 
  
      P<GW$HEADER> = LOC(OUTBUF);    # POINT GW HEADER                # 
      FFSUCLR(LOC(OUTBUF), GW$HL$TA); 
      GW$IDENT     = GW$ID$TA;       # IDENTIFY HEADER                # 
      GW$HDR$TYP   = 0;              # SET HEADER TYPE                # 
      GW$DAT$LEN   = 0;              # SET DATA LENGTH                # 
      GW$HDR$LEN   = INT (GW$HL$TA * 7.5); # SET HEADER LENGTH        # 
      GW$VERSION   = DGWVERSION;     # SET VERSION                    # 
      GW$STATUS    = 0; 
      GW$TA$ICI    = ACN$CCEPID[CCT$];
      GW$TA$SZ     = X"7FF70000"; 
      REQ$Q[RTCPNAM$] = TRUE; 
      REQ$M[RTCPNAM$] = FALSE;
      REQ$RCODE[RTCPNAM$] = RNAM"RNSENDAT"; 
      REQ$CTYPE[RTCPNAM$] = CCT$; 
      REQ$LEN[RTCPNAM$] = GW$HDR$LEN + GW$DAT$LEN;
      REQ$ADDR[RTCPNAM$] = LOC(OUTBUF); 
      FFSLNLH;
  
# 
*     CONNECTION COMPLETE INDICATION HAS ALREADY BEEN SET FOR 
*     THE CONNECTION MANAGEMENT LAYER. SET FURTHER PARAMETERS HERE. 
# 
  
      IND$CTYPE[ITCPCM$] = CCT$;
      GOTO END$CASE;
  
CLOSE$SAP:  
  
# 
*     INDICATION ALREADY SET - PASS FURTHER PARAMETERS. 
*     NOTE:- THE A-A CONNECTION IS NOT CLEARED BY THIS LAYER. 
# 
  
      ACN$TSAPID[CCT$] = 0; 
      ACN$CSAPID[CCT$] = 0; 
      IND$CTYPE[ITCPCM$] = CCT$;
      GOTO END$CASE;
  
DISCNFIRM:  
  
# 
*     CLEAR OUT TCP FIELDS IN CCT ENTRY.
*     INDICATION ALREADY SET - PASS FURTHER PARAMETERS. 
# 
  
      ACN$DIPFIU[CCT$] = IP$FIUSTAT"NONE";
      ACN$DIPNET[CCT$] = 0; 
      ACN$DIPHST[CCT$] = 0; 
      IF EPTFLAG EQ FTPC$ 
      THEN
        BEGIN                        # CLIENT CONN. - CLEAR SRCE PORT # 
        ACN$STCPRT[CCT$] = 0; 
        ACN$STCPIU[CCT$] = FALSE; 
        END 
      ELSE
        BEGIN                        # SERVER CONN. - CLEAR DEST PORT # 
        ACN$DTCPRT[CCT$] = 0; 
        ACN$DTCPIU[CCT$] = FALSE; 
        END 
  
      ACN$TCEPID[CCT$] = 0; 
      ACN$TURGNT[CCT$] = FALSE; 
      IND$CTYPE[ITCPCM$] = CCT$;
      GOTO END$CASE;
  
DISCNNECT:  
  
# 
*     PERFORM DISCONNECT REQUEST NOW - AVOIDS UPPER LAYERS NEEDING TO 
*     DO IT.
*     SET UP DISCONNECT HEADER. 
*     CALL FFSLNLH TO SEND THE BLOCK. 
# 
  
      P<GW$HEADER> = LOC(OUTBUF);    # POINT GW HEADER                # 
      FFSUCLR(LOC(OUTBUF), GW$HL$TD); 
      GW$IDENT     = GW$ID$TD;       # IDENTIFY HEADER                # 
      GW$HDR$TYP   = 0;              # SET HEADER TYPE                # 
      GW$DAT$LEN   = 0;              # SET DATA LENGTH                # 
      GW$HDR$LEN   = INT (GW$HL$TD * 7.5); # SET HEADER LENGTH        # 
      GW$VERSION   = DGWVERSION;     # SET VERSION                    # 
      GW$STATUS    = 0; 
      GW$TD$ICI    = ACN$CCEPID[CCT$];
      REQ$Q[RTCPNAM$] = TRUE; 
      REQ$M[RTCPNAM$] = FALSE;
      REQ$RCODE[RTCPNAM$] = RNAM"RNSENDAT"; 
      REQ$CTYPE[RTCPNAM$] = CCT$; 
      REQ$LEN[RTCPNAM$] = GW$HDR$LEN + GW$DAT$LEN;
      REQ$ADDR[RTCPNAM$] = LOC(OUTBUF); 
      FFSLNLH;
  
      GOTO END$CASE;
  
ERROR:  
  
# 
*     BECAUSE THE ABORT BIT HAS BEEN SET ON THE ULP TIMEOUT PARAMETER 
*     ON ACTIVE/PASSIVE CONNECTS, ERROR INDICATIONS SHOULD NEVER BE 
*     RECEIVED. THEORETICALLY THEY SHOULD BE HANDLED THE SAME AS AN 
*     ABORT INDICATION. THE FOLLOWING CODE ABORTS IF ONE COMES IN.
# 
  
      MESSAGE(BADTCP, 0); 
      ABORT;
  
  
FLOW: 
  
# 
*     FLOW CONTROL INDICATIONS SHOULD NOT BE RECEIVED. THEY WILL
*     BE IGNORED HERE RATHER THAN ABORTING. 
# 
  
      GOTO END$CASE;
  
DATA: 
  
# 
*     . DATA RECEIVED INDICATION TO NEXT LAYER ALREADY SET. 
*       PASS FURTHER PARAMETERS.
*     . CHECK IF DATA HAS HEADER AND PROCESS APPROPRIATELY... 
*     . IF URGENT DATA IS RECEIVED ON A CONNECTION WITH TELNET PROTOCOL 
*       THEN THE DATA IS A TELNET PROTOCOL ELEMENT. IT WILL BE IGNORED
*       BY DROPPING THE BLOCK.
* 
*     . DATA ON CONTROL CONNECTION IS PASSED THROUGH TO CLIENT CONN.
* 
*     NOTE:- DATA FROM CONTROL STATEMENT PASSES THRU HERE TOO.
# 
  
      P<GW$HEADER> = IND$ADDR[INAMTCP$];        # POINT HEADER AT DATA #
      IND$ADDR[ITCPCM$] = IND$ADDR[INAMTCP$];   # GET DATA ADDRESS     #
      IND$LEN[ITCPCM$]  = IND$LEN[INAMTCP$];    # GET DATA LENGTH      #
  
      IF DN$T$DOFF NQ 0 
      THEN
        BEGIN                            # DATA HAS HEADER             #
        ACN$TURGNT[CCT$]  = GW$TR$URG;   # PASS URGENT FLAG SETTING    #
        IND$ADDR[ITCPCM$] = IND$ADDR[INAMTCP$] # ADDRESS OF DATA PASS..#
                            + DN$T$DOFF;       #..HEADER.              #
        IND$LEN[ITCPCM$]  = IND$LEN[INAMTCP$]  # LENGTH EXCLUDE HEADER #
                            - GW$HDR$LEN; 
        IF     (GW$TR$URG)
           AND (ACN$PTYPE[CCT$] EQ S"PTTELNET") 
        THEN
          BEGIN                        # IF URGENT DATA ON TELNET PRTL #
          IND$ICODE[ITCPCM$] = ICM"NULL"; 
          RETURN;                      # GET OUT OF HERE QUICKLY       #
          END 
  
        END                            # DATA HAS HEADER               #
  
      IND$CTYPE[ITCPCM$] = CCT$;
      IND$M[ITCPCM$]    = IND$M[INAMTCP$];
      IND$Q[ITCPCM$]    = IND$Q[INAMTCP$];
      GOTO END$CASE;
  
INVALID:  
  
# 
*     SHOULD NEVER GET THIS FROM TCP GATEWAY..
*     ABORT.
# 
  
      MESSAGE(BADTCP, 0); 
      ABORT;
  
END$CASE: 
  
# 
*     END CASE OF INDICATION
# 
  
      RETURN; 
  
      END  # FFSITIH #
  
      TERM
