view src/g23m-fad/tcpip/socket_api.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/* 
+------------------------------------------------------------------------------
|  File:       socket.c
+------------------------------------------------------------------------------
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 The receipt of or possession of this file does not convey 
|                 any rights to reproduce or disclose its contents or to 
|                 manufacture, use, or sell anything it may describe, in 
|                 whole, or in part, without the specific written consent of 
|                 Texas Instruments Berlin, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  This file implements the socket API functionality.
|             For a description of this file read g23m\condat\doc\8462_601.doc
+----------------------------------------------------------------------------- 
*/ 

#ifndef SAP_DCM
#define SAP_DCM
#endif /* !SAP_DCM */

#define ENTITY_TCPIP

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "socket_api.h"

#include "custom.h"
#include "pei.h"   
#include "socket_int.h"
#include "dcm.h"
#include "aci_all.h"


LOCAL const int UNUSED = 0;

/* this function maps the DCM result codes to the Socket-API result codes */
LOCAL T_SOCK_RESULT map_dcm_result_code(S32 result)
{
  switch(result)
  {
    case DCM_OK:                return SOCK_RESULT_OK;
    case DCM_NOT_READY:         return SOCK_RESULT_NOT_READY;
    case DCM_ALREADY_ACTIVATED: return SOCK_RESULT_BEARER_ACTIVE;
    case DCM_UNKNOWN_EVENT:     return SOCK_RESULT_INTERNAL_ERROR;
    case DCM_INVALID_PARAMETER: return SOCK_RESULT_INVALID_PARAMETER;
    case DCM_BUSY:              return SOCK_RESULT_IN_PROGRESS;
    case DCM_PS_CONN_BROKEN:    return SOCK_RESULT_NETWORK_LOST;
    case DCM_NO_NETWORK:        return SOCK_RESULT_BEARER_NOT_READY;
    default:                    return SOCK_RESULT_INTERNAL_ERROR;
  }
}


/*******************************************************************************
** Function  :   FindSocketData
** Parameter :   T_SOCK_API_INSTANCE_DATA*
**               T_SOCK_SOCKET
** Description : The function returns a pointer to the data structure of a socket.
**               If the socket does not exist or api_data is NULL,
**               then it returns NULL.
*******************************************************************************/
LOCAL T_SOCK_SOCKET_DATA* FindSocketData(T_SOCK_API_INSTANCE_DATA* api_data,
                                         T_SOCK_SOCKET tcpip_socket)
{
  T_SOCK_SOCKET_DATA* socket_data;

  TRACE_FUNCTION("FindSocketData()");

  /* must be checked whether api_data is NULL or not.*/
  if(api_data != NULL)       
     socket_data = api_data->socket_data;
  else
  {
    TRACE_ERROR("FindSocketData: api_data = NULL!");
     return NULL;
  }
  
  while((socket_data != NULL) && (tcpip_socket != socket_data->tcpip_socket))
  {
    socket_data = socket_data->next_socket_data;
  }

  TRACE_EVENT_P2("FindSocketData: tcpip_data=%x, ret=%x",tcpip_socket,socket_data );
  return socket_data;
} /* FindSocketData */



/*******************************************************************************
** Function  : ReleaseSocketData
** Parameter : T_SOCK_API_INSTANCE_DATA*
**             T_SOCK_SOCKET_DATA*
** Description : The function releases the specified socket data.
*******************************************************************************/
static void ReleaseSocketData(T_SOCK_API_INSTANCE_DATA* api_data,
                              T_SOCK_SOCKET_DATA* socket_data)
{
  T_SOCK_SOCKET_DATA* temp_socket_data;

  TRACE_FUNCTION("ReleaseSocketData()");

  /* take socket data from linked list */
  if(api_data->socket_data == socket_data)
  {
    api_data->socket_data = socket_data->next_socket_data;
  }
  else
  {
    temp_socket_data = api_data->socket_data;
    while(temp_socket_data->next_socket_data != socket_data)
    {
      temp_socket_data = temp_socket_data->next_socket_data;
    }
    temp_socket_data->next_socket_data = socket_data->next_socket_data;
  }
  
  /* release socket data  */
  MFREE(socket_data);
} /* ReleaseSocketData */


/******************************************************************************/
BOOL sock_api_initialize(T_SOCK_API_INSTANCE *api_instance,
                         T_HANDLE app_handle,
                         char* app_name)
{
  T_SOCK_API_INSTANCE_DATA* api_data_p;
  T_HANDLE                  hCommAPP;
  T_HANDLE                  hCommTCPIP;
  T_HANDLE                  hCommDCM;

  TRACE_FUNCTION("[Socket API] sock_api_initialize()");

  /* open communication handles */
  if((hCommTCPIP = vsi_c_open (app_handle, TCPIP_NAME)) < VSI_OK)
  {
    TRACE_ERROR( "sock_api_initialize: vsi_c_open(TCP) failed");
    return FALSE;
  }

  if((hCommAPP = vsi_c_open (app_handle, app_name)) < VSI_OK)
  {
    TRACE_ERROR( "sock_api_initialize: vsi_c_open(APP) failed");
    return FALSE;
  }
  
  if((hCommDCM = vsi_c_open (app_handle, DCM_NAME)) < VSI_OK)
  {
    TRACE_ERROR( "sock_api_initialize: vsi_c_open(DCM) failed");
    return FALSE;
  }
  /* initialization successful */
  
  /* allocate API Data structure */
  MALLOC(api_data_p, sizeof(T_SOCK_API_INSTANCE_DATA));
  
  /*initialize API Data */
  api_data_p->app_handle  = app_handle;
  api_data_p->hCommAPP    = hCommAPP;
  api_data_p->hCommTCPIP  = hCommTCPIP;
  api_data_p->hCommDCM    = hCommDCM;
  api_data_p->socket_data = NULL;
 
  /* derefernce 'api_instance' and save address of 'api_data' */
  *api_instance = (T_SOCK_API_INSTANCE)api_data_p;
  return TRUE;
} /* sock_api_initialize */


/******************************************************************************/
void sock_api_deinitialize(T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_API_INSTANCE_DATA* api_data_p;
  T_SOCK_SOCKET_DATA*       socket_data1;
  T_SOCK_SOCKET_DATA*       socket_data2;

  TRACE_FUNCTION("[Socket API] sock_api_deinitialize()");

  /* get the address of 'api_data' */
  api_data_p = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  
  /*close communication channels */
  vsi_c_close (api_data_p->app_handle, api_data_p->hCommAPP);
  vsi_c_close (api_data_p->app_handle, api_data_p->hCommTCPIP);
  vsi_c_close (api_data_p->app_handle, api_data_p->hCommDCM);

  /* release all socket data */
  socket_data1 = api_data_p->socket_data;

  while(socket_data1 != NULL)
  {
    socket_data2 = socket_data1;
    socket_data1 = socket_data1->next_socket_data;
    MFREE(socket_data2);
  }

  /* release API data */
  MFREE(api_data_p);
} 


/******************************************************************************/
T_SOCK_RESULT sock_open_bearer(T_SOCK_API_INSTANCE api_instance,
                               T_SOCK_BEARER_TYPE bearer_select,
                               int profile_number,
                               T_SOCK_BEARER_INFO *params,
                               T_SOCK_CALLBACK sock_cb,
                               void *context)
{
  T_SOCK_API_INSTANCE_DATA* api_data_p;

  TRACE_FUNCTION("[Socket API] sock_open_bearer()");
  
if(sock_cb EQ NULL)
  return SOCK_RESULT_INVALID_PARAMETER;

  /* set API data pointer */
  api_data_p = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  api_data_p->context = context;
  api_data_p->callback = sock_cb;
  
  /* send primitive to DCM */
  {
    PALLOC(dcm_open_conn_req, DCM_OPEN_CONN_REQ);
    dcm_open_conn_req->api_instance = api_instance;
    dcm_open_conn_req->bearer_select = bearer_select;
    dcm_open_conn_req->profile_number = profile_number;

    dcm_open_conn_req->dcm_info_conn.bearer_handle = UNUSED;
    dcm_open_conn_req->dcm_info_conn.app_handle = params->app_handle;
    dcm_open_conn_req->dcm_info_conn.bearer_type = params->bearer_type;
    dcm_open_conn_req->dcm_info_conn.apn_valid = params->apn_valid;
    memcpy(dcm_open_conn_req->dcm_info_conn.apn, params->apn, SOCK_MAX_APN_LEN+1);
    dcm_open_conn_req->dcm_info_conn.phone_number_valid = params->phone_nr_valid;
    memcpy(dcm_open_conn_req->dcm_info_conn.phone_number, params->phone_nr,
           SOCK_MAX_PHONENUM_LEN+1);
    dcm_open_conn_req->dcm_info_conn.user_id_valid = params->user_id_valid;
    memcpy(dcm_open_conn_req->dcm_info_conn.user_id, params->user_id,
           SOCK_MAX_USERID_LEN+1);
    dcm_open_conn_req->dcm_info_conn.password_valid = params->password_valid;
    memcpy(dcm_open_conn_req->dcm_info_conn.password, params->password,
           SOCK_MAX_PASSWORD_LEN+1);
    dcm_open_conn_req->dcm_info_conn.cid = params->cid;
    dcm_open_conn_req->dcm_info_conn.ip_address = params->ip_address;
    dcm_open_conn_req->dcm_info_conn.dns1 = params->dns1;
    dcm_open_conn_req->dcm_info_conn.dns2 = params->dns2;
    dcm_open_conn_req->dcm_info_conn.gateway = params->gateway;
    dcm_open_conn_req->dcm_info_conn.auth_type = params->authtype;
    dcm_open_conn_req->dcm_info_conn.data_compr = params->data_compr;
    dcm_open_conn_req->dcm_info_conn.header_compr = params->header_comp;
    dcm_open_conn_req->dcm_info_conn.precedence = params->precedence;
    dcm_open_conn_req->dcm_info_conn.delay = params->precedence;
    dcm_open_conn_req->dcm_info_conn.reliability = params->reliability;
    dcm_open_conn_req->dcm_info_conn.peak_throughput = params->peak_throughput;
    dcm_open_conn_req->dcm_info_conn.mean_throughput = params->mean_througput;
    dcm_open_conn_req->dcm_info_conn.shareable = params->shareable;

    PSEND(api_data_p->hCommDCM, dcm_open_conn_req);
  }
  return SOCK_RESULT_OK;
}

/******************************************************************************/
LOCAL void sock_open_bearer_cnf(T_DCM_OPEN_CONN_CNF *dcm_open_conn_cnf,
                                      T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_OPEN_BEARER_CNF sock_open_bearer_cnf;
  T_SOCK_API_INSTANCE_DATA *api_data_p;

  TRACE_FUNCTION("[Socket API] sock_open_bearer_cnf()");

  api_data_p = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  
  /* fill signal struct */
  sock_open_bearer_cnf.result = map_dcm_result_code(dcm_open_conn_cnf->result);
  sock_open_bearer_cnf.socket = UNUSED;
  sock_open_bearer_cnf.event_type = SOCK_OPEN_BEARER_CNF;
  sock_open_bearer_cnf.bearer_handle = dcm_open_conn_cnf->bearer_handle;

  /* release primitive */
  PFREE(dcm_open_conn_cnf);
  
  api_data_p->callback((T_SOCK_EVENTSTRUCT *)&sock_open_bearer_cnf,
                       api_data_p->context);
}

/******************************************************************************/
T_SOCK_RESULT sock_close_bearer(T_SOCK_API_INSTANCE api_instance,
                                T_SOCK_BEARER_HANDLE bearer_handle,
                                T_SOCK_CALLBACK sock_cb,
                                void *context)
{
  T_SOCK_API_INSTANCE_DATA* api_data_p;

  TRACE_FUNCTION("[Socket API] sock_close_bearer()");

  if(sock_cb EQ NULL) {
   return SOCK_RESULT_INVALID_PARAMETER;
  }

  /* set API data pointer */
  api_data_p = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  api_data_p->callback = sock_cb;
  api_data_p->context = context;

  /* send primitive to DCM */
  {
    PALLOC(dcm_close_conn_req, DCM_CLOSE_CONN_REQ);
    dcm_close_conn_req->api_instance = api_instance;
    dcm_close_conn_req->bearer_handle = bearer_handle;
    PSEND(api_data_p->hCommDCM, dcm_close_conn_req);
  }
  
  return SOCK_RESULT_OK;
}

/******************************************************************************/
LOCAL void sock_close_bearer_cnf(T_DCM_CLOSE_CONN_CNF *dcm_close_conn_cnf,
                                        T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_CLOSE_BEARER_CNF sock_close_bearer_cnf;
  T_SOCK_API_INSTANCE_DATA *api_data_p;

  TRACE_FUNCTION("[Socket API] dcm_close_conn_cnf()");

  api_data_p = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  sock_close_bearer_cnf.result = map_dcm_result_code(dcm_close_conn_cnf->result);
  sock_close_bearer_cnf.socket = UNUSED;
  sock_close_bearer_cnf.event_type = SOCK_CLOSE_BEARER_CNF;

  /* release primitive */
  PFREE(dcm_close_conn_cnf);

  /* call callback function */
  api_data_p->callback((T_SOCK_EVENTSTRUCT *)&sock_close_bearer_cnf,
                       api_data_p->context);
}

/******************************************************************************/
T_SOCK_RESULT sock_bearer_info(T_SOCK_API_INSTANCE api_instance,
                               T_SOCK_BEARER_HANDLE bearer_handle,
                               T_SOCK_CALLBACK sock_cb,
                               void *context)
{
  T_SOCK_API_INSTANCE_DATA* api_data_p;

  TRACE_FUNCTION("[Socket API] sock_bearer_info()");

  if(sock_cb EQ NULL)
   return SOCK_RESULT_INVALID_PARAMETER;

  /* set API data pointer */
  api_data_p = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  api_data_p->callback = sock_cb;
  api_data_p->context = context;

  /* send primitive to DCM */
  {
    PALLOC(dcm_get_current_conn_req, DCM_GET_CURRENT_CONN_REQ);
    dcm_get_current_conn_req->api_instance = api_instance;
    dcm_get_current_conn_req->bearer_handle = bearer_handle;
    PSEND(api_data_p->hCommDCM, dcm_get_current_conn_req);
  }
  return SOCK_RESULT_OK;
}


/******************************************************************************/
LOCAL void sock_bearer_info_cnf(T_DCM_GET_CURRENT_CONN_CNF *current_conn_cnf,
                                      T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_BEARER_INFO_CNF bearer_info;
  T_SOCK_API_INSTANCE_DATA *api_data_p;

  TRACE_FUNCTION("[Socket API] sock_bearer_info_cnf()");

  api_data_p = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  bearer_info.result = map_dcm_result_code(current_conn_cnf->result);
  bearer_info.socket = UNUSED;
  bearer_info.event_type = SOCK_BEARER_INFO_CNF;

  bearer_info.bearer_params.bearer_handle = current_conn_cnf->dcm_info_conn.bearer_handle;
  bearer_info.bearer_params.app_handle = current_conn_cnf->dcm_info_conn.app_handle;
  bearer_info.bearer_params.bearer_type =(T_SOCK_BEARER_TYPE)current_conn_cnf->dcm_info_conn.bearer_type;
  bearer_info.bearer_params.apn_valid = current_conn_cnf->dcm_info_conn.apn_valid;
  memcpy(bearer_info.bearer_params.apn,
         current_conn_cnf->dcm_info_conn.apn, SOCK_MAX_APN_LEN);
  bearer_info.bearer_params.phone_nr_valid = current_conn_cnf->dcm_info_conn.phone_number_valid;
  memcpy(bearer_info.bearer_params.phone_nr,current_conn_cnf->dcm_info_conn.phone_number,
         SOCK_MAX_PHONENUM_LEN);
  bearer_info.bearer_params.user_id_valid = current_conn_cnf->dcm_info_conn.user_id_valid;
  memcpy(bearer_info.bearer_params.user_id, current_conn_cnf->dcm_info_conn.user_id,
         SOCK_MAX_USERID_LEN);
  bearer_info.bearer_params.password_valid = current_conn_cnf->dcm_info_conn.password_valid;
  memcpy(bearer_info.bearer_params.password, current_conn_cnf->dcm_info_conn.password,
         SOCK_MAX_PASSWORD_LEN);
  bearer_info.bearer_params.cid = current_conn_cnf->dcm_info_conn.cid;
  bearer_info.bearer_params.ip_address = current_conn_cnf->dcm_info_conn.ip_address;
  bearer_info.bearer_params.dns1 = current_conn_cnf->dcm_info_conn.dns1;
  bearer_info.bearer_params.dns2 = current_conn_cnf->dcm_info_conn.dns2;
  bearer_info.bearer_params.gateway = current_conn_cnf->dcm_info_conn.gateway;
  bearer_info.bearer_params.authtype = (T_SOCK_AUTHTYPE)current_conn_cnf->dcm_info_conn.auth_type;
  bearer_info.bearer_params.data_compr = current_conn_cnf->dcm_info_conn.data_compr;
  bearer_info.bearer_params.header_comp = current_conn_cnf->dcm_info_conn.header_compr;
  bearer_info.bearer_params.precedence = current_conn_cnf->dcm_info_conn.precedence;
  bearer_info.bearer_params.delay = current_conn_cnf->dcm_info_conn.delay;
  bearer_info.bearer_params.reliability = current_conn_cnf->dcm_info_conn.reliability;
  bearer_info.bearer_params.peak_throughput = current_conn_cnf->dcm_info_conn.peak_throughput;
  bearer_info.bearer_params.mean_througput = current_conn_cnf->dcm_info_conn.mean_throughput;
  bearer_info.bearer_params.shareable = current_conn_cnf->dcm_info_conn.shareable;

  /* release primitive */
  PFREE(current_conn_cnf);

  /* call callback function */
  api_data_p->callback((T_SOCK_EVENTSTRUCT *)&bearer_info, api_data_p->context);
}


/******************************************************************************/
LOCAL void sock_dcm_error_ind(T_DCM_ERROR_IND *dcm_error_ind,
                                    T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_BAERER_CLOSED_IND sock_bearer_closed_ind;
  T_SOCK_API_INSTANCE_DATA *api_data_p;

  TRACE_FUNCTION("[Socket API] sock_dcm_error_ind()");

  api_data_p = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  sock_bearer_closed_ind.event_type = SOCK_BAERER_CLOSED_IND;
  sock_bearer_closed_ind.result = map_dcm_result_code(dcm_error_ind->result);
  sock_bearer_closed_ind.socket = UNUSED;
  sock_bearer_closed_ind.dcm_error = dcm_error_ind->dcm_err;

  PFREE(dcm_error_ind);
  
  if(api_data_p->callback NEQ NULL)
  {
    api_data_p->callback((T_SOCK_EVENTSTRUCT *)&sock_bearer_closed_ind,
                         api_data_p->context);
  }
}


/* ******************* Socket related functions ***************************** */

/******************************************************************************/
T_SOCK_RESULT sock_create(T_SOCK_API_INSTANCE api_instance,
                          T_SOCK_IPPROTO ipproto,
                          T_SOCK_CALLBACK callback,
                          void* context)
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA*       socket_data;

  TRACE_FUNCTION("[Socket API] sock_create()");
  TRACE_EVENT_P1("IP-Protocol=%d",(U32)ipproto);
  
  /* set api_data  */
  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  
 if(callback EQ NULL)
  return SOCK_RESULT_INVALID_PARAMETER;

 /* check for correct data */
  if((ipproto != SOCK_IPPROTO_UDP) && (ipproto != SOCK_IPPROTO_TCP))
  {
    TRACE_ERROR("[Socket API] Error: Invalid IP-Protocol");
    return SOCK_RESULT_INVALID_PARAMETER;
  } 
  if( api_data == NULL )
  {
    TRACE_ERROR("[Socket API] Error: api_instance == NULL!");
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  /* allocate socket data */
  MALLOC(socket_data, sizeof(T_SOCK_SOCKET_DATA));
  
  /* put socket data in linked list */
  socket_data->next_socket_data = api_data->socket_data;
  api_data->socket_data         = socket_data;
  
  /* initialize socket data */
  socket_data->api_data        = api_data;
  socket_data->tcpip_socket    = 0;
  socket_data->callback        = callback;
  socket_data->context         = context;
  socket_data->rx_flow_control = SOCK_FLOW_XON;
  socket_data->tx_flow_control = SOCK_FLOW_XON;
  socket_data->rx_window       = 1;
  socket_data->tx_window       = 1;
  
  /* send primitive to TCPIP */
  {
    PALLOC(tcpip_create_req_prim, TCPIP_CREATE_REQ);

    tcpip_create_req_prim->app_handle = api_data->hCommAPP;
    tcpip_create_req_prim->ipproto    = ipproto;
    tcpip_create_req_prim->request_id = (T_SOCK_SOCKET)socket_data;

    PSEND(api_data->hCommTCPIP, tcpip_create_req_prim);
  }

  return SOCK_RESULT_OK;
}/* sock_create */


/*****************************************************************************************
** Function  : sock_create_cnf
** Parameter : T_TCPIP_CREATE_CNF *
**             T_SOCK_API_INSTANCE ' this value will be ignored in this function
**             because you can find socket_data only using request_id
*****************************************************************************************/
LOCAL void sock_create_cnf(T_TCPIP_CREATE_CNF  *tcpip_create_cnf,
                                  T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_SOCKET_DATA* socket_data;
  T_SOCK_CREATE_CNF   sock_create_cnf;

  TRACE_FUNCTION("[Socket API] sock_create_cnf()");

  /* set socket data */
  socket_data = (T_SOCK_SOCKET_DATA*)tcpip_create_cnf->request_id;
  
  /* set received values */
  socket_data->tcpip_socket = tcpip_create_cnf->socket;
  
  /* fill confirm struct */
  sock_create_cnf.event_type = (T_SOCK_EVENTTYPE)tcpip_create_cnf->event_type;
  sock_create_cnf.result     = (T_SOCK_RESULT)tcpip_create_cnf->result;
  sock_create_cnf.socket     = (T_SOCK_SOCKET)socket_data;
  
  socket_data->callback((T_SOCK_EVENTSTRUCT *)&sock_create_cnf, socket_data->context);

  /* release socket data if context creation was not successful */
  if(tcpip_create_cnf->result != TCPIP_RESULT_OK)
  {
    TRACE_ERROR("[Socket API] Error: sock_create() failed");
    ReleaseSocketData(socket_data->api_data, socket_data);
  }
  
  PFREE(tcpip_create_cnf);
}/* sock_create_cnf */


/******************************************************************************/
T_SOCK_RESULT sock_close(T_SOCK_SOCKET socket)
{
  T_SOCK_API_INSTANCE_DATA*  api_data;
  T_SOCK_SOCKET_DATA* sock_data;

  TRACE_FUNCTION("[Socket API] sock_close()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  if(sock_data == NULL)
  {
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  api_data = sock_data->api_data;
   
  /* send primitive to TCPIP */
  {
    PALLOC(tcpip_close_req_prim, TCPIP_CLOSE_REQ);
    tcpip_close_req_prim->app_handle = api_data->hCommAPP;
    tcpip_close_req_prim->socket = sock_data->tcpip_socket;
    PSEND(api_data->hCommTCPIP, tcpip_close_req_prim);
  }
  return SOCK_RESULT_OK;
}/* sock_close */


/*******************************************************************************
** Function  : sock_close_cnf
** Parameter : T_SOCK_CLOSE_CNF *
*******************************************************************************/
LOCAL void sock_close_cnf(T_TCPIP_CLOSE_CNF *tcpip_close_cnf,
                                 T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_SOCKET_DATA* sock_data;
  T_SOCK_CLOSE_CNF   sock_close_cnf;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("[Socket API] sock_close_cnf()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  sock_data =  FindSocketData(api_data ,tcpip_close_cnf->socket);
  if(sock_data == NULL)
  {
    PFREE(tcpip_close_cnf);
    return;
  }

  /* fill confirm struct */
  sock_close_cnf.event_type  = (T_SOCK_EVENTTYPE)tcpip_close_cnf->event_type;
  sock_close_cnf.result      = (T_SOCK_RESULT)tcpip_close_cnf->result;
  sock_close_cnf.socket      = (T_SOCK_SOCKET)sock_data;
  
  sock_data->callback(&sock_close_cnf, sock_data->context);

  /* release socket data if sock closing was successful */
  if(tcpip_close_cnf->result == TCPIP_RESULT_OK)
  {
    ReleaseSocketData(sock_data->api_data, sock_data);
  }
  
  PFREE(tcpip_close_cnf);
}/* sock_close_cnf */


/******************************************************************************/
T_SOCK_RESULT sock_bind(T_SOCK_SOCKET socket, T_SOCK_PORT  port)
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA *sock_data;

  TRACE_FUNCTION("[Socket API] sock_bind()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  if(sock_data == NULL)
  {
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  api_data = sock_data->api_data;
  {
    PALLOC (tcpip_bind_req_prim, TCPIP_BIND_REQ);
    tcpip_bind_req_prim->app_handle = api_data->hCommAPP;
    tcpip_bind_req_prim->socket     = sock_data->tcpip_socket;
    tcpip_bind_req_prim->port       = port;
    PSEND(api_data->hCommTCPIP, tcpip_bind_req_prim);
  }
  return SOCK_RESULT_OK;
}/* sock_bind */


/*******************************************************************************
** Function  : sock_bind_cnf
** Parameter : T_SOCK_BIND_CNF *
**                   T_SOCK_API_INSTANCE
*******************************************************************************/
LOCAL void sock_bind_cnf(T_TCPIP_BIND_CNF  *tcpip_bind_cnf,
                                T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_SOCKET_DATA *sock_data;
  T_SOCK_BIND_CNF sock_bind_cnf;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("[Socket API] sock_bind_cnf()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  sock_data =  FindSocketData(api_data ,tcpip_bind_cnf->socket);
  if(sock_data == NULL)
  {
    PFREE(tcpip_bind_cnf);
    return;
  }

  /* fill confirm struct */
  sock_bind_cnf.event_type = (T_SOCK_EVENTTYPE)tcpip_bind_cnf->event_type;
  sock_bind_cnf.result     = (T_SOCK_RESULT)tcpip_bind_cnf->result; 
  sock_bind_cnf.socket     = (T_SOCK_SOCKET)sock_data;

  sock_data->callback(&sock_bind_cnf,sock_data->context);

  PFREE(tcpip_bind_cnf);
}/* sock_bind_cnf */


/******************************************************************************/
T_SOCK_RESULT sock_listen(T_SOCK_SOCKET socket )
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA* sock_data;
    
  TRACE_FUNCTION("[Socket API] sock_listen()");
    
  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  if(sock_data == NULL)
  {
    TRACE_ERROR("[Socket API] listen() error: Invalid socket data");
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  api_data   = sock_data->api_data;
  {
    PALLOC (tcpip_listen_req_prim, TCPIP_LISTEN_REQ);
    tcpip_listen_req_prim->app_handle = api_data->hCommAPP;
    tcpip_listen_req_prim->socket = sock_data->tcpip_socket;
    PSEND(api_data->hCommTCPIP,tcpip_listen_req_prim );
  }
	return SOCK_RESULT_OK;
}/* sock_listen */


/*******************************************************************************
** Function  : sock_listen_cnf
** Parameter : T_SOCK_LISTEN_CNF *
**             T_SOCK_API_INSTANCE
*******************************************************************************/
LOCAL void sock_listen_cnf(T_TCPIP_LISTEN_CNF *tcpip_listen_cnf,
                                 T_SOCK_API_INSTANCE api_instance )
{
  T_SOCK_SOCKET_DATA *sock_data;
  T_SOCK_LISTEN_CNF sock_listen_cnf;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("[Socket API] sock_listen_cnf()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  sock_data = FindSocketData(api_data ,tcpip_listen_cnf->socket);
  if(sock_data == NULL)
  {
    PFREE(tcpip_listen_cnf);
    return;
  }

  /* fill confirm struct */
  sock_listen_cnf.event_type = (T_SOCK_EVENTTYPE)tcpip_listen_cnf->event_type;
  sock_listen_cnf.result     = (T_SOCK_RESULT)tcpip_listen_cnf->result; 
  sock_listen_cnf.socket     = (T_SOCK_SOCKET)sock_data;

  sock_data->callback(&sock_listen_cnf,sock_data->context);

  PFREE(tcpip_listen_cnf);
} /* sock_listen_cnf */


/******************************************************************************/
T_SOCK_RESULT sock_connect(T_SOCK_SOCKET socket,
                           T_SOCK_IPADDR ipaddr,
                           T_SOCK_PORT port)
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA* sock_data;

  TRACE_FUNCTION("sock_connect()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  if(sock_data == NULL)
  {
      TRACE_ERROR("[Socket API] connect error: Invalid socket data");
      return SOCK_RESULT_INVALID_PARAMETER;
  }

  api_data = sock_data->api_data;
  {
    PALLOC (tcpip_connect_req_prim, TCPIP_CONNECT_REQ);
    tcpip_connect_req_prim->app_handle = api_data->hCommAPP;
    tcpip_connect_req_prim->socket = sock_data->tcpip_socket;
    tcpip_connect_req_prim->ipaddr = ipaddr;
    tcpip_connect_req_prim->port   = port;
    PSEND(api_data->hCommTCPIP, tcpip_connect_req_prim);
  }
  return SOCK_RESULT_OK;
} /* sock_connect */


/*******************************************************************************
** Function  : sock_connect_cnf
** Parameter : T_SOCK_CONNECT_CNF *
**             T_SOCK_API_INSTANCE
*******************************************************************************/
LOCAL void sock_connect_cnf(T_TCPIP_CONNECT_CNF *tcpip_connect_cnf,
                                   T_SOCK_API_INSTANCE api_instance )
{
  T_SOCK_SOCKET_DATA *sock_data;
  T_SOCK_CONNECT_CNF sock_connect_cnf;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("sock_connect_cnf()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  TRACE_EVENT_P3("api_data %d, socket %d, reslut %d",api_data,
                 tcpip_connect_cnf->socket,tcpip_connect_cnf->result);

  sock_data =  FindSocketData(api_data ,tcpip_connect_cnf->socket);
  if(sock_data == NULL)
  {
    TRACE_EVENT("sock data NULL !!!");
    PFREE(tcpip_connect_cnf);
    return;
  }

  /* fill confirm struct */
  sock_connect_cnf.event_type = (T_SOCK_EVENTTYPE)tcpip_connect_cnf->event_type;
  sock_connect_cnf.result     = (T_SOCK_RESULT)tcpip_connect_cnf->result; 
  sock_connect_cnf.socket     = (T_SOCK_SOCKET)sock_data;

  sock_data->callback(&sock_connect_cnf,sock_data->context);

  PFREE(tcpip_connect_cnf);
} /* sock_connect_cnf */


/******************************************************************************/
T_SOCK_RESULT sock_getsockname(T_SOCK_SOCKET socket)
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA* sock_data;

  TRACE_FUNCTION("sock_getsockname()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  if(sock_data == NULL)
  {
    TRACE_ERROR("[Socket API] getsockname() error: Invalid socket data");
    return SOCK_RESULT_INVALID_PARAMETER;
  }
    api_data   = sock_data->api_data;

  {
    PALLOC(tcpip_sockname_req_prim, TCPIP_SOCKNAME_REQ);
    tcpip_sockname_req_prim->app_handle = api_data->hCommAPP;
    tcpip_sockname_req_prim->socket = sock_data->tcpip_socket;
    PSEND(api_data->hCommTCPIP, tcpip_sockname_req_prim);
  }
  return SOCK_RESULT_OK;
} /* sock_getsockname */



/*******************************************************************************
** Function  : sock_connect_cnf
** Parameter : T_SOCK_SOCKNAME_CNF *
**             T_SOCK_API_INSTANCE
*******************************************************************************/
LOCAL void sock_sockname_cnf(T_TCPIP_SOCKNAME_CNF *tcpip_sockname_cnf,
                                    T_SOCK_API_INSTANCE api_instance )
{
  T_SOCK_SOCKET_DATA *sock_data;
  T_SOCK_SOCKNAME_CNF sock_sockname_cnf;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("sock_getsockname_cnf()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  sock_data =  FindSocketData(api_data , tcpip_sockname_cnf->socket);
  if(sock_data == NULL)
  {
    PFREE(tcpip_sockname_cnf);
    return;
  }

  /* fill confirm struct */
  sock_sockname_cnf.event_type = (T_SOCK_EVENTTYPE)tcpip_sockname_cnf->event_type;
  sock_sockname_cnf.result     = (T_SOCK_RESULT)tcpip_sockname_cnf->result; 
  sock_sockname_cnf.socket     = (T_SOCK_SOCKET)sock_data;
  sock_sockname_cnf.ipaddr     = tcpip_sockname_cnf->ipaddr;
  sock_sockname_cnf.port       = tcpip_sockname_cnf->port;

  sock_data->callback((T_SOCK_EVENTSTRUCT*)&sock_sockname_cnf,sock_data->context);

  PFREE(tcpip_sockname_cnf);
} /* sock_sockname_cnf */


/******************************************************************************/
T_SOCK_RESULT sock_getpeername(T_SOCK_SOCKET socket)
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA* sock_data;

  TRACE_FUNCTION("sock_getpeername()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  api_data   = sock_data->api_data;
  
  if((sock_data == NULL) OR (api_data == NULL))
  {
    TRACE_ERROR("[Socket API] getpeername() error: Invalid socket data");
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  {
    PALLOC (tcpip_peername_req_prim, TCPIP_PEERNAME_REQ);
    tcpip_peername_req_prim->app_handle = api_data->hCommAPP;
    tcpip_peername_req_prim->socket = sock_data->tcpip_socket;
    PSEND(api_data->hCommTCPIP, tcpip_peername_req_prim);
  }
  return SOCK_RESULT_OK;
} /* sock_getpeername */


/*******************************************************************************
** Function  : sock_peername_cnf
** Parameter : T_SOCK_PEERNAME_CNF *
**                   T_SOCK_API_INSTANCE
*******************************************************************************/
LOCAL void sock_peername_cnf(T_TCPIP_PEERNAME_CNF *tcpip_peername_cnf,
                                   T_SOCK_API_INSTANCE api_instance )
{
  T_SOCK_SOCKET_DATA *sock_data;
  T_SOCK_PEERNAME_CNF sock_peername_cnf;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("sock_getpeername_cnf()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  sock_data =  FindSocketData(api_data ,tcpip_peername_cnf->socket);
  if(sock_data == NULL)
  {
    PFREE(tcpip_peername_cnf);
    return;
  }

  sock_peername_cnf.event_type = (T_SOCK_EVENTTYPE)tcpip_peername_cnf->event_type;
  sock_peername_cnf.result     = (T_SOCK_RESULT)tcpip_peername_cnf->result; 
  sock_peername_cnf.socket     = (T_SOCK_SOCKET)sock_data;
  sock_peername_cnf.ipaddr     = tcpip_peername_cnf->ipaddr;
  sock_peername_cnf.port       = tcpip_peername_cnf->port;
   
  sock_data->callback((T_SOCK_EVENTSTRUCT*)&sock_peername_cnf,sock_data->context);

  PFREE(tcpip_peername_cnf);
} /* sock_peername_cnf */


/******************************************************************************/
T_SOCK_RESULT sock_gethostbyname(T_SOCK_API_INSTANCE api_instance,
                                 char* hostname, 
                                 T_SOCK_CALLBACK callback,
                                 void* context)
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA*       socket_data;

  TRACE_FUNCTION("sock_gethostbyname()");
  TRACE_EVENT_P1("hostname: %s",hostname);

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  if(callback EQ NULL)
   return SOCK_RESULT_INVALID_PARAMETER;

  if(api_data == NULL)
  {
    TRACE_ERROR("[Socket API] gethostbyname() error: Invalid socket data");
    return SOCK_RESULT_INVALID_PARAMETER;
  }
  
  MALLOC(socket_data, sizeof(T_SOCK_SOCKET_DATA));
  
  /* put socket data in linked list */
  socket_data->next_socket_data = api_data->socket_data;
  api_data->socket_data         = socket_data;
  
  /* initialize socket data */
  socket_data->api_data        = api_data;
  socket_data->tcpip_socket    = 0;
  socket_data->callback        = callback;
  socket_data->context         = context;
  socket_data->rx_flow_control = SOCK_FLOW_XON; 
  socket_data->tx_flow_control = SOCK_FLOW_XON;
  socket_data->rx_window       = 1;
  socket_data->tx_window       = 1;

  {
    PALLOC (tcpip_hostinfo_req_prim , TCPIP_HOSTINFO_REQ);
    tcpip_hostinfo_req_prim->app_handle = api_data->hCommAPP;
    tcpip_hostinfo_req_prim->ipaddr = 0;
    strcpy((char*)tcpip_hostinfo_req_prim->hostname, hostname);
    tcpip_hostinfo_req_prim->request_id = (T_SOCK_SOCKET)socket_data;     
    PSEND(api_data->hCommTCPIP,tcpip_hostinfo_req_prim);
  }
  return SOCK_RESULT_OK;
} /* sock_gethostbyname */


/*******************************************************************************
** Function  : sock_hostinfo_cnf
** Parameter : T_SOCK_HOSTINFO_CNF *
**             T_SOCK_API_INSTANCE    this value will be ignored ...
**                                    because you can find sock_data using request_id.
*******************************************************************************/
LOCAL void sock_hostinfo_cnf(T_TCPIP_HOSTINFO_CNF* tcpip_hostinfo_cnf , 
                                       T_SOCK_API_INSTANCE api_instance )
{
  T_SOCK_SOCKET_DATA* socket_data;
  T_SOCK_HOSTINFO_CNF  sock_hostinfo_cnf;

  socket_data = (T_SOCK_SOCKET_DATA*)tcpip_hostinfo_cnf->request_id;
  
  /* set received values */
  socket_data->tcpip_socket = tcpip_hostinfo_cnf->socket;
  
  /* fill confirm struct */
  sock_hostinfo_cnf.event_type = (T_SOCK_EVENTTYPE)tcpip_hostinfo_cnf->event_type;
  sock_hostinfo_cnf.result     = (T_SOCK_RESULT)tcpip_hostinfo_cnf->result;
  sock_hostinfo_cnf.socket     = (T_SOCK_SOCKET)socket_data;
  sock_hostinfo_cnf.ipaddr     =  tcpip_hostinfo_cnf->ipaddr;
  strcpy(sock_hostinfo_cnf.hostname,(char*)tcpip_hostinfo_cnf->hostname);

  socket_data->callback((T_SOCK_EVENTSTRUCT*)&sock_hostinfo_cnf, socket_data->context);

  ReleaseSocketData(socket_data->api_data, socket_data);
  
  PFREE(tcpip_hostinfo_cnf);
} /* sock_hostinfo_cnf */


/******************************************************************************/
T_SOCK_RESULT sock_send(T_SOCK_SOCKET socket, char* buffer, U16 buffer_length)
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA* sock_data;

  TRACE_FUNCTION("[Socket API] sock_send()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  if(sock_data == NULL)
  {
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  api_data   = sock_data->api_data;

  if(sock_data->tx_window != 0)
  {
    PALLOC(tcpip_data_req_prim,TCPIP_DATA_REQ);
  	tcpip_data_req_prim->app_handle = api_data->hCommAPP;
  	tcpip_data_req_prim->socket     = sock_data->tcpip_socket;
  	tcpip_data_req_prim->ipaddr     = 0;
  	tcpip_data_req_prim->port       = 0;
  	tcpip_data_req_prim->buflen     =  buffer_length;
  	tcpip_data_req_prim->data       = (U32) M_ALLOC(buffer_length);

  	if(tcpip_data_req_prim->data)
  	{
      /* copy the user data buffer, 
         the prim-data is freed by tcpip_clear_send_buffer() */
      memcpy((char *)tcpip_data_req_prim->data,buffer,buffer_length);
    }
  	else
  	{
      PFREE(tcpip_data_req_prim);
      return SOCK_RESULT_OUT_OF_MEMORY;
    }
    sock_data->tx_window--;
  	PSEND(api_data->hCommTCPIP,tcpip_data_req_prim); 
  	return SOCK_RESULT_OK;
  }
  else /* tx_window = 0 */
  {
    sock_data->tx_flow_control = SOCK_FLOW_XOFF;
    return SOCK_RESULT_NO_BUFSPACE;
  }
} /* sock_send */


/******************************************************************************/
T_SOCK_RESULT sock_sendto(T_SOCK_SOCKET socket, char* buffer,U16 buffer_length,
                          T_SOCK_IPADDR ipaddr,T_SOCK_PORT port)
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA* sock_data;

  TRACE_FUNCTION("[Socket API] sock_sendto()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  if(sock_data == NULL)
      return SOCK_RESULT_INVALID_PARAMETER;
  api_data   = sock_data->api_data;

  if(sock_data->tx_window != 0)
  {
    PALLOC(tcpip_data_req_prim,TCPIP_DATA_REQ);
  	tcpip_data_req_prim->app_handle = api_data->hCommAPP;
  	tcpip_data_req_prim->socket        = sock_data->tcpip_socket;
  	tcpip_data_req_prim->ipaddr        = ipaddr;
  	tcpip_data_req_prim->port          = port;
  	tcpip_data_req_prim->buflen        =  buffer_length;
	  tcpip_data_req_prim->data=(U32) M_ALLOC(buffer_length);
  	if(tcpip_data_req_prim->data )
  	{
      /* copy the user data buffer, 
         the prim-data is freed by tcpip_clear_send_buffer() */
      memcpy((char *)tcpip_data_req_prim->data,buffer,buffer_length);
  	}
  	else
  	{
  	  PFREE(tcpip_data_req_prim);
  	  return SOCK_RESULT_OUT_OF_MEMORY;
  	}

 	  sock_data->tx_window--;
 	  PSEND(api_data->hCommTCPIP, tcpip_data_req_prim);
    return SOCK_RESULT_OK;
  }
  else /* tx_window = 0 */
  {
    sock_data->tx_flow_control = SOCK_FLOW_XOFF;
    return SOCK_RESULT_NO_BUFSPACE;
  }
}

  
/*******************************************************************************
** Function  : sock_mtu_size_cnf
** Parameter : T_SOCK_MTU_SIZE_CNF *
**             T_SOCK_API_INSTANCE
*******************************************************************************/
LOCAL void sock_mtu_size_cnf(T_TCPIP_MTU_SIZE_CNF *tcpip_mtu_size_cnf ,
                                   T_SOCK_API_INSTANCE api_instance )
{
  T_SOCK_SOCKET_DATA *sock_data;
  T_SOCK_MTU_SIZE_CNF sock_mtu_size_cnf;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("[Socket API] sock_mtu_size_cnf()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  sock_data =  FindSocketData(api_data ,tcpip_mtu_size_cnf->socket);
  if(sock_data == NULL)
  {
    PFREE(tcpip_mtu_size_cnf);
    return;
  }

  sock_mtu_size_cnf.event_type = (T_SOCK_EVENTTYPE)tcpip_mtu_size_cnf->event_type;
  sock_mtu_size_cnf.result     = (T_SOCK_RESULT)tcpip_mtu_size_cnf->result; 
  sock_mtu_size_cnf.socket     = (T_SOCK_SOCKET)sock_data;
  sock_mtu_size_cnf.mtu_size   =  tcpip_mtu_size_cnf->mtu_size;

  sock_data->callback((T_SOCK_EVENTSTRUCT*)&sock_mtu_size_cnf,sock_data->context);

  PFREE(tcpip_mtu_size_cnf);
} /* sock_mtu_size_cnf */



/*******************************************************************************
** Function  : sock_connect_ind
** Parameter : T_SOCK_CONNECT_IND *
**                   T_SOCK_API_INSTANCE
** Description : new socket_data will be linked to current socket_data(listening socke_data)
*******************************************************************************/
LOCAL void sock_connect_ind(T_TCPIP_CONNECT_IND *tcpip_connect_ind , 
                                  T_SOCK_API_INSTANCE api_instance )
{
  T_SOCK_SOCKET_DATA *cur_sock_data;   /* listening socket_data */
  T_SOCK_SOCKET_DATA *new_sock_data;   /* connected socket_data */
  T_SOCK_CONNECT_IND sock_connect_ind;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("[Socket API] sock_connect_ind()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  /* find listening socket_data
   * tcpip_connent_ind->socket is listening socket descrpitor
   */
  cur_sock_data =  FindSocketData(api_data ,tcpip_connect_ind->socket);
  if(cur_sock_data == NULL)
  {
    PFREE(tcpip_connect_ind);
    return;
  }

  /* allocate socket data */
  MALLOC(new_sock_data, sizeof(T_SOCK_SOCKET_DATA));

  /* put socket data in linked list */
  new_sock_data->next_socket_data = NULL;     
  cur_sock_data->next_socket_data = new_sock_data;

  /* initialize socket data */
  new_sock_data->api_data        = api_data;
  new_sock_data->tcpip_socket    = tcpip_connect_ind->new_socket;
  /* server must register callback using socket_get_callback() after receiving */
  /* connect ind event.                                                        */
  new_sock_data->callback        = NULL; 
  new_sock_data->context         = NULL;  
  new_sock_data->rx_flow_control = SOCK_FLOW_XON;
  new_sock_data->tx_flow_control = SOCK_FLOW_XON;
  new_sock_data->rx_window       = 1;
  new_sock_data->tx_window       = 1;

  /* fill confirm struct */
  sock_connect_ind.event_type   = (T_SOCK_EVENTTYPE)tcpip_connect_ind->event_type;
  sock_connect_ind.result       = (T_SOCK_RESULT)tcpip_connect_ind->result; 
  /* Check !!! why cur_sock data become new_sock_data */
  /* sock_connect_ind.socket       = (T_SOCK_SOCKET)cur_sock_data;*/
  sock_connect_ind.socket          = (T_SOCK_SOCKET)new_sock_data;   
  sock_connect_ind.new_socket   =  tcpip_connect_ind->new_socket;
  sock_connect_ind.peer_ipaddr  =  tcpip_connect_ind->ipaddr;
  sock_connect_ind.peer_port    =  tcpip_connect_ind->port;

  cur_sock_data->callback((T_SOCK_EVENTSTRUCT*)&sock_connect_ind,cur_sock_data->context);

  PFREE(tcpip_connect_ind);
} /* sock_connect_ind */


/*******************************************************************************
** Function  : sock_conn_closed_ind
** Parameter : T_SOCK_CONN_CLOSED_IND *
**             T_SOCK_API_INSTANCE
**             Release closed socket data
*******************************************************************************/
LOCAL void sock_conn_closed_ind(T_TCPIP_CONN_CLOSED_IND *tcpip_conn_closed_ind,
                                      T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_SOCKET_DATA *sock_data;
  T_SOCK_CONN_CLOSED_IND sock_conn_closed_ind;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("[Socket API] sock_closed_ind()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;

  sock_data =  FindSocketData(api_data, tcpip_conn_closed_ind->socket);
  if(sock_data != NULL)
  {
    sock_conn_closed_ind.event_type = (T_SOCK_EVENTTYPE)tcpip_conn_closed_ind->event_type; 
    sock_conn_closed_ind.result     = (T_SOCK_RESULT)tcpip_conn_closed_ind->result;  
    sock_conn_closed_ind.socket     = (T_SOCK_SOCKET)sock_data;

    sock_data->callback(&sock_conn_closed_ind,sock_data->context);

    ReleaseSocketData(sock_data->api_data,sock_data);
  }
  else {;}

  PFREE(tcpip_conn_closed_ind);
} /* sock_conn_closed_ind */


/*******************************************************************************
** Function  : sock_error_ind
** Parameter : T_SOCK_ERROR_IND *
**             T_SOCK_API_INSTANCE
*******************************************************************************/
LOCAL void sock_error_ind(T_TCPIP_ERROR_IND* tcpip_error_ind , 
                                T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_SOCKET_DATA*   sock_data;
  T_SOCK_ERROR_IND sock_error_ind;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("[Socket API] sock_error_ind()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  
  sock_data =  FindSocketData(api_data , tcpip_error_ind->socket);
  if(sock_data != NULL)
  {
    /* fill confirm struct */
    sock_error_ind.event_type   = (T_SOCK_EVENTTYPE)tcpip_error_ind->event_type;
    sock_error_ind.result       = (T_SOCK_RESULT)tcpip_error_ind->result; 
    sock_error_ind.socket       = (T_SOCK_SOCKET)sock_data;

    sock_data->callback(&sock_error_ind,sock_data->context);
  }
  else {;}
  
  PFREE(tcpip_error_ind);
} /* sock_error_ind */


/******************************************************************************/
T_SOCK_RESULT sock_gethostbyaddr(T_SOCK_API_INSTANCE api_instance,
                                 T_SOCK_IPADDR ipaddr, 
                                 T_SOCK_CALLBACK callback,
                                 void* context )
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA*     socket_data;

  TRACE_FUNCTION("[Socket API] sock_gethostbyaddr()");

  if(callback EQ NULL)
   return SOCK_RESULT_INVALID_PARAMETER;

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  
  MALLOC(socket_data, sizeof(T_SOCK_SOCKET_DATA));
   
  /* put socket data in linked list */
  socket_data->next_socket_data = api_data->socket_data;
  api_data->socket_data         = socket_data;
  
  /* initialize socket data */
  socket_data->api_data        = api_data;
  socket_data->tcpip_socket    = 0;
  socket_data->callback        = callback;
  socket_data->context         = context;
  socket_data->rx_flow_control = SOCK_FLOW_XON;
  socket_data->tx_flow_control = SOCK_FLOW_XON;
  socket_data->rx_window       = 1;
  socket_data->tx_window       = 1;
  
  {
    PALLOC (tcpip_hostinfo_req_prim ,TCPIP_HOSTINFO_REQ);
    tcpip_hostinfo_req_prim->app_handle = api_data->hCommAPP;
    tcpip_hostinfo_req_prim->ipaddr = ipaddr;
    *tcpip_hostinfo_req_prim->hostname = 0;
    tcpip_hostinfo_req_prim->request_id = (T_SOCK_SOCKET)socket_data;     
    PSEND(api_data->hCommTCPIP, tcpip_hostinfo_req_prim);
 }
 return SOCK_RESULT_OK;
} /* sock_gethostbyaddr */


/*******************************************************************************
   Function     :  sock_recv_ind
   Parameter    :  T_TCPIP_DATA_IND*
                   T_SOCK_API_INSTANCE  
   Return       : VOID
   Return Event : None
*******************************************************************************/
static void sock_recv_ind(T_TCPIP_DATA_IND* tcpip_data_ind,
                                T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_SOCKET_DATA*   sock_data;
  T_SOCK_RECV_IND sock_receive_ind;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("[Socket API] sock_recv_ind()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  
  sock_data =  FindSocketData(api_data , tcpip_data_ind->socket);
  if(sock_data == NULL)
  {
    MFREE(tcpip_data_ind->data);
    PFREE(tcpip_data_ind);
    return;
  }

  sock_data->rx_window--;  /* when data received, window size will be descreased..*/

  if(sock_data->rx_flow_control == SOCK_FLOW_XOFF )
  {
    /* case sock flow xoff, sock_data will be stored and send to the application
       with sock_flow_xon() */
    sock_data->recv_ind.socket  = tcpip_data_ind->socket;
    sock_data->recv_ind.result = (T_SOCK_RESULT)tcpip_data_ind->result;
    sock_data->recv_ind.event_type = (T_SOCK_EVENTTYPE)tcpip_data_ind->event_type;
    sock_data->recv_ind.data_length = tcpip_data_ind->buflen;
    sock_data->recv_ind.data_buffer = (char*)tcpip_data_ind->data;
  }
  else 
  {
    /* case sock flow xon , sock_data will be sent to application...*/
    sock_receive_ind.event_type   =  (T_SOCK_EVENTTYPE)tcpip_data_ind->event_type;
    sock_receive_ind.result       =  (T_SOCK_RESULT)tcpip_data_ind->result;
    sock_receive_ind.socket       =  (T_SOCK_SOCKET)sock_data;
    sock_receive_ind.data_length  =  tcpip_data_ind->buflen;
    sock_receive_ind.data_buffer  =  (char *)tcpip_data_ind->data;

    sock_data->callback((T_SOCK_EVENTSTRUCT*)&sock_receive_ind,sock_data->context);

    /* send primitive */
    if( (sock_data->rx_flow_control != SOCK_FLOW_XOFF) &&
        (sock_data->rx_window == 0) )
    {
      PALLOC(tcpip_data_res_prim,TCPIP_DATA_RES);
      tcpip_data_res_prim->app_handle = api_data->hCommAPP;
      ACI_ASSERT(sock_data->tcpip_socket == tcpip_data_ind->socket);
      tcpip_data_res_prim->socket       =  tcpip_data_ind->socket ;
      tcpip_data_res_prim->window       = 1;  
      sock_data->rx_window   = 1;
      PSEND(api_data->hCommTCPIP, tcpip_data_res_prim);	
    }
  }
  PFREE(tcpip_data_ind);
} /* sock_recv_ind */


/*******************************************************************************
** Function  : sock_send_cnf
** Parameter : T_TCPIP_DATA_CNF *
**                   T_SOCK_API_INSTANCE
*******************************************************************************/
static void sock_send_cnf(T_TCPIP_DATA_CNF* tcpip_data_cnf,
                                T_SOCK_API_INSTANCE api_instance)
{
  T_SOCK_SOCKET_DATA *sock_data;
  T_SOCK_API_INSTANCE_DATA *api_data;
  T_SOCK_FLOW_READY_IND sock_flow_ready_ind;

  TRACE_FUNCTION("[Socket API] sock_send_cnf()");

  api_data = (T_SOCK_API_INSTANCE_DATA*)api_instance;
  sock_data =  FindSocketData(api_data , tcpip_data_cnf->socket);

  if(sock_data == NULL)
  {
    PFREE(tcpip_data_cnf);
    return;
  }
  /* if tcpip_data_cnf->window is 0,*/
  /* this value will be 1 because 0 and 1 is the same meaning in the Rnet TCPIP.*/
  if( tcpip_data_cnf->window  == 0 )
  {
    sock_data->tx_window  = 1;
  }
  else
  {
    sock_data->tx_window = tcpip_data_cnf->window;
  }

  sock_flow_ready_ind.event_type = (T_SOCK_EVENTTYPE)tcpip_data_cnf->event_type;
  sock_flow_ready_ind.result     = (T_SOCK_RESULT)tcpip_data_cnf->result; 
  sock_flow_ready_ind.socket     = (T_SOCK_SOCKET)sock_data;
  /* permit next packet to be send */
  sock_data->tx_flow_control     = SOCK_FLOW_XON;

  sock_data->callback(&sock_flow_ready_ind,sock_data->context);

  PFREE(tcpip_data_cnf);
}


/******************************************************************************/
T_SOCK_RESULT sock_set_callback(T_SOCK_SOCKET socket ,T_SOCK_CALLBACK new_callback, 
                                void* new_context)
{
  T_SOCK_SOCKET_DATA* sock_data;

  sock_data = (T_SOCK_SOCKET_DATA*)socket;

  if(new_callback EQ NULL)
   return SOCK_RESULT_INVALID_PARAMETER;

  if(sock_data == NULL)
  {
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  sock_data->callback = new_callback;
  sock_data->context = new_context;

  return SOCK_RESULT_OK;
}


/******************************************************************************/
T_SOCK_RESULT sock_get_callback(T_SOCK_SOCKET socket, T_SOCK_CALLBACK *callback_p,
                                void **context_p)
{
  T_SOCK_SOCKET_DATA* sock_data;

  TRACE_FUNCTION("[Socket API] sock_get_callback()");
  
  /* get current callback,context */    
  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  if(sock_data == NULL)
  {
    return SOCK_RESULT_INVALID_PARAMETER;
  }
  if(callback_p != NULL)
  {
    callback_p = &sock_data->callback;
  }
  if(context_p != NULL)
  {
    context_p  = &sock_data->context;
  }
  return SOCK_RESULT_OK;
} /* socket_get_callback */


/******************************************************************************/
T_SOCK_RESULT sock_flow_xoff(T_SOCK_SOCKET socket)
{
  T_SOCK_SOCKET_DATA* sock_data;

  TRACE_FUNCTION("[Socket API] sock_flow_xoff()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;
  if(sock_data == NULL)
  {
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  sock_data->rx_flow_control = SOCK_FLOW_XOFF;

  return SOCK_RESULT_OK;
 
} /* sock_flow_xoff */


/******************************************************************************/
T_SOCK_RESULT sock_flow_xon(T_SOCK_SOCKET socket)
{
  T_SOCK_SOCKET_DATA* sock_data;
  T_SOCK_RECV_IND sock_receive_ind;
  T_SOCK_API_INSTANCE_DATA *api_data;

  TRACE_FUNCTION("[Socket API] sock_flow_xon()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;

  if(sock_data == NULL)
  {
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  api_data = sock_data->api_data;
  sock_data->rx_flow_control = SOCK_FLOW_XON;
  
  if(sock_data->recv_ind.data_length != 0)
  {     
    sock_receive_ind.event_type  = sock_data->recv_ind.event_type;
    sock_receive_ind.result      = sock_data->recv_ind.result;
    sock_receive_ind.socket      = (T_SOCK_SOCKET)sock_data;
    sock_receive_ind.data_length  = sock_data->recv_ind.data_length;
    sock_receive_ind.data_buffer  = sock_data->recv_ind.data_buffer;

    /* clear recv_ind struct, buffer is freed by application */
    memset(&sock_data->recv_ind, 0x00 , sizeof(T_SOCK_RECV_IND)); 

    sock_data->callback((T_SOCK_EVENTSTRUCT*)&sock_receive_ind,sock_data->context);
  }

  if((sock_data->rx_flow_control != SOCK_FLOW_XOFF) && (sock_data->rx_window == 0))
  {
    PALLOC(tcpip_data_res_prim,TCPIP_DATA_RES);
    tcpip_data_res_prim->app_handle = api_data->hCommAPP;
    tcpip_data_res_prim->socket   =  sock_data->tcpip_socket;
    tcpip_data_res_prim->window  = 1;
    sock_data->rx_window = 1;

    PSEND(api_data->hCommTCPIP, tcpip_data_res_prim);
  }
  return SOCK_RESULT_OK;
} /* sock_flow_xon */


/******************************************************************************/
T_SOCK_RESULT sock_get_mtu_size(T_SOCK_SOCKET socket)
{
  T_SOCK_API_INSTANCE_DATA* api_data;
  T_SOCK_SOCKET_DATA* sock_data;

  TRACE_FUNCTION("[Socket API] sock_get_mtu_size()");

  sock_data = (T_SOCK_SOCKET_DATA*)socket;

  /* check whether sock_data is NULL or not */
  if(sock_data == NULL)
  {
    return SOCK_RESULT_INVALID_PARAMETER;
  }

  api_data   = sock_data->api_data;

  /* send primitive */
  {
    PALLOC (tcpip_mtu_size_req_prim, TCPIP_MTU_SIZE_REQ);
    tcpip_mtu_size_req_prim->app_handle = api_data->hCommAPP;
    tcpip_mtu_size_req_prim->socket     = sock_data->tcpip_socket;
    PSEND(api_data->hCommTCPIP, tcpip_mtu_size_req_prim);
  }
  return SOCK_RESULT_OK;
} /* sock_get_mtu_size */


/******************************************************************************/
LOCAL void pei_not_supported (void *data)
{
  TRACE_FUNCTION ("pei_not_supported()");

  PFREE (data);
}


/******************************************************************************/
BOOL sock_api_handles_primitive( T_SOCK_API_INSTANCE api_instance, T_PRIM* prim)
{
  LOCAL const T_FUNC tcpip_table[] = 
  {
    MAK_FUNC_N( pei_not_supported,     0 /*TCPIP_INITIALIZE_CNF*/ ),  /* 0x00 */
    MAK_FUNC_N( pei_not_supported,     0 /*TCPIP_SHUTDOWN_CNF*/   ),  /* 0x01 */
    MAK_FUNC_N( pei_not_supported,     0 /*TCPIP_IFCONFIG_CNF */  ),  /* 0x02 */
    MAK_FUNC_N( pei_not_supported,     0 /*TCPIP_DTI_CNF*/        ),  /* 0x03 */
    MAK_FUNC_0( sock_create_cnf,       TCPIP_CREATE_CNF           ),  /* 0x04 */
    MAK_FUNC_0( sock_close_cnf,        TCPIP_CLOSE_CNF            ),  /* 0x05 */
    MAK_FUNC_0( sock_bind_cnf,         TCPIP_BIND_CNF             ),  /* 0x06 */
    MAK_FUNC_0( sock_listen_cnf,       TCPIP_LISTEN_CNF           ),  /* 0x07 */
    MAK_FUNC_0( sock_connect_cnf,      TCPIP_CONNECT_CNF          ),  /* 0x08 */
    MAK_FUNC_0( sock_send_cnf,         TCPIP_DATA_CNF             ),  /* 0x09 */
    MAK_FUNC_0( sock_recv_ind,         TCPIP_DATA_IND             ),  /* 0x0a */
    MAK_FUNC_0( sock_sockname_cnf,     TCPIP_SOCKNAME_CNF         ),  /* 0x0b */
    MAK_FUNC_0( sock_peername_cnf,     TCPIP_PEERNAME_CNF         ),  /* 0x0c */
    MAK_FUNC_0( sock_hostinfo_cnf,     TCPIP_HOSTINFO_CNF         ),  /* 0x0d */
    MAK_FUNC_0( sock_mtu_size_cnf,     TCPIP_MTU_SIZE_CNF         ),  /* 0x0e */
    MAK_FUNC_0( sock_connect_ind,      TCPIP_CONNECT_IND          ),  /* 0x0f */
    MAK_FUNC_0( sock_conn_closed_ind,  TCPIP_CONN_CLOSED_IND      ),  /* 0x10 */
    MAK_FUNC_0( sock_error_ind,        TCPIP_ERROR_IND            ),  /* 0x11 */
  };

  LOCAL const T_FUNC dcm_table[] =
  {
    MAK_FUNC_0( sock_open_bearer_cnf,     DCM_OPEN_CONN_CNF       ),
    MAK_FUNC_0( sock_close_bearer_cnf,    DCM_CLOSE_CONN_CNF      ),
    MAK_FUNC_0( sock_bearer_info_cnf,     DCM_GET_CURRENT_CONN_CNF),
    MAK_FUNC_0( sock_dcm_error_ind,       DCM_ERROR_IND           ),
  };

  TRACE_FUNCTION("sock_api_handles_primitive()");

  if(prim NEQ NULL)
  {
    ULONG        opc = prim->custom.opc;
    USHORT       tabsize;
    const T_FUNC *table = 0;

    switch( SAP_NR(opc) )
    {
      case SAP_NR(TCPIP_DL):
        table = tcpip_table;
        tabsize = TAB_SIZE (tcpip_table);
        break;
      case SAP_NR(DCM_UL):
        table = dcm_table;
        tabsize = TAB_SIZE(dcm_table);
        break;       
      default:
        /* Primitive is not for these SAP's */
        return FALSE;
    }
    
    if (PRIM_NR(opc) < tabsize)
    {
      table += PRIM_NR(opc);
      { 
        TRACE_EVENT_P1( "sock_api_handles_primitive: %d", PRIM_NR(opc) );
      }
      JUMP (table->func) (P2D(prim),api_instance);
    }
    else
    {
      TRACE_ERROR("PRIM_NR(opc) >= tabsize");
      return FALSE;
    }
  }
  return TRUE;
} /* sock_api_handles_primitive */