view src/aci2/aci/dcm_utils.c @ 662:8cd8fd15a095

SIM speed enhancement re-enabled and made configurable TI's original code supported SIM speed enhancement, but Openmoko had it disabled, and OM's disabling of speed enhancement somehow caused certain SIM cards to start working which didn't work before (OM's bug #666). Because our FC community is much smaller in year 2020 than OM's community was in their day, we are not able to find one of those #666-affected SIMs, thus the real issue they had encountered remains elusive. Thus our solution is to re-enable SIM speed enhancement and simply wait for if and when someone runs into a #666-affected SIM once again. We provide a SIM_allow_speed_enhancement global variable that allows SIM speed enhancement to be enabled or disabled per session, and an /etc/SIM_spenh file in FFS that allows it to enabled or disabled on a non-volatile basis. SIM speed enhancement is now enabled by default.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 24 May 2020 05:02:28 +0000
parents 93999a60b835
children
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :  DCM and TCPIP
|  Modul   :  ACI
+-----------------------------------------------------------------------------
|  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.
+-----------------------------------------------------------------------------
|  Description :  This file contains Useful DCM (Data connection manager)functions.
+-----------------------------------------------------------------------------
*/

/************************************  INCLUDES ********************************************/
#include "aci_all.h"

#include "aci.h"
#include "aci_cmh.h"
#include "Gaci_cmh.h"
#include "dcm.h"
#include "dcm_utils.h"
#include "dcm_state.h"
#include "dcm_env.h"
#include "dcm_f.h"
#include "psa_dcm.h"
#include "socket_api.h"

#include "wap_aci.h"

/**************************** LOCAL VARIABLE DEFINITION  ************************************/

/**************************** EXTERN VARIABLE DEFINITION  ***********************************/
EXTERN T_DCM_ENV_CTRL_BLK *dcm_env_ctrl_blk_p;


/**************************** LOCAL FUCNTION DEFINITION  ************************************/
LOCAL T_DCM_RET dcm_send_cgdcont_get_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_cgdcont_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_cgatt_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_cgdeact_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_cgpco_auth_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_cgpco_get_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_cgerep_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_cgpaddr_cmd(U8 current_row);
LOCAL T_DCM_RET dcm_send_percentppp_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_sat_dn_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_percentppp_get_cmd(U8 row);
LOCAL T_DCM_RET dcm_send_percentcal_get_cmd(UBYTE row);
LOCAL T_DCM_RET dcm_send_sat_abort_cmd(U8 row);

LOCAL ULONG dcm_ipaddr_htonl(ULONG horder_ipaddr);

LOCAL void set_state_from_ctrl_blk();

/************************** EXTERN FUCNTION DEFINITION  *********************************/
EXTERN T_DCM_RET dcm_handle_message (T_DCM_HDR *msg_p);
EXTERN void psaTCPIP_Shutdown_Req(void);



/***************************************************************************************
*   Function       :  dcm_process_unwaited_events_state_intermediate_conn
*   Parameter      :  T_DCM_HDR *
*                     -Pointer on the header of the message.
*   Return         :  T_DCM_RET
*                     DCM_OK or DCM errors
*   Description    :  Function used in all intermediate states where events is unwaited,
*                     but must be processed.
***************************************************************************************/
T_DCM_RET dcm_process_unwaited_events_state_intermediate_conn(T_DCM_HDR * msg_p)
{
  T_DCM_OPEN_CONN_REQ_MSG * dcm_open_conn_req_msg_p;
  T_DCM_CLOSE_CONN_REQ_MSG * dcm_close_conn_req_msg_p;
  U8 current_row = dcm_env_ctrl_blk_p->current_row;

  TRACE_FUNCTION("DCM: dcm_process_unwaited_events_state_intermediate_conn()");

  switch(msg_p->msg_id)
  {
    case DCM_ERROR_IND_MSG:
      return dcm_process_event_error_reception(msg_p);
      /*lint -e527 suppress Warning -- Unreachable */
      break;
      /*lint +e527 */
    case DCM_OPEN_CONN_REQ_MSG:
      dcm_open_conn_req_msg_p = (T_DCM_OPEN_CONN_REQ_MSG*)msg_p;
      return psaDCM_open_conn_cnf(DCM_BUSY,
                                 dcm_open_conn_req_msg_p->conn_req.api_instance);
      /*lint -e527 suppress Warning -- Unreachable */
      break;
      /*lint +e527 */
    case DCM_CLOSE_CONN_REQ_MSG:
      dcm_close_conn_req_msg_p = (T_DCM_CLOSE_CONN_REQ_MSG*)msg_p;
      // DCM CLOSE REQ have to be accepted in ACTVATING STATE
      if(dcm_env_ctrl_blk_p->state[0] == DCM_ACTIVATING_CONN)
      {
        dcm_process_close_conn_event(dcm_close_conn_req_msg_p);
      }
      else
      {
        psaDCM_close_conn_cnf(DCM_BUSY,
                              dcm_close_conn_req_msg_p->close_req.api_instance);
      }
      return DCM_OK;
      /*lint -e527 suppress Warning -- Unreachable */
      break;
      /*lint +e527 */
    default:
      /* Ignore event - Stay in the same state. */
      return DCM_UNKNOWN_EVENT;
  }
}


/*
 * Function used to close a connection (with PS and later with api_instance)
 *
 * The closing is always on demand of the IPU_id, or may be internally launched.
 * The closing of the connection begin by the closing of the port with the PS.
 * - Close the connection with the PS.
 *
 * @param   T_DCM_CLOSE_CONN_REQ_MSG*
 * @return  DCM_OK or DCM errors
 */
/***************************************************************************************
*   Function       :  dcm_process_close_conn_event
*   Parameter      :  T_APPLI_USER
*                     -Pointer on the header of the message.
*   Return         :  T_DCM_RET
*                     DCM_OK or DCM errors
*   Description    :  Function used in all intermediate states where events is unwaited,
*                     but must be processed.
***************************************************************************************/
T_DCM_RET dcm_process_close_conn_event(T_DCM_CLOSE_CONN_REQ_MSG *close_conn_p )
{
  U8 i;
  U8 current_bearer_count;

  TRACE_FUNCTION("DCM: dcm_process_close_conn_event()");

  for (i=0; i < DCM_MAX_NUMBER_IPU; i++)
  {
    if( (dcm_env_ctrl_blk_p->ipu_list[i].api_instance ==
         close_conn_p->close_req.api_instance) &&
         (dcm_env_ctrl_blk_p->ipu_list[i].row_state) )
    {
      if(dcm_env_ctrl_blk_p->ipu_list[i].bearer_type == DCM_BEARER_GPRS)
      {
        current_bearer_count = dcm_env_ctrl_blk_p->gprs_current_total_row;
      }
      else
      {
        current_bearer_count = dcm_env_ctrl_blk_p->gsm_current_total_row;
      }
      /* raise the flag that indicates a disconnection */
      dcm_env_ctrl_blk_p->ipu_list[i].row_state = ROW_CLOSING;
      dcm_new_state(DCM_CLOSING_CONN , DCM_SUB_NO_ACTION);

      if(current_bearer_count == 1)
      {
        if(dcm_env_ctrl_blk_p->ipu_list[i].bearer_type == DCM_BEARER_GPRS)
        {
          dcm_send_cgdeact_cmd(i);
        }
        else
        {
          dcm_send_percentcal_get_cmd(i);
        }
      }
      else
      {
        psaDCM_close_conn_cnf(DCM_OK,close_conn_p->close_req.api_instance);
        /* free the row used */
        dcm_free_row(i);
        set_state_from_ctrl_blk();
      }
    }
  }
  return DCM_OK;
}


/*******************************************************************************
 * Function used to open a connection (with PS)
 *
 * The opening is always on demand of the IPU_id.
 * - Open the connection with the PS.
 *
 * @return  DCM_OK or DCM errors
*******************************************************************************/
T_DCM_RET dcm_process_open_conn_event(T_DCM_OPEN_CONN_REQ_MSG *open_conn_p)
{
  U8 row_id, row_id_free;

  TRACE_FUNCTION("DCM: dcm_process_open_conn_event()");

  /* check if the max number of IPU is reached */
  if (( dcm_env_ctrl_blk_p->gsm_current_total_row +
        dcm_env_ctrl_blk_p->gprs_current_total_row ) >= DCM_MAX_NUMBER_IPU )
  {
    /* Too many IPU_id opened */
    /* send the negative confirmation to the IPU */
    return psaDCM_open_conn_cnf(DCM_NOT_READY,
                                open_conn_p->conn_req.api_instance);
  }

  /* if possible, get the next row */
  for (row_id = 0, row_id_free = DCM_MAX_NUMBER_IPU; row_id < DCM_MAX_NUMBER_IPU; row_id++)
  {
    if (dcm_env_ctrl_blk_p->ipu_list[row_id].row_state)
    {
      /* send a negative confirmation whether the IPU already exists */
      if (dcm_env_ctrl_blk_p->ipu_list[row_id].api_instance ==
          open_conn_p->conn_req.api_instance)
      {
        /* send the negative confirmation to the IPU */
        return psaDCM_open_conn_cnf(DCM_ALREADY_ACTIVATED,
                                    open_conn_p->conn_req.api_instance);
      }
    }
    else
    {
      /* get the first entry */
      if (row_id_free == DCM_MAX_NUMBER_IPU)
      {
        row_id_free = row_id;
      }
    }
  }

  if (row_id_free == DCM_MAX_NUMBER_IPU)
  {
    /* send the negative confirmation to the IPU */
    return psaDCM_open_conn_cnf(DCM_NOT_READY,
                                open_conn_p->conn_req.api_instance);
  }
  /* Check the bearer type */
  /* check best one bearer */
  if(open_conn_p->conn_req.bearer_select == DCM_BEARER_ANY)
  {
    T_CGATT_STATE  cgatt_state;
    qAT_PlusCGATT(CMD_SRC_LCL,&cgatt_state);

    if(cgatt_state == CGATT_STATE_ATTACHED)
      open_conn_p->conn_req.bearer_select = DCM_BEARER_GPRS;
    else
      open_conn_p->conn_req.bearer_select = DCM_BEARER_GSM;
  }

  /* If application doesn't give any connection parameters than use default */
  if(open_conn_p->conn_req.bearer_select == DCM_BEARER_GSM   OR
     open_conn_p->conn_req.bearer_select == DCM_BEARER_GPRS)
  {
    psaDCM_open_conn_cnf(DCM_INVALID_PARAMETER,open_conn_p->conn_req.api_instance);
    return DCM_INVALID_PARAMETER;
  }

  /* If application gives the necessary parameters for a connection use these */
  else if(open_conn_p->conn_req.bearer_select == DCM_BEARER_AS_SPECIFIED)
  {
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].bearer_handle =
      open_conn_p->conn_req.dcm_info_conn.bearer_handle;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].app_handle    =
      open_conn_p->conn_req.dcm_info_conn.app_handle;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].bearer_type   =
      open_conn_p->conn_req.dcm_info_conn.bearer_type;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].apn_valid     =
      open_conn_p->conn_req.dcm_info_conn.apn_valid;
    if(dcm_env_ctrl_blk_p->ipu_list[row_id_free].apn_valid)
    {
      strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row_id_free].apn,
             (char*)open_conn_p->conn_req.dcm_info_conn.apn);
    }
    else
    {
      strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row_id_free].apn,"");
    }
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].phone_number_valid =
      open_conn_p->conn_req.dcm_info_conn.phone_number_valid;
    if(dcm_env_ctrl_blk_p->ipu_list[row_id_free].phone_number_valid)
    {
      strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row_id_free].phone_number,
             (char*)open_conn_p->conn_req.dcm_info_conn.phone_number);
    }
    else
    {
      strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row_id_free].phone_number,"");
    }
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].user_id_valid =
      open_conn_p->conn_req.dcm_info_conn.user_id_valid;
    if(dcm_env_ctrl_blk_p->ipu_list[row_id_free].user_id_valid)
    {
      strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row_id_free].user_id,
             (char*)open_conn_p->conn_req.dcm_info_conn.user_id);
    }
    else
    {
      strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row_id_free].user_id,"");
    }
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].password_valid =
      open_conn_p->conn_req.dcm_info_conn.password_valid;
    if(dcm_env_ctrl_blk_p->ipu_list[row_id_free].password_valid)
    {
      strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row_id_free].password,
             (char*)open_conn_p->conn_req.dcm_info_conn.password);
    }
    else
    {
      strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row_id_free].password,"");
    }
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].cid             = open_conn_p->conn_req.dcm_info_conn.cid;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].ip_address      = open_conn_p->conn_req.dcm_info_conn.ip_address;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].dns1            = open_conn_p->conn_req.dcm_info_conn.dns1;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].dns2            = open_conn_p->conn_req.dcm_info_conn.dns2;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].gateway         = open_conn_p->conn_req.dcm_info_conn.gateway;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].auth_type       = open_conn_p->conn_req.dcm_info_conn.auth_type;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].data_compr      = open_conn_p->conn_req.dcm_info_conn.data_compr;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].header_compr    = open_conn_p->conn_req.dcm_info_conn.header_compr;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].precedence      = open_conn_p->conn_req.dcm_info_conn.precedence;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].delay           = open_conn_p->conn_req.dcm_info_conn.delay;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].reliability     = open_conn_p->conn_req.dcm_info_conn.reliability;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].peak_throughput = open_conn_p->conn_req.dcm_info_conn.peak_throughput;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].mean_throughput = open_conn_p->conn_req.dcm_info_conn.mean_throughput;
    dcm_env_ctrl_blk_p->ipu_list[row_id_free].shareable       = open_conn_p->conn_req.dcm_info_conn.shareable;
  }

  dcm_env_ctrl_blk_p->ipu_list[row_id_free].api_instance =
    open_conn_p->conn_req.api_instance;

  /* keep the curretn row */
  dcm_env_ctrl_blk_p->current_row = row_id_free;

  /* mark the row as used */
  dcm_env_ctrl_blk_p->ipu_list[row_id_free].row_state = ROW_ASSIGNED;

  /* sum the total of actual rows */
  if(dcm_env_ctrl_blk_p->ipu_list[row_id_free].bearer_type == DCM_BEARER_GPRS)
  {
    dcm_env_ctrl_blk_p->gprs_current_total_row++;
  }
  else
  {
    dcm_env_ctrl_blk_p->gsm_current_total_row++;
  }

  if(dcm_env_ctrl_blk_p->gprs_current_total_row > 1 OR
     dcm_env_ctrl_blk_p->gsm_current_total_row > 1)
  {
    psaDCM_open_conn_cnf(DCM_ALREADY_ACTIVATED,open_conn_p->conn_req.api_instance);
    return DCM_ALREADY_ACTIVATED;
  }

  set_gpf_tcpip_call();

  /* DCM state change */
  dcm_new_state(DCM_ACTIVATING_CONN,DCM_SUB_NO_ACTION);

  /* if GPRS: send first GPRS AT Command qAT_CGDCONT  */
  if(dcm_env_ctrl_blk_p->ipu_list[row_id_free].bearer_type == DCM_BEARER_GPRS)
  {
    dcm_send_cgdcont_get_cmd(dcm_env_ctrl_blk_p->current_row);
  }
  else /*send first GSM AT Command sAT_PercentPPP */
  {
    dcm_send_percentppp_cmd(dcm_env_ctrl_blk_p->current_row);
  }

  return DCM_OK;
}


/******************************************************************************/
T_DCM_RET dcm_process_get_current_conn_event(T_DCM_GET_CURRENT_CONN_REQ_MSG *current_conn_p)
{
  TRACE_FUNCTION("DCM: dcm_process_get_current_conn_event()");

  if(dcm_env_ctrl_blk_p->ipu_list[dcm_env_ctrl_blk_p->current_row].row_state ==
     ROW_ASSIGNED) {
    psaDCM_get_current_conn_cnf(DCM_OK,
                                current_conn_p->current_conn_req.api_instance,
                                dcm_env_ctrl_blk_p);
  }
  else {
    psaDCM_get_current_conn_cnf(DCM_NOT_READY,
                                current_conn_p->current_conn_req.api_instance,
                                dcm_env_ctrl_blk_p);
  }
  return DCM_OK;
}


/******************************************************************************/
T_DCM_RET dcm_process_unknown_event_in_idle(T_DCM_HDR* msg_p)
{
  T_DCM_CLOSE_CONN_REQ_MSG *close_conn_req_p;
  T_DCM_RET ret;

  TRACE_FUNCTION("DCM: dcm_process_unknown_event_in_idle()");

  if(msg_p == NULL)
    return DCM_INVALID_PARAMETER;

  switch(msg_p->msg_id)
  {
    case DCM_CLOSE_CONN_REQ_MSG :
      close_conn_req_p =(T_DCM_CLOSE_CONN_REQ_MSG *)msg_p;
      psaDCM_close_conn_cnf(DCM_UNKNOWN_EVENT,
                            close_conn_req_p->close_req.api_instance);
      set_state_from_ctrl_blk();
      ret = DCM_OK;
      break;
    default:
      ret = DCM_UNKNOWN_EVENT;
      break;
  }
  return ret;
}


/******************************************************************************/
T_DCM_RET dcm_free_row(U8 current_row)
{
  TRACE_FUNCTION("DCM: dcm_free_row()");

  /* Decrease the current number of IPU */
  dcm_env_ctrl_blk_p->ipu_list[current_row].row_state = ROW_FREE;
  if(dcm_env_ctrl_blk_p->ipu_list[current_row].bearer_type == DCM_BEARER_GPRS)
    dcm_env_ctrl_blk_p->gprs_current_total_row--;
  else
    dcm_env_ctrl_blk_p->gsm_current_total_row--;

  /* clear the row in the structure of IP Users */
  dcm_clear_ipu_info(current_row);
  return DCM_OK;
}


/*
 * Function used to store some IPU informations
 *
 * @param   row to access [0, 256],
 * @param   IPU id
 * @param   bearer type
 * @param   apn, mtu, pdp@, cid, user, password, dns1, dns2, gateway
 * @return    DCM_OK or DCM errors
 */
T_DCM_RET dcm_store_ipu_info(U8 row, T_BEARER_TYPE bearer_type, char *apn,
                             char *number, char *pdp_addr, U8 cid_used,
                             char *user, char *password, U32 dns1, U32 dns2,
                             U32 gateway)
{
  TRACE_FUNCTION("DCM: dcm_store_ipu_info()");

  if(bearer_type == DCM_BEARER_GPRS)
    strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row].apn, apn);
  else if (bearer_type == DCM_BEARER_GSM)
    strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row].phone_number,number);
  else
    return DCM_INVALID_PARAMETER;
  dcm_env_ctrl_blk_p->ipu_list[row].bearer_type = bearer_type;
  dcm_env_ctrl_blk_p->ipu_list[row].cid = cid_used;
  strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row].user_id, user);
  strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row].password, password);
  dcm_env_ctrl_blk_p->ipu_list[row].dns1 = dns1;
  dcm_env_ctrl_blk_p->ipu_list[row].dns2 = dns2;
  dcm_env_ctrl_blk_p->ipu_list[row].gateway = gateway;

  return DCM_OK;
}


/* resets parameters of a row */
T_DCM_RET dcm_clear_ipu_info(U8 row)
{
  char empty[] = "";
  TRACE_FUNCTION("DCM: dcm_clear_ipu_info()");

  dcm_env_ctrl_blk_p->ipu_list[row].bearer_type = DCM_BEARER_NO;
  strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row].apn, empty);
  strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row].phone_number,empty);
  dcm_env_ctrl_blk_p->ipu_list[row].cid = 0;
  strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row].user_id, empty);
  strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row].password, empty);
  dcm_env_ctrl_blk_p->ipu_list[row].dns1 = 0;
  dcm_env_ctrl_blk_p->ipu_list[row].dns2 = 0;
  dcm_env_ctrl_blk_p->ipu_list[row].gateway = 0;

  return DCM_OK;
}

/*
 * Function used to send the <AT+CGDCONT=?> command
 *
 * This command is used to get the next Context IDentifier available in the PS.
 * This cid will be used very often in the suite
 *
 * @param   row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
LOCAL T_DCM_RET dcm_send_cgdcont_get_cmd(U8 row)
{
  T_GPRS_CONT_REC defCtxts[MAX_CID_PLUS_EINS];
  SHORT cid_array[MAX_CID_PLUS_EINS];
  UBYTE i;

  TRACE_FUNCTION("DCM: dcm_send_cgdcont_get_cmd()");

  if(qAT_PlusCGDCONT(CMD_SRC_LCL, &defCtxts, cid_array) != AT_CMPL)
  {
    psaDCM_open_conn_cnf( DCM_NOT_READY, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();
    return DCM_OK;
  }
  else
  {
    for( i= 0; i < MAX_CID_PLUS_EINS ; i++)
    {
      if(cid_array[i] == dcm_env_ctrl_blk_p->ipu_list[row].cid)
      {
        TRACE_EVENT_P2("DCM: dcm cid is the same %d=%d",
                       cid_array[i],
                       dcm_env_ctrl_blk_p->ipu_list[row].cid);
      }
    }
    return  dcm_send_cgdcont_cmd(row);
  }

}


/*
 * Function used to send the <AT+CGDCONT=cid, "IP", "apn", "", 0, 0> command
 *
 * This command is used to declare the PDP Context.
 *
 * @param   row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
LOCAL T_DCM_RET dcm_send_cgdcont_cmd(U8 row)
{
  T_GPRS_CONT_REC input_txt;

  TRACE_FUNCTION("DCM: dcm_send_cgdcont_cmd()");
  TRACE_EVENT_P1("DCM: ipu_list[row].apn = %s",dcm_env_ctrl_blk_p->ipu_list[row].apn);

  strcpy(input_txt.apn,(char*)dcm_env_ctrl_blk_p->ipu_list[row].apn);
  strcpy(input_txt.pdp_type,"IP");
  memset(input_txt.pdp_addr,'\0',MAX_PDP_ADDR_LEN);
  input_txt.d_comp = CGDCONT_D_COMP_OMITTED;
  input_txt.h_comp = CGDCONT_H_COMP_OMITTED;
  memset(&input_txt.qos,0,sizeof(T_QOS));
  memset(&input_txt.min_qos,0,sizeof(T_QOS));

  if(sAT_PlusCGDCONT(CMD_SRC_LCL,dcm_env_ctrl_blk_p->ipu_list[row].cid, &input_txt) != AT_CMPL)
  {
    psaDCM_open_conn_cnf(DCM_NOT_READY, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();
    return DCM_OK;
  }
  else
  {
    dcm_send_cgatt_cmd(row);
    return DCM_OK;
  }
}


/*
 * Function used to send the <AT+CGATT=cid> command
 *
 * This command is used to force attachment to the network.
 *
 * @param   row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
LOCAL T_DCM_RET dcm_send_cgatt_cmd(U8 row)
{
  TRACE_FUNCTION("DCM: dcm_send_cgatt_cmd()");

  /* prepare the AT command including some dynamic info like cid */
  switch(sAT_PlusCGATT(CMD_SRC_LCL, CGATT_STATE_ATTACHED))
  {
    case AT_FAIL:
    case AT_BUSY:
      psaDCM_open_conn_cnf(DCM_NOT_READY, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
      dcm_free_row(row);
      set_state_from_ctrl_blk();
      break;

    case AT_CMPL:
      dcm_send_cgpco_auth_cmd(row);
      break;

    case AT_EXCT:
      dcm_env_ctrl_blk_p->dcm_call_back = dcm_handle_message;
      dcm_new_state(DCM_ACTIVATING_CONN, DCM_SUB_WAIT_CGATT_CNF);
      break;

    default :
      break;
  }
  return DCM_OK;
}


/*
 * Function used to send the <AT%CGPCO=0, cid, "PAP, username,
 * password, 0.0.0.0, 0.0.0.0"> command
 *
 * This command is used to configure the PS to TCPIP over SNDCP
 *
 * @param   row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
LOCAL T_DCM_RET dcm_send_cgpco_auth_cmd(U8 row)
{
  CHAR dns[2];
  strcpy(dns, "");

  TRACE_FUNCTION("DCM: dcm_send_cgpco_auth_cmd()");
  TRACE_EVENT_P2("DCM: user=%s, password=%s",
                 dcm_env_ctrl_blk_p->ipu_list[row].user_id,
                 dcm_env_ctrl_blk_p->ipu_list[row].password);

  if(sAT_PercentCGPCO(CMD_SRC_LCL,dcm_env_ctrl_blk_p->ipu_list[row].cid,
                      ACI_PCO_AUTH_PROT_PAP,
                      (char*)dcm_env_ctrl_blk_p->ipu_list[row].user_id,
                      (char*)dcm_env_ctrl_blk_p->ipu_list[row].password,
                      dns,dns) != AT_CMPL)
  {
    psaDCM_open_conn_cnf(DCM_NOT_READY, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();
    return DCM_OK;
  }
  else
  {
    dcm_send_cgerep_cmd(row);
    return DCM_OK;
  }
}


/*
 * Function used to send the <AT+CGEREP=cid, 0> command
 *
 * This command is used to configure the PS to send EVENT to us
 *
 * @param   row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
LOCAL T_DCM_RET dcm_send_cgerep_cmd(U8 row)
{
  TRACE_FUNCTION("DCM: dcm_send_cgerep_cmd()");

  /* prepare the AT command including some dynamic info like cid */
  if (sAT_PlusCGEREP(CMD_SRC_LCL,CGEREP_MODE_BUFFER,CGEREP_BFR_CLEAR) != AT_CMPL)
  {
    psaDCM_open_conn_cnf(DCM_NOT_READY, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();
    return DCM_OK;
  }
  else
  {
    strcpy((char*)dcm_env_ctrl_blk_p->ipu_list[row].phone_number,"*98*1#");
    dcm_send_sat_dn_cmd(row);
    return DCM_OK;
  }
}


/*
 * Function used to send the <AT+CGACT=cid, 0> command
 *
 * This command is used to deactivate the PDP decontext.
 *
 * @param   row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
LOCAL T_DCM_RET dcm_send_cgdeact_cmd(U8 row)
{
  T_CGATT_STATE gprs_attach_state;
  SHORT cids[MAX_CID_PLUS_EINS] = {GPRS_CID_1,INVALID_CID};

  TRACE_FUNCTION("DCM: dcm_send_cgdeact_cmd()");

  /* Packet Counter */
  sAT_PercentSNCNT(CMD_SRC_LCL,SN_RESET_YES);

  qAT_PlusCGATT(CMD_SRC_LCL,&gprs_attach_state);
  TRACE_EVENT_P1("DCM: Attatch State %d",gprs_attach_state);

  if(gprs_attach_state != CGATT_STATE_ATTACHED)
  {
    psaDCM_close_conn_cnf(DCM_OK,dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();
    return DCM_OK;
  }

  /* GPRS BEARER CLOSING */
  switch(sAT_PlusCGACT(CMD_SRC_LCL,CGACT_STATE_DEACTIVATED,cids))
  {
    case AT_FAIL:
    case AT_BUSY:
      psaDCM_close_conn_cnf(DCM_NOT_READY,
                            dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
      set_state_from_ctrl_blk();
      break;

    case AT_CMPL:
      psaDCM_close_conn_cnf(DCM_OK, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
      dcm_free_row(row);
      set_state_from_ctrl_blk();
      break;

    case AT_EXCT:
      dcm_new_state(DCM_CLOSING_CONN, DCM_SUB_WAIT_CGDEACT_CNF);
      dcm_env_ctrl_blk_p->dcm_call_back = dcm_handle_message;
      break;

    default :
      break;
  }
  return DCM_OK;
}


LOCAL T_DCM_RET dcm_send_sat_h_cmd(U8 row)
{
  SHORT cid_array[1];
  cid_array[0] = INVALID_CID;

  TRACE_FUNCTION("DCM: dcm_send_sat_h_cmd()");

  switch(sAT_H(CMD_SRC_LCL))
  {
    case AT_FAIL:
    case AT_BUSY:
      psaDCM_close_conn_cnf(DCM_NOT_READY, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
      set_state_from_ctrl_blk();
      break;

    case AT_CMPL:
      break;

    case AT_EXCT:
      dcm_new_state(DCM_CLOSING_CONN, DCM_SUB_WAIT_SATH_CNF);
      dcm_env_ctrl_blk_p->dcm_call_back = dcm_handle_message;
      break;

    default :
      break;
  }
  return DCM_OK;
}


/*
 * Function used to send the <AT+CGPADDR=cid> command
 *
 * This command is used to get back the pdp@ of the module
 *
 * @param   row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
LOCAL T_DCM_RET dcm_send_cgpaddr_cmd(U8 row)
{
  T_PDP_ADDRESS pdp_address[MAX_CID];
  SHORT cid_array[MAX_CID];
  cid_array[0] = dcm_env_ctrl_blk_p->ipu_list[row].cid;
  cid_array[1] =INVALID_CID;

  TRACE_FUNCTION("DCM: dcm_send_cgpaddr_cmd()");

  memset(pdp_address , 0x00, sizeof(T_PDP_ADDRESS)*MAX_CID);

  /* prepare the AT command including some dynamic info like cid */
  if(sAT_PlusCGPADDR(CMD_SRC_LCL,cid_array,pdp_address) != AT_CMPL)
  {
    psaDCM_open_conn_cnf(DCM_NOT_READY,
                         dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();
    return DCM_OK;
  }
  else
  {
    memcpy(dcm_env_ctrl_blk_p->ipu_list[row].pdp_addr,
           pdp_address[0],
           sizeof(T_PDP_ADDRESS));
    TRACE_EVENT_P1("DCM: PDP addr=%s",dcm_env_ctrl_blk_p->ipu_list[row].pdp_addr);
    dcm_send_cgpco_get_cmd(row);
    return DCM_OK;
  }
}


/*
 * Function used to send the <AT%CGPCO=1,1,,cid> command
 *
 * This command is used to get back the dns1, dns2 and gateway @
 *
 * @param   row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
LOCAL T_DCM_RET dcm_send_cgpco_get_cmd(U8 row)
{
  TRACE_FUNCTION("DCM: dcm_send_cgpco_get_cmd()");

  psaDCM_open_conn_cnf(DCM_OK, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
  dcm_env_ctrl_blk_p->dcm_call_back = dcm_handle_message;
  dcm_new_state(DCM_CONN_ACTIVATED, DCM_SUB_NO_ACTION);

  return DCM_OK;
}


T_DCM_RET dcm_send_percentppp_cmd(U8 row)
{
  TRACE_FUNCTION("DCM: dcm_send_percentppp_cmd()");
  if(sAT_PercentPPP(CMD_SRC_LCL,
                    A_PAP,
                    (char*)dcm_env_ctrl_blk_p->ipu_list[row].user_id,
                    (char*)dcm_env_ctrl_blk_p->ipu_list[row].password,
                    USE_NO_PPP_FOR_AAA) != AT_CMPL)
  {
    psaDCM_open_conn_cnf(DCM_NOT_READY,
                         dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();  }
  else
  {
    // reset the WAP-data if not done at call termination before
    sAT_PercentWAP(0,0);
    sAT_PercentWAP(0,1);
    dcm_send_sat_dn_cmd(row);
  }

  return DCM_OK;
}


LOCAL T_DCM_RET dcm_send_sat_dn_cmd(U8 row)
{
  TRACE_FUNCTION("DCM: dcm_send_sat_dn_cmd()");

  switch(sAT_Dn(CMD_SRC_LCL,
                (char*)dcm_env_ctrl_blk_p->ipu_list[row].phone_number,
                D_CLIR_OVRD_Default,
                D_CUG_CTRL_NotPresent,
                D_TOC_Data))
  {
    case AT_FAIL:
    case AT_BUSY:
    case AT_CMPL:
      psaDCM_open_conn_cnf(DCM_NOT_READY,
                           dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
      dcm_free_row(row);
      set_state_from_ctrl_blk();
      break;

    case AT_EXCT:
      dcm_env_ctrl_blk_p->dcm_call_back = dcm_handle_message;
      if(dcm_env_ctrl_blk_p->ipu_list[row].bearer_type == DCM_BEARER_GPRS) {
        dcm_new_state(DCM_ACTIVATING_CONN, DCM_SUB_WAIT_CGACT_CNF);
      }
      else {
        dcm_new_state(DCM_ACTIVATING_CONN, DCM_SUB_WAIT_SATDN_CNF);
      }
      break;

    default:
      break;
  }

  return DCM_OK;
}


LOCAL T_DCM_RET dcm_send_percentppp_get_cmd(U8 row)
{
  ULONG dns1=0;
  ULONG dns2 =0;
  ULONG ipaddr = 0 ;

  TRACE_FUNCTION("DCM: dcm_send_percentppp_get_cmd()");

  if(qAT_PercentPPP(CMD_SRC_LCL, &ipaddr,&dns1,&dns2) != AT_CMPL)
  {
    psaDCM_open_conn_cnf(DCM_NOT_READY,
                         dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();
  }
  else
  {
    psaDCM_open_conn_cnf(DCM_OK,
                         dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_env_ctrl_blk_p->dcm_call_back = dcm_handle_message;
    dcm_new_state(DCM_CONN_ACTIVATED,DCM_SUB_NO_ACTION);
  }

  return DCM_OK;
}


/*
 * Function used to process the events and errors received from PS
 *
 * @param   received message
 * @return  DCM_OK or DCM errors
 */
T_DCM_RET dcm_process_event_error_reception(T_DCM_HDR * msg_p)
{
  U8 row = dcm_env_ctrl_blk_p->current_row;;

  TRACE_FUNCTION("DCM: dcm_process_event_error_reception()");

  /* check if this port number is really used by DCM */
  if(dcm_env_ctrl_blk_p->ipu_list[row].row_state)
  {
    psaDCM_error_ind((T_DCM_STATUS_IND_MSG*)msg_p,
                      dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    /* We cannot use this function call here (set_state_from_ctrl_blk();)
       since this will execute reset_gpf_tcpip_call() immediately, but we need
       to evaulate this flag later on */
    if((dcm_env_ctrl_blk_p->gsm_current_total_row +
       dcm_env_ctrl_blk_p->gprs_current_total_row ) > 0)
    {
      /* another active connection */
      dcm_new_state(DCM_CONN_ACTIVATED, DCM_SUB_NO_ACTION);
    }
    else
    {
      dcm_new_state(DCM_IDLE, DCM_SUB_NO_ACTION);
    }
  }
  return DCM_OK;
}


/*
 * Function used to process the reception of the answer to AT+CGATT=...
 *
 * @param   received message, and row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
T_DCM_RET dcm_process_cgatt_ans(T_DCM_HDR * msg_p, U8 row)
{
  TRACE_FUNCTION("DCM: dcm_process_cgatt_ans()");

  if(msg_p->msg_id == DCM_NEXT_CMD_READY_MSG)
  {
    /* send next AT command */
    return dcm_send_cgpco_auth_cmd(row);
  }
  else
  {
    psaDCM_open_conn_cnf(DCM_NOT_READY,
                         dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();
    return DCM_OK;
  }
}


/*
 * Function used to process the reception of the answer to AT+CGACT=...
 *
 * @param   received message, and row in the IPU structure related to the actual command
 * @return  DCM_OK or DCM errors
 */
T_DCM_RET dcm_process_cgact_ans(T_DCM_HDR * msg_p, U8 row)
{
  TRACE_FUNCTION("DCM: dcm_process_cgact_ans()");

  if (msg_p->msg_id == DCM_NEXT_CMD_READY_MSG)
  {
    return dcm_send_cgpaddr_cmd(row);
  }
  else
  {
    psaDCM_open_conn_cnf(DCM_NOT_READY,
                         dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    /*set_state_from_ctrl_blk();*/
    /* We cannot use this function call here (set_state_from_ctrl_blk();)
       since this will execute reset_gpf_tcpip_call() immediately, but we need
       to evaulate this flag later on */

    if((dcm_env_ctrl_blk_p->gsm_current_total_row +
       dcm_env_ctrl_blk_p->gprs_current_total_row ) > 0)
    {
      /* another active connection */
      dcm_new_state(DCM_CONN_ACTIVATED, DCM_SUB_NO_ACTION);
    }
    else
    {
      dcm_new_state(DCM_IDLE, DCM_SUB_NO_ACTION);
    }
    return DCM_OK;
  }
}


T_DCM_RET dcm_process_cgdeact_ans(T_DCM_HDR * msg_p, U8 row)
{
  TRACE_FUNCTION("DCM: dcm_process_cgdeact_ans()");

  if(msg_p->msg_id == DCM_NEXT_CMD_READY_MSG)
  {
    psaDCM_close_conn_cnf(DCM_OK,
                          dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
  }
  else
  {
    psaDCM_close_conn_cnf(DCM_NOT_READY,
                          dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_env_ctrl_blk_p->ipu_list[row].row_state = ROW_ASSIGNED;
  }
  set_state_from_ctrl_blk();
  return DCM_OK;
}


T_DCM_RET dcm_process_sat_dn_ans(T_DCM_HDR * msg_p, U8 row)
{
  TRACE_FUNCTION("DCM: dcm_process_sat_dn_ans()");

  if(msg_p->msg_id == DCM_NEXT_CMD_READY_MSG)
  {
    return dcm_send_percentppp_get_cmd(row);
  }
  else
  {
    T_DCM_STATUS_IND_MSG * message = (T_DCM_STATUS_IND_MSG *)msg_p;
    /* We need to check if TCPIP has been already initialised successfully or not*/
    if ( wap_state EQ TCPIP_Activation)
    {
      /* Make shure we shutdown TCPIP properly */
      wap_state = TCPIP_Deactivation;
      psaTCPIP_Shutdown_Req();
    }
    psaDCM_open_conn_cnf(message->result, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
    set_state_from_ctrl_blk();
    return DCM_OK;
  }
}


T_DCM_RET dcm_process_sat_h_ans(T_DCM_HDR * msg_p, U8 row)
{
  TRACE_FUNCTION("DCM: dcm_process_sat_h_ans()");

  if(msg_p->msg_id == DCM_NEXT_CMD_READY_MSG)
  {
    psaDCM_close_conn_cnf(DCM_OK,dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
    dcm_free_row(row);
  }
  else
  {
    psaDCM_close_conn_cnf(DCM_NOT_READY,
                          dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
  }
  set_state_from_ctrl_blk();
  return DCM_OK;
}


GLOBAL ULONG bytes2ipv4addr(UBYTE *host)
{
  UBYTE c1;
  ULONG addr = 0;
  char *tmp;
  if (!host || host[0]>'9' || host[0]<'0') return -1;

  tmp=(char *)host;
  c1 = atoi(tmp);
  addr = addr | c1 << 24;
  tmp = strstr(tmp, ".");
  if(!tmp) return -1;
  tmp++;
  c1 = atoi(tmp);
  addr = addr | c1 << 16;
  tmp = strstr(tmp, ".");
  if(!tmp) return -1;
  tmp++;
  c1 = atoi(tmp);
  addr = addr | c1 <<8 ;
  tmp = strstr(tmp, ".");
  if(!tmp) return -1;
  tmp++;
  c1 = atoi(tmp);
  addr = addr | c1 ;
  return dcm_ipaddr_htonl(addr);
}


LOCAL ULONG dcm_ipaddr_htonl(ULONG horder_ipaddr)
{
  return((U32)((((U32)(horder_ipaddr) & 0x000000ffU) << 24) |
          (((U32)(horder_ipaddr) & 0x0000ff00U) <<  8) |
          (((U32)(horder_ipaddr) & 0x00ff0000U) >>  8) |
          (((U32)(horder_ipaddr) & 0xff000000U) >> 24)));
}


LOCAL T_DCM_RET dcm_send_percentcal_get_cmd(UBYTE row)
{
  T_ACI_CAL_ENTR call_tab[MAX_CALL_NR];
  UBYTE i;
  UBYTE count = 0;

  TRACE_FUNCTION("DCM: dcm_send_percentcal_get_cmd()");

  if(qAT_PercentCAL(CMD_SRC_LCL, call_tab) EQ AT_CMPL)
  {
    for(i=0; i<MAX_CALL_NR; i++)
    {
      if(call_tab[i].index == -1)
      {
        count++;
        /* in other  words no active call*/
        if(count EQ (MAX_CALL_NR -1) )
        {
          TRACE_EVENT("DCM: No active call");
          psaDCM_close_conn_cnf(DCM_OK, dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
          dcm_free_row(row);
          set_state_from_ctrl_blk();
        }
        break;
      }
      switch(call_tab[i].status)
      {
        case CAL_STAT_Active:
          dcm_send_sat_h_cmd(row);
          break;
        case CAL_STAT_Dial:
        case CAL_STAT_Alerting:
          dcm_send_sat_abort_cmd(row);
          break;

        default:
          TRACE_EVENT("DCM: dcm_send_percentcal_get_cmd DEFAULT call status");
          break;
      }
    }
    return DCM_OK;
  }
  return DCM_OK;
}


LOCAL T_DCM_RET dcm_send_sat_abort_cmd(U8 row)
{
  TRACE_FUNCTION("DCM: dcm_send_sat_h_cmd()");

  switch(sAT_Abort(CMD_SRC_LCL,AT_CMD_D))
  {
    case AT_FAIL:
    case AT_BUSY:
      psaDCM_close_conn_cnf(DCM_NOT_READY,
                            dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
      set_state_from_ctrl_blk();
      break;

    case AT_CMPL:
      psaDCM_close_conn_cnf(DCM_OK,dcm_env_ctrl_blk_p->ipu_list[row].api_instance);
      dcm_free_row(row);
      set_state_from_ctrl_blk();
      break;

    case AT_EXCT:
      dcm_new_state(DCM_CLOSING_CONN, DCM_SUB_WAIT_SATH_CNF);
      dcm_env_ctrl_blk_p->dcm_call_back = dcm_handle_message;
      break;

    default :
      break;
  }
  return DCM_OK;
}


/* This functions checks if antother conneciton is active and changes the
   DCM state corresponding */
LOCAL void set_state_from_ctrl_blk()
{
  if((dcm_env_ctrl_blk_p->gsm_current_total_row +
      dcm_env_ctrl_blk_p->gprs_current_total_row ) > 0)
  {
    /* another active connection */
    dcm_new_state(DCM_CONN_ACTIVATED, DCM_SUB_NO_ACTION);
  }
  else
  {
    dcm_new_state(DCM_IDLE, DCM_SUB_NO_ACTION);
    reset_gpf_tcpip_call();
  }
}