diff g23m/condat/ms/src/aci/cmh_sms.c @ 0:509db1a7b7b8

initial import: leo2moko-r1
author Space Falcon <falcon@ivan.Harhan.ORG>
date Mon, 01 Jun 2015 03:24:05 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/g23m/condat/ms/src/aci/cmh_sms.c	Mon Jun 01 03:24:05 2015 +0000
@@ -0,0 +1,1425 @@
+/* 
++----------------------------------------------------------------------------- 
+|  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 implements the set fuinctions related to the
+|             protocol stack adapter for GPRS session management ( SM ).
++----------------------------------------------------------------------------- 
+*/ 
+
+#if defined (GPRS) && defined (DTI)
+
+#ifndef CMH_SMS_C
+#define CMH_SMS_C
+#endif
+
+#include "aci_all.h"
+
+/*==== INCLUDES ===================================================*/
+#include "dti.h"      /* functionality of the dti library */
+#include "aci_cmh.h"
+#include "ati_cmd.h"
+#include "aci_cmd.h"
+#include "aci_io.h"
+
+#include "dti_conn_mng.h"
+#include "dti_cntrl_mng.h"
+
+#include "gaci.h"
+#include "gaci_cmh.h"
+#include "psa.h"
+#include "psa_sm.h"
+#include "psa_gppp.h"
+#include "psa_gmm.h"
+#include "psa_tcpip.h"
+
+#include "cmh.h"
+#include "cmh_sm.h"
+#include "cmh_gppp.h"
+#include "cmh_gmm.h"
+#include "gaci_srcc.h"
+#include "aci_mem.h"
+#include "phb.h"
+#include "wap_aci.h"
+
+/*==== CONSTANTS ==================================================*/
+
+/*==== EXPORT =====================================================*/
+
+/*==== VARIABLES ==================================================*/
+
+/*==== FUNCTIONS ==================================================*/
+LOCAL void string_to_dns(CHAR* dns, ULONG *dns_long);
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMS                  |
+| STATE   : finnished             ROUTINE : sAT_PlusCGQREQ           |
++--------------------------------------------------------------------+
+
+PURPOSE : This is the functional counterpart to the +CGQREQ= AT
+          command which sets the requested QOS.
+*/
+GLOBAL T_ACI_RETURN sAT_PlusCGQREQ
+            ( T_ACI_CMD_SRC srcId, SHORT cid ,T_QOS *qos)
+{
+  T_CONTEXT_STATE c_state;      /* state of context */
+
+
+  TRACE_FUNCTION ("sAT_PlusCGQREQ()");
+
+/*
+ *-------------------------------------------------------------------
+ * check entity status
+ *-------------------------------------------------------------------
+ */
+  if( smEntStat.curCmd NEQ AT_CMD_NONE )
+
+    return( AT_BUSY );
+
+/*
+ *-------------------------------------------------------------------
+ * check parameter
+ *-------------------------------------------------------------------
+ */
+  if ( (cid < GPRS_CID_OMITTED) || (cid >= GPRS_CID_INVALID) )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return AT_FAIL;
+  }
+
+  if ( qos )
+  {
+    if ( /* qos->preced < GPRS_QOS_OMITTED || */ qos->preced > 3 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+
+    if ( /* qos->delay < GPRS_QOS_OMITTED || */ qos->delay > 4 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+    if ( /* qos->relclass < GPRS_QOS_OMITTED || */ qos->relclass > 5 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+    if ( /* qos->peak < GPRS_QOS_OMITTED || */ qos->peak > 9 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+    if ( (/* qos->mean < GPRS_QOS_OMITTED || */ qos->mean > 18) && qos->mean NEQ 31 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * process parameter
+ *-------------------------------------------------------------------
+ */
+  if (cid EQ GPRS_CID_OMITTED )
+ /*
+  *   cid omitted: A special form of the set command that is not defined in the Spec.
+  *   This set the default value of QoS.
+  */
+  {
+    cmhSM_change_def_QOS(qos);
+
+  }
+  else
+  {
+    c_state = get_state_over_cid( cid );
+
+    if ( !qos ||  (qos->preced    EQ GPRS_QOS_OMITTED &&
+                   qos->delay     EQ GPRS_QOS_OMITTED &&
+                   qos->relclass  EQ GPRS_QOS_OMITTED &&
+                   qos->peak      EQ GPRS_QOS_OMITTED &&
+                   qos->mean      EQ GPRS_QOS_OMITTED     ) )
+    { /* QoS omitted ->  undefine the requested QOS */
+      if ( c_state NEQ CS_DEFINED )
+      {
+        ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+        return( AT_FAIL );
+      }
+
+      cmhSM_Set_default_QOS(cid);
+
+    }
+    else
+    { /* define the requested QOS */
+      if ( c_state NEQ CS_DEFINED )
+      {
+        ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+        return( AT_FAIL );
+      }
+
+      memcpy( &pdp_context[cid - 1].con.qos, qos, sizeof(T_QOS));
+    }
+  }
+
+  return AT_CMPL;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMS                  |
+| STATE   : finnished             ROUTINE : sAT_PlusCGQMIN           |
++--------------------------------------------------------------------+
+
+PURPOSE : This is the functional counterpart to the +CGQMIN= AT
+          command which sets the minimum acceptable QOS.
+*/
+GLOBAL T_ACI_RETURN sAT_PlusCGQMIN
+            ( T_ACI_CMD_SRC srcId, SHORT cid ,T_QOS *qos)
+{
+  T_CONTEXT_STATE c_state;      /* state of context */
+
+  TRACE_FUNCTION ("sAT_PlusCGQMIN()");
+
+/*
+ *-------------------------------------------------------------------
+ * check entity status
+ *-------------------------------------------------------------------
+ */
+  if( smEntStat.curCmd NEQ AT_CMD_NONE )
+
+    return( AT_BUSY );
+
+/*
+ *-------------------------------------------------------------------
+ * check parameter
+ *-------------------------------------------------------------------
+ */
+  if ( (cid < GPRS_CID_OMITTED) || (cid >= GPRS_CID_INVALID) )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return AT_FAIL;
+  }
+
+  if ( qos )
+  {
+    if ( /* qos->preced < GPRS_QOS_OMITTED || */ qos->preced > 3 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+
+    if ( /* qos->delay < GPRS_QOS_OMITTED || */ qos->delay > 4 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+    if ( /* qos->relclass < GPRS_QOS_OMITTED || */ qos->relclass > 5 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+    if ( /* qos->peak < GPRS_QOS_OMITTED || */ qos->peak > 9 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+    if ( (/* qos->mean < GPRS_QOS_OMITTED || */ qos->mean > 18) && qos->mean NEQ 31 )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+  }
+
+/*
+*-------------------------------------------------------------------
+* process parameter
+*-------------------------------------------------------------------
+*/
+  if (cid EQ GPRS_CID_OMITTED )
+ /*
+  *   cid omitted: A special form of the set command that is not defined in the Spec.
+  *   This set the default value of QoS.
+  */
+  {
+    cmhSM_change_def_QOS_min(qos);
+  }
+  else
+  {
+    c_state = get_state_over_cid( cid );
+
+    if ( !qos ||  (qos->preced    EQ GPRS_QOS_OMITTED &&
+                   qos->delay     EQ GPRS_QOS_OMITTED &&
+                   qos->relclass  EQ GPRS_QOS_OMITTED &&
+                   qos->peak      EQ GPRS_QOS_OMITTED &&
+                   qos->mean      EQ GPRS_QOS_OMITTED     ) )
+    { /* QoS omitted ->  undefine the requested QOS */
+      if ( c_state NEQ CS_DEFINED )
+      {
+        ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+        return( AT_FAIL );
+      }
+
+      cmhSM_Set_default_QOS_min(cid);
+    }
+    else
+    { /* define the requested QOS */
+      if ( c_state NEQ CS_DEFINED )
+      {
+        ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+        return( AT_FAIL );
+      }
+
+      memcpy( &pdp_context[cid - 1].con.min_qos, qos, sizeof(T_QOS));
+    }
+
+  }
+
+  return AT_CMPL;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMS                  |
+| STATE   : finnished             ROUTINE : sAT_PlusCGDCONT          |
++--------------------------------------------------------------------+
+
+PURPOSE : This is the functional counterpart to the +CGDCONT= AT
+          command which sets the current setting for each context.
+
+          GACI Context Definition GSM - 7.60 10.2.1
+
+          Special case +CGDCONT=<n> undefines context n
+          is handled as separate function call
+
+          otherwise:
+
++CGDCONT=[<cid> [,<PDP_TYPE> [,<APN> [,<PDP_addr> [,<h_comp> [,<d_comp>]]]]]]
+
+ Issue of what happens if user changes data of an active context.
+
+ Take simple approach, do not renegotiate current context.
+ Undefinition is more complex, reject attempt if context is active?
+
+ Current pdp address is left alone and only reset when context is
+ explicitly undefined.
+ See GSM 7.60 10.2.7.
+
+*/
+GLOBAL T_ACI_RETURN sAT_PlusCGDCONT ( T_ACI_CMD_SRC srcId, SHORT cid, T_GPRS_CONT_REC *inputCtxt)
+{
+  T_CONTEXT_STATE c_state;      /* state of context */
+  SHORT state = 0;
+
+  TRACE_FUNCTION ("sAT_PlusCGDCONT()");
+
+/*
+ *-------------------------------------------------------------------
+ * check parameter
+ *-------------------------------------------------------------------
+ */
+  /* Daniel : to convert the lower-case "ip"  
+               to the upper-case "IP" as a pdp type */
+  if (!strcmp(inputCtxt->pdp_type, "ip"))
+    strcpy(inputCtxt->pdp_type, "IP");
+  if ( (cid < GPRS_CID_OMITTED) || (cid >= GPRS_CID_INVALID) )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return AT_FAIL;
+  }
+
+  if ( inputCtxt->d_comp < CGDCONT_D_COMP_OMITTED || inputCtxt->d_comp >= CGDCONT_D_COMP_INVALID )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+  /* right now data compression is not supported, remove this block if enabled in the future */
+  if ( inputCtxt->d_comp EQ CGDCONT_D_COMP_ON )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+  if ( inputCtxt->h_comp < CGDCONT_H_COMP_OMITTED || inputCtxt->h_comp >= CGDCONT_H_COMP_INVALID )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * A special form of set command
+ *-------------------------------------------------------------------
+ */
+  if (  !(cid NEQ GPRS_CID_OMITTED             &&
+          !*(inputCtxt->pdp_type) && !*(inputCtxt->apn) && !*(inputCtxt->pdp_addr)  &&
+          inputCtxt->d_comp EQ CGDCONT_D_COMP_OMITTED   && inputCtxt->h_comp EQ CGDCONT_H_COMP_OMITTED) )
+  {
+  /*
+   *-------------------------------------------------------------------
+   * check parameter
+   *-------------------------------------------------------------------
+   */
+    if ( !*(inputCtxt->pdp_type) && *(inputCtxt->pdp_addr) )
+      {
+        ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+        return AT_FAIL;
+      }
+
+    if ( *(inputCtxt->pdp_addr) && *(inputCtxt->pdp_type) )
+      if ( !cmhSM_pdp_addr_well_formed( cmhSM_transform_pdp_type( inputCtxt->pdp_type ), inputCtxt->pdp_addr ) )
+      {
+        ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+        return AT_FAIL;
+      }
+
+    if ( *(inputCtxt->apn) )
+      if ( !cmhSM_apn_well_formed( inputCtxt->apn ) )
+      {
+        ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+        return AT_FAIL;
+      }
+
+  /*
+   *-------------------------------------------------------------------
+   * default parameter
+   *-------------------------------------------------------------------
+   */
+    if ( inputCtxt->d_comp EQ CGDCONT_D_COMP_OMITTED )
+      inputCtxt->d_comp = CGDCONT_D_COMP_OFF;
+
+    if ( inputCtxt->h_comp EQ CGDCONT_H_COMP_OMITTED )
+      inputCtxt->h_comp = CGDCONT_H_COMP_OFF;
+
+    if ( cid EQ GPRS_CID_OMITTED )
+    {
+      do
+      {
+        c_state = get_state_over_cid( ++ cid );
+      }
+      while ( cid < GPRS_CID_INVALID && c_state NEQ CS_UNDEFINED );
+
+      if( c_state NEQ CS_UNDEFINED )
+      {
+        ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+        return( AT_FAIL );
+      }
+    }
+
+    if ( !*(inputCtxt->pdp_type) )
+      strcpy(inputCtxt->pdp_type, "IP");
+
+    state = 1;
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * process parameter
+ *-------------------------------------------------------------------
+ */
+  c_state = get_state_over_cid( cid );
+
+  switch ( state )
+  {
+
+    case 0: /* undefine a PDP context */
+      if ( c_state NEQ CS_DEFINED )
+      {
+        ACI_ERR_DESC( ACI_ERR_CLASS_Cme, CME_ERR_OpNotAllow );
+        return( AT_FAIL );
+      }
+
+      set_state_over_cid( cid, CS_UNDEFINED );
+
+      break;
+    case 1: /* define a PDP context */
+      switch(c_state)
+      {
+          /* every time allowed */
+        case CS_INVALID_STATE:
+        case CS_UNDEFINED:
+        case CS_DEFINED:
+          c_state = CS_DEFINED;
+          break;
+          /* allowed during context deactivation, but
+             WITHOUT state change                     */
+        case CS_ABORT_ESTABLISH:
+        case CS_DEACTIVATE_NORMAL:
+        case CS_BREAKDOWN_LINK_NORMAL:
+        case CS_BREAKDOWN_LINK_ERROR:
+        case CS_CONTEXT_REACTIVATION_1:
+        case CS_CONTEXT_REACTIVATION_2:
+          break;
+          /* Not allowed during context activation or
+             for activated context                    */
+        case CS_ATTACHING_AFTER_UNDEF:
+        case CS_ATTACHING_AFTER_DEF:
+        case CS_ESTABLISH_1:
+        case CS_ESTABLISH_2:
+        case CS_ESTABLISH_3:
+        case CS_WAITS_FOR_ACTIVATING:
+        case CS_ACTIVATING:
+        case CS_ACTIVATED:
+        case CS_DATA_LINK:
+        default:
+        ACI_ERR_DESC( ACI_ERR_CLASS_Cme, CME_ERR_OpNotAllow );
+        return( AT_FAIL );
+      }
+
+      sAT_PlusCGDCONT_exec(srcId, cid, inputCtxt);
+      set_state_over_cid( cid, c_state );
+
+      break;
+  }
+
+  return AT_CMPL;
+}
+
+GLOBAL void sAT_PlusCGDCONT_exec ( T_ACI_CMD_SRC srcId, SHORT cid, T_GPRS_CONT_REC *inputCtxt)
+{
+  T_GPRS_CONT_REC *con = &pdp_context[cid - 1].con;
+
+  TRACE_FUNCTION("sAT_PlusCGDCONT_exec");
+
+  memcpy(&con->apn,       &inputCtxt->apn,      sizeof( T_APN ));
+  memcpy(&con->pdp_type,  &inputCtxt->pdp_type, sizeof( T_PDP_TYPE ));
+  memcpy(&con->pdp_addr,  &inputCtxt->pdp_addr, sizeof( T_PDP_ADDRESS ));
+  con->d_comp = inputCtxt->d_comp;
+  con->h_comp = inputCtxt->h_comp;
+  
+  if ( CS_DEFINED NEQ get_state_over_cid( cid ) )
+  {
+    cmhSM_Set_default_QOS     ( cid );
+    cmhSM_Set_default_QOS_min ( cid );
+  }
+
+  set_state_over_cid( cid, CS_DEFINED );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMS                  |
+| STATE   : finnished             ROUTINE : sAT_PlusCGACT            |
++--------------------------------------------------------------------+
+
+PURPOSE : This is the functional counterpart to the +CGACT= AT
+          command which causes the cids specified in the cids list to
+          be activated or deactivated according to state.
+
+          An empty list will cause all defined contexts to be
+          activated or deactivated. If taken literally, this means that
+          if more contexts are defined than supported, each will be
+          activated, resulting in 'no resource' errors for the late ones
+          as the GACI SEM will reject requests for more activations
+          than it can cope with.
+
+          Note that the context is/are activated, but no CONNECT is sent
+          to the TE. This is the difference between ACT and DATA commands.
+
+          SMREG activate req does not need l2p to be sent, but in this case
+          the PDP config options are undefined (see below).
+
+          How does a DATA call bind these 'orphan' connections to a TE given
+          that a cid definition is a 'template' due to its ambiguity.
+
+          Practically, the activate form of this command has little meaning in the
+          case of PPP and loopback protocols (only ones supported at present).
+
+          Simplest option at the moment is not to support the activate form until
+          a protocol type is supported can make real use of it. The deactivate form
+          is of use in switching off a Loopback connection.
+
+          If activation before protocol establishment is supported, a NULL protocol service
+          will have to be provided which supplies a default (empty?) PCO list to SMREG for
+          activation and stores the network PCO response until a CGDATA is issued, must then
+          convert the protocol into that requested by the CGDATA command.
+          For future implementation
+
+
+          Other issues for multiple context activation :
+
+          - need to add a para onto GACI activate to tell it whether
+          to do a CONNECT or an OK callback on activation.
+
+*/
+GLOBAL T_ACI_RETURN sAT_PlusCGACT
+            ( T_ACI_CMD_SRC srcId, T_CGACT_STATE state, SHORT *cids )
+{
+  T_CONTEXT_STATE ctx_state;
+  SHORT i = 0, j = 0;
+  int ret_val;
+  TRACE_FUNCTION ("sAT_PlusCGACT()");
+
+/*
+ *-------------------------------------------------------------------
+ * check command source
+ *-------------------------------------------------------------------
+ */
+  if(!cmh_IsVldCmdSrc (srcId))
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * check parameter
+ *-------------------------------------------------------------------
+ */
+  if ( (state < CGACT_STATE_OMITTED) || (state >= CGACT_STATE_INVALID) )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return AT_FAIL;
+  }
+
+  for (i = 0; cids[i] NEQ INVALID_CID; i++)
+  {
+    if ( (cids[i] < GPRS_CID_1 || cids[i] >= GPRS_CID_INVALID) || i >= MAX_CID_PLUS_EINS )
+    {
+      ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+      return( AT_FAIL );
+    }
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * default parameter
+ *-------------------------------------------------------------------
+ */
+  if ( state EQ CGACT_STATE_OMITTED )
+  { /* state is not optional */
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return AT_FAIL;
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * enable +CGACT to deactivate a context during activation
+ *-------------------------------------------------------------------
+ */
+  if( CGACT_STATE_DEACTIVATED EQ state )
+  {
+    ret_val = cmhSM_deactivateContexts(srcId, cids);
+    switch(ret_val)
+    {
+      case AT_EXCT:
+       smEntStat.curCmd = AT_CMD_CGACT;
+       smEntStat.entOwn = srcId;
+       smShrdPrm.owner  = (UBYTE) srcId;
+       return AT_EXCT;
+      default:
+       return ret_val;
+    }
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * check entity status
+ *-------------------------------------------------------------------
+ */
+  if( smEntStat.curCmd NEQ AT_CMD_NONE )
+    return( AT_BUSY );
+
+  if( gpppEntStat.curCmd EQ AT_CMD_CGDATA )
+    return( AT_BUSY );
+
+
+/*
+ *-------------------------------------------------------------------
+ * process parameter
+ *-------------------------------------------------------------------
+ */
+
+  cid_pointer = 0;
+
+  if ( *cids EQ INVALID_CID ) /* all defined or activated contexts (dependent by state) */
+  {
+    for (i = 0; i < MAX_CID; i++)
+    {
+        if ( CS_DEFINED EQ get_state_over_cid((SHORT) (i + 1)) )
+        {
+          work_cids[j] = i + 1;
+          j++;
+        }
+      }
+    work_cids[j] = INVALID_CID;
+
+    if (!*work_cids)
+      return AT_CMPL;
+  }
+  else   /* all declarated contexts */
+  {
+    /* copy cid list */
+    for (i = 0; cids[i] NEQ INVALID_CID; i++)
+    {
+      work_cids[i] = cids[i];
+    }
+    work_cids[i] = INVALID_CID;
+
+    for (j = 0; work_cids[j] NEQ INVALID_CID; j++)
+    {
+      ctx_state = get_state_over_cid( work_cids[j] );
+
+        if ( CS_UNDEFINED EQ ctx_state )
+        { /* context not defined */
+          sAT_PlusCGDCONT_exec (srcId, work_cids[j], &defaultCtx);
+          set_state_over_cid(work_cids[j], CS_UNDEFINED);
+        }
+      else if ( CS_DEFINED NEQ ctx_state )
+          {
+            cid_pointer = 0;
+            work_cids[0] = INVALID_CID;
+            return ( AT_FAIL );
+          }
+        }
+      }
+
+ /*
+  *-------------------------------------------------------------------
+  * check number of context
+  *-------------------------------------------------------------------
+  */
+  TRACE_EVENT("activating context!");
+      if ( TRUE NEQ srcc_reserve_sources( SRCC_NULL_SNDCP_LINK, j ) )
+  {
+    cid_pointer  = 0;
+    *work_cids = 0;
+    return AT_FAIL;
+  }
+
+      smEntStat.curCmd = AT_CMD_CGACT;
+      smEntStat.entOwn = srcId;
+      smShrdPrm.owner  = (UBYTE) srcId;
+
+      set_conn_param_on_all_working_cids( (UBYTE)srcId, DTI_ENTITY_NULL );
+  if (AT_FAIL EQ cmhSM_activate_context())
+  {
+     set_conn_param_on_all_working_cids( (UBYTE)srcId, DTI_ENTITY_INVALID );
+     smEntStat.curCmd = AT_CMD_NONE;
+     gpppEntStat.curCmd = AT_CMD_NONE;
+     cid_pointer  = 0;
+     *work_cids = 0;
+    return AT_FAIL;
+  }
+
+  return AT_EXCT;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMS                  |
+| STATE   : finnished             ROUTINE : sAT_PlusCGDATA           |
++--------------------------------------------------------------------+
+
+PURPOSE : This is the functional counterpart to the +CGDATA= AT
+          command which establish the communication.
+*/
+GLOBAL T_ACI_RETURN sAT_PlusCGDATA  ( T_ACI_CMD_SRC srcId, char *L2P, SHORT *cids )
+{
+  SHORT j = 0;
+  T_ACI_RETURN    retCd     = AT_CMPL;             /* holds return code */
+  T_DTI_ENTITY_ID connectToEntity = DTI_ENTITY_INVALID;
+
+  TRACE_FUNCTION ("sAT_PlusCGDATA()");
+
+/*
+ *-------------------------------------------------------------------
+ * check command source
+ *-------------------------------------------------------------------
+ */
+  if(!cmh_IsVldCmdSrc (srcId))
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+
+/*
+ *-------------------------------------------------------------------
+ * check entity status
+ *-------------------------------------------------------------------
+ */
+  if( smEntStat.curCmd NEQ AT_CMD_NONE )
+    return( AT_BUSY );
+
+  if( gpppEntStat.curCmd NEQ AT_CMD_NONE )
+    return( AT_BUSY );
+
+  if (pb_get_fdn_mode () EQ FDN_ENABLE)
+  {
+    if (pb_check_fdn (0, (const UBYTE *)"*99#") NEQ PHB_OK)
+    {
+      TRACE_EVENT("sAT_PlusCGDATA: Entry not found in FDN, GPRS not allowed.");
+      ACI_ERR_DESC( ACI_ERR_CLASS_Cme, CME_ERR_OpNotAllow);
+      return (AT_FAIL);
+    }
+    TRACE_EVENT("sAT_PlusCGDATA: Entry found in FDN, GPRS allowed.");
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * check parameter
+ *-------------------------------------------------------------------
+ */
+  /* 
+   *  in maximum 1 cid allowed 
+   */
+  if ( GPRS_CID_OMITTED NEQ cids[0] &&
+     GPRS_CID_OMITTED NEQ cids[1]   )
+  {
+    return AT_FAIL;
+  }
+
+
+  if ( L2P[0] EQ 0 )
+    strcpy (L2P, "PPP"); /* default value */
+  
+  if ( !strcmp(L2P, "PPP"))
+  {
+    if ( TRUE NEQ srcc_reserve_sources( SRCC_PPPS_SNDCP_LINK, 1 ) )
+      return ( AT_FAIL );
+    
+    connectToEntity = DTI_ENTITY_PPPS;
+  }
+#if defined(FF_PKTIO) OR defined(FF_TCP_IP) OR defined(FF_PSI)
+  else if( !strcmp(L2P, "M-PKT") OR !strcmp(L2P, "M-IP")) 
+  {
+    if ( TRUE NEQ srcc_reserve_sources( SRCC_PKTIO_SNDCP_LINK, 1 ) )
+      return ( AT_FAIL );
+  }
+#endif /* FF_PKTIO OR FF_TCP_IP OR FF_PSI */
+  else 
+  {
+    return ( AT_FAIL );
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * process parameter
+ *-------------------------------------------------------------------
+ */
+  j = cmhSM_define_cid_list( srcId, cids );
+
+  if ( !j )
+    return( AT_FAIL );
+
+/*
+ *-------------------------------------------------------------------
+ * process function
+ *-------------------------------------------------------------------
+ */
+  smShrdPrm.direc = DIREC_MO;
+
+  set_conn_param_on_working_cid( (UBYTE)srcId, connectToEntity );
+
+  if( DTI_ENTITY_PPPS EQ connectToEntity )
+  {
+    retCd = cmhGMM_attach_if_necessary( srcId, AT_CMD_CGDATA );
+    gpppEntStat.curCmd = AT_CMD_CGDATA;
+    gpppEntStat.entOwn = srcId;
+    gpppShrdPrm.owner  = (UBYTE) srcId;
+  }
+  else if( DTI_ENTITY_INVALID EQ connectToEntity )
+  {
+    smEntStat.curCmd = AT_CMD_CGDATA;
+    smEntStat.entOwn = srcId;
+    smShrdPrm.owner  = (UBYTE) srcId;  
+  }
+
+  if ( retCd EQ AT_CMPL )
+    cmhSM_data_link_context();
+  else
+  {
+    if ( retCd EQ AT_EXCT )
+      switch ( get_state_working_cid() )
+      {
+        case CS_DEFINED:
+          set_state_working_cid( CS_ATTACHING_AFTER_DEF );
+          break;
+        case CS_UNDEFINED:
+          set_state_working_cid( CS_ATTACHING_AFTER_UNDEF );
+          break;
+      }
+    else
+    {
+      smEntStat.curCmd  = AT_CMD_NONE;
+      gpppEntStat.curCmd = AT_CMD_NONE;
+      return AT_FAIL;
+    }
+  }
+
+  return AT_EXCT;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMS                  |
+| STATE   : finnished             ROUTINE : sAT_PlusCGPADDR          |
++--------------------------------------------------------------------+
+
+PURPOSE : This is the functional counterpart to the +CGPADDR= AT
+          command which give the PDP address back.
+*/
+GLOBAL T_ACI_RETURN sAT_PlusCGPADDR ( T_ACI_CMD_SRC srcId, SHORT *cids, T_PDP_ADDRESS *pdp_adress )
+{
+  SHORT cid = 1, index = 0;
+
+  TRACE_FUNCTION ("sAT_PlusCGPADDR()");
+
+/*
+ *-------------------------------------------------------------------
+ * check entity status
+ *-------------------------------------------------------------------
+ */
+  if( smEntStat.curCmd NEQ AT_CMD_NONE )
+    return( AT_BUSY );
+
+/*
+ *-------------------------------------------------------------------
+ * process parameter
+ *-------------------------------------------------------------------
+ */
+  if ( *cids EQ GPRS_CID_OMITTED )
+  {
+    /*
+     *  the PDP addresse for all defined contexts are returned
+     */
+    for (cid = 1; cid <= MAX_CID; cid++)
+    {
+      cids[index] = cmhSM_get_pdp_addr_for_CGPADDR( cid, pdp_adress[index] );
+      if ( cids[index] NEQ INVALID_CID )
+        index ++;
+    }
+
+    cids[index] = INVALID_CID;
+  }
+  else
+  {
+    /*
+     *  the PDP addresse for all specified contexts are returned
+     */
+    while ( cids[index] NEQ GPRS_CID_OMITTED )
+    {
+      if ( cids[index] < GPRS_CID_1 || cids[index] >= GPRS_CID_INVALID )
+        return AT_FAIL;
+
+      cmhSM_get_pdp_addr_for_CGPADDR( cids[index], pdp_adress[index] );
+      index ++;
+    }
+    cids[index] = INVALID_CID;
+  }
+
+  return AT_CMPL;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMS                  |
+| STATE   : finnished             ROUTINE : sAT_PlusCGAUTO           |
++--------------------------------------------------------------------+
+
+PURPOSE : This is the functional counterpart to the +CGAUTO= AT
+          command which set the mode of automatic response to
+          network request for PDP context activation.
+*/
+GLOBAL T_ACI_RETURN sAT_PlusCGAUTO ( T_ACI_CMD_SRC srcId, T_CGAUTO_N n )
+{
+  TRACE_FUNCTION ("sAT_PlusCGAUTO()");
+
+/*
+ *-------------------------------------------------------------------
+ * check entity status
+ *-------------------------------------------------------------------
+ */
+  if( smEntStat.curCmd NEQ AT_CMD_NONE )
+
+    return( AT_BUSY );
+
+/*
+ *-------------------------------------------------------------------
+ * check parameter
+ *-------------------------------------------------------------------
+ */
+  if ( (n < CGAUTO_N_OMITTED) || (n >= CGAUTO_N_INVALID) )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return AT_FAIL;
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * default parameter
+ *-------------------------------------------------------------------
+ */
+  if ( n EQ CGAUTO_N_OMITTED )
+    n = CGAUTO_N_MCM_GPRS_CSC;
+
+/*
+ *-------------------------------------------------------------------
+ * process parameter
+ *-------------------------------------------------------------------
+ */
+  automatic_response_mode = (SHORT) n;
+
+  /* the MT shall attempt to perform a GPRS attach if it is not already attached */
+  if ( n EQ 1 )
+  {
+    return sAT_PlusCGATT ( srcId, CGATT_STATE_ATTACHED );
+  }
+  return AT_CMPL;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMS                  |
+| STATE   : finnished             ROUTINE : sAT_PlusCGANS            |
++--------------------------------------------------------------------+
+
+PURPOSE : This is the functional counterpart to the +CGANS= AT
+          command to respond manual to a network request for
+          PDP context activation.
+*/
+GLOBAL T_ACI_RETURN sAT_PlusCGANS ( T_ACI_CMD_SRC srcId, SHORT response,
+                                    char *l2p, SHORT cid )
+{
+  char L2P[MAX_L2P_LENGTH];
+  T_GPRS_CONT_REC ctx = defaultCtx;
+  SHORT           i = 0, cid_list[2] = { INVALID_CID };
+
+  TRACE_FUNCTION ("sAT_PlusCGANS()");
+
+/*
+ *-------------------------------------------------------------------
+ * check entity status
+ *-------------------------------------------------------------------
+ */
+  if( smEntStat.curCmd NEQ AT_CMD_NONE )
+
+    return( AT_BUSY );
+
+/*
+ *-------------------------------------------------------------------
+ * check command source
+ *-------------------------------------------------------------------
+ */
+  if(!cmh_IsVldCmdSrc (srcId))
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * check parameter
+ *-------------------------------------------------------------------
+ */
+  if ( (response <= CGANS_RESPONSE_OMITTED) || (response >= CGANS_RESPONSE_INVALID) )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * default parameter
+ *-------------------------------------------------------------------
+ */
+  if ( response EQ CGANS_RESPONSE_OMITTED )
+    response = CGANS_RESPONSE_REJECT;
+
+/*
+ *-------------------------------------------------------------------
+ * check call table
+ *-------------------------------------------------------------------
+ */
+  if ( gprs_ct_index EQ current_gprs_ct_index )
+    return ( AT_FAIL );
+
+/*
+ *-------------------------------------------------------------------
+ * process parameter
+ *-------------------------------------------------------------------
+ */
+  switch ( response )
+  {
+    case CGANS_RESPONSE_REJECT:
+      psaSM_PDP_No_activate(gprs_call_table[current_gprs_ct_index].sm_ind.smreg_ti, SMREG_RC_ACT_REJ_UNSPEC);
+
+      cmhSM_next_call_table_entry();
+
+#ifdef FF_ATI
+      io_setRngInd ( IO_RING_OFF, CRING_TYP_NotPresent, CRING_TYP_NotPresent ); /* V.24 Ring Indicator Line */
+#endif
+
+      for( i = 0; i < CMD_SRC_MAX; i++ )
+      {
+        R_AT( RAT_CRING_OFF, i )( 0 );
+      }
+      return AT_CMPL;
+    case CGANS_RESPONSE_ACCEPT:
+     /*
+      *-------------------------------------------------------------------
+      * check number of context
+      *-------------------------------------------------------------------
+      */
+      if ( TRUE NEQ srcc_reserve_sources( SRCC_PPPS_SNDCP_LINK, 1 ) )
+        return ( AT_FAIL );
+     /*
+      *-------------------------------------------------------------------
+      * check the last two command arguments
+      *-------------------------------------------------------------------
+      */
+      if ( !gprs_call_table[current_gprs_ct_index].L2P[0] )
+      {
+        if ( l2p NEQ NULL )
+        {
+          if ( !*l2p )
+            strcpy(L2P, "PPP");
+          else
+          {
+            strncpy(L2P, l2p, MAX_L2P_LENGTH - 1);
+            L2P[MAX_L2P_LENGTH - 1] = 0;
+          }
+        }
+        else
+          strcpy(L2P, "PPP");
+
+        if ( strcmp(L2P, "PPP") )
+        {
+          ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+          return( AT_FAIL );
+        }
+
+        cid_list[0] = cid;
+      }
+      else
+      {
+        cid_list[0] = gprs_call_table[current_gprs_ct_index].cid;
+      }
+
+      if ( 1 NEQ cmhSM_define_cid_list( srcId, cid_list ))
+        return( AT_FAIL );
+
+     /*
+      *-------------------------------------------------------------------
+      * set the actually context data
+      *-------------------------------------------------------------------
+      */
+/*      ctx.qos.preced    =  gprs_call_table[current_gprs_ct_index].sm_ind.smreg_qos.preced;
+      ctx.qos.delay     =  gprs_call_table[current_gprs_ct_index].sm_ind.smreg_qos.delay;
+      ctx.qos.relclass  =  gprs_call_table[current_gprs_ct_index].sm_ind.smreg_qos.relclass;
+      ctx.qos.peak      =  gprs_call_table[current_gprs_ct_index].sm_ind.smreg_qos.peak;
+      ctx.qos.mean      =  gprs_call_table[current_gprs_ct_index].sm_ind.smreg_qos.mean;*/
+
+      strncpy(ctx.apn,
+              (const char *) gprs_call_table[current_gprs_ct_index].sm_ind.smreg_apn.buffer,
+                             gprs_call_table[current_gprs_ct_index].sm_ind.smreg_apn.c_buffer);
+      if ( 4 EQ gprs_call_table[current_gprs_ct_index].sm_ind.pdp_address.c_buff )
+        sprintf(ctx.pdp_addr, "%03hd.%03hd.%03hd.%03hd",
+                gprs_call_table[current_gprs_ct_index].sm_ind.pdp_address.buff[0],
+                gprs_call_table[current_gprs_ct_index].sm_ind.pdp_address.buff[1],
+                gprs_call_table[current_gprs_ct_index].sm_ind.pdp_address.buff[2],
+                gprs_call_table[current_gprs_ct_index].sm_ind.pdp_address.buff[3]);
+      else
+        return( AT_FAIL );
+
+      switch ( gprs_call_table[current_gprs_ct_index].sm_ind.pdp_type )
+      {
+        case X_121:
+          return( AT_FAIL );
+        case IP_V_4:
+          strcpy(ctx.pdp_type, "IP");
+          break;
+        case IP_V_6:
+          return( AT_FAIL );
+        default:
+          return( AT_FAIL );
+      }
+
+     /*
+      *-------------------------------------------------------------------
+      * set some parameter of the call table
+      *-------------------------------------------------------------------
+      */
+      if ( !gprs_call_table[current_gprs_ct_index].L2P[0])
+      {
+        /*lint -e{645} */ /* L2P is initialized within the same if-construct some lines above */
+        strcpy (gprs_call_table[current_gprs_ct_index].L2P, L2P);
+        gprs_call_table[current_gprs_ct_index].cid = *cid_list;
+      }
+
+      sAT_PlusCGDCONT_exec (srcId, *cid_list, &ctx);
+      
+      pdp_context[*cid_list - 1].smreg_ti = gprs_call_table[current_gprs_ct_index].sm_ind.smreg_ti;
+
+     /*
+      *-------------------------------------------------------------------
+      * process function
+      *-------------------------------------------------------------------
+      */
+      gpppEntStat.curCmd = AT_CMD_CGDATA;
+      gpppEntStat.entOwn = srcId;
+      gpppShrdPrm.owner  = (UBYTE) srcId;
+
+      smShrdPrm.direc    = DIREC_MT;
+
+      set_conn_param_on_working_cid( (UBYTE)srcId, DTI_ENTITY_PPPS );
+
+      cmhSM_data_link_context();
+      return AT_EXCT;
+  }
+
+  return AT_FAIL;
+}
+
+GLOBAL T_ACI_RETURN sAT_PlusCGEREP  ( T_ACI_CMD_SRC srcId, T_CGEREP_MODE mode, T_CGEREP_BFR bfr )
+{
+
+  TRACE_FUNCTION ("sAT_PlusCGEREP()");
+
+/*
+ *-------------------------------------------------------------------
+ * check entity status
+ *-------------------------------------------------------------------
+ */
+  if( smEntStat.curCmd NEQ AT_CMD_NONE )
+    return( AT_BUSY );
+
+/*
+ *-------------------------------------------------------------------
+ * check first command argument
+ *-------------------------------------------------------------------
+ */
+  if ( mode < CGEREP_MODE_OMITTED || mode >= CGEREP_MODE_INVALID )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+  if ( bfr < CGEREP_BFR_OMITTED || bfr >= CGEREP_BFR_INVALID )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * process parameter
+ *-------------------------------------------------------------------
+ */
+
+  if ( mode NEQ CGEREP_MODE_OMITTED )
+    ati_user_output_cfg[srcId].CGEREP_mode = mode;
+
+  if ( bfr NEQ CGEREP_BFR_OMITTED )
+    ati_user_output_cfg[srcId].CGEREP_bfr  = bfr;
+
+  switch ( mode )
+  {
+    case CGEREP_MODE_BUFFER:
+    case CGEREP_MODE_DICARD_RESERVED:
+      srcId_cb = srcId;
+      cmhSM_cgerep_buffer ( );
+      break;
+    case CGEREP_MODE_BUFFER_RESERVED:
+      break;
+    case CGEREP_MODE_INVALID:
+    case CGEREP_MODE_OMITTED:
+    default:
+      break;
+  }
+
+  return AT_CMPL;
+}
+
+#ifdef DTI
+GLOBAL T_ACI_RETURN sAT_PlusCGSMS   ( T_ACI_CMD_SRC srcId, T_CGSMS_SERVICE service )
+{
+  T_ACI_RETURN    retCd = AT_CMPL;    /* holds return code */
+
+  TRACE_FUNCTION ("sAT_PlusCGSMS()");
+
+/*
+ *-------------------------------------------------------------------
+ * check entity status
+ *-------------------------------------------------------------------
+ */
+  if( smEntStat.curCmd NEQ AT_CMD_NONE )
+
+    return( AT_BUSY );
+
+/*
+ *-------------------------------------------------------------------
+ * check first command argument
+ *-------------------------------------------------------------------
+ */
+  if ( service < CGSMS_SERVICE_OMITTED || service >= CGSMS_SERVICE_INVALID )
+  {
+    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
+    return( AT_FAIL );
+  }
+
+/*
+ *-------------------------------------------------------------------
+ * process parameter
+ *-------------------------------------------------------------------
+ */
+  if ( service EQ CGSMS_SERVICE_OMITTED )
+    service = sm_cgsms_service;
+
+  if ( service NEQ sm_cgsms_service )
+  {
+    smEntStat.curCmd = AT_CMD_CGSMS;
+    smEntStat.entOwn = srcId;
+    smShrdPrm.owner  = (UBYTE) srcId;
+
+    cmhSM_set_sms_service ( service );
+
+    retCd = AT_EXCT;
+  }
+
+  return retCd;
+}
+#endif
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)               MODULE  : CMH_SMS            |
+| STATE   : finished                    ROUTINE : string_to_dns      |
++--------------------------------------------------------------------+
+
+PURPOSE : 
+*/
+LOCAL void string_to_dns(CHAR* dns, ULONG *dns_long)
+{
+     UBYTE dns_len = 4;
+     CHAR dns_adrtest[3];
+     UBYTE dns_adr [4];
+     UBYTE i = 0;
+
+     memset(&dns_adrtest,0,dns_len-1);
+     memset(&dns_adr,0,dns_len);
+
+     if(strlen(dns) NEQ 0)
+    {
+        for(i=0;i<dns_len;i++)
+        {
+          strncpy(dns_adrtest,dns,dns_len-1);
+          dns_adr[i] = (UBYTE)atoi(dns_adrtest);
+          dns = dns+dns_len;
+         }
+         for(i=0;i<dns_len;i++)
+         {
+           *dns_long= *dns_long + dns_adr[i];
+           if (i<(dns_len-1))
+             *dns_long = *dns_long<<8;
+        }
+    }    
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (8441)         MODULE  : CMH_SMS                  |
+| STATE   : finished              ROUTINE : sAT_PercentCGPCO         |
++--------------------------------------------------------------------+
+
+PURPOSE : This is the functional counterpart to the ?CGPCO= AT
+          command to set protocol configuration options for the
+          PDP context activation.
+*/
+
+GLOBAL T_ACI_RETURN sAT_PercentCGPCO (T_ACI_CMD_SRC srcId, 
+                                      SHORT cid, USHORT protocol,
+                                      CHAR *user, CHAR *pwd, CHAR *dns1, CHAR *dns2)
+{
+  USHORT  pco_len = ACI_PCO_MAX_LEN;
+  UBYTE   *pco_array;
+  int     i, ret;
+  ULONG dns_adr1 = 0x00000000;
+  ULONG dns_adr2 = 0x00000000;
+
+
+  TRACE_FUNCTION("sAT_PercentCGPCO");
+  
+  ACI_MALLOC (pco_array, ACI_PCO_MAX_LEN);
+
+  string_to_dns(dns1,&dns_adr1);
+  string_to_dns(dns2,&dns_adr2);
+  
+  ret = utl_create_pco (pco_array, &pco_len,
+                        ACI_PCO_CONTENTMASK_AUTH | 
+                        ACI_PCO_CONTENTMASK_DNS1 |
+                        ACI_PCO_CONTENTMASK_DNS2,
+                        ACI_PCO_CONFIG_PROT_PPP,
+                        protocol, (UBYTE*)user, (UBYTE*)pwd, dns_adr1, dns_adr2);
+  if (ret < 0)
+  {
+    TRACE_EVENT_P1 ("sAT_PercentCGPCO(): invalid protocol=%d", protocol);
+    ACI_MFREE (pco_array);
+
+    return (AT_FAIL);
+  }
+  if (cid EQ 0)
+  {
+    for (i = 0; i < MAX_CID; i++)
+    {
+      pdp_context[i].user_pco.len = (UBYTE)pco_len;
+      memcpy (pdp_context[i].user_pco.pco, pco_array, pco_len);
+    }
+  }
+  else
+  {
+    pdp_context[cid - 1].user_pco.len = (UBYTE)pco_len;
+    memcpy (pdp_context[cid - 1].user_pco.pco, pco_array, pco_len);
+  }
+
+  ACI_MFREE (pco_array);
+
+  return (AT_CMPL);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GPRS                         MODULE  : CMH_SMS           |
+| STATE   : finished                     ROUTINE : qAT_PercentCGPCO  |
++--------------------------------------------------------------------+
+
+  PURPOSE : %CGPCO command
+              * analyze network PCO a cid
+*/
+
+GLOBAL T_ACI_RETURN qAT_PercentCGPCO ( UBYTE srcId, ULONG * gateway, 
+                                       ULONG * dns1,ULONG * dns2, USHORT cid)
+{  
+
+  TRACE_FUNCTION("qAT_PercentCGPCO");
+
+  switch(pdp_context[cid - 1].state)
+  {
+     case CS_ACTIVATED:
+     case CS_ESTABLISH_3:
+     case CS_DATA_LINK:
+          utl_analyze_pco((UBYTE*)pdp_context[cid - 1].network_pco.pco, (USHORT)pdp_context[cid - 1].network_pco.len, dns1, dns2, gateway);
+          break;
+     default:
+          break;
+   }
+   return (AT_CMPL);
+}
+
+
+#endif  /* GPRS */
+/*==== EOF ========================================================*/