view gsm-fw/g23m-gsm/sms/sms_cp.c @ 700:2913c4fdd34a

top level README: describe the project at a higher level
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Thu, 02 Oct 2014 00:06:50 +0000
parents 2f7df7a314f8
children 833f2fee131b
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :  GSM-F&D (8411)
|  Modul   :  SMS_CP
+-----------------------------------------------------------------------------
|  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 Modul defines the functions for the control protocol
|             of the component SMS.
+-----------------------------------------------------------------------------
*/

#ifndef SMS_CP_C
#define SMS_CP_C

#define ENTITY_SMS

/*==== INCLUDES ===================================================*/

#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include "typedefs.h"
#include "pcm.h"
#include "vsi.h"
#include "custom.h"
#include "gsm.h"
#include "message.h"
#include "ccdapi.h"
#include "prim.h"
#include "cus_sms.h"
#include "cnf_sms.h"
#include "mon_sms.h"
#include "pei.h"
#include "tok.h"
#include "sms.h"
#include "sms_em.h"

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

/*==== PRIVAT ======================================================*/

/*==== VARIABLES ===================================================*/

/*==== FUNCTIONS ===================================================*/
  
/* Implements Measure# 4 */  
/*
+------------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                         |
| STATE   : code                ROUTINE : cp_send_err_ind_errcs          |
+------------------------------------------------------------------------+  

  PURPOSE : This routine process the signal CP_DATA_IND_CP_ERROR for the 
            cases CP_MM_CONNECTION_ESTABLISHED and  CP_WAIT_FOR_ACK    
            
*/

LOCAL void cp_send_err_ind_errcs(UBYTE errcs)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION("cp_send_err_ind_errcs()");
  /*
   * Check if the cmms_mode is enabled or not
   * If enabled dont release the MM connection
   */
  if(!CMMS_ACTIVE)
  {
    cp_send_release_req (SMS_INST.ti); 
    SMS_INST_SET_STATE (STATE_CP, CP_IDLE); 
    SMS_INST.r_flag = FALSE; 
  }
  else
  {
    sms_data->cmms_release_pending = TRUE;
  }
 
  rl_error_ind (CAUSE_MAKE(DEFBY_STD, ORIGSIDE_NET,
                SMSCP_ORIGINATING_ENTITY, errcs));  
  
}

/* Implements Measure# 3 */
/*
+------------------------------------------------------------------------- -+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                            |
| STATE   : code                ROUTINE : cp_send_err_ind_msg_type_unknown  |
+---------------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_DATA_IND_CP_UNKNOWN for the 
            cases CP_MM_CONNECTION_ESTABLISHED and CP_WAIT_FOR_ACK
            
*/

LOCAL void cp_send_err_ind_msg_type_unknown(void)
{
  GET_INSTANCE_DATA; 
  TRACE_FUNCTION("cp_send_err_ind_msg_type_unknown()");
  
  cp_build_cp_error (SMS_CP_CS_MSG_TYPE_NON_EXIST);
  
  /*
   * Check if the cmms_mode is enabled or not
   * If enabled dont release the MM connection
   */
  if(!CMMS_ACTIVE)
  {
    cp_send_release_req (SMS_INST.ti);
    SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
    SMS_INST.r_flag = FALSE;
  }
  else
  {
    sms_data->cmms_release_pending = TRUE;
  }

  rl_error_ind (CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS,
                SMSCP_ORIGINATING_ENTITY, SMS_CP_CS_MSG_TYPE_NON_EXIST));  
  
}

/* Implements Measure# 8 */
/*
+------------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                         |
| STATE   : code                ROUTINE : cp_send_err_ind_msg_not_comp   |
+------------------------------------------------------------------------+  

  PURPOSE : This routine process the signals CP_DATA_IND_CP_ACK and CP_DATA_IND_CP_DATA
            for the cases CP_MM_CONNECTION_ESTABLISHED and CP_WAIT_FOR_ACK
            
*/

LOCAL void cp_send_err_ind_msg_not_comp (void)
{
  GET_INSTANCE_DATA; 
  TRACE_FUNCTION("cp_send_err_ind_msg_not_comp()");
  
  cp_build_cp_error (SMS_CP_CS_MSG_NOT_COMP);
  
  cp_send_release_req (SMS_INST.ti);
  SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
  SMS_INST.r_flag = FALSE;
  
  rl_error_ind (CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS,
                SMSCP_ORIGINATING_ENTITY, SMS_CP_CS_MSG_NOT_COMP));  
  
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_init                    |
+--------------------------------------------------------------------+

  PURPOSE : Initialize the control protocol.

*/

GLOBAL void cp_init (void)
{
  GET_INSTANCE_DATA;	

  TRACE_FUNCTION ("cp_init()");

  memset (sms_data, 0, sizeof (T_SMS_DATA));

  sms_data->data[0].state[STATE_CP] = CP_IDLE;
  sms_data->data[1].state[STATE_CP] = CP_IDLE;

  /*
   * Initialize the timer_values with default values
   */
  sms_data->timer_values[TC1M] = TC1M_VALUE;
  sms_data->timer_values[TR1M] = TR1M_VALUE;
  sms_data->timer_values[TR2M] = TR2M_VALUE;
  sms_data->timer_values[TRAM] = TRAM_VALUE;
  sms_data->timer_values[TLCT] = TLCT_VALUE;
  sms_data->timer_values[TMMS] = TMMS_VALUE;

#if defined (GPRS)
  {
    int i;
    /*
     * default for MO SM: CCT preferred,
     * no LLC flow information known yet
     */
    SMS_ROUTE_PREF(sms_data) = GPRS_SMS_CCT_PREF;
    SMS_LLC_FLOW(sms_data)   = SMS_LLC_UNKNOWN;
    SMS_SMS_FLOW(sms_data)   = SMS_FLOW_UNKNOWN;

    /*
     * initialize downlink info of each instance
     */
    for (i = 0; i < MAX_SMS_CALLS; i++)
    {
      sms_data->data[i].downlink = SMS_DOWNLINK_NONE;
      sms_data->data[i].ack_type = SMS_CP_NONE;
      sms_data->data[i].cp_cause = NOT_PRESENT_8BIT;
      sms_data->data[i].cp_user_data_dl = NULL;
    }
  }
#endif
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_add_pd_ti               |
+--------------------------------------------------------------------+

  PURPOSE : Add Protocol Discriminator and Transaction Identifier to
            the SDU and modify its parameters accordingly.
*/
void cp_add_pd_ti (UBYTE ti,
                   T_sdu *sdu)
{
  if (sdu NEQ NULL)
  {
    sdu->o_buf -= BSIZE_TI_PD;
    sdu->l_buf += BSIZE_TI_PD;
    sdu->buf[BYTELEN_POS(sdu->o_buf)] = PD_SMS | (ti << 4);

    memset (sdu->buf, 0, BYTELEN(sdu->o_buf));
  }
}

#if defined (GPRS)
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_init_ll_unitdata_req    |
+--------------------------------------------------------------------+

  PURPOSE : Initialize a ll_unitdata_req.

*/
void cp_init_ll_unitdata_req (T_LL_UNITDATA_REQ * unitdata_req)
{
  unitdata_req->sapi              = LL_SAPI_7;
  unitdata_req->tlli              = LL_TLLI_INVALID;
  unitdata_req->ll_qos.delay      = LL_DELAY_SUB;
  unitdata_req->ll_qos.relclass   = LL_RLC_PROT;
  unitdata_req->ll_qos.peak       = LL_PEAK_SUB;
  unitdata_req->ll_qos.preced     = LL_PRECED_SUB;
  unitdata_req->ll_qos.mean       = LL_MEAN_SUB;
  unitdata_req->radio_prio        = LL_RADIO_PRIO_1;
  unitdata_req->cipher            = LL_CIPHER_OFF;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_send_getunitdata_req    |
+--------------------------------------------------------------------+

  PURPOSE : Initialize ready to receive protocol.

*/

GLOBAL void cp_send_getunitdata_req (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cp_send_getunitdata_req()");

  if (SMS_SMS_FLOW(sms_data) NEQ SMS_FLOW_AVAILABLE)
  {
    PALLOC (get_unitdata_req, LL_GETUNITDATA_REQ);

    memset (get_unitdata_req, 0, sizeof (T_LL_GETUNITDATA_REQ));
    get_unitdata_req->sapi = LL_SAPI_7;
    get_unitdata_req->tlli = LL_TLLI_INVALID;
    SMS_SMS_FLOW(sms_data) = SMS_FLOW_AVAILABLE;

    PSENDX (LLC, get_unitdata_req);
  }
}
#endif /* GPRS */

/*---- PRIMITIVES --------------------------------------------------*/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_mmsms_error_ind         |
+--------------------------------------------------------------------+

  PURPOSE : Processing the primitive MMSMS_ERROR_IND.

*/

GLOBAL void cp_mmsms_error_ind (T_MMSMS_ERROR_IND *error_ind)
{
  register T_SMS_DATA *sms_data = GET_SMS_INSTANCE (error_ind->ti);

  TRACE_FUNCTION_P1 ("cp_mmsms_error_ind(TI=%u)", error_ind->ti);

  if (sms_data)
  {
    TRACE_EVENT_P1 ("MMSMS_ERROR_IND.CAUSE: 0x%4.4hX", error_ind->cause);

    SMS_EM_LOSS_OF_MM_CONNECTION;

    cp_send_release_req (error_ind->ti);

    switch (SMS_INST_GET_STATE (STATE_CP))
    {
    case CP_MM_CONNECTION_PENDING:
      {
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
        SMS_INST.ti = error_ind->ti;

        /* This is meant for SMS over GSM as preference and GPRS as fallback.
         */

#ifdef GPRS
        if(sms_data->mo_dst_pref EQ GPRS_SMS_CCT_PREF)
        {
          TRACE_FUNCTION ("GSM Failed trying with GPRS ");
          rl_establish_cnf(FALSE);
        }
        else
#endif
        {
          SMS_INST.r_flag = FALSE;
          /*
           * RL_ERROR_IND =>
           */
          rl_error_ind (error_ind->cause);
        }
        break;
      }

    case CP_WAIT_FOR_ACK:
     /*
      * stop timer TC1M
      */
      sms_timer_stop(TC1M);

      SMS_RETX(sms_data)   = 0;
      SMS_INST.r_flag = FALSE;
      SMS_INST.ti = error_ind->ti;
    
      /*FALLTHROUGH*/ /*lint -fallthrough*/

    case CP_MM_CONNECTION_ESTABLISHED:

      SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
      rl_error_ind (error_ind->cause);
      break;

    default:
      SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
      FREE_SMS_INSTANCE (error_ind->ti);
      break;
    }
  }
  PFREE (error_ind);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_mmsms_establish_cnf     |
+--------------------------------------------------------------------+

  PURPOSE : Processing the primitive MMSMS_ESTABLISH_CNF.

*/

GLOBAL void cp_mmsms_establish_cnf (T_MMSMS_ESTABLISH_CNF *establish_cnf)
{
  register T_SMS_DATA *sms_data = GET_SMS_INSTANCE (establish_cnf->ti);

  TRACE_FUNCTION_P1 ("cp_mmsms_establish_cnf(TI=%u)", establish_cnf->ti);

  SMS_EM_MM_CONNECTION_ESTABLISHED;

  if (sms_data)
  {
   /*
    * set TI
    */
    sms_data->data[INST_MO].ti = establish_cnf->ti;
   /*
    * reset ack pending
    */
    SMS_INST.cp_ack_pending = FALSE;
    switch (SMS_INST_GET_STATE (STATE_CP))
    {
      case CP_MM_CONNECTION_PENDING:
      {
        /*
         * CP state transition
         */
         SMS_INST_SET_STATE (STATE_CP, CP_MM_CONNECTION_ESTABLISHED);
        /*
         * RL_ESTABLISH_CNF =>
         */
         rl_establish_cnf(TRUE);
         break;
      }
      default:
        TRACE_ERROR("MMSMS_ESTABLISH_CNF in wrong state received!");
        break;
    }
  }
  PFREE (establish_cnf);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_mmsms_release_ind       |
+--------------------------------------------------------------------+

  PURPOSE : Processing the primitive MMSMS_RELEASE_IND.

*/

GLOBAL void cp_mmsms_release_ind (T_MMSMS_RELEASE_IND *release_ind)
{
  register T_SMS_DATA *sms_data = GET_SMS_INSTANCE (release_ind->ti);

  TRACE_FUNCTION_P1 ("cp_mmsms_release_ind(TI=%u)", release_ind->ti);

  if (sms_data)
  {
    TRACE_EVENT_P1 ("MMSMS_RELEASE_IND: cause=0x%4.4hX", 
                    release_ind->cause);

    SMS_EM_MM_CONNECTION_FAILED;

    switch (SMS_INST_GET_STATE (STATE_CP))
    {
   /* ------------------------------------ */
      case CP_MM_CONNECTION_PENDING:
   /* ------------------------------------ */
      {
        /*
         * safe TI
         */
        SMS_INST.ti = release_ind->ti;
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);

        /* This is meant for SMS over GSM as preference and GPRS as fallback.
         */

#ifdef GPRS
        if(sms_data->mo_dst_pref EQ GPRS_SMS_CCT_PREF)
        {
           TRACE_FUNCTION ("GSM Failed trying with GPRS ");
           rl_establish_cnf(FALSE);
        }
        else
#endif
        {
           SMS_INST.r_flag = FALSE;
           /* RL_ERROR_IND */
           rl_error_ind (release_ind->cause);
         }
         break;
   	}

   /* ------------------------------------ */
      case CP_MM_CONNECTION_ESTABLISHED:
   /* ------------------------------------ */
      {
       /*
        * CP state transition CP_IDLE
        */
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
        SMS_INST.r_flag = FALSE;
       /*
        * RL_ERROR_IND =>
        */
        rl_error_ind (release_ind->cause);
        break;
      }
   /* ------------------------------------ */
      case CP_WAIT_FOR_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
       /*
        * CP state transition CP_IDLE
        */
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
        SMS_RETX(sms_data)   = 0;
        SMS_INST.r_flag = FALSE;
       /*
        * RL_ERROR_IND =>
        */
        rl_error_ind (release_ind->cause);
        break;
      }
   /* ------------------------------------ */
      default:
   /* ------------------------------------ */
       /*
        * CP state transition CP_IDLE
        */
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
        FREE_SMS_INSTANCE (release_ind->ti);
        break;
    }    
  }
  PFREE (release_ind);
}

/*---- SIGNALS -----------------------------------------------------*/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_abort_req               |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_ABORT_REQ.

*/

GLOBAL void cp_abort_req (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_abort_req(TI=%u)",SMS_INST.ti);


  SMS_EM_ABORT_OF_MM_CONNECTION;

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_CP))
    {
   /* ------------------------------------ */
      case CP_MM_CONNECTION_ESTABLISHED:
   /* ------------------------------------ */
      {
        CCD_START;
       /*
        * check whether CP ACK needs to be send
        */
        if (SMS_INST.cp_ack_pending EQ TRUE)
        {
          cp_build_cp_ack ();
        }
       /*
        * generate CP_ERROR
        */
        cp_build_cp_error (SMS_CP_CS_PROTOCOL_ERROR);
       /*
        * release connection
        */
        SMS_INST.r_flag = FALSE;
        cp_send_release_req (SMS_INST.ti);
        CCD_END;
        break;
      }

   /* ------------------------------------ */
      case CP_MM_CONNECTION_PENDING:
   /* ------------------------------------ */
      {
       /*
        * release connection
        */
        SMS_INST.r_flag = FALSE;
        cp_send_release_req (SMS_INST.ti);
        break;
      }

   /* ------------------------------------ */
      case CP_WAIT_FOR_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
        CCD_START;
       /*
        * check whether CP ACK needs to be send
        */
        if (SMS_INST.cp_ack_pending EQ TRUE)
        {
          cp_build_cp_ack ();
        }
       /*
        * generate CP_ERROR
        */
        cp_build_cp_error (SMS_CP_CS_PROTOCOL_ERROR);
       /*
        * release connection
        */
        SMS_INST.r_flag = FALSE;
        cp_send_release_req (SMS_INST.ti);

        CCD_END;
        break;
      }

#if defined (GPRS)
   /* ------------------------------------ */
      case CP_GSMS_MO_WAIT_FOR_CP_DATA:
   /* ------------------------------------ */
      case CP_GSMS_MT_WAIT_FOR_RP_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
        cp_error_req_gsms (SMS_CP_CS_PROTOCOL_ERROR, FALSE);
        break;
      }
#endif /* GPRS */
    }
#if defined (GPRS)
    if (SMS_CP_ACK_TYPE(sms_data) EQ SMS_CP_NONE)
#endif /* GPRS */
    {
      SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_data_ind_cp_ack         |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_DATA_IND_CP_ACK.

*/

GLOBAL void cp_data_ind_cp_ack (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_data_ind_cp_ack(TI=%u)", SMS_INST.ti);

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_CP))
    {
   /* ------------------------------------ */
      case CP_MM_CONNECTION_ESTABLISHED:
   /* ------------------------------------ */
      {
        /* Implements Measure# 8 */
        cp_send_err_ind_msg_not_comp ();  
        break;
      }

   /* ------------------------------------ */
      case CP_WAIT_FOR_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
          sms_timer_stop(TC1M);


        if (SMS_INST.r_flag)
        {
          SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
          SMS_INST.r_flag   = FALSE;

          cp_send_release_req (SMS_INST.ti);
          FREE_SMS_INSTANCE (SMS_INST.ti);
        }
        else
        {
          SMS_INST_SET_STATE (STATE_CP, CP_MM_CONNECTION_ESTABLISHED);
        }
        break;
      }

#if defined (GPRS)
    /* ------------------------------------ */
     case CP_GSMS_IDLE:
   /* ------------------------------------ */
      {
        if (SMS_INST.r_flag)
        {
          SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
          SMS_INST.r_flag   = FALSE;
          FREE_SMS_INSTANCE (SMS_INST.ti);
        }
        else
        {
          cp_error_req_gsms (SMS_CP_CS_MSG_NOT_COMP, TRUE);
        }
        break;
      }

   /* ------------------------------------ */
      case CP_GSMS_MO_WAIT_FOR_CP_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
        if (SMS_INST.r_flag)
        {
          SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
          SMS_INST.r_flag   = FALSE;
          FREE_SMS_INSTANCE (SMS_INST.ti);
        }
        else
        {
          SMS_INST_SET_STATE (STATE_CP, CP_GSMS_MO_WAIT_FOR_CP_DATA);
        }
        break;
      }

   /* ------------------------------------ */
      case CP_GSMS_MT_WAIT_FOR_CP_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
        if (SMS_INST.r_flag)
        {
          SMS_INST.r_flag   = FALSE;
        }
        FREE_SMS_INSTANCE (SMS_INST.ti);
        break;
      }

   /* ------------------------------------ */
      case CP_GSMS_MO_WAIT_FOR_CP_DATA:
   /* ------------------------------------ */
      case CP_GSMS_MT_WAIT_FOR_RP_ACK:
   /* ------------------------------------ */
      {
        cp_error_req_gsms (SMS_CP_CS_MSG_NOT_COMP, FALSE);
        rl_error_ind (CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS,
                                SMSCP_ORIGINATING_ENTITY, SMS_CP_CS_MSG_NOT_COMP));

        break;
      }
#endif /* GPRS */
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_data_ind_cp_data        |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_DATA_IND_CP_DATA.

*/
GLOBAL void cp_data_ind_cp_data (T_D_CP_DATA *cp_data)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_data_ind_cp_data(TI=%u)", SMS_INST.ti);

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_CP))
    {
   /* ------------------------------------ */
      case CP_WAIT_FOR_ACK:
   /* ------------------------------------ */
      {
        if (SMS_INST.r_flag)
        {
          /* Nothing expected anymore */

         /*
          * stop timer TC1M
          */
          sms_timer_stop(TC1M);
          /* Implements Measure# 8 */
          cp_send_err_ind_msg_not_comp ();  
          break;
        }
        else
        {
          TRACE_EVENT ("CP ACK lost");
          cp_data_ind_cp_ack ();
        }
      }
      /*FALLTHROUGH*/ /*lint -fallthrough*/

   /* ------------------------------------ */
      case CP_MM_CONNECTION_ESTABLISHED:
   /* ------------------------------------ */
      {
       /*
        * remember to cp ack
        */
        SMS_INST.cp_ack_pending = TRUE;
       /*
        * RL_DATA_IND =>
        */
        rl_data_ind (&cp_data->cp_user_data_dl);
        break;
      }

#if defined (GPRS)
   /* ------------------------------------ */
      case CP_GSMS_IDLE:
   /* ------------------------------------ */
      {
        if (SMS_LLC_FLOW(sms_data) EQ SMS_LLC_AVAILABLE)
        {
          cp_build_cp_ack ();
        }
        else
        {
          SMS_CP_ACK_TYPE(sms_data) = SMS_CP_ACK;
          SMS_LLC_FLOW(sms_data) = SMS_LLC_BUSY_WAITING;
        }
        SMS_INST_SET_STATE (STATE_CP, CP_GSMS_MT_WAIT_FOR_RP_ACK);
        rl_data_ind (&cp_data->cp_user_data_dl);
        break;
      }

   /* ------------------------------------ */
      case CP_GSMS_MO_WAIT_FOR_CP_DATA:
   /* ------------------------------------ */
      {
        if (SMS_LLC_FLOW(sms_data) EQ SMS_LLC_AVAILABLE)
        {
         /* 
          * generate CP_ACK
          */
          cp_build_cp_ack ();
         /*
          * RL_DATA_IND =>
          */
          rl_data_ind (&cp_data->cp_user_data_dl);
        }
        else
        {
          if (SMS_CP_UDL(sms_data) EQ NULL)
          {
            MALLOC(SMS_CP_UDL(sms_data), sizeof(T_cp_user_data_dl));
          }
          memcpy (SMS_CP_UDL(sms_data), &cp_data->cp_user_data_dl,
                  sizeof(T_cp_user_data_dl));
          SMS_CP_ACK_TYPE(sms_data) = SMS_CP_ACK;
          SMS_LLC_FLOW(sms_data) = SMS_LLC_BUSY_WAITING;
          SMS_INST_SET_STATE (STATE_CP, CP_GSMS_IDLE);
          SMS_INST.r_flag = TRUE;
        }
        break;
      }
   /* ------------------------------------ */
      case CP_GSMS_MO_WAIT_FOR_CP_ACK:
   /* ------------------------------------ */
      case CP_GSMS_MT_WAIT_FOR_CP_ACK:
   /* ------------------------------------ */
      case CP_GSMS_MT_WAIT_FOR_RP_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
        cp_error_req_gsms (SMS_CP_CS_MSG_NOT_COMP, FALSE);

        rl_error_ind (CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS,
                                SMSCP_ORIGINATING_ENTITY, SMS_CP_CS_MSG_NOT_COMP));
        break;
      }
#endif /* GPRS */
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_data_ind_cp_error       |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_DATA_IND_CP_ERROR.
            The cause value is marked as CP-ERROR
*/
GLOBAL void cp_data_ind_cp_error (UBYTE      errcs)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_data_ind_cp_error(TI=%u)", SMS_INST.ti);
  TRACE_EVENT_P1 ("CP Error Cause = %d", (int)errcs);

  if (sms_data)
  {
    TRACE_EVENT_P1 ("CP_ERROR.CAUSE rcvd: 0x%2.2X", (int)errcs);

    switch (SMS_INST_GET_STATE (STATE_CP))
    {
   /* ------------------------------------ */
      case CP_MM_CONNECTION_ESTABLISHED:
   /* ------------------------------------ */
      {
        /* Implements Measure# 4 */      
        cp_send_err_ind_errcs(errcs);
        break;
      }

   /* ------------------------------------ */
      case CP_WAIT_FOR_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
        /* Implements Measure# 4 */
        cp_send_err_ind_errcs(errcs);
        break;
      }

#if defined (GPRS)
   /* ------------------------------------ */
      case CP_GSMS_IDLE:
   /* ------------------------------------ */
      {
        SMS_INST.r_flag = FALSE;
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);

        /* FREE_SMS_INSTANCE (SMS_INST.ti); */
        break;
      }

   /* ------------------------------------ */
      case CP_GSMS_MO_WAIT_FOR_CP_DATA:
   /* ------------------------------------ */
      case CP_GSMS_MT_WAIT_FOR_RP_ACK:
   /* ------------------------------------ */
      {
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
        SMS_INST.r_flag = FALSE;

        rl_error_ind (CAUSE_MAKE(DEFBY_STD, ORIGSIDE_NET,
                                SMSCP_ORIGINATING_ENTITY, errcs));
        /* FREE_SMS_INSTANCE (SMS_INST.ti); */
        break;
      }

   /* ------------------------------------ */
      case CP_GSMS_MO_WAIT_FOR_CP_ACK:
   /* ------------------------------------ */
      case CP_GSMS_MT_WAIT_FOR_CP_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);

        SMS_INST.r_flag = FALSE;
        rl_error_ind (CAUSE_MAKE(DEFBY_STD, ORIGSIDE_NET,
                      SMSCP_ORIGINATING_ENTITY, errcs));

        /*FREE_SMS_INSTANCE (SMS_INST.ti);*/
        break;
      }
#endif /* GPRS */

    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_data_ind_cp_unknown     |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_DATA_IND_CP_UNKNOWN.

*/
GLOBAL void cp_data_ind_cp_unknown (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_data_ind_cp_unknown(TI=%u)", SMS_INST.ti);

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_CP))
    {
   /* ------------------------------------ */
      case CP_MM_CONNECTION_ESTABLISHED:
   /* ------------------------------------ */
      {
        /* Implements Measure# 3 */
        cp_send_err_ind_msg_type_unknown();  
        break;
      }

   /* ------------------------------------ */
      case CP_WAIT_FOR_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
        /* Implements Measure# 3 */  
        cp_send_err_ind_msg_type_unknown();  
        break;
      }

#if defined (GPRS)
   /* ------------------------------------ */
      case CP_GSMS_IDLE:
   /* ------------------------------------ */
      {
        cp_error_req_gsms (SMS_CP_CS_MSG_TYPE_NON_EXIST, TRUE);
        break;
      }

   /* ------------------------------------ */
      case CP_GSMS_MO_WAIT_FOR_CP_ACK:
   /* ------------------------------------ */
      case CP_GSMS_MT_WAIT_FOR_CP_ACK:
   /* ------------------------------------ */
      {
       /*
        * stop timer TC1M
        */
        sms_timer_stop(TC1M);
      }
      /*FALLTHROUGH*/ /*lint -fallthrough*/
   /* ------------------------------------ */
      case CP_GSMS_MO_WAIT_FOR_CP_DATA:
   /* ------------------------------------ */
      case CP_GSMS_MT_WAIT_FOR_RP_ACK:
   /* ------------------------------------ */
      {
        cp_error_req_gsms (SMS_CP_CS_MSG_TYPE_NON_EXIST, FALSE);
        rl_error_ind (CAUSE_MAKE(DEFBY_STD, ORIGSIDE_MS,
                                SMSCP_ORIGINATING_ENTITY, SMS_CP_CS_MSG_TYPE_NON_EXIST));

        break;
      }
#endif /* GPRS */
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_establish_req           |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_ESTABLISH_REQ.

*/

GLOBAL void cp_establish_req (UBYTE ti)
{
  GET_INSTANCE_DATA;
    TRACE_FUNCTION_P1 ("cp_establish_req(TI=%u)",ti);

#if defined (GPRS)
    /*
     * send data on selected downlink
     */
    if (SMS_INST.downlink EQ SMS_DOWNLINK_MMSMS)
    {
#endif /* GPRS */

     /*
      * GSM - establish connection
      */
      switch (SMS_INST_GET_STATE (STATE_CP))
      {
     /* ------------------------------------ */
        case CP_IDLE:
     /* ------------------------------------ */
        default:
     /* ------------------------------------ */
        {
          PALLOC (establish_req, MMSMS_ESTABLISH_REQ);

          SMS_EM_MM_CONNECTION_ESTABLISHMENT;

          establish_req->ti = ti;

          SMS_INST_SET_STATE (STATE_CP, CP_MM_CONNECTION_PENDING);

          PSENDX (MM, establish_req);
          break;
        }
     /* ------------------------------------ */
        //default:
     /* ------------------------------------ */
        //   TRACE_ERROR("CP_ESTABLISH_REQ in wrong state received!");
      }
#if defined (GPRS)
    }
    else if (SMS_INST.downlink EQ SMS_DOWNLINK_LL_CHECK)
    {
     /*
      * GMMSMS_REG_STATE_REQ ==>
      */
      PALLOC (reg_state_req, GMMSMS_REG_STATE_REQ);
      PSENDX (GMM, reg_state_req);
     /*
      * CP state transition
      */
      SMS_INST_SET_STATE (STATE_CP, CP_MM_CONNECTION_PENDING);
     /*
      * set TI
      */
      sms_data->data[INST_MO].ti = ti;
    }
    else
    {
     /*
      * set TI
      */
      sms_data->data[INST_MO].ti = ti;
     /*
      * GPRS - do nothing
      */
      rl_establish_cnf(TRUE); /* synchronous call back */
    }
#endif /* GPRS */

}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_data_req                |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_DATA_REQ.

*/

GLOBAL void cp_data_req (T_U_CP_DATA *cp_data)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_data_req(TI=%u)",SMS_INST.ti);

  if (sms_data)
  {
    /*
     * U_CP_DATA contains a maximum of 252 Bytes
     */
    PALLOC_SDU (data_req, MMSMS_DATA_REQ, LEN_U_CP_DATA);

    data_req->sdu.o_buf = ENCODE_OFFSET;

    cp_data->msg_type = U_CP_DATA;

    ccd_codeMsg (CCDENT_SMS,
                 UPLINK,
                 (T_MSGBUF *)&data_req->sdu,
                 (UBYTE *)cp_data,
                 NOT_PRESENT_8BIT);

    cp_add_pd_ti (SMS_CP_REF(sms_data), &data_req->sdu);
#if defined (GPRS)
    /*
     * send data on selected downlink
     */
    if (SMS_INST.downlink EQ SMS_DOWNLINK_MMSMS)
    {
#endif /* GPRS */

      switch (SMS_INST_GET_STATE (STATE_CP))
      {
     /* ------------------------------------ */
        case CP_MM_CONNECTION_ESTABLISHED:
     /* ------------------------------------ */
        {
          USHORT bsize_message = D_SDU_OFF (data_req)+
                                 D_SDU_LEN (data_req);
          PALLOC_SDU (tx_data_req, MMSMS_DATA_REQ, bsize_message);
         /*
          * check whether CP ACK needs to be send
          */
          if (SMS_INST.cp_ack_pending EQ TRUE)
          {
            cp_build_cp_ack ();
          }
         /*
          * reset retry counter
          */
          SMS_RETX(sms_data) = 0;
         /*
          * save data req
          */
          if (SMS_DATA_REQ(sms_data) NEQ NULL)
            PFREE (SMS_DATA_REQ(sms_data));
          SMS_DATA_REQ(sms_data) = data_req;
         /*
          * CP state transition CP_WAIT_FOR_ACK
          */
          SMS_INST_SET_STATE (STATE_CP, CP_WAIT_FOR_ACK);

          SMS_EM_SEND_CP_DATA;

#if FALSE
          PCOPY (tx_data_req, data_req);
#else
          SMS_SDU_COPY (tx_data_req, data_req, MMSMS_DATA_REQ);
#endif
          TRACE_BINDUMP(sms_handle,
                        TC_USER4,
                        "U_CP_DATA",
                        (&(tx_data_req->sdu.buf[0]) + ((tx_data_req->sdu.o_buf >> 3) -1)),
                        ((tx_data_req->sdu.l_buf >> 3) + 1));
          PSENDX (MM, tx_data_req);
         /*
          * start timer TC1M
          */
          sms_timer_start(TC1M);
          break;
        }

     /* ------------------------------------ */
        default:
     /* ------------------------------------ */
        {
          TRACE_ERROR("CP_DATA_REQ in wrong state received!");
          PFREE (data_req);
          break;
        }
      }

#if defined (GPRS)
    }
    else
      cp_data_req_gsms (data_req);
#endif /* GPRS */

  }
}

#if defined (GPRS)
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_send_data_gsms          |
+--------------------------------------------------------------------+

  PURPOSE : Send CP_DATA_REQ on LL downlink. LLC availability to be
            checked by the caller
*/

GLOBAL void cp_send_data_gsms (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cp_send_data_gsms()");

  if (sms_data)
  {
    USHORT bsize_message = ENCODE_OFFSET +
                           D_SDU_LEN (SMS_DATA_REQ(sms_data));
    PALLOC_SDU (unitdata_req, LL_UNITDATA_REQ, bsize_message);

    /*
     * copy stored mo message sdu to unitdata sdu buffer
     */
    SMS_SDU_COPY (unitdata_req, SMS_DATA_REQ(sms_data), LL_UNITDATA_REQ);

    cp_init_ll_unitdata_req (unitdata_req);
    TRACE_BINDUMP(sms_handle,
                  TC_USER4,
                  "U_CP_DATA",
                  (&(unitdata_req->sdu.buf[0]) + ((unitdata_req->sdu.o_buf >> 3) -1)),
                  ((unitdata_req->sdu.l_buf >> 3) + 1));
    PSENDX (LLC, unitdata_req);
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_data_req_gsms           |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_DATA_REQ on LL downlink.

*/

GLOBAL void cp_data_req_gsms (T_MMSMS_DATA_REQ *data_req)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cp_data_req_gsms()");

  if (sms_data)
  {
    /*
     * check if LL is still registered
     */
    if (SMS_INST.downlink EQ SMS_DOWNLINK_LL_CHECK)
    {
      PALLOC (reg_state_req, GMMSMS_REG_STATE_REQ);
      memset (reg_state_req, 0, sizeof (T_GMMSMS_REG_STATE_REQ));
      PSENDX (GMM, reg_state_req);

      SMS_INST_SET_STATE (STATE_CP, CP_GSMS_IDLE);
    }

    switch (SMS_INST_GET_STATE (STATE_CP))
    {
      case CP_IDLE:
      case CP_GSMS_IDLE:
      case CP_GSMS_MO_WAIT_FOR_CP_DATA:
      case CP_GSMS_MT_WAIT_FOR_RP_ACK:
      {
        /*
         * save message for later usage
         */
        if (SMS_DATA_REQ(sms_data) NEQ NULL)
        {
          PFREE (SMS_DATA_REQ(sms_data));
        }
        SMS_DATA_REQ(sms_data) = data_req;

        /*
         * send message if flow control allows
         */
        if (SMS_INST.downlink EQ SMS_DOWNLINK_LL)
        {
          if (SMS_LLC_FLOW(sms_data) EQ SMS_LLC_AVAILABLE)
          {
            cp_send_data_gsms ();
            SMS_LLC_FLOW(sms_data) = SMS_LLC_BUSY;
          }
          else
          {
            SMS_LLC_FLOW(sms_data) = SMS_LLC_BUSY_WAITING;
          }
          if ((SMS_INST_GET_STATE (STATE_CP)) EQ CP_GSMS_MT_WAIT_FOR_RP_ACK)
          {
            SMS_INST_SET_STATE (STATE_CP, CP_GSMS_MT_WAIT_FOR_CP_ACK);
          }
          else if ((SMS_INST_GET_STATE (STATE_CP)) EQ CP_GSMS_MO_WAIT_FOR_CP_DATA)
          {
            SMS_INST_SET_STATE (STATE_CP, CP_GSMS_IDLE);
          }
          else
          {
            SMS_INST_SET_STATE (STATE_CP, CP_GSMS_MO_WAIT_FOR_CP_ACK);
          }
          SMS_RETX(sms_data) = 0;
         /*
          * start timer TC1M
          */
          sms_timer_start(TC1M);
        }
        break;
      }

      default:
      {
        PFREE (data_req);
        break;
      }
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_error_req_gsms          |
+--------------------------------------------------------------------+

  PURPOSE : Sending CP-ERROR over GPRS with consideration of LLC
            flow control.
*/

GLOBAL void cp_error_req_gsms (UBYTE      cause,
                               BOOL       free_ti)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cp_error_req_gsms()");

  if (sms_data)
  {
    if (SMS_LLC_FLOW(sms_data) EQ SMS_LLC_AVAILABLE)
    {
      CCD_START;
      cp_build_cp_error (cause);
      CCD_END;

      SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
      SMS_INST.r_flag = FALSE;
      if(free_ti)
      {
        FREE_SMS_INSTANCE (SMS_INST.ti);
      }
      sms_data->llc_flow = SMS_LLC_BUSY;
    }
    else
    {
      SMS_CP_ACK_TYPE(sms_data) = SMS_CP_ERROR;
      SMS_CP_CAUSE(sms_data) = cause;

      SMS_INST_SET_STATE (STATE_CP, CP_GSMS_IDLE);
      SMS_LLC_FLOW(sms_data) = SMS_LLC_BUSY_WAITING;
    }
  }
}
#endif /* GPRS */

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_est_ind_cp_ack          |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_EST_IND_CP_ACK.

*/

GLOBAL void cp_est_ind_cp_ack (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_est_ind_cp_ack(TI=%u)",SMS_INST.ti);

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_CP))
    {
      case CP_IDLE:
      {
        cp_build_cp_error (SMS_CP_CS_MSG_NOT_COMP);

        SMS_INST.r_flag = FALSE;
        /*FALLTHROUGH*/ /*lint -fallthrough*/
      default:
        cp_send_release_req (SMS_INST.ti);

        FREE_SMS_INSTANCE (SMS_INST.ti);
        break;
      }
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_est_ind_cp_data         |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_EST_IND_CP_DATA.

*/

GLOBAL void cp_est_ind_cp_data (T_D_CP_DATA *cp_data)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_est_ind_cp_data(TI=%u)",SMS_INST.ti);

  switch (SMS_INST_GET_STATE (STATE_CP))
  {
    case CP_IDLE:
    {
     /*
      * generate CP_ACK
      */
      cp_build_cp_ack ();
     /*
      * CP state transition CP_MM_CONNECTION_ESTABLISHED
      */
      SMS_INST_SET_STATE (STATE_CP, CP_MM_CONNECTION_ESTABLISHED);
     /*
      * r flag
      */
      SMS_INST.r_flag         = FALSE;
     /*
      * RL_DATA_IND =>
      */
      rl_data_ind (&cp_data->cp_user_data_dl);
      break;
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_est_ind_cp_error        |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_EST_IND_CP_ERROR.

*/

GLOBAL void cp_est_ind_cp_error (UBYTE      cp_error)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_est_ind_cp_error(TI=%u)", SMS_INST.ti);
  TRACE_EVENT_P1 ("CP Error Cause = %d", (int)cp_error);

  if (sms_data)
  {
    TRACE_EVENT_P1 ("CP_ERROR.CAUSE rcvd: 0x%2.2X", (int)cp_error);

    switch (SMS_INST_GET_STATE (STATE_CP))
    {
      case CP_IDLE:
      {
        SMS_INST.r_flag = FALSE;

        cp_send_release_req (SMS_INST.ti);
        FREE_SMS_INSTANCE (SMS_INST.ti);
        break;
      }
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_est_ind_cp_unknown      |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_EST_IND_CP_UNKNOWN.

*/

GLOBAL void cp_est_ind_cp_unknown (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_est_ind_cp_unknown(TI=%u)", SMS_INST.ti);

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_CP))
    {
      case CP_IDLE:
      {
        cp_build_cp_error (SMS_CP_CS_INFO_NON_EXIST);

        SMS_INST.r_flag = FALSE;

        cp_send_release_req (SMS_INST.ti);

        FREE_SMS_INSTANCE (SMS_INST.ti);
        break;
      }
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_release_req             |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal CP_RELEASE_REQ.

*/

GLOBAL void cp_release_req (UBYTE ti)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION_P1 ("cp_release_req(TI=%u)", ti);

  if (sms_data)
  {
    switch (SMS_INST_GET_STATE (STATE_CP))
    {
      case CP_IDLE:
        SMS_INST.r_flag = FALSE;
        FREE_SMS_INSTANCE (ti);
        break;

      case CP_WAIT_FOR_ACK:
        SMS_INST.r_flag = TRUE;
        break;

      case CP_MM_CONNECTION_PENDING:
       /*
        * new connection establishment pending 
        * while releasing old connection
        * (-> concat sms)
        */
       /*
        * check whether CP ACK needs to be send
        */
        if (SMS_INST.cp_ack_pending EQ TRUE)
        {
          cp_build_cp_ack ();
        }
       /*
        * release connection
        */
        SMS_INST.r_flag = FALSE;
        cp_send_release_req (ti);
        break;

      case CP_MM_CONNECTION_ESTABLISHED:
       /*
        * check whether CP ACK needs to be send
        */
        if (SMS_INST.cp_ack_pending EQ TRUE)
        {
          cp_build_cp_ack ();
        }
       /*
        * CP state transition CP_IDLE
        */
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
       /*
        * release connection
        */
        SMS_INST.r_flag = FALSE;
        cp_send_release_req (ti);
        break;

#ifdef GPRS
      case CP_GSMS_IDLE:
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
        SMS_INST.r_flag = FALSE;
        FREE_SMS_INSTANCE (SMS_INST.ti);
        break;

      case CP_GSMS_MO_WAIT_FOR_CP_ACK:
      case CP_GSMS_MT_WAIT_FOR_CP_ACK:
        SMS_INST.r_flag = TRUE;
        break;

      case CP_GSMS_MO_WAIT_FOR_CP_DATA:
      case CP_GSMS_MT_WAIT_FOR_RP_ACK:
        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
        SMS_INST.r_flag = FALSE;
        FREE_SMS_INSTANCE (SMS_INST.ti);
        break;
#endif /* #ifdef GPRS */

      default:
        break;
    }
  }
}

#if defined (GPRS)
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_gmmsms_reg_state_cnf    |
+--------------------------------------------------------------------+

  PURPOSE : Processing the signal GMMSMS_REG_STATE_CNF (GSMS only).

*/
GLOBAL void cp_gmmsms_reg_state_cnf (T_GMMSMS_REG_STATE_CNF *reg_state_cnf)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cp_gmmsms_reg_state_cnf()");

  if (sms_data EQ NULL)
  {
     TRACE_ERROR("Horror: sms_data=NULL");
     return;
  }

  if (SMS_INST_GET_STATE (STATE_CP) EQ CP_MM_CONNECTION_PENDING)
  {
     /*
      * CP state transition
      */
      SMS_INST_SET_STATE (STATE_CP, CP_GSMS_IDLE);
      if (reg_state_cnf->reg_state EQ SMS_RS_REGISTERED)
      {
         TRACE_EVENT("downlink = SMS_DOWNLINK_LL");
         SMS_INST.downlink = SMS_DOWNLINK_LL;
         cp_send_getunitdata_req ();
        /*
         * RL_ESTABLISH_CNF =>
         */
         rl_establish_cnf(TRUE);
      }
      else
      {
        /*
         * RL_ESTABLISH_CNF =>
         */
         rl_establish_cnf(FALSE);
      }
  }
  else if (SMS_INST_GET_STATE (STATE_CP) EQ CP_GSMS_IDLE)
  {
    if (reg_state_cnf->reg_state EQ SMS_RS_REGISTERED)
    {
      SMS_INST.downlink = SMS_DOWNLINK_LL;
      cp_send_getunitdata_req ();

      if (SMS_LLC_FLOW(sms_data) EQ SMS_LLC_AVAILABLE)
      {
        /*
         * using LL is possible, send message
         */
        cp_send_data_gsms ();
        SMS_LLC_FLOW(sms_data) = SMS_LLC_BUSY;
      }
      else
      {
        SMS_LLC_FLOW(sms_data) = SMS_LLC_BUSY_WAITING;
      }
      SMS_INST_SET_STATE (STATE_CP, CP_GSMS_MO_WAIT_FOR_CP_ACK);
      SMS_RETX(sms_data) = 0;
     /*
      * start timer TC1M
      */
      sms_timer_start(TC1M);
    }
    else
    {
      SMS_LLC_FLOW(sms_data) = SMS_LLC_UNKNOWN;

      if (sms_data->mo_dst_pref EQ GPRS_SMS_GPRS_PREF)
      {
        /*
         * unsing the preferred downlink LL failed, use CSD
         */

        PALLOC (establish_req, MMSMS_ESTABLISH_REQ);
        TRACE_EVENT("GPRS not registered, fallback to CSD");

        establish_req->ti = SMS_INST.ti;

        SMS_INST.downlink = SMS_DOWNLINK_MMSMS;
        SMS_INST_SET_STATE (STATE_CP, CP_MM_CONNECTION_PENDING);

        PSENDX (MM, establish_req);
      }
      else
      {
        /*
         * only GPRS is configured to be used, abort
         */
        cp_send_release_req (SMS_INST.ti);

        SMS_INST_SET_STATE (STATE_CP, CP_IDLE);
        SMS_INST.r_flag = FALSE;
        
        SMS_INST.downlink = SMS_DOWNLINK_NONE;

        rl_error_ind (SMS_CAUSE_NO_SERVICE);
        
        /* FREE_SMS_INSTANCE (SMS_INST.ti); */
      }
    }
  }
  PFREE (reg_state_cnf);
}
#endif /* GPRS */

/*---- FUNCTIONS ---------------------------------------------------*/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_build_cp_ack            |
+--------------------------------------------------------------------+

  PURPOSE : Processing the function CP_BUILD_CP_ACK.
            (GPRS: the appropriate downlink is determined first)
*/
GLOBAL void cp_build_cp_ack (void)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cp_build_cp_ack()");

 /*
  * reset cp ack pending
  */
  SMS_INST.cp_ack_pending = FALSE;

#if defined (GPRS)
  if (SMS_INST.downlink EQ SMS_DOWNLINK_MMSMS)
#endif /* GPRS */
  {
    PALLOC_SDU (data_req, MMSMS_DATA_REQ, ENCODE_OFFSET+BSIZE_B_CP_ACK);

    data_req->sdu.o_buf = ENCODE_OFFSET;
    data_req->sdu.l_buf = BSIZE_B_CP_ACK;

    data_req->sdu.buf[BYTELEN_POS(data_req->sdu.o_buf)] = B_CP_ACK;
    cp_add_pd_ti (SMS_CP_REF(sms_data), &data_req->sdu);

    SMS_EM_SEND_CP_ACKNOWLEDGE;
    TRACE_BINDUMP(sms_handle,
                  TC_USER4,
                  "B_CP_ACK",
                  (&(data_req->sdu.buf[0]) + ((data_req->sdu.o_buf >> 3) -1)),
                  ((data_req->sdu.l_buf >> 3) + 1));
    PSENDX (MM, data_req);
    return;
  }

#if defined (GPRS)
  if ((SMS_INST.downlink EQ SMS_DOWNLINK_LL) /*AND
      (sms_data->llc_flow EQ SMS_LLC_AVAILABLE)*/)
  {
    /*
     * build cp_ack for LL downlink
     */
    PALLOC_SDU (unitdata_req, LL_UNITDATA_REQ, ENCODE_OFFSET+BSIZE_B_CP_ACK);

    unitdata_req->sdu.o_buf = ENCODE_OFFSET;
    unitdata_req->sdu.l_buf = BSIZE_B_CP_ACK;

    unitdata_req->sdu.buf[BYTELEN_POS(unitdata_req->sdu.o_buf)] = B_CP_ACK;
    cp_add_pd_ti (SMS_CP_REF(sms_data), &unitdata_req->sdu);

    cp_init_ll_unitdata_req (unitdata_req);

    SMS_LLC_FLOW(sms_data) = SMS_LLC_BUSY;
    TRACE_BINDUMP(sms_handle,
                  TC_USER4,
                  "B_CP_ACK",
                  (&(unitdata_req->sdu.buf[0]) + ((unitdata_req->sdu.o_buf >> 3) -1)),
                  ((unitdata_req->sdu.l_buf >> 3) + 1));
    PSENDX (LLC, unitdata_req);
  }
#endif /* GPRS */
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_build_cp_error          |
+--------------------------------------------------------------------+

  PURPOSE : Processing the function CP_BUILD_CP_ERROR.

*/
GLOBAL void cp_build_cp_error (UBYTE      error)
{
  GET_INSTANCE_DATA;
  if (sms_data)
  {
    TRACE_EVENT_P1 ("CP_ERROR.CAUSE sent: 0x%2.2X", (int)error);

#if defined (GPRS)
    if (SMS_INST.downlink EQ SMS_DOWNLINK_MMSMS)
#endif /* GPRS */

    {
      MCAST (cp_error, B_CP_ERROR);
      PALLOC_MSG (data_req, MMSMS_DATA_REQ, B_CP_ERROR);

      TRACE_FUNCTION ("cp_build_cp_error()");

      SMS_EM_SEND_CP_ERROR;

     /*
      * check whether CP ACK needs to be send
      */
      if (SMS_INST.cp_ack_pending EQ TRUE)
      {
        cp_build_cp_ack ();
      }

      data_req->sdu.o_buf = ENCODE_OFFSET;

      cp_error->msg_type = B_CP_ERROR;
      cp_error->cp_cause = error;

      ccd_codeMsg (CCDENT_SMS,
                   UPLINK,
                   (T_MSGBUF *) &data_req->sdu,
                   (UBYTE *) _decodedMsg,
                   NOT_PRESENT_8BIT);

      cp_add_pd_ti (SMS_CP_REF(sms_data), &data_req->sdu);
      TRACE_BINDUMP(sms_handle,
                    TC_USER4,
                    "B_CP_ERROR",
                    (&(data_req->sdu.buf[0]) + ((data_req->sdu.o_buf >> 3) -1)),
                    ((data_req->sdu.l_buf >> 3) + 1));
      PSENDX (MM, data_req);
      return;
    }

#if defined (GPRS)
    if ((SMS_INST.downlink EQ SMS_DOWNLINK_LL) /*&&
        (sms_data->llc_flow EQ SMS_LLC_AVAILABLE)*/)
    {
      /*
       * build cp_error for LL downlink
       */
      MCAST (cp_error, B_CP_ERROR);

      PALLOC_MSG (unitdata_req, LL_UNITDATA_REQ, B_CP_ERROR);

      TRACE_FUNCTION ("cp_build_cp_error() - LL downlink");

      unitdata_req->sdu.o_buf = ENCODE_OFFSET;

      cp_error->msg_type = B_CP_ERROR;
      cp_error->cp_cause = error;

      ccd_codeMsg (CCDENT_SMS,
                   UPLINK,
                   (T_MSGBUF *) &unitdata_req->sdu,
                   (UBYTE *) _decodedMsg,
                   NOT_PRESENT_8BIT);

      cp_add_pd_ti (SMS_CP_REF(sms_data), &unitdata_req->sdu);
      cp_init_ll_unitdata_req (unitdata_req);
      TRACE_BINDUMP(sms_handle,
                    TC_USER4,
                    "B_CP_ERROR",
                    (&(unitdata_req->sdu.buf[0]) + ((unitdata_req->sdu.o_buf >> 3) -1)),
                    ((unitdata_req->sdu.l_buf >> 3) + 1));
      PSENDX (LLC, unitdata_req);
    }
#endif /* GPRS */
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (8410)       MODULE  : SMS_CP                     |
| STATE   : code                ROUTINE : cp_send_release_req        |
+--------------------------------------------------------------------+

  PURPOSE : Send a MMSMS_RELEASE_REQ.
            (GPRS: only if this is not an LL downlink)

*/
GLOBAL void cp_send_release_req ( UBYTE ti)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cp_send_release_req()");

  if (sms_data)
  {
#if defined (GPRS)
    if (SMS_INST.downlink EQ SMS_DOWNLINK_MMSMS)
    {
#endif
      PALLOC (release_req, MMSMS_RELEASE_REQ);

      release_req->ti = ti;

      PSENDX (MM, release_req);

#if defined (GPRS)
    }
#endif
  }
}

#endif