/************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 1997-2005, All Rights Reserved */ /* */ /* PROPRIETARY AND CONFIDENTIAL */ /* */ /* MODULE NAME : cospmain.c */ /* PRODUCT(S) : MOSI Stack (over TP4) */ /* */ /* MODULE DESCRIPTION : */ /* This file implements functions common to CALLING and */ /* CALLED side of the COSP protocol. */ /* */ /* For information see the: */ /* ISO 8326 "Information processing systems - Open Systems */ /* Interconnection - Basic connection oriented session service */ /* definition. */ /* ISO 8327 "Information processing systems - Open Systems */ /* Interconnection - Basic connection oriented session protocol */ /* specification. */ /* ISO 8327/ADD.2 (Draft for Version2). */ /* */ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* */ /* cosp_bind */ /* cosp_unbind */ /* */ /* cosp_con_req */ /* cosp_con_rsp_pos */ /* cosp_con_rsp_neg */ /* */ /* cosp_rel_req */ /* cosp_rel_rsp_pos */ /* */ /* cosp_u_abort_req */ /* */ /* cosp_data_req */ /* */ /* tp4_bind_cnf */ /* tp4_unbind_cnf */ /* */ /* tp4_connect_ind */ /* tp4_connect_cnf */ /* tp4_disconnect_ind */ /* tp4_data_ind */ /* tp4_expdata_ind */ /* */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 07/30/08 JRB 21 Chg log msg from ERR to ENC. */ /* 04/28/08 GLB 20 Removed CALLED_ONLY and CALLING_ONLY */ /* 04/09/08 JRB 19 Fix log message for unsupported SPDU. */ /* 05/05/05 EJV 18 cosp_con_req: copy new port param. */ /* 09/17/04 JRB 17 cosp_con_req: save tp4_conn_id returned from */ /* modified tp4_connect (need for abort fix). */ /* cosp_u_abort_req: if waiting for T-CONNECT.cnf,*/ /* call tp4_disconnect (correct ISO 8327 action).*/ /* 01/20/04 EJV 16 acse_free_con: add a_free_part_security_info.*/ /* 11/14/03 JRB 15 Save encrypt_ctrl ONLY for TP0 (not for TP4).*/ /* 08/25/03 EJV 14 Added param to tp4_connect(). */ /* tp4_connect_ind, cnf: save encrypt_ctrl */ /* 06/20/02 JRB 13 Chg addr args to tp4_connect_ind & */ /* copy them to ACSE_CONN. */ /* 06/05/02 JRB 12 Allow Called SSEL=NULL (0 length) on conn req*/ /* 09/10/01 JRB 11 Remove last change but fix cosp_cn_ptr free. */ /* 08/01/01 JRB 10 Del rem_addr from cosp_enc_cn_ac calls. */ /* Del use of cosp_cn_ptr, cosp_cn_len. */ /* 05/09/01 JRB 09 On S-CONNECT.ind, save SSELs in ACSE_CONN. */ /* 03/14/01 JRB 08 Use new SMEM allocation functions. */ /* Add global variable "session_cfg". */ /* 09/13/99 MDE 07 Added SD_CONST modifiers */ /* 08/13/98 JRB 06 Lint cleanup. */ /* 06/17/98 JRB 05 Allow second call to cosp_bind if SSEL same. */ /* 12/30/97 JRB 04 cosp_bind return same as tp4_bind if it fails*/ /* 07/31/97 JRB 03 cosp_bind & cosp_con_req: set "tp_type" in */ /* tp4_addr. */ /* Don't set NSAP on tp4_bind call (ignored). */ /* 05/27/97 JRB 7.00 MMSEASE 7.0 release. */ /* 03/20/97 EJV 02 Enhanced logging and collision handling. */ /* 02/07/97 EJV 01 Created */ /************************************************************************/ #include "glbtypes.h" #include "sysincs.h" #ifdef DEBUG_SISCO SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__; /* Define for SLOG mechanism */ #endif #include "mem_chk.h" #include "tp4api.h" #include "tp4.h" /* need MIN_TP0_CONN_ID definition */ #include "acse2.h" #include "cosp_log.h" #include "cosp.h" #include "cosp_usr.h" /*======================================================*/ /* */ /* L O C A L V A R I A B L E S */ /* A N D */ /* F U N C T I O N S P R O T O T Y P E S */ /* */ /*======================================================*/ /* define actions to perform after return from one of decode functions */ #define COSP_S_P_ABORT_IND 1 #define COSP_SEND_ABORT_SPDU 2 #define COSP_T_DISCONNECT 4 ST_RET cosp_send_abort (ACSE_CONN *con, ST_INT err_code); static ST_RET cosp_process_connect (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf); static ST_RET cosp_process_finish (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf); static ST_RET cosp_process_accept (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf); static ST_RET cosp_process_refuse (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf); static ST_RET cosp_process_discon (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf); static ST_RET cosp_process_abort (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf); static ST_RET cosp_process_data (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf); /************************************************************************/ /* Global and static variables. */ /************************************************************************/ /* flag below prevents calling acse_free_con twice (if we are in func */ /* tp4_connect and tp4_disconnect_ind is called) */ static ST_BOOLEAN cosp_in_tp4_func; static ST_BOOLEAN cosp_bind_called; /* only 1 binding allowed */ ST_UCHAR cosp_only_ssel [1+MAX_SSEL_LEN]; SESSION_CFG session_cfg; /* Session layer configuration */ /*======================================================*/ /* */ /* B I N D I N G F U N C T I O N S */ /* */ /*======================================================*/ /************************************************************************/ /* cosp_bind */ /*----------------------------------------------------------------------*/ /* Function called by SS-user to bind to local Session Address. */ /* The SS-user should implement the u_cosp_bind_cnf function. */ /* */ /* Parameters: */ /* ST_LONG cosp_user_bind_id COSP User's id for this binding.*/ /* PRES_ADDR *loc_addr Local Address to bind to */ /* ST_INT sharable Ignored, (for compatibility with*/ /* ST_INT max_conns Ignored, previous versions) */ /* */ /* Return: */ /* SD_SUCCESS (0) if bind successful */ /* error code otherwise */ /************************************************************************/ ST_RET cosp_bind (ST_LONG cosp_user_bind_id, PRES_ADDR *loc_addr, ST_INT sharable, ST_INT max_conns) { ST_INT ret; TP4_ADDR tp4_addr; ST_LONG user_bind_id; /* TP4 user bind id */ COSP_LOG_ENC1 ("S-BIND.req: cosp_user_bind_id =0x%08X", cosp_user_bind_id); ret = SD_SUCCESS; /* Check SSEL. If OK, save it. */ if (!cosp_bind_called) { /* If local SSEL len is legal, save SSEL. */ if (loc_addr->ssel_len <= MAX_SSEL_LEN) { if ((cosp_only_ssel [0] = (ST_UCHAR) loc_addr->ssel_len) > 0) memcpy (&cosp_only_ssel [1], loc_addr->ssel, loc_addr->ssel_len); } else { ret = COSP_ERR_INV_SSEL; /* invalid loc SSEL */ COSP_LOG_ERR1 ("COSP-ERROR: S-BIND.req: Invalid length=%d of SSEL.", loc_addr->ssel_len); } } else { /* Second Bind. Only allow it if the SSEL is the same. */ if (cosp_only_ssel [0] != (ST_UCHAR) loc_addr->ssel_len || (loc_addr->ssel_len != 0 && memcmp (&cosp_only_ssel [1], loc_addr->ssel, loc_addr->ssel_len))) { COSP_LOG_ERR0 ("COSP-ERROR: Cannot BIND to different SSEL"); ret = COSP_ERR_INV_SSEL; } } /* Bind to Transport. */ if (ret == SD_SUCCESS) { /* Copy tsel from pres_addr to tp4_addr struct. Don't copy nsap */ /* because tp4_bind ignores it anyway. */ if (loc_addr->tsel_len <= sizeof (tp4_addr.tp4_sel)) { tp4_addr.tp4_sel_len = loc_addr->tsel_len; memcpy (tp4_addr.tp4_sel, loc_addr->tsel, loc_addr->tsel_len); tp4_addr.tp_type = loc_addr->tp_type; /* TP4 or TCP? */ user_bind_id = cosp_user_bind_id; /* pass bind id down */ if ((ret = tp4_bind (user_bind_id, &tp4_addr, sharable, max_conns)) != SD_SUCCESS) { COSP_LOG_ERR0 ("COSP-ERROR: S-BIND.req: T-BIND.req failed."); } } else { ret = COSP_ERR_INV_TP4_ADDR; /* TP4 bind failed */ COSP_LOG_ERR2 ("COSP-ERROR: S-BIND.req: Invalid TSEL length=%d or NSAP length=%d.", loc_addr->tsel_len, loc_addr->nsap_len); } } /* end Transport binding section */ /* If successful, set called flag. Otherwise, treat next bind like first.*/ if (ret == SD_SUCCESS) cosp_bind_called = SD_TRUE; return (ret); } /************************************************************************/ /* tp4_bind_cnf */ /*----------------------------------------------------------------------*/ /* This function is called by the TP-provider to indicate the result of */ /* the bind operation (see cosp_bind func). */ /* */ /* Parameters: */ /* ST_LONG user_bind_id User's id (COSP id) for this binding. */ /* ST_LONG tp4_bind_id TP4 assigned ID for this binding. */ /* ST_INT result Indicates if the bind was successful: */ /* = 0 Success */ /* <> 0 Error code */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID tp4_bind_cnf (ST_LONG user_bind_id, ST_LONG tp4_bind_id, ST_RET result) { ST_LONG cosp_user_bind_id; ST_LONG cosp_bind_id; cosp_user_bind_id = user_bind_id; /* we passing same bind id up */ cosp_bind_id = tp4_bind_id; /* COSP bind id same as TP4 */ COSP_LOG_DEC3 ("S-BIND.cnf: cosp_user_bind_id =0x%08X cosp_bind_id =%9ld result =%d", cosp_user_bind_id, cosp_bind_id, result); u_cosp_bind_cnf (cosp_user_bind_id, cosp_bind_id, result); } /************************************************************************/ /* cosp_unbind */ /*----------------------------------------------------------------------*/ /* Function called by SS-user to unbind from local Session Address. */ /* The SS-user should implement the u_cosp_unbind_cnf function. */ /* */ /* Parameters: */ /* ST_LONG cosp_bind_id COSP's id to unbind. */ /* */ /* Return: */ /* SD_SUCCESS (0) if unbind successful */ /* error code otherwise */ /************************************************************************/ ST_RET cosp_unbind (ST_LONG cosp_bind_id) { ST_LONG tp4_bind_id; COSP_LOG_ENC1 ("S-UNBIND.req: cosp_bind_id =%9ld", cosp_bind_id); tp4_bind_id = cosp_bind_id; /* unbind the transport */ if (tp4_unbind (tp4_bind_id) != SD_SUCCESS) { COSP_LOG_ERR0 ("COSP-ERROR: S-UNBIND.req: T-UNBIND.req failed."); return (COSP_ERR_TP4_RET); } return (SD_SUCCESS); } /************************************************************************/ /* tp4_unbind_cnf */ /*----------------------------------------------------------------------*/ /* This function is called by the TP4-provider to indicate that the */ /* unbind operation completed. */ /* */ /* Parameters: */ /* ST_LONG user_bind_id User's id for this binding. */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID tp4_unbind_cnf (ST_LONG user_bind_id) { ST_LONG cosp_user_bind_id; cosp_user_bind_id = user_bind_id; COSP_LOG_DEC1 ("S-UNBIND.cnf: cosp_user_bind_id =0x%08X", cosp_user_bind_id); u_cosp_unbind_cnf (cosp_user_bind_id); } /************************************************************************/ /* acse_free_con */ /*----------------------------------------------------------------------*/ /* This function will free the pointer to connection info. */ /* In most cases the COSP engine is responsible for releasing the con */ /* pointer. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to connection info struct */ /* */ /* Return: */ /* ST_VOID none */ /************************************************************************/ ST_VOID acse_free_con (ACSE_CONN *con) { if (con) { /* free partner Authentication Info */ a_free_part_security_info ((ST_LONG) con); if (con->cosp_cn_ptr) M_FREE (MSMEM_COSP_CN, con->cosp_cn_ptr); /* free saved encoded CN SPDU */ M_FREE (MSMEM_ACSE_CONN, con); } } /*======================================================*/ /* */ /* C O N N E C T (CALLED SIDE) F U N C T I O N S */ /* */ /*======================================================*/ /************************************************************************/ /* tp4_connect_ind */ /*----------------------------------------------------------------------*/ /* This function is called by the TP4-provider to indicate that a */ /* remote node wishes to establish a connection. */ /* */ /* Parameters: */ /* ST_LONG user_bind_id User's id for this binding. */ /* ST_LONG tp4_conn_id COSP connection id for this connect. */ /* ST_UCHAR *loc_tsel Local (called) TSEL. */ /* ST_UCHAR *rem_tsel Remote (calling) TSEL. */ /* ST_UCHAR *rem_nsap Remote (calling) NSAP (TP4) or */ /* ST_ULONG rem_ip Remote (calling) IP addr(TP0) */ /* ST_INT conndata_len Length of opt connect data <= 32 bytes */ /* char *conndata Pointer to opt connect data. */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID tp4_connect_ind (ST_LONG user_bind_id, ST_LONG tp4_conn_id, ST_UCHAR *loc_tsel, ST_UCHAR *rem_tsel, ST_UCHAR *rem_nsap, ST_ULONG rem_ip, ST_INT conndata_len, char *conndata) { ACSE_CONN *con; tp4_reldata (conndata); /* !!! we ignoring conndata */ con = (ACSE_CONN *) M_CALLOC (MSMEM_ACSE_CONN, 1, sizeof (ACSE_CONN)); /* accept incomming transport connection */ if (tp4_accept (tp4_conn_id, (ST_LONG) con, 0, NULL) == SD_SUCCESS) { con->cosp_state = COSP_CSTATE_IDLE_TCON; con->cosp_bind_id = user_bind_id; /* save the id to pass to COPP */ con->cosp_vtca = SD_TRUE; /* transport conn acceptor */ con->tp4_conn_id = tp4_conn_id; /* Save TSELs, NSAP in ACSE_CONN struct. */ memcpy (con->loc_tsel, loc_tsel, loc_tsel [0]+1); memcpy (con->rem_tsel, rem_tsel, rem_tsel [0]+1); if (tp4_conn_id >= MIN_TP0_CONN_ID) /* This is TP0 conn. Save IP addr*/ { con->remNetAddr.ip = rem_ip; #if defined (TP0_ENABLED) /* If connection is TP0, save encrypt_ctrl. */ if (tp4_conn_id >= MIN_TP0_CONN_ID) { /* this is TP0 connection */ TP0_CONN *tp0_conn = &tp0_conn_arr [tp4_conn_id-MIN_TP0_CONN_ID]; /* save the encryption info in ACSE_CONN */ con->encrypt_ctrl = tp0_conn->sock_info->encrypt_ctrl; } #endif } else /* This is TP4 conn. Save NSAP */ memcpy (con->remNetAddr.nsap, rem_nsap, rem_nsap [0]+1); } else { COSP_LOG_ERR0 ("COSP-ERROR: T-CONNECT.ind: T-ACCEPT.req connection failed."); M_FREE (MSMEM_STARTUP, con); /* reject incomming transport connection, accept failed */ tp4_disconnect (tp4_conn_id, 0, NULL); } } /************************************************************************/ /* cosp_con_rsp_pos */ /*----------------------------------------------------------------------*/ /* Function called by SS-user to Accept an incomming connection. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to con info struct */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ ST_RET cosp_con_rsp_pos (ACSE_CONN *con) { ST_INT ret; ST_UINT spdu_len; char *spdu_ptr; COSP_LOG_ENC2 ("S-CONNECT.rsp+: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_ENCC1 ("User data length: %d", con->ppdu_len); COSP_LOG_ENCH (con->ppdu_len, con->ppdu_ptr); ret = SD_SUCCESS; if (con->cosp_state == COSP_CSTATE_WAIT_CON_RSP) { /* encode ACCEPT SPDU */ ret = cosp_enc_cn_ac (con, NULL, &spdu_ptr, &spdu_len, COSP_SI_ACCEPT); if (ret == SD_SUCCESS) { if (tp4_data (con->tp4_conn_id, SD_TRUE, spdu_len, spdu_ptr) == SD_SUCCESS) { con->cosp_state = COSP_CSTATE_DATA_XFER; con->cosp_vcoll = SD_FALSE; con->cosp_vdnr = SD_FALSE; } else { ret = COSP_ERR_TP4_RET; COSP_LOG_ERR1 ("COSP-ERROR: S-CONNECT.rsp+ acse_conn_id=0x%08X: T-DATA.req failed.", con); } } else { COSP_LOG_ERR1 ("COSP-ERROR: S-CONNECT.rsp+ acse_conn_id=0x%08X: Encoding ACCEPT SPDU failed.", con); } } else { ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: S-CONNECT.rsp+ acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); } return (ret); } /************************************************************************/ /* cosp_con_rsp_neg */ /*----------------------------------------------------------------------*/ /* Function called by SS-user to Reject an incomming connection. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to con info struct */ /* ST_INT reason Reason for reject COSP_CON_RSP_U_... */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ ST_RET cosp_con_rsp_neg (ACSE_CONN *con, ST_INT reason) { ST_INT ret; ST_UINT spdu_len; char *spdu_ptr; ST_UCHAR reason_code; COSP_LOG_ENC3 ("S-CONNECT.rsp-: acse_conn_id =0x%08X user_conn_id =%4ld reason =%d", con, con->user_conn_id, reason); COSP_LOG_ENCC1 ("User data length: %d", con->ppdu_len); COSP_LOG_ENCH (con->ppdu_len, con->ppdu_ptr); ret = SD_SUCCESS; if (con->cosp_state == COSP_CSTATE_WAIT_CON_RSP) { /* encode REFUSE SPDU */ switch (reason) { case COSP_CON_RSP_U_CONGESTION: reason_code = COSP_RF_REASON_U_CONGESTION; break; case COSP_CON_RSP_U_IN_UDATA: reason_code = COSP_RF_REASON_U_REJECT; /* SS-user data should be present in this case */ break; case COSP_CON_RSP_U_NOT_SPECIFIED: default: reason_code = COSP_RF_REASON_U_NOT_SPECIFIED; } /* check if user data present */ if (reason == COSP_CON_RSP_U_IN_UDATA) { /* SS-user data should be present in this case */ if (con->ppdu_len == 0) ret = COSP_ERR_INV_UDATA_LEN; } else { /* SS-user data should NOT be present in this case */ if (con->ppdu_len != 0) ret = COSP_ERR_INV_UDATA_LEN; } if (ret == SD_SUCCESS) { ret = cosp_enc_rf (con, &spdu_ptr, &spdu_len, reason_code); if (ret == SD_SUCCESS) { if (tp4_data (con->tp4_conn_id, SD_TRUE, spdu_len, spdu_ptr) == SD_SUCCESS) { con->cosp_state = COSP_CSTATE_WAIT_TDISCON_IND; tp4_session_timer (con->tp4_conn_id, SD_TRUE); /* start timer */ } else { ret = COSP_ERR_TP4_RET; COSP_LOG_ERR1 ("COSP-ERROR: S-CONNECT.rsp- acse_conn_id=0x%08X: T-DATA.req failed.", con); } } else { COSP_LOG_ERR1 ("COSP-ERROR: S-CONNECT.rsp- acse_conn_id=0x%08X: Encoding REFUSE SPDU failed.", con); } } else { COSP_LOG_ERR3 ("COSP-ERROR: S-CONNECT.rsp- acse_conn_id=0x%08X: Invalid SS-UserData length=%u for Reason=%d.", con, con->ppdu_len, reason); } } else { ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: S-CONNECT.rsp- acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); } return (ret); } /*======================================================*/ /* */ /* C O N N E C T (CALLING SIDE) F U N C T I O N S */ /* */ /*======================================================*/ /************************************************************************/ /* cosp_con_req */ /*----------------------------------------------------------------------*/ /* Function called by SS-user to establish Session Layer connection. */ /* SS-user should implement the u_cosp_con_cnf_pos & u_cosp_con_cnf_neg */ /* functions to receive confirm for this request. */ /* If this function returns value other then SD_SUCCESS then the function */ /* u_cosp_con_cnf_xxx will not be called. */ /* */ /* Parameters: */ /* ST_LONG cosp_bind_id COSP bind id */ /* PRES_ADDR *rem_addr Remote Address */ /* ACSE_CONN *con Pointer to connection info */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ ST_RET cosp_con_req (ST_LONG cosp_bind_id, PRES_ADDR *rem_addr, ACSE_CONN *con) { ST_RET ret; TP4_ADDR tp4_addr; ST_UINT spdu_len; char *spdu_ptr; ST_LONG tp4_user_bind_id; COSP_LOG_ENC3 ("S-CONNECT.req: acse_conn_id =0x%08X user_conn_id =%4ld cosp_bind_id =%9ld", con, con->user_conn_id, cosp_bind_id); COSP_LOG_ENCC1 ("User data length: %d", con->ppdu_len); COSP_LOG_ENCH (con->ppdu_len, con->ppdu_ptr); if (con->cosp_state != COSP_CSTATE_IDLE) { ret = COSP_ERR_INV_CON_STATE; /* invalid connect state*/ COSP_LOG_ERR2 ("COSP-ERROR: S-CONNECT.req acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); return (ret); } tp4_user_bind_id = cosp_bind_id; /* we using only one id */ /* Check "Called" SSEL. May be NULL (i.e. length=0) */ if (rem_addr->ssel_len <= MAX_SSEL_LEN) { /* Save SSEL in ACSE_CONN struct. */ con->rem_ssel[0] = rem_addr->ssel_len; /* first byte is len */ memcpy (&con->rem_ssel[1], rem_addr->ssel, rem_addr->ssel_len); ret = cosp_enc_cn_ac (con, rem_addr, &spdu_ptr, &spdu_len, COSP_SI_CONNECT); if (ret == SD_SUCCESS) { /* we always will initiate new transport connection for every new */ /* session connection, so find empty spot for con info */ /* Copy tsel and nsap from pres_addr to tp4_addr struct */ tp4_addr.tp4_sel_len = rem_addr->tsel_len; memcpy (tp4_addr.tp4_sel, rem_addr->tsel, rem_addr->tsel_len); tp4_addr.tp_type = rem_addr->tp_type; if (rem_addr->tp_type == TP_TYPE_TP4) { tp4_addr.net_addr_len = rem_addr->nsap_len; memcpy (tp4_addr.netAddr.nsap, rem_addr->netAddr.nsap, rem_addr->nsap_len); } else { tp4_addr.netAddr.ip = rem_addr->netAddr.ip; /* IP Addr */ tp4_addr.port = rem_addr->port; } /* Note: !!! the tp4_disconnect_ind may be called before the */ /* tp4_connect function returns (SD_FAILURE), we want to log the err */ /* only in one place (here) */ cosp_in_tp4_func = SD_TRUE; /* prevents logging err */ /* request transport connection (no connect data) */ if ((con->tp4_conn_id = tp4_connect (tp4_user_bind_id, (ST_LONG) con, &tp4_addr, 0, NULL, &con->encrypt_ctrl)) >= 0) { /* save the encoded CN until T-CONNECT.cnf received */ con->cosp_state = COSP_CSTATE_WAIT_TCON_CNF; con->cosp_cn_len = spdu_len; con->cosp_cn_ptr = (ST_CHAR *) M_MALLOC (MSMEM_COSP_CN, spdu_len); memcpy (con->cosp_cn_ptr, spdu_ptr, spdu_len); con->cosp_vtca = SD_FALSE; /* transport conn initiator */ } else { ret = COSP_ERR_TP4_RET; COSP_LOG_ENC1 ("COSP-ERROR: S-CONNECT.req acse_conn_id=0x%08X: T-CONNECT.req failed.", con); } cosp_in_tp4_func = SD_FALSE; /* turn off the flag */ } else { COSP_LOG_ERR1 ("COSP-ERROR: S-CONNECT.req acse_conn_id=0x%08X: Encoding CONNECT SPDU failed.", con); } } else { ret = COSP_ERR_INV_SSEL; /* invalid SSEL (length) */ COSP_LOG_ERR2 ("COSP-ERROR: S-CONNECT.req acse_conn_id=0x%08X: Invalid remote SSEL length=%d.", con, rem_addr->ssel_len); } return (ret); } /************************************************************************/ /* tp4_connect_cnf */ /*----------------------------------------------------------------------*/ /* This function is called by the TP4-provider to indicate that the */ /* transport connection has been established. */ /* NOTE: cosp_con_req saved the TP4 connection ID in con->tp4_conn_id. */ /* It should match the tp4_conn_id passed to this function. */ /* */ /* Parameters: */ /* ST_LONG user_conn_id User's connection id for this connect. */ /* ST_LONG tp4_conn_id TP4 connection id for this connect. */ /* ST_INT conndata_len Length of optional connect data. */ /* char *conndata Pointer to optional connect data. */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID tp4_connect_cnf (ST_LONG user_conn_id, ST_LONG tp4_conn_id, ST_INT conndata_len, char *conndata) { ACSE_CONN *con; tp4_reldata (conndata); /* !!! we ignoring conndata */ con = (ACSE_CONN *) user_conn_id; if (con->cosp_state == COSP_CSTATE_WAIT_TCON_CNF) { #if defined (TP0_ENABLED) /* If connection is TP0, save encrypt_ctrl. */ if (tp4_conn_id >= MIN_TP0_CONN_ID) { /* this is TP0 connection */ TP0_CONN *tp0_conn = &tp0_conn_arr [tp4_conn_id-MIN_TP0_CONN_ID]; /* save the encryption info in ACSE_CONN */ con->encrypt_ctrl = tp0_conn->sock_info->encrypt_ctrl; } #endif /* send the CN (already encoded) on the established transport connection */ if (tp4_data (tp4_conn_id, SD_TRUE, con->cosp_cn_len, con->cosp_cn_ptr) == SD_SUCCESS) { con->cosp_state = COSP_CSTATE_WAIT_AC; /* wait AC or RF */ /* we are done with the encoding buffer for CN */ if (con->cosp_cn_ptr) { M_FREE (MSMEM_COSP_CN, con->cosp_cn_ptr); con->cosp_cn_len = 0; con->cosp_cn_ptr = NULL; } } else { COSP_LOG_ERR1 ("COSP-ERROR: T-CONNECT.cnf acse_conn_id=0x%08X: T-DATA.req failed", con); } } else { COSP_LOG_ERR2 ("COSP-ERROR: T-CONNECT.cnf acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); } } /*======================================================*/ /* */ /* C O N N E C T I O N R E L E A S E (CALLED SIDE) */ /* */ /*======================================================*/ /************************************************************************/ /* cosp_rel_rsp_pos */ /*----------------------------------------------------------------------*/ /* Function called by SS-user to Accept a release of connection. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to connection info */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ ST_RET cosp_rel_rsp_pos (ACSE_CONN *con) { ST_INT ret; ST_UINT spdu_len; char *spdu_ptr; COSP_LOG_ENC2 ("S-RELEASE.rsp+: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_ENCC1 ("User data length: %d", con->ppdu_len); COSP_LOG_ENCH (con->ppdu_len, con->ppdu_ptr); if (con->cosp_state == COSP_CSTATE_WAIT_REL_RSP) { /* some additional predicates must be also true */ if (!con->cosp_vcoll || (con->cosp_vcoll && con->cosp_vdnr) || /* collision but DN received */ (con->cosp_vcoll && !con->cosp_vtca)) /* collision and we are con initiator */ { /* connection released confirmed by COPP, encode and send DISCONNECT SPDU */ /* Transport connections are not reused. */ ret = cosp_enc_fn_dn (con, &spdu_ptr, &spdu_len, COSP_SI_DISCON); if (ret == SD_SUCCESS) { if (tp4_data (con->tp4_conn_id, SD_TRUE, spdu_len, spdu_ptr) == SD_SUCCESS) { if (!con->cosp_vcoll || (con->cosp_vcoll && con->cosp_vdnr)) /* collision but DN received */ { con->cosp_state = COSP_CSTATE_WAIT_TDISCON_IND; tp4_session_timer (con->tp4_conn_id, SD_TRUE); /* start timer */ } else { /* collision and we are the con initiator */ con->cosp_state = COSP_CSTATE_WAIT_DN; } } else { ret = COSP_ERR_TP4_RET; COSP_LOG_ERR1 ("COSP-ERROR: S-RELEASE.rsp+ acse_conn_id=0x%08X: T-DATA.req failed.", con); } } else { COSP_LOG_ERR1 ("COSP-ERROR: S-RELEASE.rsp+ acse_conn_id=0x%08X: Encoding DISCONNECT SPDU failed.", con); } } else { ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR1 ("COSP-ERROR: S-RELEASE.rsp+ acse_conn_id=0x%08X: Connection Release Collision\n" " (DN not received or not a connection initiator).", con); } } else { ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: S-RELEASE.rsp+ acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); } return (ret); } /*======================================================*/ /* */ /* C O N N E C T I O N R E L E A S E (CALLING SIDE)*/ /* */ /*======================================================*/ /************************************************************************/ /* cosp_rel_req */ /*----------------------------------------------------------------------*/ /* Function called by SS-user to release a Session connection. */ /* SS-user should implement the u_cosp_rel_cnf_pos function to receive */ /* confirm for this request. Negative confirm is not implemented. */ /* If this function returns value other then SD_SUCCESS then the function */ /* u_cosp_rel_cnf_pos will not be called. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to connection info */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ ST_RET cosp_rel_req (ACSE_CONN *con) { ST_INT ret; ST_UINT spdu_len; char *spdu_ptr; COSP_LOG_ENC2 ("S-RELEASE.req: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_ENCC1 ("User data length: %d", con->ppdu_len); COSP_LOG_ENCH (con->ppdu_len, con->ppdu_ptr); ret = SD_SUCCESS; if (con->cosp_state == COSP_CSTATE_WAIT_REL_RSP || con->cosp_state == COSP_CSTATE_DATA_XFER) { /* connection is beeing released, encode and send FINISH SPDU */ ret = cosp_enc_fn_dn (con, &spdu_ptr, &spdu_len, COSP_SI_FINISH); if (ret == SD_SUCCESS) { if (tp4_data (con->tp4_conn_id, SD_TRUE, spdu_len, spdu_ptr) == SD_SUCCESS) { if (con->cosp_state == COSP_CSTATE_WAIT_REL_RSP) { /* collision occurred, request to release con while waiting */ /* for resp to S-RELEASE.ind */ con->cosp_vcoll = SD_TRUE; /* remain in the same state */ } else con->cosp_state = COSP_CSTATE_WAIT_DN; } else { ret = COSP_ERR_TP4_RET; COSP_LOG_ERR1 ("COSP-ERROR: S-RELEASE.req acse_conn_id=0x%08X: T-DATA.req failed.", con); } } else { COSP_LOG_ERR1 ("COSP-ERROR: S-RELEASE.req acse_conn_id=0x%08X: Encoding FINISH SPDU failed.", con); } } else { ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: S-RELEASE.req acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); } return (ret); } /************************************************************************/ /* tp4_disconnect_ind */ /*----------------------------------------------------------------------*/ /* This function is called by the TP4-provider to indicate that a */ /* transport connection is beeing released. */ /* */ /* Parameters: */ /* ST_LONG user_conn_id User's connection id for this connect. */ /* ST_INT reason Reason for disconnect */ /* ST_INT conndata_len Length of opt connect data <= 32 bytes */ /* char *conndata Pointer to opt connect data. */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID tp4_disconnect_ind (ST_LONG user_conn_id, ST_INT reason, ST_INT conndata_len, char *conndata) { ACSE_CONN *con; tp4_reldata (conndata); /* !!! we ignoring conndata */ con = (ACSE_CONN *) user_conn_id; switch (con->cosp_state) { case COSP_CSTATE_IDLE: /* ignore this tp4_disconnect_ind if in tp4_connect (returns SD_FAILURE) */ if (!cosp_in_tp4_func) { COSP_LOG_ERR2 ("COSP-ERROR: T-DISCONNECT.ind acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); } break; case COSP_CSTATE_IDLE_TCON: /* disconnected before a CN has been received (COPP has no */ /* knowledge about this connection at this point). */ acse_free_con (con); break; case COSP_CSTATE_WAIT_TCON_CNF: case COSP_CSTATE_WAIT_AC: case COSP_CSTATE_WAIT_DN: case COSP_CSTATE_WAIT_CON_RSP: case COSP_CSTATE_WAIT_REL_RSP: case COSP_CSTATE_DATA_XFER: /* issue S-P-ABORT.ind to local SS-user (use code from cosp_usr.h)*/ COSP_LOG_DEC4 ("S-P-ABORT.ind: acse_conn_id =0x%08X user_conn_id =%4ld reason =%d (TP4 reason=0x%02x)", con, con->user_conn_id, (ST_INT) COSP_P_AB_IND_TP_DISCON, reason); u_cosp_p_abort_ind (con, COSP_P_AB_IND_TP_DISCON); acse_free_con (con); break; case COSP_CSTATE_WAIT_TDISCON_IND: tp4_session_timer (con->tp4_conn_id, SD_FALSE); /* stop timer */ acse_free_con (con); break; default: COSP_LOG_ERR2 ("COSP-ERROR: T-DISCONNECT.ind acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); } } /************************************************************************/ /* tp4_session_timer_expired */ /*----------------------------------------------------------------------*/ /* This function is called by TP4 when the session_timer expire. */ /* */ /* Parameters: */ /* ST_LONG user_conn_id COSP connection id for this connect. */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID tp4_session_timer_expired (ST_LONG user_conn_id) { ACSE_CONN *con; con = (ACSE_CONN *) user_conn_id; if (con->cosp_state == COSP_CSTATE_WAIT_TDISCON_IND) { tp4_disconnect (con->tp4_conn_id, 0, NULL); acse_free_con (con); } else { COSP_LOG_ERR2 ("COSP-ERROR: S-TIMER.expired acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); } } /*======================================================*/ /* */ /* A B O R T F U N C T I O N S */ /* */ /*======================================================*/ /************************************************************************/ /* cosp_u_abort_req */ /*----------------------------------------------------------------------*/ /* Function called by SS-user to Abort a connection (S-U-ABORT) */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to connection info */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /* CRITICAL: this function may free the ACSE_CONN struct so the struct */ /* MUST NOT be accessed after calling this function. */ /************************************************************************/ ST_RET cosp_u_abort_req (ACSE_CONN *con) { ST_INT ret; COSP_LOG_ENC2 ("S-U-ABORT.req: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_ENCC1 ("User data length: %d", con->ppdu_len); COSP_LOG_ENCH (con->ppdu_len, con->ppdu_ptr); ret = SD_SUCCESS; switch (con->cosp_state) { case COSP_CSTATE_WAIT_TCON_CNF: tp4_disconnect (con->tp4_conn_id, 0, NULL); acse_free_con (con); /* done with this connection */ break; case COSP_CSTATE_WAIT_AC: case COSP_CSTATE_WAIT_DN: case COSP_CSTATE_WAIT_CON_RSP: case COSP_CSTATE_WAIT_REL_RSP: case COSP_CSTATE_DATA_XFER: /* send ABORT SPDU and wait for T-DISCONNECT.ind */ if ((ret = cosp_send_abort (con, 0)) == SD_SUCCESS) { con->cosp_state = COSP_CSTATE_WAIT_TDISCON_IND; tp4_session_timer (con->tp4_conn_id, SD_TRUE); /* start timer */ } break; default: ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: S-U-ABORT.req acse_conn_id=0x%08X: Invalid state=%d.", con, con->cosp_state); } if (ret != SD_SUCCESS) { /* disconnect if we couldn't send abort */ tp4_disconnect (con->tp4_conn_id, 0, NULL); acse_free_con (con); } /* we always will return success */ return (SD_SUCCESS); } /************************************************************************/ /* cosp_send_abort */ /*----------------------------------------------------------------------*/ /* Function to sends ABORT SPDU to remote SS-user. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to conn info struct */ /* ST_INT err_code Error code (defined by COSP) */ /* If =0 then S-U-ABORT sent */ /* If !=0 then S-P-ABORT sent */ /* Return: */ /* SD_SUCCESS (0) if abort successful */ /* error code otherwise */ /************************************************************************/ ST_RET cosp_send_abort (ACSE_CONN *con, ST_INT err_code) { ST_RET ret; char spdu_buf [COSP_P_AB_SPDU_LEN]; ST_UINT spdu_len; char *spdu_ptr; if (err_code != 0) { /* encode S-P-ABORT (error code will be encoded and we supply encoding buffer) */ spdu_len = sizeof (spdu_buf); spdu_ptr = spdu_buf; if ((ret = cosp_enc_p_ab (spdu_ptr, err_code)) == SD_SUCCESS) { if (tp4_data (con->tp4_conn_id, SD_TRUE, spdu_len, spdu_ptr) != SD_SUCCESS) { ret = COSP_ERR_TP4_RET; COSP_LOG_ERR1 ("COSP-ERROR: S-P-ABORT acse_conn_id=0x%08X: T-DATA.req failed.", con); } } else { COSP_LOG_ERR1 ("COSP-ERROR: S-P-ABORT acse_conn_id=0x%08X: Encoding of P-ABORT SPDU failed.", con); } } else { /* encode S-U-ABORT (user data should be already encoded) */ if ((ret = cosp_enc_u_ab (con, &spdu_ptr, &spdu_len)) == SD_SUCCESS) { if (tp4_data (con->tp4_conn_id, SD_TRUE, spdu_len, spdu_ptr) != SD_SUCCESS) { ret = COSP_ERR_TP4_RET; COSP_LOG_ERR1 ("COSP-ERROR: S-U-ABORT.req acse_conn_id=0x%08X: T-DATA.req failed.", con); } } else { COSP_LOG_ERR1 ("COSP-ERROR: S-U-ABORT.req acse_conn_id=0x%08X: Encoding of U-ABORT SPDU failed.", con); } } return (ret); } /*======================================================*/ /* */ /* D A T A F U N C T I O N S */ /* */ /*======================================================*/ /************************************************************************/ /* tp4_data_ind */ /*----------------------------------------------------------------------*/ /* Function to process data indication. */ /* Note that the tp4_data_ind is called when complete SPDU has been */ /* received, so the eot flag is always SD_TRUE. */ /* */ /* Parameters: */ /* ST_LONG user_conn_id User's connection id for this connect. */ /* ST_INT eot Indicates if last part of SPDU received.*/ /* ST_UINT data_len Length of data. */ /* char *data Pointer to data buffer. */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ //void called_conn_disconnect(ACSE_CONN *con);//lnk编译删除,原前置程序未使用 ST_VOID tp4_data_ind (ST_LONG user_conn_id, ST_INT eot, ST_UINT data_len, char *data) { ST_INT ret; ST_UINT action; ACSE_CONN *con; ret = SD_SUCCESS; action = 0; con = (ACSE_CONN *) user_conn_id; /* Note: the protocol requires following steps to be taken for invalid*/ /* incomming-event/state intersection (default: in switch) or */ /* if the incomming SPDU can't be correctly process: */ /* - issue S-P-ABORT */ /* - send an ABORT SPDU */ /* - start timer */ /* - wait for T-DISCONNECT or ABORT ACCEPT SPDU */ switch (data [0]) /* First byte is SPDU Session Identifier */ { case COSP_SI_CONNECT: switch (con->cosp_state) { case COSP_CSTATE_IDLE_TCON: /* if we are the transport connection acceptor, process CN */ if (con->cosp_vtca) ret = cosp_process_connect (con, data_len, data); else action = COSP_T_DISCONNECT; break; case COSP_CSTATE_WAIT_TDISCON_IND: tp4_session_timer (con->tp4_conn_id, SD_FALSE); /* stop timer */ action = COSP_T_DISCONNECT; break; default: /* in invalid state */ ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Invalid state=%d (for CONNECT SPDU).", con, con->cosp_state); } break; case COSP_SI_FINISH: switch (con->cosp_state) { case COSP_CSTATE_IDLE_TCON: action = COSP_T_DISCONNECT; break; case COSP_CSTATE_WAIT_DN: /* collision of conn releases */ con->cosp_vcoll = SD_TRUE; /* go to next case */ case COSP_CSTATE_DATA_XFER: ret = cosp_process_finish (con, data_len, data); break; case COSP_CSTATE_WAIT_TDISCON_IND: /* we ignore the FINISH SPDU and remain in the same state */ break; default: /* in invalid state */ ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Invalid state=%d (for FINISH SPDU).", con, con->cosp_state); } break; case COSP_SI_ACCEPT: switch (con->cosp_state) { case COSP_CSTATE_IDLE_TCON: action = COSP_T_DISCONNECT; break; case COSP_CSTATE_WAIT_AC: con->cosp_vcoll = SD_FALSE; con->cosp_vdnr = SD_FALSE; ret = cosp_process_accept (con, data_len, data); break; case COSP_CSTATE_WAIT_TDISCON_IND: /* we ignore the ACCEPT SPDU and remain in the same state */ break; default: /* in invalid state */ ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Invalid state=%d (for ACCEPT SPDU).", con, con->cosp_state); } break; case COSP_SI_REFUSE: switch (con->cosp_state) { case COSP_CSTATE_IDLE_TCON: action = COSP_T_DISCONNECT; break; case COSP_CSTATE_WAIT_AC: if ((ret = cosp_process_refuse (con, data_len, data)) == SD_SUCCESS) action = COSP_T_DISCONNECT; break; case COSP_CSTATE_WAIT_TDISCON_IND: /* we ignore the REFUSE SPDU and remain in the same state */ break; default: /* in invalid state */ ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Invalid state=%d (for REFUSE SPDU).", con, con->cosp_state); } break; case COSP_SI_DISCON: switch (con->cosp_state) { case COSP_CSTATE_IDLE_TCON: action = COSP_T_DISCONNECT; break; case COSP_CSTATE_WAIT_DN: if ((ret = cosp_process_discon (con, data_len, data)) == SD_SUCCESS) action = COSP_T_DISCONNECT; break; case COSP_CSTATE_WAIT_REL_RSP: /* collision */ if (con->cosp_vcoll && con->cosp_vtca) { con->cosp_vdnr = SD_TRUE; ret = cosp_process_discon (con, data_len, data); /* remain in the same state */ } else { ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR1 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Collision flag not set or not a connection acceptor.", con); } break; case COSP_CSTATE_WAIT_TDISCON_IND: /* we ignore the DN SPDU and remain in the same state */ break; default: /* in invalid state */ ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Invalid state=%d (for DISCONNECT SPDU).", con, con->cosp_state); } break; case COSP_SI_ABORT: /* !always! disconnect transport */ /* otherwise we may loop sending ABORTs */ action = COSP_T_DISCONNECT; switch (con->cosp_state) { case COSP_CSTATE_IDLE_TCON: break; case COSP_CSTATE_WAIT_AC: case COSP_CSTATE_WAIT_DN: case COSP_CSTATE_WAIT_CON_RSP: case COSP_CSTATE_WAIT_REL_RSP: case COSP_CSTATE_DATA_XFER: if ((ret = cosp_process_abort (con, data_len, data)) != SD_SUCCESS) { /* even if we failed to decode abort we still will generate S-P-ABORT */ action |= COSP_S_P_ABORT_IND; } break; case COSP_CSTATE_WAIT_TDISCON_IND: tp4_session_timer (con->tp4_conn_id, SD_FALSE); /* stop timer */ break; default: /* in invalid state */ ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Invalid state=%d (for ABORT SPDU).", con, con->cosp_state); action |= COSP_S_P_ABORT_IND; } break; case COSP_SI_AB_ACCEPT: /* this SPDU may be sent by remote COSP engine even if the */ /* transport connection is not to be kept */ action = COSP_T_DISCONNECT; /* !always! disconnect transport */ switch (con->cosp_state) { case COSP_CSTATE_IDLE_TCON: break; case COSP_CSTATE_WAIT_TDISCON_IND: tp4_session_timer (con->tp4_conn_id, SD_FALSE); /* stop timer */ break; default: /* in invalid state */ ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Invalid state=%d (for ABORT ACCEPT SPDU).", con, con->cosp_state); /* ABORT ACCEPT can be received only in response to already */ /* sent ABORT, so we will not send another one here */ } break; /* case COSP_SI_GIVE_TOKEN: !!! GIVE-TOKEN is concatinated with DATA*/ case COSP_SI_DATA: /* SPDU and both have the same code=1 */ switch (con->cosp_state) { case COSP_CSTATE_IDLE_TCON: action = COSP_T_DISCONNECT; break; case COSP_CSTATE_WAIT_DN: if (con->cosp_vcoll) { ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Invalid state=%d (for DATA SPDU).", con, con->cosp_state); break; } /* process the received DATA SPDU and remain in the same state */ /* go to next case */ case COSP_CSTATE_DATA_XFER: ret = cosp_process_data (con, data_len, data); break; case COSP_CSTATE_WAIT_TDISCON_IND: /* we ignore the DATA SPDU and remain in the same state */ break; default: /* in invalid state */ ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Invalid state=%d (for DATA SPDU).", con, con->cosp_state); } break; default: ret = COSP_ERR_DEC_INV_SPDU; COSP_LOG_ERR2 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Unsupported SPDU SI code=%d received.", con, (ST_INT)(data [0])); action = COSP_S_P_ABORT_IND | COSP_SEND_ABORT_SPDU; } /* end of switch */ tp4_reldata (data); /* we are done with the TP4 data buffer */ if (ret != SD_SUCCESS) { /* if error occurred and SPDU other then an ABORT or ABORT ACCEPT */ /* received then issue S-P-ABORT and SEND an ABORT SPDU. */ if ((data [0] != COSP_SI_ABORT) && (data [0] != COSP_SI_AB_ACCEPT)) action = COSP_S_P_ABORT_IND | COSP_SEND_ABORT_SPDU; } /*--------------------------------------------------------------------*/ /* abort/disconnect if processing of received SPDU failed or this is */ /* the protocol specification */ /*--------------------------------------------------------------------*/ if (action & COSP_SEND_ABORT_SPDU) { /* encode and send ABORT SPDU to remote SS-user, ret is the error code */ if (cosp_send_abort (con, ret) == SD_SUCCESS) { con->cosp_state = COSP_CSTATE_WAIT_TDISCON_IND; tp4_session_timer (con->tp4_conn_id, SD_TRUE); /* start timer */ } else { con->cosp_state = COSP_CSTATE_IDLE; action |= COSP_T_DISCONNECT; /* disconnect if we can't abort */ } } if (action & COSP_S_P_ABORT_IND) { /* issue S-P-ABORT.ind to local SS-user (use code from cosp_usr.h) */ COSP_LOG_DEC3 ("S-P-ABORT.ind: acse_conn_id =0x%08X user_conn_id =%4ld reason =%d", con, con->user_conn_id, (ST_INT) COSP_P_AB_IND_PROT_ERR); u_cosp_p_abort_ind (con, COSP_P_AB_IND_PROT_ERR); } if (action & COSP_T_DISCONNECT) { tp4_disconnect (con->tp4_conn_id, 0, NULL); /*renxiaobao20220831 °²È«¼ì²â*/ //called_conn_disconnect(con);//lnk编译删除,原前置程序未使用 acse_free_con (con); /* we are disconnected, free con struct */ } } /************************************************************************/ /* tp4_expdata_ind */ /*----------------------------------------------------------------------*/ /* Function to process a expedited S-DATA.ind. */ /* */ /* Parameters: */ /* ST_LONG user_conn_id User's connection id for this connect. */ /* ST_UINT data_len Length of data. */ /* char *data Pointer to data buffer. */ /* */ /* Return: */ /* ST_VOID */ /************************************************************************/ ST_VOID tp4_expdata_ind (ST_LONG user_conn_id, ST_UINT data_len, char *data) { /* Treat like normal data. Assume "eot" = 1 */ tp4_data_ind (user_conn_id, 1, data_len, data); } /************************************************************************/ /* cosp_data_req */ /*----------------------------------------------------------------------*/ /* Function called by SS-user to transfer normal data on a previously */ /* established connection. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to connection info */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ ST_RET cosp_data_req (ACSE_CONN *con) { ST_INT ret; ST_UINT spdu_len; char *spdu_ptr; COSP_LOG_ENC2 ("S-DATA.req: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_ENCC1 ("User data length: %d", con->ppdu_len); COSP_LOG_ENCH (con->ppdu_len, con->ppdu_ptr); ret = SD_SUCCESS; if ((con->cosp_state == COSP_CSTATE_DATA_XFER) || (con->cosp_state == COSP_CSTATE_WAIT_REL_RSP && !con->cosp_vcoll)) { if ((ret = cosp_enc_dt (con, &spdu_ptr, &spdu_len)) == SD_SUCCESS) { if (tp4_data (con->tp4_conn_id, SD_TRUE, spdu_len, spdu_ptr) != SD_SUCCESS) { ret = COSP_ERR_TP4_RET; COSP_LOG_ERR0 ("COSP-ERROR: S-DATA.req acse_conn_id=0x%08X: T-DATA.req failed."); } } else { COSP_LOG_ERR1 ("COSP-ERROR: S-DATA.req acse_conn_id=0x%08X: Encoding of DATA SPDU failed.", con); } } else { ret = COSP_ERR_INV_CON_STATE; COSP_LOG_ERR2 ("COSP-ERROR: S-DATA.req acse_conn_id=0x%08X: Invalid state=%d (or collision flag set).", con, con->cosp_state); } return (ret); } /*======================================================*/ /* */ /* L O C A L S P D U P R O C E S S I N G F U N C */ /* */ /*======================================================*/ /************************************************************************/ /* cosp_process_connect */ /*----------------------------------------------------------------------*/ /* This function will decode the CONNECT SPDU and call SS-user's funct */ /* u_cosp_con_ind to indicate to the SS-user incomming connection req. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to con info struct */ /* ST_UINT spdu_len Length of SPDU */ /* char *spdu_buf Pointer to SPDU buffer */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ static ST_RET cosp_process_connect (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf) { ST_INT ret; COSP_CN_AC dec_par; /* decoded connection params */ ST_LONG cosp_user_bind_id; /*----------------------------*/ /* decode the CONNECT SPDU */ /*----------------------------*/ ret = cosp_dec_cn_ac (&dec_par, spdu_buf, spdu_len, COSP_SI_CONNECT); if (ret == SD_SUCCESS) { /* Save SSELs in ACSE_CONN struct. */ memcpy (con->loc_ssel, dec_par.loc_ssel, dec_par.loc_ssel [0]+1); memcpy (con->rem_ssel, dec_par.rem_ssel, dec_par.rem_ssel [0]+1); /* generate S-CONNECT.ind to the SS-user */ con->cosp_state = COSP_CSTATE_WAIT_CON_RSP; con->ppdu_len = dec_par.udata_len; con->ppdu_ptr = dec_par.udata_ptr; /* user_conn_id (created by ACSE-user) is invalid at this point, */ /* we probably should set it to -1 (an invalid value). Note that 0 */ /* is a valid id. */ con->user_conn_id = -1L; cosp_user_bind_id = con->cosp_bind_id; /* COSP id = COSP User's bind id */ COSP_LOG_DEC1 ("S-CONNECT.ind: acse_conn_id =0x%08X", con); COSP_LOG_DECC1 ("User data length: %d", con->ppdu_len); COSP_LOG_DECH (con->ppdu_len, con->ppdu_ptr); u_cosp_con_ind (cosp_user_bind_id, con); } else { COSP_LOG_ERR1 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Decoding of CONNECT SPDU failed.", con); } return (ret); } /************************************************************************/ /* cosp_process_finish */ /*----------------------------------------------------------------------*/ /* This function will decode the FINISH SPDU and call SS-user's function*/ /* u_cosp_rel_ind to indicate to the SS-user that the remote wants to */ /* release connection. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to con info struct */ /* ST_UINT spdu_len Length of SPDU */ /* char *spdu_buf Pointer to SPDU buffer */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ static ST_RET cosp_process_finish (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf) { ST_INT ret; COSP_FN_DN dec_par; /* decoded con rel params */ /*------------------------------------*/ /* decode and check the FINISH SPDU */ /*------------------------------------*/ ret = cosp_dec_fn_dn (&dec_par, spdu_buf, spdu_len, COSP_SI_FINISH); if (ret == SD_SUCCESS) { /* generate S-RELEASE.ind */ con->cosp_state = COSP_CSTATE_WAIT_REL_RSP; con->ppdu_len = dec_par.udata_len; con->ppdu_ptr = dec_par.udata_ptr; COSP_LOG_DEC2 ("S-RELEASE.ind: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_DECC1 ("User data length: %d", con->ppdu_len); COSP_LOG_DECH (con->ppdu_len, con->ppdu_ptr); u_cosp_rel_ind (con); } else { COSP_LOG_ERR1 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Decoding of FINISH SPDU failed.", con); } return (ret); } /************************************************************************/ /* cosp_process_accept */ /*----------------------------------------------------------------------*/ /* This function will decode the ACCEPT SPDU and call SS-user's funct */ /* u_cosp_con_cnf_pos to indicate to the SS-user that the connection has*/ /* been established. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to con info struct */ /* ST_UINT spdu_len Length of SPDU */ /* char *spdu_buf Pointer to SPDU buffer */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ static ST_RET cosp_process_accept (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf) { ST_INT ret; COSP_CN_AC dec_par; /* decoded accept params */ /*----------------------------------*/ /* decode and check the ACCEPT SPDU */ /*----------------------------------*/ ret = cosp_dec_cn_ac (&dec_par, spdu_buf, spdu_len, COSP_SI_ACCEPT); if (ret == SD_SUCCESS) { /* generate S-CONNECT.cnf+ */ con->cosp_state = COSP_CSTATE_DATA_XFER; con->ppdu_len = dec_par.udata_len; con->ppdu_ptr = dec_par.udata_ptr; COSP_LOG_DEC2 ("S-CONNECT.cnf+: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_DECC1 ("User data length: %d", con->ppdu_len); COSP_LOG_DECH (con->ppdu_len, con->ppdu_ptr); u_cosp_con_cnf_pos (con); } else { COSP_LOG_ERR1 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Decoding of ACCEPT SPDU failed.", con); } return (ret); } /************************************************************************/ /* cosp_process_refuse */ /*----------------------------------------------------------------------*/ /* This function will decode the REFUSE SPDU and call SS-user's function*/ /* u_cosp_con_cnf_neg to indicate to the SS-user that the establishment */ /* of connection failed. */ /* Note that this implementation will not reuse the transport connection*/ /* for another session connect (transport will be disconnected). */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to con info struct */ /* ST_UINT spdu_len Length of SPDU */ /* char *spdu_buf Pointer to SPDU buffer */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ static ST_RET cosp_process_refuse (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf) { ST_INT ret; COSP_RF dec_par; /* decoded refuse connection params */ ST_INT result; ST_INT reason; /*----------------------------------*/ /* decode and check the REFUSE SPDU */ /*----------------------------------*/ ret = cosp_dec_rf (&dec_par, spdu_buf, spdu_len); if (ret == SD_SUCCESS) { con->cosp_state = COSP_CSTATE_IDLE; /* generate S-CONNECT.cnf- */ if (dec_par.reason <= 2) result = COSP_CON_CNF_U_REJECT; /* remote SS-user reject */ else result = COSP_CON_CNF_P_REJECT; /* remote SS-provider reject */ /* convert the reason code from SPDU to reason codes in cosp_usr.h */ switch ((ST_UINT) dec_par.reason) { case 0: /* rejection by called SS-user??, reason not specified */ reason = COSP_CON_CNF_U_NOT_SPECIFIED; break; case 1: /* rejection by called SS-user, tmp congestion */ reason = COSP_CON_CNF_U_CONGESTION; break; case 2: /* rejection by called SS-user, user data may follow */ reason = COSP_CON_CNF_U_IN_UDATA; con->ppdu_len = dec_par.udata_len; con->ppdu_ptr = dec_par.udata_ptr; break; case 128+1: /* rejection by called SS-prov, SSEL unknown */ reason = COSP_CON_CNF_P_INV_SSEL; break; case 128+2: /* rejection by called SS-prov, SS-user not attached */ reason = COSP_CON_CNF_P_NOT_ATTACHED; break; case 128+3: /* rejection by called SS-prov, congestion */ reason = COSP_CON_CNF_P_CONGESTION; break; case 128+4: /* rejection by called SS-prov, prot version not supported */ case 128+5: /* rejection by called SS-prov, reason not specified */ case 128+6: /* rejection by called SS-prov, implementation restriction stated in PICS */ default: reason = COSP_CON_CNF_P_NOT_SPECIFIED; } /* end of switch */ COSP_LOG_DEC4 ("S-CONNECT.cnf-: acse_conn_id =0x%08X user_conn_id =%4ld result =%d reason =%d", con, con->user_conn_id, result, reason); COSP_LOG_DECC1 ("User data length: %d", con->ppdu_len); COSP_LOG_DECH (con->ppdu_len, con->ppdu_ptr); /* S-CONNECT.cnf- */ u_cosp_con_cnf_neg (con, result, reason); } else { COSP_LOG_ERR1 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Decoding of REFUSE SPDU failed.", con); } return (ret); } /************************************************************************/ /* cosp_process_discon */ /*----------------------------------------------------------------------*/ /* This function will decode the DN SPDU and call SS-user's function */ /* u_cosp_rel_cnf_pos to indicate to the SS-user the result of session */ /* release request. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to con info struct */ /* ST_UINT spdu_len Length of SPDU */ /* char *spdu_buf Pointer to SPDU buffer */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ static ST_RET cosp_process_discon (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf) { ST_INT ret; COSP_FN_DN dec_par; /* decoded con rel params */ /*------------------------------------*/ /* decode and check the DN SPDU */ /*------------------------------------*/ ret = cosp_dec_fn_dn (&dec_par, spdu_buf, spdu_len, COSP_SI_DISCON); if (ret == SD_SUCCESS) { /* do not change here the state, new state depends on previous */ /* state and if collision of S-RELEASEs occurred. */ /* generate S-RELEASE.cnf+ */ con->ppdu_len = dec_par.udata_len; con->ppdu_ptr = dec_par.udata_ptr; COSP_LOG_DEC2 ("S-RELEASE.cnf+: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_DECC1 ("User data length: %d", con->ppdu_len); COSP_LOG_DECH (con->ppdu_len, con->ppdu_ptr); u_cosp_rel_cnf_pos (con); /* currently only positive cnf possible */ } else { COSP_LOG_ERR1 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Decoding of DISCONNECT SPDU failed.", con); } return (ret); } /************************************************************************/ /* cosp_process_abort */ /*----------------------------------------------------------------------*/ /* This function will decode the ABORT SPDU and call SS-user's function */ /* u_cosp_abort_ind to indicate to the SS-user that the session */ /* connection has been aborted by remote. */ /* Note that this implementation will not reuse the transport connection*/ /* for another session connect (transport will be disconnected). */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to con info struct */ /* ST_UINT spdu_len Length of SPDU */ /* char *spdu_buf Pointer to SPDU buffer */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ static ST_RET cosp_process_abort (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf) { ST_INT ret; COSP_AB dec_par; /* decoded abort connection params */ ST_INT reason; ST_INT err_code; /*------------------------------------*/ /* decode and check the ABORT SPDU */ /*------------------------------------*/ ret = cosp_dec_ab (&dec_par, spdu_buf, spdu_len); if (ret == SD_SUCCESS) { con->cosp_state = COSP_CSTATE_IDLE; /* generate S-U-ABORT.ind or S-P-ABORT.ind */ if (dec_par.reason & COSP_AB_REASON_USER_ABORT) { /* remote SS-user abort */ con->ppdu_len = dec_par.udata_len; con->ppdu_ptr = dec_par.udata_ptr; COSP_LOG_DEC2 ("S-U-ABORT.ind: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_DECC1 ("User data length: %d", con->ppdu_len); COSP_LOG_DECH (con->ppdu_len, con->ppdu_ptr); u_cosp_u_abort_ind (con); } else { /* SS-provider abort */ if (dec_par.reason & COSP_AB_REASON_PROT_ERROR) { reason = COSP_P_AB_IND_PROT_ERR; err_code = 0; /* Log the ABORT error code */ if (dec_par.reflect_par_len == 2) err_code = ((ST_UINT16) dec_par.reflect_par [0] << 8) + (ST_UINT16) dec_par.reflect_par [1]; COSP_LOG_DEC4 ("S-P-ABORT.ind: acse_conn_id =0x%08X user_conn_id =%4ld reason =%d err_code =0x%04X", con, con->user_conn_id, reason, err_code); } else { reason = COSP_P_AB_IND_UNDEFINED; COSP_LOG_DEC3 ("S-P-ABORT.ind: acse_conn_id =0x%08X user_conn_id =%4ld reason =%d", con, con->user_conn_id, reason); } u_cosp_p_abort_ind (con, reason); } } else { COSP_LOG_ERR1 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Decoding of ABORT SPDU failed.", con); } return (ret); } /************************************************************************/ /* cosp_process_data */ /*----------------------------------------------------------------------*/ /* This function will decode a DATA SPDU and generate a S-DATA.ind. */ /* */ /* Parameters: */ /* ACSE_CONN *con Pointer to con info struct */ /* ST_UINT spdu_len Length of SPDU */ /* char *spdu_buf Pointer to SPDU buffer */ /* */ /* Return: */ /* SD_SUCCESS (0) if successful */ /* error code otherwise */ /************************************************************************/ static ST_RET cosp_process_data (ACSE_CONN *con, ST_UINT spdu_len, char *spdu_buf) { ST_INT ret; COSP_DT dec_par; /* decoded refuse connection params */ /*------------------------------------*/ /* decode and check the DATA SPDU */ /*------------------------------------*/ ret = cosp_dec_dt (&dec_par, spdu_buf, spdu_len); if (ret == SD_SUCCESS) { /* generate S-DATA.ind */ con->ppdu_len = dec_par.udata_len; con->ppdu_ptr = dec_par.udata_ptr; COSP_LOG_DEC2 ("S-DATA.ind: acse_conn_id =0x%08X user_conn_id =%4ld", con, con->user_conn_id); COSP_LOG_DECC1 ("User data length: %d", con->ppdu_len); COSP_LOG_DECH (con->ppdu_len, con->ppdu_ptr); u_cosp_data_ind (con); } else { COSP_LOG_ERR1 ("COSP-ERROR: T-DATA.ind acse_conn_id=0x%08X: Decoding of DATA SPDU failed.", con); } return (ret); }