view src/aci2/aci/cmh_smf.c @ 686:59f07d67eb45

luna target split into luna1 and luna2 luna1 is FC Luna based on iWOW DSK v4.0 or v5.0 motherboard luna2 is FC Luna based on FC Caramel2 MB
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 12 Oct 2020 18:51:24 +0000
parents 93999a60b835
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  
|  Modul   :  
+----------------------------------------------------------------------------- 
|  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 module defines the functions used by the command
|             handler for GPRS session management ( SM ).
+----------------------------------------------------------------------------- 
*/ 

#if defined (GPRS) && defined (DTI)

#ifndef CMH_SMF_C
#define CMH_SMF_C
#endif

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

#include "dti.h"      /* functionality of the dti library */
#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_cmd.h"
#include "aci_lst.h"
#include "aci.h"

#include "dti_conn_mng.h"
#include "dti_cntrl_mng.h"

#include "gaci.h"
#include "gaci_cmh.h"
#include "psa.h"
#include "psa_gmm.h"
#include "psa_sm.h"
#include "psa_gppp.h"

#include "phb.h"
#include "cmh.h"
#include "cmh_gmm.h"

#include "cmh_sm.h"
#include "cmh_gppp.h"
#include "gaci_srcc.h"
#include "psa_cc.h"

#if defined (CO_UDP_IP) || defined (FF_GPF_TCPIP)
#include "wap_aci.h"
#include "psa_tcpip.h"
#include "cmh_ipa.h"
#endif /* WAP  || FF_GPF_TCPIP OR SAT E */

#ifdef SIM_TOOLKIT
#include "psa_sat.h"
#include "cmh_sat.h"
#endif

#include "psa_sim.h"
#include "cmh_sim.h"

#include "cmh_snd.h"

/* temp needed because of use of ATI functions here: should eventually disappear */
#include "ati_int.h"

#ifdef FF_GPF_TCPIP
#include "dcm_utils.h"
#include "dcm_state.h"
#include "dcm_env.h"
#endif
#include "dcm_f.h"
#include "psa_uart.h"


/*==== CONSTANTS ==================================================*/

/*==== TYPES ======================================================*/
typedef struct
{
  T_CGEREP_EVENT            event;
  T_CGEREP_EVENT_REP_PARAM  parm;

} T_CGERP_EVENT_BUFFER;

typedef enum
{
  T_CDS_IDLE,
  T_CDS_RUNNING

} T_CONTEXTS_DEACTIVATION_STATUS;

typedef struct
{
  T_CONTEXTS_DEACTIVATION_STATUS state;
  USHORT         nsapi_set;
  T_ACI_CMD_SRC  srcId;
  USHORT         cid_set;

} T_CONTEXTS_DEACTIVATION_INFORMATION;


/*==== EXPORT =====================================================*/

/*==== VARIABLES ==================================================*/
GLOBAL SHORT                nsapi_to_cid[SMH_NSAPI_MAX];
static T_CGSMS_SERVICE      m_service;
static T_CGERP_EVENT_BUFFER gprs_event_buffer[GPRS_EVENT_REPORTING_BUFFER_SIZE];
static SHORT                gprs_eb_current_p, gprs_eb_oldest_p;
static BOOL                 m_mt_te_link;
static BOOL                 call_waits_in_table;
static T_CONTEXTS_DEACTIVATION_INFORMATION  working_cgact_actions;
/*==== FUNCTIONS ==================================================*/

/*
 *  functions for ATA and ATH
 */
/* GLOBAL  BOOL    cmhSM_sAT_H               ( T_ACI_CMD_SRC srcId, T_ACI_RETURN *aci_ret ); */
/* GLOBAL  BOOL    cmhSM_sAT_A               ( T_ACI_CMD_SRC srcId, T_ACI_RETURN *aci_ret ); */
static  BOOL    cmhSM_sAT_A_H_intern      ( T_ACI_CMD_SRC srcId, T_ACI_RETURN *aci_ret, SHORT mode);

/*
 *    functions for DTI
 */
/* GLOBAL ULONG cmhSM_get_link_id_SNDCP_peer ( SHORT cid, T_SNDCP_PEER which ); */
/* GLOBAL BOOL  cmhSM_context_deactivated    ( USHORT nsapi_set ); */

/* GLOBAL T_ACI_RETURN cmhSNDCP_Disable( UBYTE dti_id ); */



/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Init               |
+--------------------------------------------------------------------+

  PURPOSE : Fill variables for the own use with default values.
*/
GLOBAL void cmhSM_Init (void)
{
  SHORT i = 0;

  /* SM CMH global parameter */
  smEntStat.curCmd = AT_CMD_NONE;
  smEntStat.entOwn = OWN_NONE;

  /* GPRS event reporting */
  memset(gprs_event_buffer,     0, sizeof(T_CGERP_EVENT_BUFFER) * GPRS_EVENT_REPORTING_BUFFER_SIZE);
  gprs_eb_current_p = 0;
  gprs_eb_oldest_p  = 0;


  cmhSM_empty_call_table();

  /* used for network requested context reactivation */
  call_waits_in_table = FALSE;

  working_cgact_actions.state     = T_CDS_IDLE;
  working_cgact_actions.nsapi_set = 0;
  working_cgact_actions.srcId     = CMD_SRC_NONE;
  working_cgact_actions.cid_set   = 0;


  /*
   *    The following command has to be in the init and the reset function!!!
   *
   *    Set all to zero in init. In the reset function is a contion action to
   *    not equeal zero.
   */
  memset(pdp_context,0 , sizeof(T_GPRS_CONT_CLASS) * MAX_CID);

  for (i = 0; i < MAX_CID; i++)
  {
    pdp_context[i].link_id_uart = DTI_LINK_ID_NOTPRESENT;
    pdp_context[i].link_id_new  = DTI_LINK_ID_NOTPRESENT;
    pdp_context[i].link_id_sn   = DTI_LINK_ID_NOTPRESENT;
  }

  m_mt_te_link = FALSE;
}

GLOBAL void cmhSM_ResetNonWorkingContexts( void )
{
  SHORT i = 0, j = 0;
  UBYTE srcId = srcId_cb;
  UBYTE gprs_default_pco[] = {
                                0x80,0x80,0x21,0x10,0x01,0x01,0x00,0x10,0x81,0x06,
                                0x00,0x00,0x00,0x00,0x83,0x06,0x00,0x00,0x00,0x00
                             };
  for (i = 0; i < MAX_CID; i++)
  {
    if ( (pdp_context[i].state EQ CS_UNDEFINED) OR (pdp_context[i].state EQ CS_DEFINED) )
    {
     
      for (j = 0; j < SMH_NSAPI_MAX; j++)
      {
        if ( nsapi_to_cid[j] EQ i + 1 )
        {
          nsapi_to_cid[j] = INVALID_CID;
        }
      }

      memset(&pdp_context[i], 0, sizeof(T_GPRS_CONT_CLASS));

      pdp_context[i].state        = CS_UNDEFINED;
      pdp_context[i].smreg_ti     = UNDEFINED_TI;
      pdp_context[i].link_id_uart = DTI_LINK_ID_NOTPRESENT;
      pdp_context[i].link_id_new  = DTI_LINK_ID_NOTPRESENT;
      pdp_context[i].link_id_sn   = DTI_LINK_ID_NOTPRESENT;

      pdp_context[i].user_pco.len = sizeof (gprs_default_pco);
      memcpy (pdp_context[i].user_pco.pco, gprs_default_pco, sizeof (gprs_default_pco));
    }
  }

  memset(work_cids, 0, sizeof(SHORT)  * MAX_CID_PLUS_EINS);
  cid_pointer = 0;

  /* set default context parameter */
  memset(&defaultCtx,   0, sizeof(T_GPRS_CONT_REC));
  strcpy(defaultCtx.pdp_type,"IP" );

  /* mode of CGAUTO*/
  automatic_response_mode = 3;

  m_service = CGSMS_SERVICE_CS_PREFERRED;

  /* GPRS event reporting */
  ati_user_output_cfg[srcId].CGEREP_mode    = CGEREP_MODE_BUFFER;
  ati_user_output_cfg[srcId].CGEREP_bfr     = CGEREP_BFR_CLEAR;
  sm_cgsms_service  = CGSMS_SERVICE_CS_PREFERRED;    
}

GLOBAL void cmhSM_Reset( void )
{
  SHORT i = 0;
  UBYTE gprs_default_pco[] = {
                                0x80,0x80,0x21,0x10,0x01,0x01,0x00,0x10,0x81,0x06,
                                0x00,0x00,0x00,0x00,0x83,0x06,0x00,0x00,0x00,0x00
                             };

  /* SMF CMH local parameter */

  memset(pdp_context,           0, sizeof(T_GPRS_CONT_CLASS) * MAX_CID);

  for (i = 0; i < MAX_CID; i++)
  {
    pdp_context[i].state    = CS_UNDEFINED;
    pdp_context[i].smreg_ti = UNDEFINED_TI;
    pdp_context[i].link_id_uart = DTI_LINK_ID_NOTPRESENT;
    pdp_context[i].link_id_new  = DTI_LINK_ID_NOTPRESENT;
    pdp_context[i].link_id_sn   = DTI_LINK_ID_NOTPRESENT;

    pdp_context[i].user_pco.len = sizeof (gprs_default_pco);
    memcpy (pdp_context[i].user_pco.pco, gprs_default_pco, sizeof (gprs_default_pco));
  }

  memset(work_cids,             0, sizeof(SHORT)  * MAX_CID_PLUS_EINS);

  for (i = 0; i < SMH_NSAPI_MAX; i++)
    nsapi_to_cid[i] = INVALID_CID;

  cid_pointer               = 0;

  /* set default context parameter */
  memset(&defaultCtx,   0, sizeof(T_GPRS_CONT_REC));
  strcpy(defaultCtx.pdp_type,"IP" );

  /* mode of CGAUTO*/
  automatic_response_mode = 3;

  m_service = CGSMS_SERVICE_CS_PREFERRED;

  /* GPRS event reporting */
  ati_user_output_cfg[CMD_SRC_ATI].CGEREP_mode = CGEREP_MODE_BUFFER;
  ati_user_output_cfg[CMD_SRC_ATI].CGEREP_bfr  = CGEREP_BFR_CLEAR;
  sm_cgsms_service  = CGSMS_SERVICE_CS_PREFERRED;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_empty_call_table   |
+--------------------------------------------------------------------+

  PURPOSE : Fill variables for the own use with default values.
*/
GLOBAL void cmhSM_empty_call_table (void)
{
  memset (gprs_call_table, 0, sizeof(T_GPRS_CALL_TABLE) *MAX_GPRS_CALL_TABLE_ENTRIES);
  current_gprs_ct_index = 0;
  gprs_ct_index = 0;
  gprs_call_table[0].sm_ind.smreg_ti = UNDEFINED_TI;
}

/*
+-------------------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                                  |
| STATE   : code             ROUTINE : cmhSM_getSrcIdOfRunningCGACTDeactivation |
+-------------------------------------------------------------------------------+

  PURPOSE : Returns a source ID if the given cid is requested to deactivate
            by +CGACT. The source ID indicates where the +CGACT was started.
*/
GLOBAL T_ACI_CMD_SRC cmhSM_getSrcIdOfRunningCGACTDeactivation(SHORT cid)
{
  switch( working_cgact_actions.state )
  {
    case T_CDS_RUNNING:
      if( (1 << (cid - 1) & working_cgact_actions.cid_set)               OR
           INVALID_NSAPI NEQ pdp_context[cid - 1].nsapi                  AND
          (pdp_context[cid - 1].nsapi & working_cgact_actions.nsapi_set)     )
      {
        return working_cgact_actions.srcId;
      }
      break;
    case T_CDS_IDLE:
      break;
  }
  return CMD_SRC_NONE;
}


/*
+-------------------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                                  |
| STATE   : code             ROUTINE : cmhSM_getSrcIdOfRunningCGACTDeactivation |
+-------------------------------------------------------------------------------+

  PURPOSE : Returns TRUE if +CGACT is running on the given cid -> NO_CARRIER
                    FASE if no CGACT was running on this cid   -> CME_ERROR
*/
GLOBAL BOOL isContextDeactivationRequestedByCGACT(SHORT cid)
{
  TRACE_FUNCTION("***isContextDeactivationRequestedByCGACT");

  switch( working_cgact_actions.state )
  {
    case T_CDS_RUNNING:
      if  ( (1 << (cid - 1)) & working_cgact_actions.cid_set )
      {
        return TRUE;
      }
  }
  return FALSE;
}



/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : code             ROUTINE : cmhSM_connection_down           |
+----------------------------------------------------------------------+

  PURPOSE : Control the answer of context deactivations 
            started by an AT command.
*/
GLOBAL void cmhSM_connection_down( UBYTE dti_id ) 
{
  SHORT cid = gaci_get_cid_over_dti_id( dti_id );

  TRACE_FUNCTION("cmhSM_connection_down");

  switch( working_cgact_actions.state )
  {
    case T_CDS_RUNNING:
      TRACE_EVENT_P1("T_CDS_RUNNING, cid:%d", cid);
      if  ( (1 << (cid - 1)) & working_cgact_actions.cid_set )
      { /* nsapi deactivation is requested */
        working_cgact_actions.cid_set &= (USHORT) ~(1U << (cid - 1));
        TRACE_EVENT_P1("new set: %d",working_cgact_actions.cid_set);

        if ( ! (working_cgact_actions.cid_set  OR
                working_cgact_actions.nsapi_set  ) )
        { 
            R_AT( RAT_OK, working_cgact_actions.srcId ) ( AT_CMD_CGACT );
            working_cgact_actions.state = T_CDS_IDLE;
        }
        else
        {
          TRACE_EVENT_P2("NO OK: cid_set:%d, nsapi_set:%d",working_cgact_actions.cid_set,working_cgact_actions.nsapi_set);
        }
      }
      else
      {      
        TRACE_EVENT_P1("meets not the set: %d",working_cgact_actions.cid_set);
      }
      break;
    case T_CDS_IDLE:
      TRACE_EVENT("T_CDS_IDLE");
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_GetNewNSapi        |
+--------------------------------------------------------------------+

  PURPOSE : Give a free NSapi no. or invalid if all NSapi's are in use.
*/
LOCAL UBYTE cmhSM_GetNewNSapi ( void )
{
  BYTE i = SMH_FIRST_FREE_NSAPIS;

  TRACE_FUNCTION("cmhSM_GetNewNSapi");

  while ( i <= SMH_LAST_FREE_NSAPIS AND nsapi_to_cid[i] NEQ INVALID_CID )
    i++;

  if ( i <= SMH_LAST_FREE_NSAPIS)
  {
    pdp_context[work_cids[cid_pointer] - 1].nsapi = i;
    nsapi_to_cid[i] = work_cids[cid_pointer];

    TRACE_EVENT_P1("new NSAPI: %d", i);

    return i;
  }

  return INVALID_NSAPI;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_GiveNSapiFree      |
+--------------------------------------------------------------------+

  PURPOSE : Give a NSapi free after use.
*/
GLOBAL void cmhSM_GiveNSapiFree ( USHORT cid )
{
  UBYTE *nsapi = &pdp_context[cid - 1].nsapi;
  
  if ( *nsapi <= SMH_LAST_FREE_NSAPIS )
  {
    nsapi_to_cid[*nsapi] = INVALID_CID;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_contextDeactivated |
+--------------------------------------------------------------------+

  PURPOSE : Detach mobile if necessary?
*/
GLOBAL void cmhSM_contextDeactivated ( void )
{

  if  ( ! cmhSM_isContextActive() )
  {
    cmhGMM_allContextsDeactivated();
  }
}


/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Get_pdp_type       |
+--------------------------------------------------------------------+

  PURPOSE : Give the PDP type of the current PDP context that will build.
*/
GLOBAL  UBYTE cmhSM_Get_pdp_type ( void )
{
  if (!strcmp(pdp_context[work_cids[cid_pointer] - 1].con.pdp_type, "IP"))
    return IP_V_4;

  return 0;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Get_pdp_address    |
+--------------------------------------------------------------------+

  PURPOSE : Give the PDP address of the current PDP context that will build.
*/
GLOBAL  void  cmhSM_Get_pdp_address ( T_pdp_address *pdp_address )
{

  pdp_address->c_buff =
          (UBYTE) cmhSM_pdp_address_to_ip(&pdp_context[work_cids[cid_pointer] - 1].con.pdp_addr, (UBYTE*) pdp_address->buff);

#ifdef _SIMULATION_
memset (pdp_address->buff + pdp_address->c_buff, 0, sizeof(pdp_address->buff) - pdp_address->c_buff);
#endif
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_pdp_address_to_ip  |
+--------------------------------------------------------------------+

  PURPOSE : Transform a PDP address to 4 BYTE IP form.
*/
GLOBAL  SHORT  cmhSM_pdp_address_to_ip ( T_PDP_ADDRESS *pdp_address, UBYTE *ip )
{
  SHORT i = 0;
  BOOL  isDynamicIP = TRUE;
  char  *start = *pdp_address,
        *end;

  if ( **pdp_address )
  {
    for (i = 0; i < 4; i++)
    {
      ip[i] = (UBYTE) strtol(start, &end, 10);
      start = end + 1;
     /*
      *   dynamic ip patch
      *   12.02.02 brz
      *
      *   if it is a dynamic IP Address than the SM entity need the length set to zero
      */
      if ( ip[i]  )
      {
        isDynamicIP = FALSE;
      }
    }

    if ( isDynamicIP EQ TRUE )
    {
      return 0;
    }
    else
    {
      return 4;
    }
  }
  else
  {
  *ip = 0;
  }

  return 0;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_ip_to_pdp_address  |
+--------------------------------------------------------------------+

  PURPOSE : Transform a 4 BYTE IP form to the PDP address.
*/
GLOBAL  void  cmhSM_ip_to_pdp_address ( UBYTE *ip, T_PDP_ADDRESS pdp_address )
{

  sprintf(pdp_address, "%03hd.%03hd.%03hd.%03hd", ip[0], ip[1], ip[2], ip[3] );

}

/*
+-------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                 |
| STATE   : finished              ROUTINE : convert_netaddr_to_apn  |
+-------------------------------------------------------------------+

  PURPOSE : converts a domain name into an APN

  Technical Information:

            The APN contains out of labels separated by dots.
            (e.g. xxx.yyy.zzz)

            This string representation must be translated to a network
            representation.

            The APN network representation contains out of a sequence of
            a length field (not ASCII) followed by a ASCII string.

            xxx.yyy.zzz => 3xxx3yyy3zzz
*/
LOCAL void convert_netaddr_to_apn ( T_smreg_apn *apn )
{
  UBYTE counter  = 0, 
        buffer   = apn->buffer[0],
        *pdest   = apn->buffer + apn->c_buffer,
        *psource = pdest - 1;

  if(apn->c_buffer EQ 0)
  {
    return;
  }

  if(apn->c_buffer >= sizeof apn->buffer)
  {
    apn->c_buffer = 0;
    TRACE_EVENT_P2 ("convert_netaddr_to_apn: array out of bounds exeption (%d >= %d)", apn->c_buffer, sizeof apn->buffer);
    return;
  }

  /* The network representation is 1 byte longer. */
  apn->c_buffer++;

  /* A sentinel */
  apn->buffer[0] = '.';
  
  /* Algorithm: copy from back to front! */
  while(pdest > apn->buffer )
  {
    counter = 0;
    while(*psource NEQ '.')
    {
      *(pdest--) = *(psource--);
      counter++;
    }
    *(pdest--) = counter;
    psource--;
  }

  /* Correction according to the sentinel */
  apn->buffer[1] = buffer;
  apn->buffer[0] = ++counter;

  /* Modify special empty APN to the need of SMREG_SAP */
  if ((apn->c_buffer EQ 2) AND (apn->buffer[0] EQ 1) AND (apn->buffer[1] EQ 255))
  {
    apn->c_buffer = 1; /* Special SMREG_SAP indicating that there is an APN present but empty */
    apn->buffer[0]= 0;
  }
}
/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Get_smreg_apn      |
+--------------------------------------------------------------------+

  PURPOSE : Give the APN of the current PDP context that will build.
*/
GLOBAL  void  cmhSM_Get_smreg_apn ( T_smreg_apn *smreg_apn )
{

  smreg_apn->c_buffer = strlen(pdp_context[work_cids[cid_pointer] - 1].con.apn);
  strncpy((char *)smreg_apn->buffer, (const char *)pdp_context[work_cids[cid_pointer] - 1].con.apn, smreg_apn->c_buffer);
  convert_netaddr_to_apn(smreg_apn);

#ifdef _SIMULATION_
memset (smreg_apn->buffer + smreg_apn->c_buffer, 0, sizeof(smreg_apn->buffer) - smreg_apn->c_buffer);
#endif
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Get_h_comp         |
+--------------------------------------------------------------------+

  PURPOSE : Give the h_comp of the current PDP context that will build.
*/
GLOBAL  UBYTE cmhSM_Get_h_comp ( void )
{

  return (UBYTE) pdp_context[work_cids[cid_pointer] - 1].con.h_comp;

}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Get_d_comp         |
+--------------------------------------------------------------------+

  PURPOSE : Give the d_comp of the current PDP context that will build.
*/
GLOBAL  UBYTE cmhSM_Get_d_comp ( void )
{

  return (UBYTE) pdp_context[work_cids[cid_pointer] - 1].con.d_comp;

}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_change_def_QOS     |
+--------------------------------------------------------------------+

  PURPOSE : Set the quality of service (requested) of default context.

*/
GLOBAL  void    cmhSM_change_def_QOS      ( T_QOS *qos )
{

  memcpy(&defaultCtx.qos, qos, sizeof(T_QOS));

}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_change_def_QOS_min |
+--------------------------------------------------------------------+

  PURPOSE : Set the quality of service (min.) of default context.

*/
GLOBAL  void    cmhSM_change_def_QOS_min  ( T_QOS *qos )
{

  memcpy(&defaultCtx.min_qos, qos, sizeof(T_QOS));

}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Set_default_QOS    |
+--------------------------------------------------------------------+

  PURPOSE : Set the quality of service of the spezified PDP context
            to default.
*/
GLOBAL  void  cmhSM_Set_default_QOS ( SHORT cid )
{

  memcpy(&pdp_context[cid - 1].con.qos, &defaultCtx.qos, sizeof(T_QOS));

}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Set_default_QOS    |
+--------------------------------------------------------------------+

  PURPOSE : Set the quality of service of the spezified PDP context
            to default.
*/
GLOBAL  void  cmhSM_Set_default_QOS_min ( SHORT cid )
{

  memcpy(&pdp_context[cid - 1].con.min_qos, &defaultCtx.min_qos, sizeof(T_QOS));

}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Get_QOS            |
+--------------------------------------------------------------------+

  PURPOSE : Give the requested quality of service of the current
            PDP context that will build.
*/
GLOBAL  void  cmhSM_Get_QOS ( T_smreg_qos *dest_qos )
{
  T_QOS *source_qos = &pdp_context[work_cids[cid_pointer] - 1].con.qos;

  dest_qos->preced   = source_qos->preced;
  dest_qos->delay    = source_qos->delay;
  dest_qos->relclass = source_qos->relclass;
  dest_qos->peak     = source_qos->peak;
  dest_qos->mean     = source_qos->mean;

}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_Get_QOS_min        |
+--------------------------------------------------------------------+

  PURPOSE : Give the minimum acceptable quality of service of the
            current PDP context that will build.
*/
GLOBAL  void  cmhSM_Get_QOS_min ( T_smreg_min_qos *dest_qos_min )
{
  T_QOS *source_qos = &pdp_context[work_cids[cid_pointer] - 1].con.min_qos;

  dest_qos_min->preced   = source_qos->preced;
  dest_qos_min->delay    = source_qos->delay;
  dest_qos_min->relclass = source_qos->relclass;
  dest_qos_min->peak     = source_qos->peak;
  dest_qos_min->mean     = source_qos->mean;

}

GLOBAL  USHORT cmhSM_pdp_typ_to_string ( UBYTE pdp_typ_no, char* string )
{
  switch ( pdp_typ_no )
  {
    case 0:
      strcpy (string, "X_121");
      return 5;
    case 33:
      strcpy (string, "IP_V_4");
      return 6;
    case 87:
      strcpy (string, "IP_V_6");
      return 6;
    default:
      strcpy (string, "");
      return 0;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_ring_gprs_par      |
+--------------------------------------------------------------------+

  PURPOSE : Return the information for CRING.
*/
GLOBAL  char* cmhSM_ring_gprs_par ( void )
{
  static char string[MAX_CRING_INFORMATION_LENGTH] = "\"";
  unsigned int i = 1;

  i += cmhSM_pdp_typ_to_string(gprs_call_table[current_gprs_ct_index].sm_ind.pdp_type, string + i);
  string[i++] = '\"';

  string[i++] = ',';

  string[i++] = '\"';
  memcpy (string + i, gprs_call_table[current_gprs_ct_index].sm_ind.pdp_address.buff,
                      gprs_call_table[current_gprs_ct_index].sm_ind.pdp_address.c_buff);

  i += gprs_call_table[current_gprs_ct_index].sm_ind.pdp_address.c_buff + 1;
  string[i++] = '\"';

  if ( *gprs_call_table[current_gprs_ct_index].L2P )
  {
  string[i++] = ',';

  string[i++] = '\"';
  strcpy (string + i, gprs_call_table[current_gprs_ct_index].L2P);
  i += strlen (gprs_call_table[current_gprs_ct_index].L2P);
  string[i++] = '\"';
  }

  string[i] = 0;

  return string;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_call_answer        |
+--------------------------------------------------------------------+

  PURPOSE : Return TRUE in this case, if an auto answer is needed.
*/
GLOBAL  BOOL  cmhSM_call_answer ( UBYTE ring_counter, T_ACI_CRING_MOD mode )
{

  switch(automatic_response_mode)
  {
    case 0: /* GPRS off, GSM controlled by S0 */
      if ( mode NEQ CRING_MOD_Gprs   AND
           at.S[0] AND at.S[0] <= ring_counter )
           return TRUE;
      break;
    case 1: /* GPRS on, GSM controlled by S0 */
      if ( mode EQ CRING_MOD_Gprs )
        return TRUE;
      if (at.S[0] AND at.S[0] <= ring_counter)
        return TRUE;
      break;
    case 2: /* modem copatibility mode, GPRS on, GSM off */
      if ( mode NEQ CRING_MOD_Gprs )
        break;
      /*lint -fallthrough*/
    case 3: /* modem copatibility mode, GPRS on, GSM on */
      if (at.S[0] AND ring_counter >= at.S[0])
        return TRUE;
  }

  return FALSE;
}


/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_call_reject        |
+--------------------------------------------------------------------+

  PURPOSE : Return TRUE in this case, if an auto reject is needed.
*/
GLOBAL  BOOL  cmhSM_call_reject ( UBYTE ring_counter, T_ACI_CRING_MOD mode )
{
  switch(automatic_response_mode)
  {
    case 0: /* GPRS off, GSM controlled by S0 */
      return FALSE;
    case 1: /* GPRS on, GSM controlled by S0 */
      if (at.S99 AND mode EQ CRING_MOD_Gprs )
        return TRUE;
      break;
    case 2: /* modem copatibility mode, GPRS on, GSM off */
    case 3: /* modem copatibility mode, GPRS on, GSM on */
      if ( mode NEQ CRING_MOD_Gprs )
        break;
      if (at.S99 AND ring_counter >= at.S99)
        return TRUE;
  }

  return FALSE;
}




LOCAL BOOL is_GSM_call_active (void)
{
  SHORT ctbIdx;               /* holds call table index */

  for( ctbIdx = 0; ctbIdx < MAX_CALL_NR; ctbIdx++ )
  {
    if (ccShrdPrm.ctb[ctbIdx] NEQ NULL)
    {
      return (TRUE);
    }
  }

  return (FALSE);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_sAT_H              |
+--------------------------------------------------------------------+

  PURPOSE : handle GPRS calls and return FALSE if a circuit switched
            call need a handle.
*/
GLOBAL  BOOL  cmhSM_sAT_H ( T_ACI_CMD_SRC srcId, T_ACI_RETURN *aci_ret )
{

  SHORT cid_array[1] = { INVALID_CID };
  T_ATI_SRC_PARAMS *src_params = find_element (ati_src_list, (UBYTE)srcId, search_ati_src_id);

  if ( ( at.rngPrms.isRng EQ TRUE ) AND ( at.rngPrms.mode EQ CRING_MOD_Gprs) )
  {
   /*
    *   brz patch: In the case of context reactivation over SMREG_PDP_ACTIVATE_IND with an used ti
    *              the GPRS ATH command doesn't do anything!
    *
    *   Why?       Because the Windows Dial-Up Networking client send every time an ATH after termination
    *              of the connection and with this a context reactivation was impossible. 
    */
    if ( gprs_call_table[current_gprs_ct_index].reactivation EQ GCTT_NORMAL )
    {
      return cmhSM_sAT_A_H_intern(srcId, aci_ret, 0);
    }
    return TRUE;
  }
  else
  {
    if (is_GSM_call_active())
    {
      return (FALSE);
    }
   /* if AT_H has been called and no RING is active, then disconnect the active
       context */
#ifdef FF_GPF_TCPIP
    if(is_gpf_tcpip_call())
    {
      T_DCM_STATUS_IND_MSG err_ind_msg;
      err_ind_msg.hdr.msg_id = DCM_ERROR_IND_MSG;
      err_ind_msg.result = DCM_PS_CONN_BROKEN;
      dcm_send_message(err_ind_msg, DCM_SUB_NO_ACTION);
    }
#endif
    *aci_ret = sAT_PlusCGACT ( srcId, CGACT_STATE_DEACTIVATED, cid_array );

    switch (*aci_ret)
    {
      case (AT_CMPL):                         /*operation completed*/
        return FALSE; /* return false, so that GSM calls will be canceled */
      case (AT_EXCT):
        src_params->curAtCmd    = AT_CMD_CGACT;
        return TRUE;
      default:
        cmdCmeError(CME_ERR_Unknown);         /*Command failed*/
        return FALSE;
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_sAT_A              |
+--------------------------------------------------------------------+

  PURPOSE : handle GPRS calls and return FALSE if a circuit switched
            call need a handle.
*/
GLOBAL  BOOL  cmhSM_sAT_A ( T_ACI_CMD_SRC srcId, T_ACI_RETURN *aci_ret )
{
  BOOL b;

  b = cmhSM_sAT_A_H_intern(srcId, aci_ret, 1);

  if ( *aci_ret EQ AT_EXCT )
    cmdErrStr   = NULL;

  return b;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_sAT_A_H_intern     |
+--------------------------------------------------------------------+

  PURPOSE : handle sAT_A and cAT_H for GPRS
*/
static BOOL cmhSM_sAT_A_H_intern ( T_ACI_CMD_SRC srcId, T_ACI_RETURN *aci_ret, SHORT mode)
{
  if ( at.rngPrms.isRng EQ TRUE )
  {
    if ( at.rngPrms.mode EQ CRING_MOD_Gprs)
    {
      *aci_ret =  automatic_response_mode > 1 ? /* modem copatibility mode possible */
                  sAT_PlusCGANS(srcId, mode, NULL, GPRS_CID_OMITTED): AT_FAIL;
    }
    else  /* circuit switched call */
    {
      return FALSE;
    }
  }
  else
  {
     return FALSE;
  }
  return TRUE;
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                    |
| STATE   : finished              ROUTINE : cmhSM_pdp_addr_well_formed |
+----------------------------------------------------------------------+

  PURPOSE : check pdp address of well formed
*/
GLOBAL  BOOL cmhSM_pdp_addr_well_formed( USHORT type, T_PDP_ADDRESS pdp_addr )
{
  SHORT i = 0, state = 1;
  char *start = pdp_addr, *end;
  long temp;

  switch ( type )
  {
    case PDP_T_IP:  /* 255.255.255.255 */
      if ( *pdp_addr )
      {
        while ( state AND i < 3)
        {
          temp = strtol(start, &end, 10);
          if ( temp < 0 OR temp > 255 )
            state = 0;
          if ( *end NEQ '.' )
            state = 0;

          start = end + 1;
          i++;
        }
        temp = strtol(start, &end, 10);
        if ( temp < 0 OR temp > 255 )
          state = 0;
      }

      if(state)
        return TRUE;
      break;
    case PDP_T_X25:
      return FALSE;
    default:
      break;
  }
  return FALSE;
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                    |
| STATE   : finished              ROUTINE : cmhSM_apn_well_formed      |
+----------------------------------------------------------------------+

  PURPOSE : check APN of well formed
*/
GLOBAL  BOOL cmhSM_apn_well_formed( T_APN APN )
{
  SHORT i = 0, state = 1, length = strlen (APN);
  char *no_start_labels[] = {"rac","lac","sgsn"}, *start, *end, *mark;
  T_APN apn;

  strcpy(apn, APN);
  start = apn;

  /* change charcter of string to lower cases */
  for (i = 0; i < length; i++)
    apn[i] = tolower(apn[i]);

  /* The Network Identifier shall not start with this labels */
  for (i = 0; i < 3; i++)
  {
    if ( apn EQ strstr(apn, no_start_labels[i]) )
      return FALSE;
  }

  /* the Wild Card APN */
  if ( length EQ 1 AND *start EQ '*' )
    return TRUE;

  /* the APN with no name */
  if ( length EQ 1 AND *start EQ /*lint -e(743)*/ '\x0ff' )
    return TRUE;

  /* Oporater Identifer is optional and the Network Identifer */
  mark = strrchr(apn, '.');
  if ( mark )
    if ( strstr(mark + 1, "gprs") )
    {
      /* APN Operator Identifier contained (optional) */
      if ( length < 18 )
        return FALSE;
      mark = start + length - 18; /* start of the APN Operator Identifier */
      /* check APN Operator Identifier: "mncXXX.mccXXX.gprs" */
      if ( mark NEQ strstr(mark, "mnc") )
        return FALSE;
      if ( mark + 6 NEQ strstr(mark, ".mcc") )
        return FALSE;
      strtol(mark + 3, &end, 10);
      if ( end NEQ mark + 6 )
        return FALSE;
      strtol(mark + 10, &end, 10);
      if ( end NEQ mark + 13 )
        return FALSE;
      /* check character between APN Network Identifier and the Operator Identifer */
      mark--;
      if ( *mark NEQ '.' )
        return FALSE;
      /* set stop mark */
      *mark = 0;
    }
    else
      mark = 0;

  /* check APN Network Identifier */

  /* shall not end in ".gprs" */
  end = strrchr(apn, '.');
  if ( end )
    if ( strstr(end + 1, "gprs") )
      return FALSE;

  /* parse all labels */
  while ( *start )
  {
    /* in first at least one Label */
    while ( (*start >= 'a' AND *start <= 'z') OR (*start >= '0' AND *start <= '9') OR *start EQ '-' )
      start ++;

    /* next Label or nothing */
    if ( *start EQ '.' )
      start ++;
    else
      if ( *start NEQ 0)
        return FALSE;
  }

  /* The APN Network Identifier shall have a maximum length of 63 octets. */
  if ( start - apn > 63 )
    return FALSE;

  /* clear stop mark */
  if ( mark )
    *mark = '.';

  return TRUE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GPRS (8441)           MODULE  : CMH_SMF                  |
| STATE   : finished              ROUTINE : cmhSM_transform_pdp_type |
+--------------------------------------------------------------------+

  PURPOSE : transform pdp_type
*/
GLOBAL  USHORT cmhSM_transform_pdp_type      ( char *pdp_type )
{

  if ( !strcmp(pdp_type, "IP") )
    return PDP_T_IP;

  if ( !strcmp(pdp_type, "X25") )
    return PDP_T_X25;

  return PDP_T_NONE;
}


GLOBAL  T_CONTEXT_STATE get_state_over_cid ( SHORT cid )
{
  TRACE_FUNCTION("get_state_over_cid()");
  if ( (cid < 1) OR (cid > MAX_CID) )
  {
    TRACE_EVENT("invalid cid detected!");
    return CS_INVALID_STATE;
  }
  return pdp_context[cid - 1].state;

}

GLOBAL  void set_state_over_cid ( SHORT cid, T_CONTEXT_STATE c_state )
{
  TRACE_EVENT_P3("set_state_over_cid: %d -> %d for cid %d", pdp_context[cid - 1].state, c_state, cid) ;
  if (cid > 0 AND cid <= MAX_CID)
    pdp_context[cid - 1].state = c_state;
}

GLOBAL  T_CONTEXT_STATE   get_state_working_cid ( void )
{

  if ( work_cids[cid_pointer] EQ INVALID_CID )
  {
    TRACE_EVENT("working_cid is invalid!");
    return CS_INVALID_STATE;
  }

  return pdp_context[work_cids[cid_pointer] - 1].state;

}

GLOBAL  void  set_conn_param_on_all_working_cids ( UBYTE owner, T_DTI_ENTITY_ID entity_id )
{
  SHORT *pcid = &(work_cids[cid_pointer]);

  TRACE_FUNCTION("set_conn_param_on_all_working_cids()");

  while(INVALID_CID NEQ *pcid) {
    pdp_context[*pcid - 1].owner     = owner;
    pdp_context[*pcid - 1].entity_id = entity_id;
    pcid ++;
  }
}

GLOBAL  void  set_conn_param_on_working_cid ( UBYTE owner, T_DTI_ENTITY_ID entity_id )
{
  TRACE_FUNCTION("set_conn_param_on_working_cid()");
  
  pdp_context[work_cids[cid_pointer] - 1].owner     = owner;
  pdp_context[work_cids[cid_pointer] - 1].entity_id = entity_id;
}

GLOBAL  void  set_state_working_cid ( T_CONTEXT_STATE c_state )
{
  TRACE_FUNCTION("set_state_working_cid()");

  if ( work_cids[cid_pointer] NEQ INVALID_CID )
  {
    pdp_context[work_cids[cid_pointer] - 1].state = c_state;
  }
  else
  {
    TRACE_EVENT("working cid is invalid!");
  }

}

GLOBAL  T_CONTEXT_STATE   get_state_over_nsapi_set ( USHORT *nsapi_set, SHORT *cid )
{
  USHORT nsapi = 0;

  TRACE_FUNCTION("get_state_over_nsapi_set()");
  while( nsapi < SMH_LAST_FREE_NSAPIS AND !((*nsapi_set >> nsapi) & 1) )
    nsapi++;

  if ( !(*nsapi_set & ( 1 << nsapi )) )
  {
    return CS_INVALID_STATE;
  }

  TRACE_EVENT_P1("NSAPI: %4d", nsapi);

  *nsapi_set &= ~( 1U << nsapi );

  return get_state_over_cid( *cid = nsapi_to_cid[nsapi] );

}

GLOBAL  T_CONTEXT_STATE   get_state_over_nsapi ( USHORT nsapi )
{

  return get_state_over_cid( nsapi_to_cid[nsapi] );

}

GLOBAL  USHORT  cmhSM_Give_nsapi_set ( SHORT cid )
{

  if ( (cid < 1) OR (cid > MAX_CID) )
    return 0;

  return  1 << pdp_context[cid - 1].nsapi;

}

GLOBAL  T_ACI_CAL_OWN  get_owner_over_cid ( SHORT cid )
{

  if ( (cid < 1) OR (cid > MAX_CID) )
    return CAL_OWN_NONE;

  return pdp_context[cid - 1].owner;

}

GLOBAL void cmhGPPP_send_establish_request ( UBYTE peer )
{
  T_PPP_ESTABLISH_REQ est_req;

  memset(&est_req, 0, sizeof( T_PPP_ESTABLISH_REQ ));

  est_req.mode       = PPP_SERVER;
  est_req.mru        = PPP_MRU_DEFAULT;
  est_req.ap         = gpppShrdPrm.ppp_authentication_protocol;
  est_req.accm       = gpppShrdPrm.accm;
  est_req.rt         = gpppShrdPrm.restart_timer;
  est_req.mc         = gpppShrdPrm.max_configure;
  est_req.mt         = gpppShrdPrm.max_terminate;
  est_req.mf         = gpppShrdPrm.max_failure;

  est_req.peer_direction = DTI_CHANNEL_TO_LOWER_LAYER;
  est_req.prot_direction = DTI_CHANNEL_TO_HIGHER_LAYER;

  est_req.peer_link_id = pdp_context[work_cids[0] - 1].link_id_uart;
  est_req.prot_link_id = pdp_context[work_cids[0] - 1].link_id_new;

#ifdef _SIMULATION_
  memset (est_req.peer_channel.peer_entity,         0, CHANNEL_NAME_LENGTH);
  memset (est_req.protocol_channel.protocol_entity, 0, CHANNEL_NAME_LENGTH);
#endif  /* _SIMULATION_ */

  strcpy ( (char *) est_req.protocol_channel.protocol_entity, SNDCP_NAME);

  switch (peer)
  {
#ifdef BT_ADAPTER
    case DTI_ENTITY_BLUETOOTH:
      strcpy ( (char *) est_req.peer_channel.peer_entity, BTI_NAME);
      break;
#endif
    case DTI_ENTITY_UART:
      strcpy ( (char *) est_req.peer_channel.peer_entity, UART_NAME);
      break;
#ifdef FF_PSI      
    case DTI_ENTITY_PSI:
      strcpy ( (char *) est_req.peer_channel.peer_entity, PSI_NAME);
      break;
#endif /*FF_PSI*/
    case DTI_ENTITY_AAA:
      strcpy ( (char *) est_req.peer_channel.peer_entity, RIV_NAME);
      break;

    default:
      TRACE_ERROR ("[cmhGPPP_send_establish_request()] Unexpected peer!");
      return;
  }

  psaGPPP_Establish ( &est_req );

  set_state_working_cid( CS_ESTABLISH_1 );
}

GLOBAL void cmhSM_cgerep_buffer ( void )
{
  UBYTE srcId = srcId_cb;

  switch (ati_user_output_cfg[srcId].CGEREP_bfr)
  {
    case CGEREP_BFR_CLEAR:
      memset(gprs_event_buffer, 0, sizeof(T_CGERP_EVENT_BUFFER) * GPRS_EVENT_REPORTING_BUFFER_SIZE);
     break;
    case CGEREP_BFR_FLUSH:
      if ( uart_is_mt_te_link EQ FALSE)
      {
        while ( gprs_eb_oldest_p NEQ gprs_eb_current_p )
        {
          R_AT( RAT_CGEREP, srcId )
              ( gprs_event_buffer[gprs_eb_oldest_p].event, gprs_event_buffer[gprs_eb_oldest_p].parm );

          gprs_eb_oldest_p++;
        }
      }
      break;
    case CGEREP_BFR_OMITTED:
    case CGEREP_BFR_INVALID:
    default:
      break;
  }
}

GLOBAL void cmhSM_save_event( T_CGEREP_EVENT event, T_CGEREP_EVENT_REP_PARAM *param )
{

  /* save event */
  gprs_event_buffer[gprs_eb_current_p].event = event;
  if (param)
    memcpy (&gprs_event_buffer[gprs_eb_current_p].parm, param, sizeof(T_CGEREP_EVENT_REP_PARAM));

  /* is buffer full */
  if ( gprs_eb_oldest_p EQ gprs_eb_current_p )
    gprs_eb_oldest_p = -1;

  /* new current pointer */
  gprs_eb_current_p++;
  if ( gprs_eb_current_p EQ GPRS_EVENT_REPORTING_BUFFER_SIZE )
    gprs_eb_current_p = 0;

  /* if buffer full correct pointer to oldest event */
  if ( gprs_eb_oldest_p EQ -1 )
    gprs_eb_oldest_p = gprs_eb_current_p;

}

GLOBAL void cmhSM_set_sms_service     ( T_CGSMS_SERVICE service )
{

  {
    PALLOC (mnsms_mo_serv_req, MNSMS_MO_SERV_REQ);

    /* fill in primitive parameter: command request */
    mnsms_mo_serv_req -> mo_sms_serv = (UBYTE) service;

    PSENDX (SMS, mnsms_mo_serv_req);
  }

  m_service = service;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                      |
| STATE   : finnished        ROUTINE : cmhSM_sms_service_changed    |
+-------------------------------------------------------------------+

  PURPOSE : indicates a network initiated PDP context modification

*/
GLOBAL void cmhSM_sms_service_changed ( UBYTE service )
{

  TRACE_FUNCTION ("cmhSM_sms_service_changed()");

/*
 *-------------------------------------------------------------------
 * check for command context
 *-------------------------------------------------------------------
 */
  if ( smEntStat.curCmd EQ AT_CMD_CGSMS )
  {
    if ( m_service EQ service )
    {
      sm_cgsms_service = m_service;
      R_AT( RAT_OK, smEntStat.entOwn ) ( smEntStat.curCmd );
    }
    else
    {
      R_AT( RAT_CME, smEntStat.entOwn ) ( smEntStat.curCmd, CME_ERR_Unknown );
      /* log result */
      cmh_logRslt ( smEntStat.entOwn, RAT_CME, smEntStat.curCmd, -1, -1, CME_ERR_Unknown );
    }

    smEntStat.curCmd = AT_CMD_NONE;
  }
}

GLOBAL T_ACI_RETURN cmhSM_GprsAttached( SHORT state )
{
  SHORT i = 1;

  TRACE_FUNCTION ("cmhSM_GprsAttached()");

  if ( state )
  { /* mobile is attached */
    switch ( get_state_working_cid( ) )
    {
    case CS_ATTACHING_AFTER_DEF:
    case CS_ATTACHING_AFTER_UNDEF:
      cmhSM_data_link_context();
      return AT_EXCT;
    case CS_WAITS_FOR_ACTIVATING:
      if (cmhSM_activate_context() NEQ AT_FAIL)
      {
          return AT_EXCT;
      }
      else /*GPRS is not allowed by FDN */
      {
          return AT_FAIL;
      }      
    default:
      return AT_FAIL;
    }
  }
  else
  { /* attach failed */
    if (  smEntStat.curCmd  EQ AT_CMD_NONE AND
          gpppEntStat.curCmd EQ AT_CMD_NONE    )
      return AT_FAIL;

    /*
     *  it is enough to check only the working cid, 
     *  because only one context can be in work 
     */
    switch ( get_state_working_cid( ) )
    {
    case CS_ATTACHING_AFTER_DEF:
    case CS_ATTACHING_AFTER_UNDEF:
        pdp_context[work_cids[cid_pointer] - 1].owner = gpppEntStat.entOwn;
        gaci_RAT_caller ( RAT_NO_CARRIER, work_cids[cid_pointer], AT_CMD_CGDATA, 0 );
        break;    
    case CS_WAITS_FOR_ACTIVATING:
      pdp_context[work_cids[cid_pointer] - 1].owner = smEntStat.entOwn;
      gaci_RAT_caller ( RAT_CME, work_cids[cid_pointer], AT_CMD_CGACT, CME_ERR_GPRSUnspec );
      break;
    default:
      /*
       *  do nothing, because SM informs ACI over context deactivation
       */
      return AT_FAIL;
    }
    return cmhSM_deactivateAContext( smEntStat.entOwn, work_cids[cid_pointer] );
  }
}

GLOBAL T_ACI_RETURN cmhSM_activate_context(void)
{
  TRACE_FUNCTION ("cmhSM_activate_context()");

  if (pb_get_fdn_mode () EQ FDN_ENABLE)
  {
    if (pb_check_fdn (0, (const UBYTE *)"*99#") NEQ PHB_OK)
    {
      TRACE_EVENT("Activate Context: Entry not found in FDN, GPRS not allowed.");
      ACI_ERR_DESC( ACI_ERR_CLASS_Cme, CME_ERR_OpNotAllow);
      return (AT_FAIL);
    }
    TRACE_EVENT("Activate Context: Entry found in FDN, GPRS allowed.");
  }
  
  if( AT_CMPL EQ cmhGMM_contextActivation(smEntStat.entOwn, AT_CMD_CGACT) )
  {
    cmhSM_connect_working_cid();
    set_state_working_cid( CS_ACTIVATING );
  }
  else  /* AT_EXCT -> class BX class change requested (NOMIII) */
  {
    set_state_working_cid( CS_WAITS_FOR_ACTIVATING );  
  }
  return (AT_EXCT);
}


#if defined (CO_UDP_IP) || defined (FF_GPF_TCPIP)
/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)                 MODULE  : cmh_smf              |
| STATE   : initial                     ROUTINE : cmhSM_IP_activate_cb |
+----------------------------------------------------------------------+

  PURPOSE : callback function for WAP over GPRS.
            While handling the command ATD*98# in function atGD()
            the function psaTCPIP_Activate() is called for WAP handling.
            psaTCPIP_Activate() has this function as parameter for
            call backs.
*/
void cmhSM_IP_activate_cb(T_ACI_RETURN result)
{
  SHORT cid = gaci_get_cid_over_dti_id(wap_dti_id);
  
  TRACE_FUNCTION("cmhSM_IP_activate_cb");
  TRACE_EVENT_P1("wap_state: %s",wap_state_to_string(wap_state));
#ifndef FF_SAT_E
  ACI_ASSERT(DTI_DTI_ID_NOTPRESENT NEQ wap_dti_id);
  ACI_ASSERT(cid >= GPRS_CID_1 AND cid < GPRS_CID_INVALID);
  ACI_ASSERT(result NEQ AT_FAIL);
#endif /* not FF_SAT_E */

  if ( result EQ AT_FAIL )
  {
    /* IP activation failed. */
    TRACE_EVENT("UDP/TCP/IP activation/configuration returned AT_FAIL");
    
    if (DTI_LINK_ID_NOTPRESENT NEQ wap_dti_id)
    {
      dti_cntrl_close_dpath_from_dti_id (wap_dti_id);
      cmhSM_disconnect_cid(cid, GC_TYPE_WAP );
    }

    /* reset work_cids */
    set_state_over_cid(cid, CS_DEFINED);
    sAT_PercentWAP(smShrdPrm.owner, 0);
    smEntStat.curCmd = AT_CMD_NONE;
    dti_cntrl_erase_entry(wap_dti_id);
    cmdCmeError(CME_ERR_Unknown);

#if defined (SIM_TOOLKIT) AND defined (FF_SAT_E)
    if( cmhSAT_OpChnGPRSPend( INVALID_CID, OPCH_EST_REQ ))
    {
      cmhSAT_OpChnUDPDeactGprs();
    }
#endif  /* SIM_TOOLKIT */
    return;
  }

  switch(wap_state)
  {
    /* in case CO_UDP_IP and FF_GPF_TCPIP is defined this is a fall through case */
    UDPIP_STATEMENT(case IPA_Activated:)
    GPF_TCPIP_STATEMENT(case TCPIP_Activation:)

      if(is_gpf_tcpip_call()) {
        GPF_TCPIP_STATEMENT(set_conn_param_on_working_cid( 
                            (UBYTE)smEntStat.entOwn, DTI_ENTITY_TCPIP));
      }
      else {
        UDPIP_STATEMENT(set_conn_param_on_working_cid( 
                        (UBYTE)smEntStat.entOwn, DTI_ENTITY_IP));
      }
      cmhSM_activate_context();
      return;

    UDPIP_STATEMENT(case UDPA_Configurated:)
    GPF_TCPIP_STATEMENT(case TCPIP_Configurated:)

      /* smEntStat.curCmd = AT_CMD_NONE; */
#if defined (SIM_TOOLKIT) AND defined (FF_SAT_E)
      if( cmhSAT_OpChnGPRSPend( INVALID_CID, OPCH_EST_REQ ))
      {
        cmhSAT_OpChnUDPConfGprs();
      }
      else
#endif  /* SIM_TOOLKIT */
      {
        R_AT ( RAT_CONNECT, smEntStat.entOwn )( AT_CMD_CGACT, -1, wapId, FALSE );
      }
      smEntStat.curCmd = AT_CMD_NONE;
      smEntStat.entOwn = OWN_NONE;
#ifdef FF_GPF_TCPIP
      if(is_gpf_tcpip_call())
      {
        T_DCM_STATUS_IND_MSG msg;
        msg.hdr.msg_id = DCM_NEXT_CMD_READY_MSG;
        dcm_send_message(msg, DCM_SUB_WAIT_CGACT_CNF);
      }
#endif
      break;

    UDPIP_STATEMENT(case IPA_Deactivated:)
    GPF_TCPIP_STATEMENT(case TCPIP_Deactivated:)

      TRACE_EVENT_P1("cmhSM_IP_activate_cb, no connection, dti_id = %d", wap_dti_id);
#if defined (SIM_TOOLKIT) AND defined (FF_SAT_E)
      if( cmhSAT_OpChnGPRSPend( INVALID_CID, OPCH_NONE ))
      {
        cmhSAT_OpChnUDPDeactGprs();
      }
      else
#endif  /* SIM_TOOLKIT */
      {
        R_AT( RAT_NO_CARRIER,  pdp_context[cid - 1].owner) ( AT_CMD_CGDATA, 0 );
      }
      dti_cntrl_close_dpath_from_dti_id (wap_dti_id);
      cmhSM_connection_down(wap_dti_id);
      cmhSM_disconnect_cid(cid, GC_TYPE_WAP );
      sAT_PercentWAP(smShrdPrm.owner, 0);
      if(work_cids[cid_pointer] EQ cid)
      {
        smEntStat.curCmd = AT_CMD_NONE;
        *work_cids = 0;
        cid_pointer = 0;
      }
#ifdef FF_GPF_TCPIP
      if(is_gpf_tcpip_call())
      {
        T_DCM_STATUS_IND_MSG msg;
        msg.hdr.msg_id = DCM_NEXT_CMD_READY_MSG;
        dcm_send_message(msg, DCM_SUB_WAIT_CGDEACT_CNF);
      }
#endif
      break;

    default:
      TRACE_EVENT("Unexpected wap state in cmhSM_IP_activate_cb()");
      if(is_gpf_tcpip_call()) {
        GPF_TCPIP_STATEMENT(srcc_delete_count(SRCC_TCPIP_SNDCP_LINK ));
      }
      else {
        UDPIP_STATEMENT(srcc_delete_count(SRCC_IP_SNDCP_LINK ));
      }
      dti_cntrl_erase_entry(wap_dti_id);
      sAT_PercentWAP(smShrdPrm.owner, 0);
      smEntStat.curCmd = AT_CMD_NONE;

#if defined (SIM_TOOLKIT) AND defined (FF_SAT_E)
      if( cmhSAT_OpChnGPRSPend( INVALID_CID, OPCH_NONE ))
      {
        cmhSAT_OpChnUDPDeactGprs();
      }
      else
#endif  /* SIM_TOOLKIT */
      {
        cmdCmeError(CME_ERR_Unknown);
      }
      break;
  }
  return;
}


/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)                 MODULE  : cmh_smf              |
| STATE   : initial                     ROUTINE : cmhSM_IP_Enable      |
+----------------------------------------------------------------------+

  PURPOSE : enables IP dti connection.
*/
GLOBAL void cmhSM_IP_Enable ( T_DTI_CONN_LINK_ID link_id)
{
  TRACE_FUNCTION("cmhSM_IP_Enable");

#ifdef _SIMULATION_
  cmhSM_connect_context ( gaci_get_cid_over_link_id( link_id ),
                          DTI_ENTITY_IP, 0, 100 );
#else  /* _SIMULATION_ */
  cmhSM_connect_context ( gaci_get_cid_over_link_id( link_id ),
                          DTI_ENTITY_IP, 0, 0 );
#endif /* _SIMULATION_ */
}


/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)                 MODULE  : cmh_smf              |
| STATE   : initial                     ROUTINE : cmhSM_IP_Disable     |
+----------------------------------------------------------------------+

  PURPOSE : disables IP dti connection.
*/
GLOBAL void cmhSM_IP_Disable ()
{
  TRACE_FUNCTION("cmhSM_IP_Disable");
}

#endif /* WAP || FF_GPF_TCPIP || SAT E */

/*
+-------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                      |
| STATE   : finnished        ROUTINE : cmhSM_data_link_context      |
+-------------------------------------------------------------------+
*/

GLOBAL void cmhSM_data_link_context(void)
{

  TRACE_FUNCTION ("cmhSM_data_link_context()");

  R_AT( RAT_CONNECT, pdp_context[work_cids[cid_pointer] - 1].owner )
    ( AT_CMD_CGDATA, 0, 0, FALSE );

  /* log result */
  cmh_logRslt ( pdp_context[work_cids[cid_pointer] - 1].owner,
                RAT_CONNECT, AT_CMD_CGDATA, -1, -1, -1 );

  cmhSM_connect_working_cid();

}
/*
+-------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                      |
| STATE   : finnished        ROUTINE : cmhSM_get_cid                |
+-------------------------------------------------------------------+

*/

GLOBAL  SHORT   cmhSM_get_cid ( USHORT nsapi )
{

  return nsapi_to_cid[nsapi];
}

/*
+-------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                      |
| STATE   : finnished        ROUTINE : cmhSM_next_work_cid          |
+-------------------------------------------------------------------+

  PURPOSE : start the next context activation if requested

*/
GLOBAL  BOOL    cmhSM_next_work_cid ( T_ACI_AT_CMD curCmd )
{

  TRACE_EVENT_P1("cmhSM_next_work_cid, cid_pointer: %d", cid_pointer);

  cid_pointer ++;

  if ( work_cids[cid_pointer] EQ INVALID_CID )
  {
    smEntStat.curCmd = AT_CMD_NONE;
    gpppEntStat.curCmd = AT_CMD_NONE;

    cid_pointer  = 0;
    *work_cids = 0;
    return FALSE;
  }

  switch ( curCmd )
  {
    case AT_CMD_CGDATA:
      cmhSM_data_link_context();
      break;
    case AT_CMD_CGACT:
      if(AT_FAIL EQ cmhSM_activate_context())
      {
         smEntStat.curCmd = AT_CMD_NONE;
         gpppEntStat.curCmd = AT_CMD_NONE;
         cid_pointer  = 0;
         *work_cids = 0;
         /*R_AT (RAT_CME, smEntStat.entOwn)( AT_CMD_CGACT, CME_ERR_Unknown );*/
         return FALSE;
      }      
      break;
    default:
      cid_pointer  = 0;
      *work_cids = 0;
      return FALSE;
  }
  return TRUE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                      |
| STATE   : finnished        ROUTINE : cmhSM_define_cid_list        |
+-------------------------------------------------------------------+

  PURPOSE : define all cid's in the list, if necessary

*/
GLOBAL SHORT cmhSM_define_cid_list( T_ACI_CMD_SRC srcId, SHORT *cids )
{
  int i = 1;
  
  TRACE_FUNCTION("cmhSM_define_cid_list");  
 
  if(INVALID_CID != *work_cids)
  {
    return 0;  
  }

  if ( *cids EQ GPRS_CID_OMITTED) /* if no cid given */
  {
    while ( i <= MAX_CID AND get_state_over_cid( (SHORT)i ) NEQ CS_DEFINED )
      i++;

    if ( i > MAX_CID )
    {
      i = 1;
      while ( i <= MAX_CID AND get_state_over_cid( (SHORT)i ) NEQ CS_UNDEFINED )
        i++;

      if ( i <= MAX_CID )
      {
       /*
        *  reset of context parameter if cid undefined
        */
        sAT_PlusCGDCONT_exec (srcId, (SHORT)i, &defaultCtx);
        set_state_over_cid((SHORT)i, CS_UNDEFINED);
      }
      else
        return 0;
    }

    *cids = work_cids[0] = i;
    work_cids[1] = INVALID_CID;
    i = 1; /* no. of cids */
  }
  else  /* if cid(s) is/are given */
  {
    SHORT j = 0;
    i = 0;

    /*
     *  checks given cid parameter
     */
    while ( i < MAX_CID AND cids[i] NEQ INVALID_CID )
    {
      /* check cid */
      if ( cids[i] < GPRS_CID_1 OR cids[i] >= GPRS_CID_INVALID )
        return 0;
      /* count cids */
      i++;
    }

    if ( MAX_CID < i )
      return 0;

    memcpy (work_cids, cids, sizeof( *work_cids ) * (i + 1) );

    /*
     *  reset of context parameter if cid undefined
     */
    for (j = 0; work_cids[j] NEQ INVALID_CID; j++)
    {
      switch(get_state_over_cid(work_cids[j]))
      {
        case CS_UNDEFINED:
          sAT_PlusCGDCONT_exec (srcId, work_cids[j], &defaultCtx);
          set_state_over_cid(work_cids[j], CS_UNDEFINED);
          /*lint -fallthrough*/
        case CS_DEFINED:
        case CS_ACTIVATED:
          break;
        default:
          memset (work_cids, 0, sizeof( *work_cids ) * (i + 1) );
          return 0;
      }
    }
  }
  
  return i;
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_get_pdp_addr_for_CGPADDR  |
+----------------------------------------------------------------------+

  PURPOSE : return the PDP_address to one cid for the GPRS CGPADDR AT command

*/
GLOBAL SHORT cmhSM_get_pdp_addr_for_CGPADDR ( SHORT cid, T_PDP_ADDRESS pdp_adress )
{
  T_CONTEXT_STATE c_state;      /* state of context */

  c_state = get_state_over_cid( cid );

  if ( c_state EQ CS_UNDEFINED OR c_state EQ CS_INVALID_STATE )
  {
    *pdp_adress = 0;
    return INVALID_CID;
  }

  if ( c_state EQ CS_ACTIVATED OR c_state EQ CS_DATA_LINK )
    strcpy( pdp_adress, pdp_context[cid - 1].allocated_pdp_addr );
  else
    strcpy( pdp_adress, pdp_context[cid - 1].con.pdp_addr );

  return cid;
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_is_smreg_ti_used          |
+----------------------------------------------------------------------+

  PURPOSE : handle for used smreg_ti

*/
GLOBAL BOOL cmhSM_is_smreg_ti_used ( UBYTE smreg_ti, SHORT *cid )
{
  SHORT i = 0;

  while ( i < MAX_CID )
  {
    if ( pdp_context[i].smreg_ti EQ smreg_ti)
    {
      psaSM_PDP_Deactivate ( (USHORT) (1 << pdp_context[i].nsapi), SMREG_LOCAL);
      psaGPPP_Terminate( PPP_LOWER_LAYER_UP );

      call_waits_in_table = TRUE;
      *cid = i + 1;
      set_state_over_cid(*cid, CS_CONTEXT_REACTIVATION_1);
      return TRUE;
    }

    i++;
  }

  return FALSE;
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_context_reactivation      |
+----------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL void cmhSM_context_reactivation ( void )
{
  T_CGEREP_EVENT_REP_PARAM  event;
  T_SMREG_PDP_ACTIVATE_IND *sm_ind;
  SHORT i = 0;

  if ( call_waits_in_table EQ TRUE )
  {
    call_waits_in_table = FALSE;
   /*
    *   GPRS event reporting
    */
    sm_ind = &gprs_call_table[current_gprs_ct_index].sm_ind;

    cmhSM_pdp_typ_to_string(sm_ind->pdp_type, (char*) &event.act.pdp_type);
    memcpy(&event.act.pdp_addr, &sm_ind->pdp_address.buff, sm_ind->pdp_address.c_buff);
    event.act.cid      = gprs_call_table[current_gprs_ct_index].cid;
    for( i = 0 ; i < CMD_SRC_MAX; i++ )
    {
      R_AT( RAT_CRING, i )  ( CRING_MOD_Gprs, CRING_TYP_GPRS, CRING_TYP_NotPresent );
      R_AT( RAT_CGEREP, i ) ( CGEREP_EVENT_NW_REACT, &event );
      R_AT( RAT_P_CGEV, i ) ( CGEREP_EVENT_NW_REACT, &event );
    }
  }
  else
  {
    cmhSM_next_call_table_entry();
  }
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_stop_context_reactivation |
+----------------------------------------------------------------------+

  PURPOSE :

*/
GLOBAL void cmhSM_stop_context_reactivation ( void )
{

  call_waits_in_table = FALSE;
}

GLOBAL void cmhSM_next_call_table_entry( void )
{
  current_gprs_ct_index++;

  if ( current_gprs_ct_index >= gprs_ct_index )
  {
    cmhSM_empty_call_table();
  }
  else
  {
    cmhSM_context_reactivation();
  }
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_init_GPRS_DTI_list        |
+----------------------------------------------------------------------+

  PURPOSE : Init all DTI identifier for GPRS.
*/
GLOBAL SHORT cmhSM_connect_working_cid ( void )
{
  T_GPRS_CONT_CLASS *context_info = &pdp_context[work_cids[cid_pointer] - 1];

  switch ( context_info->entity_id )
  {
    case DTI_ENTITY_PPPS:
      srcc_new_count(SRCC_PPPS_SNDCP_LINK);

      if (IS_SRC_BT(context_info->owner))
      {
        T_DTI_ENTITY_ID entity_list[] = {DTI_ENTITY_BLUETOOTH, DTI_ENTITY_PPPS, DTI_ENTITY_SNDCP};
        UBYTE dti_id = dti_cntrl_new_dti(DTI_DTI_ID_NOTPRESENT);
        dti_cntrl_est_dpath ( dti_id,
                              entity_list,
                              3,
                              SPLIT,
                              PPP_UART_connect_dti_cb);
      }
      else
      {
        T_DTI_ENTITY_ID entity_list[] = {DTI_ENTITY_PPPS, DTI_ENTITY_SNDCP};
        dti_cntrl_est_dpath_indirect ((UBYTE)context_info->owner, 
                                       entity_list, 
                                       2, 
                                       SPLIT, 
                                       PPP_UART_connect_dti_cb, 
                                       DTI_CPBLTY_SER, 
                                       (UBYTE)work_cids[cid_pointer]);
      }

      m_mt_te_link = TRUE;
      break;
      
    case DTI_ENTITY_IP:
#ifdef CO_UDP_IP
      {
        T_DTI_ENTITY_ID entity_list[] = {DTI_ENTITY_IP, DTI_ENTITY_SNDCP};
        UBYTE dti_id;
#ifdef FF_SAT_E
        if ( satShrdPrm.opchStat EQ OPCH_EST_REQ )
          dti_id = simShrdPrm.sat_class_e_dti_id;
        else
#endif /* FF_SAT_E */          
          dti_id = wap_dti_id;

        /* link_id should be created in atGD already, so just connect: */
        if (!dti_cntrl_est_dpath( dti_id,
                                  entity_list,
                                  2,
                                  APPEND,
                                  IP_UDP_connect_dti_cb))
        {
          TRACE_EVENT("cmhSM_connect_working_cid: dti_cntrl_est_dpath returned FALSE");
          return 0;
        }
      }
#endif /* CO_UDP_IP */
      break;

#ifdef FF_SAT_E      
    case DTI_ENTITY_SIM:
    {
      T_DTI_ENTITY_ID entity_list[] = {DTI_ENTITY_SIM, DTI_ENTITY_SNDCP};
      /* create a SAT class E DTI ID if not present */
      if ( simShrdPrm.sat_class_e_dti_id EQ DTI_DTI_ID_NOTPRESENT )
      {
        simShrdPrm.sat_class_e_dti_id = dti_cntrl_new_dti(DTI_DTI_ID_NOTPRESENT);
        TRACE_EVENT_P1("sat_class_e_dti_id = %d", simShrdPrm.sat_class_e_dti_id);
      }
      srcc_new_count(SRCC_SIM_SNDCP_LINK);
      TRACE_FUNCTION("cmhSM_connect_working_cid:GC_TYPE_SIM");
      context_info->link_id_new = 
        dti_conn_compose_link_id (0, 0, simShrdPrm.sat_class_e_dti_id, DTI_TUPLE_NO_NOTPRESENT);
      dti_cntrl_est_dpath( simShrdPrm.sat_class_e_dti_id,
                           entity_list,
                           2,
                           SPLIT,
                           SIM_SNDCP_connect_dti_cb);
      break;
    }
#endif /* FF_SAT_E */

    case DTI_ENTITY_NULL:
      {
        T_DTI_ENTITY_ID entity_list[] = {DTI_ENTITY_NULL, DTI_ENTITY_SNDCP};
        UBYTE dti_id = dti_cntrl_new_dti(DTI_DTI_ID_NOTPRESENT);
        srcc_new_count(SRCC_NULL_SNDCP_LINK);
        context_info->link_id_new   = dti_conn_compose_link_id (0, 0, dti_id, DTI_TUPLE_NO_NOTPRESENT );
      
        dti_cntrl_est_dpath( dti_id,
                             entity_list,
                             2,
                             SPLIT,
                             NULL_SNDCP_connect_dti_cb);
        break;
      }
#if defined (FF_GPF_TCPIP)
    case DTI_ENTITY_TCPIP:
    {
      T_DTI_ENTITY_ID entity_list[] = {DTI_ENTITY_TCPIP, DTI_ENTITY_SNDCP};
      UBYTE dti_id;
      dti_id = wap_dti_id;
      /* link_id should be created in atGD already, so just connect: */
      if (!dti_cntrl_est_dpath( dti_id,
                                entity_list,
                                2,
                                SPLIT,
                                TCPIP_connect_dti_cb))
      {
        TRACE_EVENT("cmhSM_connect_working_cid: dti_cntrl_est_dpath returned FALSE");
        return 0;
      }
    }
    break;
#endif /* FF_GPF_TCPIP */

#if defined(FF_PKTIO) OR defined(FF_TCP_IP) OR defined (FF_PSI)
    case DTI_ENTITY_INVALID:
      {
        T_DTI_ENTITY_ID entity_list[] = {DTI_ENTITY_SNDCP};
        srcc_new_count(SRCC_PKTIO_SNDCP_LINK);
              
        dti_cntrl_est_dpath_indirect((UBYTE)context_info->owner,
                                      entity_list,
                                      1, SPLIT,
                                      PKTIO_SNDCP_connect_dti_cb,
                                      DTI_CPBLTY_PKT,
                                      (UBYTE)work_cids[cid_pointer]);
        set_state_working_cid( CS_ACTIVATING );
        break;
      }
#endif /* FF_PKTIO OR FF_TCP_IP OR FF_PSI */
    default:
      return 0;

  }

  return 1;
}


GLOBAL void cmhSM_disconnect_cid ( SHORT cid, T_GPRS_CONNECT_TYPE type )
{
  T_DTI_CONN_LINK_ID link_id = cmhSM_get_link_id_SNDCP_peer( cid, SNDCP_PEER_NORMAL );

  TRACE_FUNCTION("cmhSM_disconnect_cid");
  TRACE_EVENT_P1("link_id %d",link_id);
  if ( DTI_LINK_ID_NOTPRESENT NEQ link_id)
  {
    switch ( type )
    {
      case GC_TYPE_DATA_LINK:
        srcc_delete_count( SRCC_PPPS_SNDCP_LINK );
        pdp_context[cid - 1].link_id_sn = DTI_LINK_ID_NOTPRESENT;
        pdp_context[cid - 1].link_id_new = DTI_LINK_ID_NOTPRESENT;
        pdp_context[cid - 1].link_id_uart = DTI_LINK_ID_NOTPRESENT;
        pdp_context[cid - 1].entity_id = DTI_ENTITY_INVALID;
        m_mt_te_link = FALSE;
        break;
        
      case GC_TYPE_WAP:
        if(is_gpf_tcpip_call())
        {
          GPF_TCPIP_STATEMENT(srcc_delete_count( SRCC_TCPIP_SNDCP_LINK ));
        }
        else
        {
          srcc_delete_count( SRCC_IP_SNDCP_LINK );
        }
        pdp_context[cid - 1].link_id_sn = DTI_LINK_ID_NOTPRESENT;
        pdp_context[cid - 1].link_id_new = DTI_LINK_ID_NOTPRESENT;
        pdp_context[cid - 1].link_id_uart = DTI_LINK_ID_NOTPRESENT;
        pdp_context[cid - 1].entity_id = DTI_ENTITY_INVALID;
        break;

      case GC_TYPE_NULL:
      case GC_TYPE_EMAIL:
        switch ( pdp_context[cid - 1].entity_id )
        {
          case DTI_ENTITY_IP:
          GPF_TCPIP_STATEMENT(case DTI_ENTITY_TCPIP:)
            if(is_gpf_tcpip_call())
            {
              GPF_TCPIP_STATEMENT(srcc_delete_count( SRCC_TCPIP_SNDCP_LINK ));
            }
            else
            {
              srcc_delete_count( SRCC_IP_SNDCP_LINK );
            }
            dti_cntrl_erase_entry(EXTRACT_DTI_ID(link_id));
            break;

          case DTI_ENTITY_NULL:
            dti_cntrl_entity_disconnected( link_id, DTI_ENTITY_NULL );
            srcc_delete_count( SRCC_NULL_SNDCP_LINK );
            dti_cntrl_erase_entry(EXTRACT_DTI_ID(link_id));
            break;

#if defined(FF_PKTIO) OR defined(FF_TCP_IP) || defined(FF_GPF_TCPIP) OR defined (FF_PSI)
          case DTI_ENTITY_PKTIO:
          case DTI_ENTITY_PSI:
          case DTI_ENTITY_AAA:
            srcc_delete_count( SRCC_PKTIO_SNDCP_LINK );
            break;
#endif /* FF_PKTIO OR FF_TCP_IP || FF_GPF_TCPIP OR FF_PSI */
        }
        pdp_context[cid - 1].link_id_sn = DTI_LINK_ID_NOTPRESENT;
        pdp_context[cid - 1].link_id_new = DTI_LINK_ID_NOTPRESENT;
        pdp_context[cid - 1].link_id_uart = DTI_LINK_ID_NOTPRESENT;
        pdp_context[cid - 1].entity_id = DTI_ENTITY_INVALID;
        break;
        
    }
  }
}

GLOBAL BOOL uart_is_mt_te_link( void )
{

  return m_mt_te_link;
}

GLOBAL void cmhSNDCP_Disable( T_DTI_CONN_LINK_ID link_id )
{
  SHORT cid = gaci_get_cid_over_link_id( link_id );
  
 /*
   *  disconnects the context if the link_id is the current link_id of this context
   *
   *  the other case: 
   *      the context is switching to an other peer and the old link_id is requested 
   *      to be disconnected, NOT the context itself
   */
  if (cmhSM_get_link_id_SNDCP_peer(cid, SNDCP_PEER_NORMAL) EQ link_id)
  {
    cmhSM_deactivateAContext(CMD_SRC_NONE, cid);
  }
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_connect_context           |
+----------------------------------------------------------------------+

  PURPOSE : Connect an activated or deactivated PDP context with an entity.
*/
GLOBAL SHORT cmhSM_connect_context ( SHORT cid, T_DTI_ENTITY_ID peer, UBYTE ppp_hc, UBYTE msid )
{
  ULONG dti_neighbor;
  UBYTE dti_direction, hcomp = cmhSM_Get_h_comp() ? SMREG_COMP_BOTH_DIRECT: SMREG_COMP_NEITHER_DIRECT;

  TRACE_FUNCTION("cmhSM_connect_context()");

  switch ( peer )
  {
    case DTI_ENTITY_PPPS:
      dti_neighbor  = (ULONG) PPP_NAME;
      dti_direction = SMREG_HOME;
      break;
    case DTI_ENTITY_NULL:
      dti_neighbor  = (ULONG) NULL_NAME;
      dti_direction = SMREG_NEIGHBOR;
      smShrdPrm.direc = DIREC_MO;
      break;
    case DTI_ENTITY_IP:
      dti_neighbor  = (ULONG) IP_NAME;
      dti_direction = SMREG_NEIGHBOR;
      smShrdPrm.direc = DIREC_MO;
#ifdef FF_WAP
      if (Wap_Call)   
        rAT_WAP_start_gprs_login();
#endif /* FF_WAP */
      break;
#ifdef FF_SAT_E      
    case DTI_ENTITY_SIM:
      dti_neighbor  = (ULONG) SIM_NAME;
      dti_direction = SMREG_NEIGHBOR;
      smShrdPrm.direc = DIREC_MO;
      break;
#endif /* FF_SAT_E */      
#if defined(FF_PKTIO) OR defined(FF_TCP_IP) OR defined(FF_PSI)
    case DTI_ENTITY_PKTIO:
      dti_neighbor  = (ULONG) PKTIO_NAME;
      dti_direction = SMREG_HOME;
      smShrdPrm.direc = DIREC_MO;
      break;
    case DTI_ENTITY_PSI:
      dti_neighbor  = (ULONG) PSI_NAME;
      dti_direction = SMREG_HOME;
      smShrdPrm.direc = DIREC_MO;
      break;
    case DTI_ENTITY_AAA:
      dti_neighbor  = (ULONG) RIV_NAME;
      dti_direction = SMREG_NEIGHBOR;
      smShrdPrm.direc = DIREC_MO;
      break;
#endif /* FF_PKTIO OR FF_TCP_IP OR FF_PSI */
#ifdef FF_GPF_TCPIP
    case DTI_ENTITY_TCPIP:
      dti_neighbor  = (ULONG) TCPIP_NAME;
      dti_direction = SMREG_NEIGHBOR;
      smShrdPrm.direc = DIREC_MO;
      break;
#endif /* FF_GPF_TCPIP */
    default:
      return 0;
  }

  pdp_context[cid - 1].entity_id = peer;

#ifdef _SIMULATION_
  dti_neighbor                   = 0xfe1234ef;
#endif

  if ( DTI_LINK_ID_NOTPRESENT EQ pdp_context[cid - 1].link_id_sn )
  { /* context is deactivated */
    cmhSM_GetNewNSapi();

    psaSM_ActivateReq ( cid,
                        (UBYTE) (hcomp? ppp_hc: 0),
                        msid,
                        hcomp,
                        pdp_context[cid - 1].link_id_new,
                        dti_neighbor,
                        dti_direction );

  }
  else
  { /* context is activated */
EXTERN void psaSN_SwitchReq ( UBYTE nsapi,
                              ULONG dti_linkid,
                              ULONG dti_neighbor,
                              UBYTE dti_direction );

    psaSN_SwitchReq ( pdp_context[cid - 1].nsapi,
                      pdp_context[cid - 1].link_id_new,
                      dti_neighbor, dti_direction);

  dti_cntrl_close_dpath_from_dti_id (EXTRACT_DTI_ID(pdp_context[cid - 1].link_id_sn));
  dti_cntrl_entity_disconnected( pdp_context[cid - 1].link_id_sn, DTI_ENTITY_SNDCP );
  dti_cntrl_erase_entry( EXTRACT_DTI_ID(pdp_context[cid - 1].link_id_sn) );
  }

  return 1;
}

GLOBAL void cp_pdp_primitive(T_SMREG_PDP_ACTIVATE_CNF * pdp_activate_cnf,
                       T_PPP_PDP_ACTIVATE_RES *activate_result)
{
 
  activate_result->ppp_hc = pdp_activate_cnf->ppp_hc;
  activate_result->msid = pdp_activate_cnf->msid;

  /*
   * copy IP address
   */
  activate_result->ip = pdp_activate_cnf->pdp_address.buff[0];
  activate_result->ip = activate_result->ip << 8;
  activate_result->ip+= pdp_activate_cnf->pdp_address.buff[1];
  activate_result->ip = activate_result->ip << 8;
  activate_result->ip+= pdp_activate_cnf->pdp_address.buff[2];
  activate_result->ip = activate_result->ip << 8;
  activate_result->ip+= pdp_activate_cnf->pdp_address.buff[3];


  activate_result->sdu.l_buf = pdp_activate_cnf->sdu.l_buf;
  activate_result->sdu.o_buf = 0;

  if (pdp_activate_cnf->sdu.l_buf > 0) {
    memcpy(activate_result->sdu.buf,
           &pdp_activate_cnf->sdu.buf[pdp_activate_cnf->sdu.o_buf >> 3],
           pdp_activate_cnf->sdu.l_buf >> 3);
  }
}
  

GLOBAL SHORT cmhSM_context_connected( USHORT nsapi )
{
  T_GPRS_CONT_CLASS *context_info = &pdp_context[nsapi_to_cid[nsapi] - 1];
  UBYTE ip[4];

  TRACE_FUNCTION("cmhSM_context_connected");

  context_info->link_id_sn = context_info->link_id_new;
  context_info->link_id_new = DTI_LINK_ID_NOTPRESENT;

  switch (context_info->entity_id)
  {
    case DTI_ENTITY_PPPS:
      cmhSM_pdp_address_to_ip(&context_info->allocated_pdp_addr, ip);
      psaGPPP_PDP_Activate(0, 0, ip, 
                           context_info->network_pco.pco, context_info->network_pco.len);
      set_state_working_cid( CS_ESTABLISH_3 );
      break;

#ifdef FF_PKTIO
    case DTI_ENTITY_PKTIO:
#endif /* FF_PKTIO */
#ifdef FF_PSI
    case DTI_ENTITY_PSI:
#endif /* FF_PSI */
#ifdef FF_SAT_E 
    case DTI_ENTITY_SIM:
#endif /* FF_SAT_E */
#ifdef FF_TCP_IP
    case DTI_ENTITY_AAA:
#endif /* FF_TCP_IP */
#if defined (FF_SAT_E) OR defined (FF_TCP_IP) OR defined (FF_PKTIO) OR defined (FF_PSI)
      dti_cntrl_entity_connected( context_info->link_id_sn, DTI_ENTITY_SNDCP, DTI_OK);
      set_state_working_cid( CS_ACTIVATED );      
#if defined(FF_PKTIO) OR defined (FF_PSI)
      cmhSM_next_work_cid(smEntStat.curCmd);      
#endif /* FF_PKTIO OR FF_PSI */        
      break;
#endif /* #if defined (FF_SAT_E) OR defined (FF_TCP_IP) OR defined (FF_PKTIO) OR FF_PSI */
  } /* switch (context_info->entity_id) */
  return 1;
} /* GLOBAL SHORT cmhSM_context_connected( USHORT nsapi ) */
   

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_set_PCO                   |
+----------------------------------------------------------------------+

  PURPOSE : Set a PCO in the context of the cid.
*/
GLOBAL void cmhSM_set_PCO( SHORT cid, T_PCO_TYPE pco_type, UBYTE* buf_addr, UBYTE length)
{
  T_GPRS_CONT_PCO* dest;

  switch ( pco_type )
  {
    case PCO_USER:
      dest = &pdp_context[cid - 1].user_pco;
      break;
    case PCO_NETWORK:
      dest = &pdp_context[cid - 1].network_pco;
      break;
  }
  /*lint -e(644) */ /* all possible types defined */
  memcpy(dest->pco, buf_addr, length);
  dest->len = length;
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_get_dti_SNDCP_pper        |
+----------------------------------------------------------------------+

  PURPOSE : Give back the right DTI-ID for the SNDCP - peer connection.
*/
GLOBAL ULONG cmhSM_get_link_id_SNDCP_peer( SHORT cid, T_SNDCP_PEER which )
{

  switch ( which )
  {
    case SNDCP_PEER_NORMAL:
      return pdp_context[cid - 1].link_id_new NEQ DTI_LINK_ID_NOTPRESENT ? 
             pdp_context[cid - 1].link_id_new: pdp_context[cid - 1].link_id_sn;
    case SNDCP_PEER_SWITCHED:
      return pdp_context[cid - 1].link_id_sn;
  }

  return DTI_LINK_ID_NOTPRESENT;
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : code             ROUTINE : cmhSM_context_deactivated       |
+----------------------------------------------------------------------+

  PURPOSE : Control the answer of context deactivations 
            started by an AT command. 
*/
GLOBAL void cmhSM_context_deactivated( USHORT nsapi_set )
{

  switch( working_cgact_actions.state  )
  {
    case T_CDS_RUNNING:
      if  ( nsapi_set & working_cgact_actions.nsapi_set )
      { /* nsapi deactivation is requested */
        working_cgact_actions.nsapi_set &= ~nsapi_set;
        if ( ! (working_cgact_actions.cid_set  OR
                working_cgact_actions.nsapi_set  ) )
        { 
            R_AT( RAT_OK, working_cgact_actions.srcId ) ( AT_CMD_CGACT );
            working_cgact_actions.state = T_CDS_IDLE;
        }
      }
      break;
    case T_CDS_IDLE:
      break;
  }
}

/*
+----------------------------------------------------------------------+
| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMF                    |
| STATE   : finnished             ROUTINE : deactivateAContextForCGACT |
+----------------------------------------------------------------------+

PURPOSE       : deactivate a context for CGACT

RETURN VALUE  : TRUE  - AT_EXCT have to be returned for this context
                FALSE - AT_CMPL have to be reported for this context

*/
static T_ACI_RETURN deactivateAContextForCGACT(SHORT cid)
{
  T_CONTEXT_STATE ctx_state = get_state_over_cid( cid );
    
  SRCC_LINK_NO    srcc_link_no= SRCC_INVALID_LINK;
  T_DTI_ENTITY_ID dti_entity_id= DTI_ENTITY_INVALID;
  

  
  TRACE_FUNCTION("deactivateAContextForCGACT()");

#if defined (CO_UDP_IP) || defined (FF_GPF_TCPIP)



  /*
   *  additinal behaviour for WAP
   *  abort ATD*98# before context activation requested
   *  2003.05.06 brz
   */
  if(is_gpf_tcpip_call()) {
    GPF_TCPIP_STATEMENT(srcc_link_no  = SRCC_TCPIP_SNDCP_LINK);
    GPF_TCPIP_STATEMENT(dti_entity_id = DTI_ENTITY_TCPIP);
  }
  else {
    srcc_link_no   = SRCC_IP_SNDCP_LINK;
    dti_entity_id = DTI_ENTITY_IP;
  }
     
  if( TRUE NEQ srcc_reserve_sources( srcc_link_no, 1 )            AND
      DTI_LINK_ID_NOTPRESENT NEQ pdp_context[cid - 1].link_id_new AND
      cid  EQ work_cids[cid_pointer]                              OR
      pdp_context[cid - 1].entity_id EQ dti_entity_id)
  {
      psaTCPIP_Deactivate(cmhSM_IP_activate_cb);

      if(CS_UNDEFINED EQ ctx_state OR
         CS_DEFINED   EQ ctx_state   )
      {
        if(is_gpf_tcpip_call()) {
          GPF_TCPIP_STATEMENT(wap_state = TCPIP_Deactivation);
        }
        else {
          wap_state = UDPA_Deactivation;
        }
        dti_cntrl_close_dpath_from_dti_id(
          EXTRACT_DTI_ID(cmhSM_get_link_id_SNDCP_peer(cid , SNDCP_PEER_NORMAL)));
      }

      if( CS_ATTACHING_AFTER_UNDEF EQ ctx_state OR
          CS_ATTACHING_AFTER_DEF   EQ ctx_state OR
          CS_WAITS_FOR_ACTIVATING  EQ ctx_state     )
      {
        srcc_delete_count(srcc_link_no);
        return cmhSM_deactivateAContext(CMD_SRC_NONE, cid);
      }
      
      return AT_EXCT;
  }
  else
#endif  /* CO_UDP_IP || FF_GPF_TCPIP */
  {
    if( CS_DEFINED NEQ ctx_state AND CS_UNDEFINED NEQ ctx_state )
    {
      if( CS_ATTACHING_AFTER_UNDEF EQ ctx_state OR
          CS_ATTACHING_AFTER_DEF   EQ ctx_state OR
          CS_WAITS_FOR_ACTIVATING  EQ ctx_state     )
      {
        return cmhSM_deactivateAContext(CMD_SRC_NONE, cid);
      }
      else
      {
        dti_cntrl_close_dpath_from_dti_id(
        EXTRACT_DTI_ID(cmhSM_get_link_id_SNDCP_peer(cid , SNDCP_PEER_NORMAL)));
        return AT_EXCT;
      }
    }
  }
  return AT_CMPL;
}

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_deactivateAContext        |
+----------------------------------------------------------------------+

  PURPOSE : deactivate some contexts (able for serial multiplexer mode).
*/
GLOBAL T_ACI_RETURN cmhSM_deactivateContexts( T_ACI_CMD_SRC srcId, SHORT *cids)
{
  T_ACI_RETURN ret_value = AT_CMPL;
  T_CONTEXT_STATE state;       
  USHORT nsapi_set = 0, 
         cid_set   = 0;
  SHORT i,
        all_cids[MAX_CID + 1] = {1, 2, INVALID_CID};

  TRACE_FUNCTION("cmhSM_deactivateContexts");

  if( T_CDS_RUNNING EQ working_cgact_actions.state) {
    TRACE_EVENT("cgact_ation is running: bussy returned");
    return AT_FAIL; /* AT_BUSY */
  }

  if(INVALID_CID EQ *cids)
  {
    cids = all_cids;
  }

  for(i = 0; cids[i] NEQ INVALID_CID; i++)
  {
    state = pdp_context[cids[i] - 1].state;
#if defined (CO_UDP_IP) || defined (FF_GPF_TCPIP)
#ifndef _SIMULATION_ 
    pdp_context[cids[i] - 1].owner = srcId;
#endif
#else
    pdp_context[cids[i] - 1].owner = srcId;
#endif
    if(AT_EXCT EQ deactivateAContextForCGACT( cids[i] ))
    {
      ret_value = AT_EXCT;
      if(0 NEQ pdp_context[cids[i] - 1].nsapi)
      {
        nsapi_set |= (1 << pdp_context[cids[i] - 1].nsapi);
        
        if(state EQ CS_DATA_LINK OR
           state EQ CS_ACTIVATED OR
           state EQ CS_CONTEXT_REACTIVATION_1)
        {
          cid_set   = 1 << (cids[i] - 1);
        }
      }
      else
      {
        cid_set   = 1 << (cids[i] - 1);
      }
    }
  }

  if(cid_set OR nsapi_set) {
    working_cgact_actions.state     = T_CDS_RUNNING;
    working_cgact_actions.nsapi_set = nsapi_set;
    working_cgact_actions.cid_set   = cid_set;
    working_cgact_actions.srcId     = srcId;
  }

  cmhSM_stop_context_reactivation();

  return ret_value;
}


/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_getCurQOS                 |
+----------------------------------------------------------------------+

  PURPOSE : This function returns the current QOS settings.
*/
#ifdef FF_SAT_E
GLOBAL T_QOS* cmhSM_getCurQOS( SHORT cid )
{

  return &pdp_context[cid - 1].qos;

}
#endif /* FF_SAT_E */

/*
+----------------------------------------------------------------------+
| PROJECT : GPRS (8441)      MODULE  : CMH_SMF                         |
| STATE   : finnished        ROUTINE : cmhSM_deactivateAContext        |
+----------------------------------------------------------------------+

  PURPOSE : deactivate all contexts (able for serial multiplexer mode).
*/
GLOBAL T_ACI_RETURN cmhSM_deactivateAContext( T_ACI_CMD_SRC srcId, SHORT cid )
{
  TRACE_FUNCTION("cmhSM_deactivateAContext()") ;

  switch( get_state_over_cid( cid ) )
  {
    case CS_UNDEFINED:
    case CS_DEFINED:
      /* 
       *    context ís deactivated -> not action necessary
       */
      break;
    case CS_ATTACHING_AFTER_UNDEF:
      /* 
       *    CGDATA has started the attach procedure 
       *    before establish data link
       *    CGDATA has to be stoped
       */
      set_state_over_cid( cid, CS_UNDEFINED );
      psaGMM_Detach( GMMREG_DT_GPRS );
      gpppEntStat.curCmd = AT_CMD_NONE;
      cid_pointer  = 0;
      *work_cids = 0;
      if(CMD_SRC_NONE EQ srcId)
      {
        pdp_context[cid - 1].owner = gpppEntStat.entOwn;
        gaci_RAT_caller ( RAT_NO_CARRIER, cid, AT_CMD_CGDATA, 0 );
      }
      return AT_CMPL;

    case CS_ATTACHING_AFTER_DEF:
      /* 
       *    CGDATA has started the attach procedure 
       *    before establish data link
       *    CGDATA has to be stoped
       */
      set_state_over_cid( cid, CS_DEFINED );
      psaGMM_Detach( GMMREG_DT_GPRS );
      gpppEntStat.curCmd = AT_CMD_NONE;
      cid_pointer  = 0;
      *work_cids = 0;
      if(CMD_SRC_NONE EQ srcId)
      {
        pdp_context[cid - 1].owner = gpppEntStat.entOwn;
        gaci_RAT_caller ( RAT_NO_CARRIER, cid, AT_CMD_CGDATA, 0 );
      }
return AT_CMPL;
    
    case CS_ESTABLISH_1:
      /*
       *   context not activated, but PPP has to be terminated
       */
      set_state_over_cid( cid, CS_ABORT_ESTABLISH );
      dti_cntrl_entity_disconnected( pdp_context[cid - 1].link_id_new, DTI_ENTITY_SNDCP );
      if (uartShrdPrm.escape_seq EQ UART_DETECT_ESC)
      {
        psaGPPP_Terminate( PPP_LOWER_LAYER_DOWN );
      }
      else
      {
        psaGPPP_Terminate( PPP_LOWER_LAYER_UP );
      }
      uartShrdPrm.escape_seq = UART_DETECT_DTR;

      return AT_EXCT;
    
    case CS_DATA_LINK:
      /*lint -fallthrough*/
    case CS_ESTABLISH_2:
    case CS_ESTABLISH_3:
      /* 
       *    context has to be deactivated and PPP has to be terminated
       */
      set_state_over_cid( cid, CS_CONTEXT_REACTIVATION_1 );
      psaSM_PDP_Deactivate( (USHORT) (1 << pdp_context[cid - 1].nsapi), SMREG_NONLOCAL);
      psaGPPP_Terminate( PPP_LOWER_LAYER_UP );
      return AT_EXCT;

    case CS_ACTIVATED:
      /*
       *  special handling for context switching
       */
      if(DTI_LINK_ID_NOTPRESENT NEQ pdp_context[cid - 1].link_id_sn  AND
         DTI_LINK_ID_NOTPRESENT NEQ pdp_context[cid - 1].link_id_new     )
      {
        return AT_CMPL;
      }
      /*lint -fallthrough*/
    case CS_ACTIVATING:
      /*
       *    +CGACT aborted
       */
      set_state_over_cid( cid, CS_DEACTIVATE_NORMAL );
      psaSM_PDP_Deactivate( (USHORT) (1 << pdp_context[cid - 1].nsapi), SMREG_NONLOCAL);
      return AT_EXCT;
    case CS_WAITS_FOR_ACTIVATING:
      /*
       *    reset command state it is enough
       */
      set_state_working_cid( CS_DEFINED );
      gpppEntStat.curCmd = AT_CMD_NONE;
      smEntStat.curCmd   = AT_CMD_NONE;
      *work_cids = 0;
      cid_pointer = 0;
      return AT_CMPL;

    case CS_ABORT_ESTABLISH:
    case CS_DEACTIVATE_NORMAL:
    case CS_BREAKDOWN_LINK_ERROR:
    case CS_BREAKDOWN_LINK_NORMAL:
      /*
       *    context is during deactivation procedure -> not action necessary
       */
      return AT_EXCT;
    case CS_CONTEXT_REACTIVATION_1:
    case CS_CONTEXT_REACTIVATION_2:
      /* 
       *  context is during deactivation procedure 
       *  -> not action for context deactivation or PPP termination necessary
       */
      return AT_EXCT;
  }

  return AT_FAIL;
}

GLOBAL BOOL cmhSM_isContextActive( void )
{
  int i = SMH_FIRST_FREE_NSAPIS;

  while ( i <= SMH_LAST_FREE_NSAPIS AND ( nsapi_to_cid[i] EQ INVALID_CID))
    i++;

  if  ( i >  SMH_LAST_FREE_NSAPIS)
    return FALSE;

  return TRUE;
}

#endif  /* GPRS */
/*==== EOF ========================================================*/