Files
microser/mmslib/ositcps/cospmain.c
2026-06-15 15:48:16 +08:00

2044 lines
67 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/************************************************************************/
/* 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);
}