view src/g23m-gsm/cc/cc_est.c @ 303:f76436d19a7a default tip

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

/* 
+----------------------------------------------------------------------------- 
|  Project :  GSM-PS (6147)
|  Modul   :  CC_EST
+----------------------------------------------------------------------------- 
|  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 establishment
|             phase of the call control process of the component CC.
+----------------------------------------------------------------------------- 
*/ 

#ifndef CC_EST_C
#define CC_EST_C

#define ENTITY_CC
/*==== INCLUDES ===================================================*/

#include <string.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 "cnf_cc.h"
#include "mon_cc.h"
#include "pei.h"
#include "tok.h"
#include "cc.h"
#include "cc_em.h"

/*==== EXPORT =====================================================*/
/*==== PROTOTYPE ==================================================*/
/* Implements Measure#  19 */                                       
LOCAL void cc_send_release_cmp (USHORT cause);
LOCAL void cc_send_mncc_release_ind (UBYTE  ti, USHORT cause);
/*==== PRIVAT =====================================================*/

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

/*==== FUNCTIONS ==================================================*/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_init                    |
+--------------------------------------------------------------------+

  PURPOSE : Initialisation of CC data.

*/

GLOBAL void cc_init (void)
{
#ifdef OPTION_MULTIPLE_INSTANCES

  USHORT i;

  TRACE_FUNCTION ("cc_init()");

  for (i=0;i<MAX_INSTANCES;i++)
    cc_init_data (&data_base[i]);
}
#else

  TRACE_FUNCTION ("cc_init()");
  cc_init_data ();
#endif
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)            MODULE  : CC_EST                |
| STATE   : code                     ROUTINE : cc_init_data          |
+--------------------------------------------------------------------+

  PURPOSE : Initializes the data for one instance.

*/

GLOBAL void cc_init_data (void)
{
  GET_INSTANCE_DATA;
  USHORT i;

  TRACE_FUNCTION ("cc_init_data()");

  memset (cc_data, 0, sizeof (T_CC_DATA));

  /* No SETUP / EMERGENCY SETUP pending */
  cc_data->stored_setup = NULL;

  /* No CCBS SETUP pending */
  cc_data->stored_ccbs_setup = NULL;
  
  cc_data->channel_mode = NAS_CHM_SIG_ONLY;

  for (i=0;i<MAX_CC_CALLS;i++)
  {
    cc_data->stored_ti_values[i] = NOT_PRESENT_8BIT;
  }

  cc_csf_ms_cap ();

  /*
   * Initialise single numbering scheme
   */
  cc_data->sns_bcpara.bearer_serv = MNCC_BEARER_SERV_SPEECH;
  cc_data->sns_mode = MNCC_SNS_MODE_VOICE;

  /*
   * Initialise connection element for MTC
   */
  cc_data->conn_elem = MNCC_CONN_ELEM_NON_TRANS;

  /* 
   * Initialize setup_reattempt_ti to not present 
   */
  cc_data->setup_reattempt_ti = NOT_PRESENT_8BIT;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_mncc_configure_req      |
+--------------------------------------------------------------------+

  PURPOSE : Configuration of bearer capabilities and subaddress
            by man machine interface.

*/

static const UBYTE def_modem_type [8] = 
{
    MNCC_MT_V21,       /* user rate 300 Baud    ->  modem type V.21    */
    MNCC_MT_V22,       /* user rate 1200 Baud   ->  modem type V.22    */
    MNCC_MT_V22_BIS,   /* user rate 2400 Baud   ->  modem type V.22bis */
    MNCC_MT_V32,       /* user rate 4800 Baud   ->  modem type V32     */
    MNCC_MT_V32,       /* user rate 9600 Baud   ->  modem type V32     */
    MNCC_MT_V32,       /* 12k transparent, not supported now by ACI    */
    MNCC_MT_V23,       /* user rate 12k/75 Baud ->  modem type V23     */
    MNCC_MT_V21,       /* user rate 14.4 kBaud  ->  modem type V21 ??? */
};

GLOBAL void cc_mncc_configure_req (T_MNCC_CONFIGURE_REQ * config)
{

  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_mncc_configure_req()");

  /*
   * store own subadress if available
   * 
   * NOTE: T_called_party_sub is the wrong type here in MNCC_CONFIGURE_REQ, 
   *       this should have been T_calling_party_sub as this is that what
   *       the subaddress is used for in the uplink SETUP message later.
   *       Doesn't really matter here as the types are identical, it's 
   *       just somewhat confusing and could be occasionally be changed.
   */
  if (config->called_party_sub.c_subaddr)
  {
    cc_data->my_party_subaddr.v_tos      = TRUE;
    cc_data->my_party_subaddr.tos        = config->called_party_sub.tos;
    cc_data->my_party_subaddr.v_odd_even = TRUE;
    cc_data->my_party_subaddr.odd_even   = config->called_party_sub.odd_even;
    cc_data->my_party_subaddr.c_subaddr  = config->called_party_sub.c_subaddr;
    memcpy (cc_data->my_party_subaddr.subaddr,
            config->called_party_sub.subaddr,
            config->called_party_sub.c_subaddr);
  }
  else
    memset (&cc_data->my_party_subaddr, 0, sizeof (T_M_CC_called_subaddr));
  /*
   * Store CTM support
   */
  cc_data->ctm_ena = config->ctm_ena;
  /*
   * Store Single Numbering Scheme BC parameter and mode
   * if available
   */
  if (config->sns_mode NEQ NOT_PRESENT_8BIT)
  {
   /*
    * Store Connection Element for MTC
    * Note that setting conditionally on sns_mode NEQ NOT_PRESENT_8BIT is 
    * possible because ACI always sets sns_mode to something different from
    * NOT_PRESENT_8BIT when it sends an MNCC_CONFIGURE_REQ.
    * For future proof use of MNCC_CONFIGURE_REQ (e.g. only subaddress is valid!)
    * it is convenient and correct to consider parameters only if they
    * are valid.
    */

    cc_data->conn_elem = config->bcpara.conn_elem;

    cc_data->sns_mode = config->sns_mode;

    if (cc_data->sns_mode EQ MNCC_SNS_MODE_VOICE)
    {
      memset (&cc_data->sns_bcpara, 0 /*NOT_PRESENT_8BIT*/, sizeof (T_MNCC_bcpara));
      cc_data->sns_bcpara.bearer_serv = (cc_data->ctm_ena EQ MNCC_CTM_ENABLED)?
                                        MNCC_BEARER_SERV_SPEECH_CTM: MNCC_BEARER_SERV_SPEECH;
    }
    else
      memcpy (&cc_data->sns_bcpara, &config->bcpara, sizeof (T_MNCC_bcpara));
    /*
     * Set modem type to default values for single numbering scheme
     */
    switch (cc_data->sns_bcpara.bearer_serv)
    {
      case MNCC_BEARER_SERV_FAX:
        cc_data->sns_bcpara.modem_type = M_CC_MT_NONE;
        break;
      case MNCC_BEARER_SERV_SPEECH:
      case MNCC_BEARER_SERV_AUX_SPEECH:
      case MNCC_BEARER_SERV_SPEECH_CTM:
      case MNCC_BEARER_SERV_AUX_SPEECH_CTM:
        break;
      default:
        cc_data->sns_bcpara.modem_type = def_modem_type[config->bcpara.rate-1];
        if (config->bcpara.modem_type == MNCC_MT_V34)
        {
          cc_data->sns_bcpara.modem_type = MNCC_MT_V34;
        }
        break;
    }
  }

  /*
   * define connection element if a preferred one is set by MMI
   */
  if (cc_data->sns_bcpara.conn_elem EQ MNCC_CONN_ELEM_TRANS_PREF)
  {
    /*
     * check only if transparent asynchronous data services are supported
     */
    if (FldGet(cc_data->mscap.datCap1, AsySup))
      cc_data->sns_bcpara.conn_elem = M_CC_CE_TRANSPA;
    else
      cc_data->sns_bcpara.conn_elem = M_CC_CE_RLP;
  }

  /*
   * define connection element if a preferred one is set by MMI
   */
  if (cc_data->sns_bcpara.conn_elem EQ MNCC_CONN_ELEM_NON_TRANS_PREF)
  {
    /*
     * check only if non-transparent asynchronous data services are supported
     */
    if (FldGet (cc_data->mscap.datCap1, RLPSup))
      cc_data->sns_bcpara.conn_elem = M_CC_CE_RLP;
    else
      cc_data->sns_bcpara.conn_elem = M_CC_CE_TRANSPA;
  }

  PFREE (config);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_mncc_prompt_rsp         |
+--------------------------------------------------------------------+

  PURPOSE : A new transaction identifier during network initiated 
            mobile origination call establishment was assigned by 
            upper layers. Under normal conditions this causes the 
            emmission of an MMCC_DATA_REQ (START CC) 

*/

GLOBAL void cc_mncc_prompt_res (T_MNCC_PROMPT_RES * prompt)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_mncc_prompt_rsp()");

  /* Check parameters */
  if (prompt->ti >= 7)
  {
    /* Invalid transaction identifier */
/* Implements Measure#  36, 48 */
    cc_send_mncc_release_ind (prompt->ti, 
                                CAUSE_MAKE(DEFBY_STD, 
                                ORIGSIDE_MS, 
                                MNCC_CC_ORIGINATING_ENTITY, 
                                M_CC_CAUSE_INVALID_TI));    

    PFREE (prompt);
    return;
  }

  /* Assign ti and allocate a free entry in the call data */ 
  cc_data->ti = prompt->ti;
  cc_data->index_ti = srv_define_ti();
  if (cc_data->index_ti EQ NOT_PRESENT_8BIT)
  {
    /*
     * No call instance available
     */
/* Implements Measure#  36, 48 */
    cc_send_mncc_release_ind (prompt->ti, MNCC_CAUSE_MAX_NO_CALLS_REACHED);

    PFREE (prompt);
    return;
  }

  /* Send MMCC_PROMPT_RSP */
  {
    PALLOC (prompt_rsp, MMCM_PROMPT_RES); // T_MMCM_ESTABLISH_REQ
    prompt_rsp->ti = prompt->ti;
    PSENDX (MM, prompt_rsp);
  }
  
  /* Send MMCC_DATA_REQ (START CC) */
  
  CCD_START;
  {
    MCAST (start_cc, U_START_CC);
    cc_build_start_cc (start_cc);
    for_start_cc (start_cc);
  }
  CCD_END;

  /* Start Timer T332 */
  TIMERSTART (T332, T332_VALUE);

  PFREE (prompt);
  
  /* Next state is WAIT FOR NETWORK INFO (U0.3) */
  cc_set_state (M_CC_CS_03);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_mncc_prompt_rej         |
+--------------------------------------------------------------------+

  PURPOSE : A new transaction identifier during network initiated 
            mobile origination call establishment could not be 
            assigned by upper layers. MM is informed by
            MMCC_PROMPT_REJ.

*/

GLOBAL void cc_mncc_prompt_rej (T_MNCC_PROMPT_REJ * prompt)
{
  TRACE_FUNCTION ("cc_mncc_prompt_rej()");

  PFREE (prompt);
  
  {
    PALLOC (reject, MMCM_PROMPT_REJ);
    PSENDX (MM, reject);
  }
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_mncc_setup_req          |
+--------------------------------------------------------------------+

  PURPOSE : Starting of mobile originated call.

*/

GLOBAL void cc_mncc_setup_req (T_MNCC_SETUP_REQ * setup)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_mncc_setup_req()");
  cc_data->index_ti = srv_convert_ti (setup->ti);
  if (cc_data->index_ti NEQ NOT_PRESENT_8BIT)
  {
    /*
     * Transaction identifier already present, this means, we know this ti
     * and CC is not in M_CC_CS_0 state. This is okay for M_CC_CS_06 (CCBS), 
     * for every other state this is an internal failure.
     */
    switch (cc_data->state[cc_data->index_ti])
    {
      case M_CC_CS_06: /* RECALL present */
        /* 
         * Don't use the setup parametes from ACI, instead use 
         * the stored SETUP message in CC.
         */

        cc_data->progress_desc[cc_data->index_ti] = NOT_PRESENT_8BIT;

        /* No ugly CC setup reattempts here */
        cc_data->setup_attempts = MAX_SETUP_ATTEMPTS;
        cc_data->setup_reattempt_ti = NOT_PRESENT_8BIT;

        /* Send stored SETUP message to network and forget it */
        for_pd (cc_data->stored_ccbs_setup);
        cc_data->stored_ccbs_setup = NULL;

        /* Set parameters in cc_data */
        cc_data->call_type [cc_data->index_ti]    = CALL_TYPE_MOC;

        /* initialize disconnect collision flag */
        cc_data->disc_coll [cc_data->index_ti]    = FALSE;

        cc_data->t308_counter [cc_data->index_ti] = 0;
        cc_reset_dtmf ();

        /* Start T303 */
        TIMERSTART (T303, T303_VALUE);

        /* Next state is CALL INIT */
        cc_set_state (M_CC_CS_1);
        break;
    
      default: /* The ti is already in use and it is not CCBS recall */
        {
          PALLOC (rel, MNCC_RELEASE_IND);
          rel->ti = setup->ti;
          rel->cause = M_CC_CAUSE_INVALID_TI;
          rel->c_raw_cause = 0;
          PSENDX (MMI, rel);
        }
        break;
    }
    PFREE (setup);
    return;
  }

  if (setup->ti >= 7)
  {
    /*
     * Invalid transaction identifier
     */
/* Implements Measure#  36, 48 */
    cc_send_mncc_release_ind (setup->ti,
                                CAUSE_MAKE(DEFBY_STD, 
                                ORIGSIDE_MS, 
                                MNCC_CC_ORIGINATING_ENTITY, 
                                M_CC_CAUSE_INVALID_TI));    
    PFREE (setup);
    return;
  }

  /*
   * ti is valid here and not already in use
   */
  cc_data->ti = setup->ti;
  cc_data->index_ti = srv_define_ti ();
  if (cc_data->index_ti EQ NOT_PRESENT_8BIT)
  {
    /*
     * No call instance available
     */
/* Implements Measure#  36, 48 */
    cc_send_mncc_release_ind (setup->ti, MNCC_CAUSE_MAX_NO_CALLS_REACHED);
    PFREE (setup);
    return;
  }

  /*
   * Security check: if bcpara indicates not present,
   * set service to speech
   */
  if (setup->bcpara.bearer_serv EQ NOT_PRESENT_8BIT)
  {
    setup->bcpara.bearer_serv = (cc_data->ctm_ena EQ MNCC_CTM_ENABLED)?
                                MNCC_BEARER_SERV_SPEECH_CTM: MNCC_BEARER_SERV_SPEECH;
  }
  /*
   * Security check: if prio indicates emergency call,
   * set service to speech or speech with CTM
   */
  if (setup->prio NEQ MNCC_PRIO_NORM_CALL)
  {
    switch (setup->bcpara.bearer_serv)
    {
    case MNCC_BEARER_SERV_SPEECH:
    case MNCC_BEARER_SERV_SPEECH_CTM:
      break;
    case MNCC_BEARER_SERV_AUX_SPEECH_CTM:
      setup->bcpara.bearer_serv = MNCC_BEARER_SERV_SPEECH_CTM;
      break;
    default:
      setup->bcpara.bearer_serv = MNCC_BEARER_SERV_SPEECH;
      break;
    }
  }

  if (cc_check_capabilities (&setup->bcpara) EQ FALSE OR 
      cc_check_capabilities ((T_MNCC_bcpara *)&setup->bcpara2) EQ FALSE)
  {
    /*
     * MS doesn't support the requested services.
     */
    PALLOC ( rel, MNCC_RELEASE_IND);

    rel->ti    = setup->ti;
    rel->cause = CAUSE_MAKE(DEFBY_STD, 
                            ORIGSIDE_MS, 
                            MNCC_CC_ORIGINATING_ENTITY, 
                            M_CC_CAUSE_BEARER_NOT_IMPLEM);
    rel->c_raw_cause = 0;

    PSENDX (MMI, rel);

    srv_free_ti ();

    PFREE (setup);
  }
  else
  {
    PALLOC (est, MMCM_ESTABLISH_REQ); /* T_MMCM_ESTABLISH_REQ */
    cc_build_bc (&cc_data->bc1, &cc_data->serv1, &setup->bcpara);
    cc_data->ri = setup->ri;
    cc_data->bcpara1 = setup->bcpara;
    memcpy (&cc_data->bcpara2, &setup->bcpara2, sizeof (T_MNCC_bcpara)); 

    if (cc_data->ri EQ NOT_PRESENT_8BIT)
      cc_data->serv2 = NOT_PRESENT_8BIT;
    else
      cc_build_bc (&cc_data->bc2, &cc_data->serv2, (T_MNCC_bcpara *)&setup->bcpara2);
    memcpy (&cc_data->bcpara2, &setup->bcpara2, sizeof (T_MNCC_bcpara));
    est->org_entity = NAS_ORG_ENTITY_CC;
    est->ti = setup->ti;

    /* Set establ_serv according to chosen bearer capability */
    switch (cc_data->bcpara1.bearer_serv)
    {
      case MNCC_BEARER_SERV_SPEECH:
          est->estcs = MMCM_ESTCS_MOB_ORIG_SPCH;
        break;

      case MNCC_BEARER_SERV_ASYNC:
        if (cc_data->bcpara1.conn_elem == MNCC_CONN_ELEM_TRANS ||
          cc_data->bcpara1.conn_elem == MNCC_CONN_ELEM_TRANS_PREF)
        {
            est->estcs = MMCM_ESTCS_MOB_ORIG_DATA;
        }
        else
        {
            est->estcs = MMCM_ESTCS_MOB_ORIG_DATA;
        }
        break;

      case MNCC_BEARER_SERV_FAX:
          est->estcs = MMCM_ESTCS_MOB_ORIG_DATA;
        break;

      default:
          est->estcs = MMCM_ESTCS_MOB_ORIG_SPCH;
        break;
    }

    switch (cc_data->serv1)
    {
      case MNCC_SERV_DATA:
        if (FldGet(cc_data->mscap.datCap2, DHRSup))
        {
          /*
           * Halfrate support for data
           */
          switch (setup->bcpara.rate)
          {
            case M_CC_UR_0_3_KBIT:
            case M_CC_UR_1_2_KBIT:
            case M_CC_UR_2_4_KBIT:
            case M_CC_UR_4_8_KBIT:
            case M_CC_UR_1_2_KBIT_V23:
              est->estcs = MMCM_ESTCS_MOB_ORIG_DATA;
              break;
            default:
              est->estcs = MMCM_ESTCS_MOB_ORIG_DATA;
              break;
          }
        }
        else
          est->estcs = MMCM_ESTCS_MOB_ORIG_DATA;
        break;

      default: /* SERV_SPEECH */
        if (setup->prio EQ MNCC_PRIO_NORM_CALL)
          est->estcs = MMCM_ESTCS_MOB_ORIG_SPCH;
        else
          est->estcs = MMCM_ESTCS_EMERGE;
        break;
    }

    /* Data solely needed for possible redial attempt */
    cc_data->estcs              = est->estcs;
    cc_data->setup_attempts     = 0;

    srv_free_stored_setup ();
    cc_data->progress_desc[cc_data->index_ti] = NOT_PRESENT_8BIT;
    cc_data->call_type [cc_data->index_ti]    = CALL_TYPE_MOC;
    // PATCH LE 10.04.00
    // initialize disconnect collision flag
    cc_data->disc_coll [cc_data->index_ti]    = FALSE;
    // END PATCH LE 10.04.00
    cc_data->t308_counter [cc_data->index_ti] = 0;
    cc_reset_dtmf ();

    CCD_START;
    if (setup->prio EQ MNCC_PRIO_NORM_CALL)
    {
      MCAST (setup_msg, U_SETUP);

      cc_build_setup (setup_msg, setup);
      for_setup (setup_msg);
    }
    else
    {
      MCAST (emergency_setup_msg, U_EMERGE_SETUP);

      cc_build_emergency_setup (emergency_setup_msg);
      for_emergency_setup (emergency_setup_msg);
    }
    CCD_END;

    cc_set_state (M_CC_CS_01);
    for_est_req (est);
    TIMERSTART (T303, T303_VALUE);
    PFREE (setup);
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_mncc_alert_req          |
+--------------------------------------------------------------------+

  PURPOSE : The mobile side indicates alerting.

*/

GLOBAL void cc_mncc_alert_req (T_MNCC_ALERT_REQ * alert)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_mncc_alert_req()");

  if ((cc_data->index_ti = srv_convert_ti (alert->ti))
      EQ NOT_PRESENT_8BIT)
  {
    PFREE (alert);
    return;
  }

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_9:
      CCD_START;
      {
        MCAST (alert_msg, U_ALERT);
        
        cc_build_alert (alert_msg);
        cc_set_state (M_CC_CS_7);
        for_alert (alert_msg);
      }
      CCD_END;

      EM_CC_ALERTING_SENT;

      PFREE (alert);
      break;

    default:
      PFREE (alert);
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_mncc_setup_res          |
+--------------------------------------------------------------------+

  PURPOSE : The mobile side indicates call acceptance.

*/

GLOBAL void cc_mncc_setup_res (T_MNCC_SETUP_RES * setup_res)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_mncc_setup_res()");

  if ((cc_data->index_ti = srv_convert_ti (setup_res->ti))
      EQ NOT_PRESENT_8BIT)
  {
    PFREE (setup_res);
    return;
  }

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_7:
    case M_CC_CS_9:
      CCD_START;
      {
        MCAST (connect, U_CONNECT);
        cc_build_connect (connect);
        cc_set_state (M_CC_CS_8);
        TIMERSTART (T313, T313_VALUE);
        for_connect (connect);
      }
      CCD_END;

      EM_CC_CONNECT_SENT;
      
      PFREE (setup_res);
      break;

    default:
      PFREE (setup_res);
      break;
  }
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_alert                   |
+--------------------------------------------------------------------+

  PURPOSE : Processing an incoming alert message.

*/

GLOBAL void cc_alert (T_D_ALERT * alert)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cc_alert()");

  EM_CC_ALERTING_RECEIVED;

  switch (cc_data->state[cc_data->index_ti])
  {
    /*
     * CS_0 is handled by the formatter
     */
    case M_CC_CS_1:
    case M_CC_CS_3:
      if (cc_check_error_flag ())
      {
        PALLOC (alert_ind, MNCC_ALERT_IND);
        TIMERSTOP (TIMER_CC);

        if (alert->v_progress)
        {
          cc_data->progress_desc[cc_data->index_ti] = 
            alert->progress.progress_desc;
        }

        cc_build_mncc_alert_ind (alert, alert_ind);
        PSENDX (MMI, alert_ind);

        cc_build_facility_ind (MNCC_FAC_IN_ALERT, alert->v_facility, &alert->facility);
        cc_build_user_user_ind (MNCC_USER_IN_ALERT, alert->v_user_user, 
                                &alert->user_user);
        CCD_END;
        srv_free_stored_setup ();
        cc_set_state (M_CC_CS_4);
      }
      break;

    default:
      CCD_END;
/* Implements Measure#  3 and streamline encoding */
      cc_send_status (MNCC_CAUSE_MESSAGE_TYPE_INCOMPAT);
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_call_proceeding         |
+--------------------------------------------------------------------+

  PURPOSE : Processing an incoming call proceed message.

*/

GLOBAL void cc_call_proceeding (T_D_CALL_PROCEED * proceed)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cc_call_proceeding()");

  EM_CC_CALL_PROCEEDING_RECEIVED;

  switch (cc_data->state[cc_data->index_ti])
  {
    /*
     * CS_0 is handled by the formatter
     */
    case M_CC_CS_1:
      if (cc_check_error_flag ())
      {
        TIMERSTOP (TIMER_CC); /* timer T303 */
        if (cc_moc_compatibility (proceed) EQ OKAY)
        {
          PALLOC (proceed_ind, MNCC_CALL_PROCEED_IND);

          cc_build_mncc_proceed_ind (proceed, proceed_ind);
          PSENDX (MMI, proceed_ind);

          cc_build_facility_ind (MNCC_FAC_IN_CALL_PROCEED, 
                                   proceed->v_facility, &proceed->facility);
          if (proceed->v_progress)
          {
             cc_data->progress_desc[cc_data->index_ti] = 
               proceed->progress.progress_desc;
          }
    
          CCD_END;
          /* 
           * - start T310 unless the CALL PROCEEDING message contains a progress indicator IE 
           *   specifying progress description #1, #2, Ph2 handling is not done yet (#64), see
           *   also issue 4967
           * - start T310 unless a PROGRESS message with #1, 2, 64 has been 
           *   received, this is achieved by remembering the progress description in cc_data
           * - the case when 1. PROGRESS and 2. CALL PROCEEDING with e.g. #4 is handled by
           *   interpreting 5.2.1.1.3 of 04.08 in the manner that a 2nd progress description
           *   superseeds the first one. See also issue 4965 / CC-FIX-4965.
           */
          /* start T310 with Ph2 unless progress description value #1, #2 or #64 has been received */
          {
            UBYTE prog_desc = cc_data->progress_desc[cc_data->index_ti];
            if ((prog_desc NEQ MNCC_PROG_NO_END_TO_END_PLMN)
                  AND
               (prog_desc NEQ MNCC_PROG_DEST_NON_PLMN)
                  AND
               (prog_desc NEQ MNCC_PROG_QUEUEING))
            {
                TIMERSTART (T310, T310_VALUE);
            }
          }
          if (proceed->v_progress AND
              proceed->progress.v_progress_desc AND 
              proceed->progress.progress_desc EQ M_CC_PROG_INBAND_AVAIL)
          {
            /* 
             * Avoid more call establishment attempts if there was
             * inband announcement heard by the user. 
             * The user should have no way to realize that more than one
             * call attempt may be taken by CC.
             */
            cc_data->setup_attempts = MAX_SETUP_ATTEMPTS;
          }

          cc_set_state (M_CC_CS_3);
        }
        else /* bearer capability check on CALL PROCEEDING failed */
        {
          CCD_END;
          CCD_START;
          {
            MCAST (disconnect, U_DISCONNECT);
            PALLOC (rej_ind, MNCC_REJECT_IND);

            rej_ind->ti  = cc_data->ti;
            /* 
             * GSM 04.08 does not specify what to do / which cause to use;
             * Condat decided to use normal call clearing with cause #88
             */
            rej_ind->cause = CAUSE_MAKE(DEFBY_STD, 
                                        ORIGSIDE_MS, 
                                        MNCC_CC_ORIGINATING_ENTITY, 
                                        MNCC_CAUSE_INCOMPAT_DEST); 
            PSENDX (MMI, rej_ind);

            cc_build_disconnect (disconnect, 
                                 CAUSE_MAKE(DEFBY_STD, 
                                            ORIGSIDE_MS, 
                                            MNCC_CC_ORIGINATING_ENTITY,
                                            MNCC_CAUSE_INCOMPAT_DEST),
                                 NULL, MNCC_SS_VER_NOT_PRES);
            cc_set_state (M_CC_CS_11);
            for_disconnect (disconnect);
          }
          CCD_END;
          TIMERSTART (T305, T305_VALUE);
        }
      }
      break;

    default:
      CCD_END;
/* Implements Measure#  3 and streamline encoding */
      cc_send_status (MNCC_CAUSE_MESSAGE_TYPE_INCOMPAT);
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_connect                 |
+--------------------------------------------------------------------+

  PURPOSE : Processing an incoming connect message.

*/

GLOBAL void cc_connect (T_D_CONNECT * connect)
{
  GET_INSTANCE_DATA;
  TRACE_FUNCTION ("cc_connect()");

  switch (cc_data->state[cc_data->index_ti])
  {  
    /*
     * CS_0 is handled by the formatter
     */
    case M_CC_CS_1:
    case M_CC_CS_3:
    case M_CC_CS_4:
      if (cc_check_error_flag ())
      {
        PALLOC (setup_cnf, MNCC_SETUP_CNF);

        TIMERSTOP (TIMER_CC);

        if (connect->v_progress)
        {
          cc_data->progress_desc[cc_data->index_ti] = 
            connect->progress.progress_desc;
        }

        cc_build_mncc_setup_cnf (connect, setup_cnf);
        PSENDX (MMI, setup_cnf);
        cc_build_facility_ind (MNCC_FAC_IN_CONNECT, connect->v_facility,
                               &connect->facility);
        cc_build_user_user_ind (MNCC_USER_IN_CONNECT, connect->v_user_user,
                                &connect->user_user);
        CCD_END;
        CCD_START;
        {
          MCAST (connect_ack, B_CONNECT_ACK);

          connect_ack->msg_type = B_CONNECT_ACK;
          for_connect_ack (connect_ack);
        }
        CCD_END;
        srv_free_stored_setup ();
        cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_IDLE;
        cc_data->mpty_state[cc_data->index_ti] = M_CC_MPTY_IDLE;
        cc_set_state (M_CC_CS_10);
      }

      EM_CC_CONNECT_RECEIVED;

      break;

    default:
/* Implements Measure#  3 and streamline encoding */
    CCD_END;
      cc_send_status (MNCC_CAUSE_MESSAGE_TYPE_INCOMPAT);
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_connect_ack             |
+--------------------------------------------------------------------+

  PURPOSE : Processing an incoming connect acknowledge message.

*/

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

  switch (cc_data->state[cc_data->index_ti])
  {
    /*
     * CS_0 is handled by the formatter
     */
    case M_CC_CS_8:
      if (cc_check_error_flag ())
      {
        PALLOC (setup_comp, MNCC_SETUP_COMPL_IND);

        CCD_END;

        TIMERSTOP (TIMER_CC);

        setup_comp->ti  = cc_data->ti;
        setup_comp->cause = MNCC_CAUSE_SUCCESS;
        PSENDX (MMI, setup_comp);

        cc_data->hold_state[cc_data->index_ti] = M_CC_HLD_IDLE;
        cc_data->mpty_state[cc_data->index_ti] = M_CC_MPTY_IDLE;
        cc_set_state (M_CC_CS_10);

        EM_CC_CONNECT_ACKNOWLEDGE_RECEIVED;

      }
      break;

    default:
      CCD_END;
/* Implements Measure#  3 and streamline encoding */
      cc_send_status (MNCC_CAUSE_MESSAGE_TYPE_INCOMPAT);
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_progress                |
+--------------------------------------------------------------------+

  PURPOSE : Processing of an incoming progress message.

*/

GLOBAL void cc_progress (T_D_PROGRESS * progress)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_progress()");

  switch (cc_data->state[cc_data->index_ti])
  {
    /*
     * CS_0 is handled by the formatter
     */
    case M_CC_CS_1:
    case M_CC_CS_3:
    case M_CC_CS_4:
    case M_CC_CS_6:
    case M_CC_CS_7:
    case M_CC_CS_8:
    case M_CC_CS_9:
    case M_CC_CS_11:
    case M_CC_CS_12:
    case M_CC_CS_19:
      if (cc_check_error_flag ())
      {
        PALLOC (progress_ind, MNCC_PROGRESS_IND);

        TIMERSTOP (TIMER_CC);
        
        /* Progress indicator IE here is mandatory IE, so no 
         * checks for presence need to be done here */
        cc_data->progress_desc[cc_data->index_ti] = 
          progress->progress.progress_desc;
       
        cc_build_mncc_progress_ind (progress, progress_ind);
        PSENDX (MMI, progress_ind);
        cc_build_user_user_ind (MNCC_USER_IN_PROGRESS, progress->v_user_user,
                                &progress->user_user);
        CCD_END;
      }

      EM_CC_PROGRESS_RECEIVED;

      break;

    default:
      CCD_END;
/* Implements Measure#  3 and streamline encoding */
      cc_send_status (MNCC_CAUSE_MESSAGE_TYPE_INCOMPAT);
      break;
  }
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_cc_establishment        |
+--------------------------------------------------------------------+

  PURPOSE : Processing of an incoming CC ESTABLISHMENT message.
            Because the only interesting part in this message
            is the setup container, only the decoded SETUP message
            is delivered here.

*/

GLOBAL void cc_cc_establishment (T_U_SETUP * setup)
{
  GET_INSTANCE_DATA;	
  TRACE_FUNCTION ("cc_cc_establishment()");

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_03: /* WAIT FOR NW INFO */
      
      /* Check errors delivered by formatter */
      switch (cc_data->error) 
      {
        case M_CC_CAUSE_INVALID_MAND_INFO:
        case M_CC_CAUSE_COND_INFO_ELEM:
          CCD_END;
          /* Implements Measure#  7 and streamline encoding*/
          cc_send_status (cc_data->error);  
          return;

        default: /* No error until now */
          /* Stop TIMER T332 */
          TIMERSTOP (TIMER_CC);
   
          if (cc_data->stored_ccbs_setup NEQ NULL) 
          {
            /* 
             * There is only room for one stored CCBS SETUP message
             * for all instances. In case this is already occupied, 
             * the call is released with cause "user busy".
             * In this case the CCBS recall is not lost, but suspended
             * by the network until the mobile becomes idle.
             */
            CCD_END;
           
            /* Send RELEASE COMPLETE */
            CCD_START;
            {
              MCAST (rel_com, U_RELEASE_COMP);
              cc_build_release_complete (rel_com, CAUSE_MAKE(DEFBY_STD, 
                                                                      ORIGSIDE_MS, 
                                                                      MNCC_CC_ORIGINATING_ENTITY,
                                                                      MNCC_CAUSE_USER_BUSY));
              for_release_complete (rel_com);
            }
            CCD_END;

            /* Inform MMI */
            {
              PALLOC (release, MNCC_RELEASE_IND);
              release->ti    = cc_data->ti;
              release->cause = MNCC_CAUSE_MAX_NO_RECALLS_REACHED;
              release->c_raw_cause = 0;
              PSENDX (MMI, release);
            }

            /* Release MM connection */
            for_rel_req ();

            /* Next state is NULL */
            cc_set_state (M_CC_CS_0);
            return;
          }

          /* Check bearer capabilities, do basic recall alignment */
          if (cc_basic_service_align (setup) EQ ERROR)
          {
            /* Incompatible bearer capabilities. Clear call. */
            CCD_END;
            /* Implements Measure#  19 */
            cc_send_release_cmp (CAUSE_MAKE(DEFBY_STD,
                                           ORIGSIDE_MS, 
                                           MNCC_CC_ORIGINATING_ENTITY, 
                                           MNCC_CAUSE_INCOMPAT_DEST));
            return;
          }

          /* 
           * "If the CC Capabilities in the Setup Container IE is different
           * to that supported by the mobile station, the mobile station 
           * shall modify the CC Capabilities in the SETUP message to indicate
           * the true capabilities of the mobile station" [GSM 04.08 5.2.3.2]
           */
          setup->call_ctrl_cap = cc_data->call_ctrl_cap; /* Struct copy */

          /* 
           * Handle facility alignment 
           * ("Simple recall alignment",
           *  "Advanced recall alignment" and 
           *  "Recall alignment not essential").
           */

          /* "Simple recall alignment" handled automatically, do nothing */

          if (setup->v_fac_adv) 
          {
            /* Advanced recall alignment not supported. Reject call. */
            CCD_END;
           /* Implements Measure#  19 */
            cc_send_release_cmp (CAUSE_MAKE(DEFBY_STD,
                                           ORIGSIDE_MS, 
                                           MNCC_CC_ORIGINATING_ENTITY,
                                           MNCC_CAUSE_FACILITY_REJECT));
           
            return;
          }

          /* 
           * The recall alignment not essential facility IE 
           * need not be handled directly here, it is simply 
           * an optional IE which was ignored by CCD.
           * The only handling we do is to delete the SS-Version 
           * indicator if there are no remaining facility elements.
           */
          if (!setup->v_facility)
            setup->v_ss_version = FALSE;

          /* Store coded setup message in cc_data */
          {
            /* No assumtions made about length of this foreign message */
            PALLOC_SDU (data, MMCM_DATA_REQ, M_CC_L3MAX << 3);
            data->sdu.o_buf = CC_ENCODE_OFFSET;
            ccd_codeMsg (CCDENT_CC,
                         UPLINK,
                         (T_MSGBUF *) &data->sdu,
                         (UBYTE    *) setup,
                          NOT_PRESENT_8BIT);
            cc_data->stored_ccbs_setup = data;
          }
          CCD_END;

          /* Send MMCC_DATA_REQ (CC EST. CONFIRMED) */
          CCD_START;
          {
            MCAST (est_cnf, U_CC_EST_CONF);
            if (cc_count_active_connections () EQ 0)
              cc_build_cc_est_confirm (est_cnf, CAUSE_MAKE(DEFBY_CONDAT, 
                                                                    ORIGSIDE_MS, 
                                                                    MNCC_CC_ORIGINATING_ENTITY,
                                                                    NOT_PRESENT_8BIT));
            else
              cc_build_cc_est_confirm (est_cnf, CAUSE_MAKE(DEFBY_STD, 
                                                                    ORIGSIDE_MS, 
                                                                    MNCC_CC_ORIGINATING_ENTITY,
                                                                    MNCC_CAUSE_USER_BUSY));
            for_cc_est_confirm (est_cnf);
          }
          CCD_END;

          /* Start TIMER T335 */
          TIMERSTART (T335, T335_VALUE);
      
          /* Enter the "CC-establishment confirmed" state */
          cc_set_state (M_CC_CS_05);
          break;
      }
      break;

    default: 
      /* Message not compatible with protocol state */
      CCD_END;
      
      /* Implements Measure#  3 and streamline encoding */
      cc_send_status (MNCC_CAUSE_MESSAGE_TYPE_INCOMPAT);
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_recall                  |
+--------------------------------------------------------------------+

  PURPOSE : Processing of an incoming recall message.

*/

GLOBAL void cc_recall (T_D_RECALL * recall)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_recall");

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_05: /* CC ESTABLISHMENT CONFIRMED */
      switch(cc_data->error)
      {
        case M_CC_CAUSE_INVALID_MAND_INFO:
        case M_CC_CAUSE_COND_INFO_ELEM:
          CCD_END;
          /* Implements Measure#  7 and streamline encoding*/
          cc_send_status (cc_data->error);  
          return;

        default:
          /* Stop Timer T335 */
          TIMERSTOP (TIMER_CC);
          {
            T_U_SETUP * setup;
            UBYTE result;
            PALLOC (fac_ind, MNCC_FACILITY_IND);

            /* Process facility element. may be not present */
            fac_ind->ti = cc_data->ti;
            fac_ind->fac_context = MNCC_FAC_IN_RECALL;
            fac_ind->fac_inf.l_fac = recall->facility.c_fac << 3;
            fac_ind->fac_inf.o_fac = 0;
            memcpy (fac_ind->fac_inf.fac,  
                    recall->facility.fac,
                    recall->facility.c_fac);

            {
              PALLOC (rec_ind, MNCC_RECALL_IND); /* T_MNCC_RECALL_IND */    

              rec_ind->ti =  cc_data->ti;
              rec_ind->rcl_type = recall->recall_type.rcl_type;
              CCD_END;

              /* 
               * Unpack coded setup container.
               * Conserving memory, so already processed parameters are 
               * processed for a second time now. No errors expected.
               */
              assert (cc_data->stored_ccbs_setup NEQ NULL);
              CCD_START;
              result = ccd_decodeMsg (CCDENT_CC,
                         UPLINK,
                         (T_MSGBUF *) &cc_data->stored_ccbs_setup->sdu,
                         (UBYTE    *) _decodedMsg,
                         NOT_PRESENT_8BIT);
              assert (result EQ ccdOK);
              setup = (T_U_SETUP *)_decodedMsg;
              result = cc_basic_service_align (setup);
              assert (result NEQ ERROR);
            
              /* Process repeat indicator, BC I and BC II */
              rec_ind->ri = cc_data->neg_ri;
              memcpy (&rec_ind->bcpara, &cc_data->neg_bcpara1, 
                      sizeof (T_MNCC_bcpara));
              memcpy (&rec_ind->bcpara2, &cc_data->neg_bcpara2, 
                      sizeof (T_MNCC_bcpara));
            
              /* Process called party address */   
              rec_ind->called_party.ton          = setup->ul_called_num.ton;
              rec_ind->called_party.npi          = setup->ul_called_num.npi;
              rec_ind->called_party.c_called_num = setup->ul_called_num.c_num;
              memcpy (rec_ind->called_party.called_num, 
                      setup->ul_called_num.num, 
                      setup->ul_called_num.c_num);

              /* Process called party subaddress */
              if (setup->v_called_subaddr)
              {
                rec_ind->called_party_sub.tos =  
                  setup->called_subaddr.tos;
                rec_ind->called_party_sub.odd_even = 
                  setup->called_subaddr.odd_even;
                rec_ind->called_party_sub.c_subaddr = 
                  setup->called_subaddr.c_subaddr;
                memcpy (rec_ind->called_party_sub.subaddr,
                        setup->called_subaddr.subaddr, MNCC_SUB_LENGTH);
              }
              else
              {
                rec_ind->called_party_sub.tos = MNCC_TOS_NOT_PRES;
                rec_ind->called_party_sub.c_subaddr = 0;
              }                                             
              CCD_END;
            
              /* Send MNCC_RECALL_IND */
              PSENDX (MMI, rec_ind);
            }

            /* Handle MNCC_FACILITY_IND */
            if (fac_ind->fac_inf.l_fac)
            {
              PSENDX (MMI, fac_ind);
            }
            else
              PFREE (fac_ind);
            
            /* Next state is RECALL PRESENT */
            cc_set_state (M_CC_CS_06);
          }
          break;
      }
      break; /* esac CS_05 */
    default: 
      CCD_END;
      /* Message not compatible with protocol state */
/* Implements Measure#  3 and streamline encoding*/
      cc_send_status (MNCC_CAUSE_MESSAGE_TYPE_INCOMPAT);
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_setup                   |
+--------------------------------------------------------------------+

  PURPOSE : Processing of an incoming setup message.

*/

GLOBAL void cc_setup (T_D_SETUP * setup)
{
  GET_INSTANCE_DATA;

  TRACE_FUNCTION ("cc_setup()");

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_0:
      if (cc_data->ti < 8)
      {
        /*
         * This values are reserved for mobile originated calls.
         */
        CCD_END;
        for_rel_req ();
        break;
      }

      switch (cc_data->error)
      {
        case M_CC_CAUSE_INVALID_MAND_INFO:
        case M_CC_CAUSE_COND_INFO_ELEM:
          CCD_END;
          CCD_START;
          {
            MCAST (rel_com, U_RELEASE_COMP);

            cc_build_release_complete (rel_com, CAUSE_MAKE(DEFBY_STD, 
                                                                    ORIGSIDE_MS, 
                                                                    MNCC_CC_ORIGINATING_ENTITY,
                                                                    cc_data->error));
            for_release_complete (rel_com);
          }
          CCD_END;
          for_rel_req ();
          break;

        default:
          switch (cc_compatibility_check (setup))
          {
            case BAD_SUBADDRESS:
              CCD_END;
              CCD_START;
              {
                MCAST (rel_com, U_RELEASE_COMP);
                cc_build_release_complete (rel_com, CAUSE_MAKE(DEFBY_STD, 
                                                                        ORIGSIDE_MS, 
                                                                        MNCC_CC_ORIGINATING_ENTITY,
                                                                        MNCC_CAUSE_NO_ROUTE));
                for_release_complete (rel_com);
              }
              CCD_END;
              for_rel_req ();
              cc_set_state (M_CC_CS_0);
              break;

            case ERROR:
              CCD_END;
              CCD_START;
              {
                MCAST (rel_com, U_RELEASE_COMP);
                cc_build_release_complete (rel_com, CAUSE_MAKE(DEFBY_STD, 
                                                                        ORIGSIDE_MS, 
                                                                        MNCC_CC_ORIGINATING_ENTITY,
                                                                        MNCC_CAUSE_INCOMPAT_DEST));
                for_release_complete (rel_com);
              }
              CCD_END;
              for_rel_req ();
              cc_set_state (M_CC_CS_0);
              break;

            case OKAY:
            case NEGOTIATION:
            {
              PALLOC (setup_ind, MNCC_SETUP_IND);

              cc_data->progress_desc[cc_data->index_ti] = NOT_PRESENT_8BIT;

              if (setup->v_progress)
              {
                cc_data->progress_desc[cc_data->index_ti] = 
                  setup->progress.progress_desc;
              }

              cc_data->call_type [cc_data->index_ti] = CALL_TYPE_MTC;
              // PATCH LE 10.04.00
              // initialize disconnect collision flag
              cc_data->disc_coll [cc_data->index_ti] = FALSE;
              // END PATCH LE 10.04.00
              cc_build_mncc_setup_ind (setup, setup_ind);

              PSENDX (MMI, setup_ind);
              cc_build_facility_ind (MNCC_FAC_IN_SETUP, setup->v_facility,
                                     &setup->facility);
              cc_build_user_user_ind (MNCC_USER_IN_SETUP, setup->v_user_user,
                                      &setup->user_user);



              CCD_END;
              CCD_START;
              {
                MCAST (call_cnf, U_CALL_CONF);
  
                if (cc_count_active_connections () EQ 0)
                  cc_build_call_confirm (call_cnf, CAUSE_MAKE(DEFBY_CONDAT, 
                                                                       ORIGSIDE_MS, 
                                                                       MNCC_CC_ORIGINATING_ENTITY,
                                                                       NOT_PRESENT_8BIT));
                else
                  cc_build_call_confirm (call_cnf, CAUSE_MAKE(DEFBY_STD, 
                                                                       ORIGSIDE_MS, 
                                                                       MNCC_CC_ORIGINATING_ENTITY,
                                                                       MNCC_CAUSE_USER_BUSY));
                for_call_confirm (call_cnf);
              }
              CCD_END;
              cc_set_state (M_CC_CS_9);

              EM_CC_MM_CONNECTION_ESTABLISHED_MT;

              break;
            }

            default:
              CCD_END;
              break;
          }
          break;
      }
      break;

    default:
      CCD_END;
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_sync_ind                |
+--------------------------------------------------------------------+

  PURPOSE : Processing of an incoming sync indication from
            mobility management.

*/

GLOBAL void cc_sync_ind (T_MMCM_SYNC_IND * mmcm_sync)
{
  GET_INSTANCE_DATA;	
  PALLOC ( mncc_sync, MNCC_SYNC_IND );

  TRACE_FUNCTION ("cc_sync_ind()");


  cc_data->channel_type = mmcm_sync->sync_info.ch_info.ch_type;
  cc_data->channel_mode = mmcm_sync->sync_info.ch_info.ch_mode;

  mncc_sync->ti         = mmcm_sync->ti;

  mncc_sync->ch_info.ch_mode = mmcm_sync->sync_info.ch_info.ch_mode;
  mncc_sync->ch_info.ch_type = mmcm_sync->sync_info.ch_info.ch_type;

  mncc_sync->cause      = MNCC_CAUSE_CHANNEL_SYNC;
  PSENDX (MMI, mncc_sync);
  PFREE (mmcm_sync);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_est_cnf                 |
+--------------------------------------------------------------------+

  PURPOSE : Processing of an incoming establish confirm from
            mobility management.

*/

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

  switch (cc_data->state[cc_data->index_ti])
  {
    case M_CC_CS_01:
      {
        /* 
         * As CC may potentially do some ugly things like 
         * MAX_SETUP_ATTEMPTS > 1, we cannot use the stored 
         * SETUP or EMERGENCY SETUP message, but have to copy.
         */
        PALLOC_SDU (data, MMCM_DATA_REQ, cc_data->stored_setup->sdu.l_buf);

        data->sdu.l_buf = cc_data->stored_setup->sdu.l_buf;
        data->sdu.o_buf = cc_data->stored_setup->sdu.o_buf;
        memcpy (&data->sdu.buf[data->sdu.o_buf >> 3],
                &cc_data->stored_setup->sdu.buf[data->sdu.o_buf >> 3],
                data->sdu.l_buf >> 3);

        /* Forward the SETUP or EMERGENCY SETUP message to MM */
        for_pd (data);
      }

      cc_set_state (M_CC_CS_1);
      srv_use_stored_prim ();
      break;

    default:
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_reest_cnf               |
+--------------------------------------------------------------------+

  PURPOSE : Processing of an incoming re-establish confirm from
            mobility management.

*/

GLOBAL void cc_reest_cnf (void)
{
  GET_INSTANCE_DATA;
  
  PALLOC (sync, MNCC_SYNC_IND);

    TRACE_FUNCTION ("cc_reest_cnf()");

    switch (cc_data->state[cc_data->index_ti])
    {
      case CS_101:
        sync->ti    = cc_data->ti;
        sync->cause = MNCC_CAUSE_REEST_FINISHED;
        sync->ch_info.ch_mode = NOT_PRESENT_8BIT;
        sync->ch_info.ch_type = NOT_PRESENT_8BIT;        
        PSENDX (MMI, sync);

        cc_set_state (M_CC_CS_10);
        srv_use_stored_prim ();
        break;

      case CS_261:
        sync->ti    = cc_data->ti;
        sync->cause = MNCC_CAUSE_REEST_FINISHED;
        sync->ch_info.ch_mode = NOT_PRESENT_8BIT;
        sync->ch_info.ch_type = NOT_PRESENT_8BIT;
        PSENDX (MMI, sync);

        TIMERSTART (T323, T323_VALUE);
        cc_set_state (M_CC_CS_26); 
        srv_use_stored_prim ();
        break;

      default:
        PFREE (sync);
        break;
    }
}

#ifdef SIM_TOOLKIT
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_mncc_bearer_cap_req     |
+--------------------------------------------------------------------+

  PURPOSE:      Checks the compatibility of bearer capabilities. 
                Bearer capabilities in coded form are tranformed to 
                parameter form and vice versa.      
*/

GLOBAL void cc_mncc_bearer_cap_req (T_MNCC_BEARER_CAP_REQ * bc_req)
{
  PALLOC (bc_conf, MNCC_BEARER_CAP_CNF); 

  TRACE_FUNCTION ("cc_mncc_bearer_cap_req()");

  /* Copy input parameters */
  bc_conf->req_id = bc_req->req_id;
  bc_conf->bc_mod = bc_req->bc_mod;

  /* Set default values to no bcpara to set valid values in case cc_bearer_cap_decode returns OKAY */
  memset (&bc_conf->bcpara2, 0, sizeof (T_MNCC_bcpara));
  bc_conf->bcpara2.bearer_serv = MNCC_BEARER_SERV_NOT_PRES;

  if (bc_req->bc_mod EQ MNCC_BC_MOD_DECODE) 
  {
    /* Transform coded form into parameter form */
    
    /* Copy input parameters */
    bc_conf->bcconf = bc_req->bcconf;
    bc_conf->bcconf2 = bc_req->bcconf2;
    
    if (cc_bearer_cap_decode(&bc_req->bcconf, 
                             &bc_conf->bcpara) 
        EQ ERROR)
    {
      /* Bearer capabilities not supported */
      PFREE (bc_req);
      bc_conf->cause = CAUSE_MAKE(DEFBY_STD, 
                                ORIGSIDE_MS, 
                                MNCC_CC_ORIGINATING_ENTITY, 
                                MNCC_CAUSE_INCOMPAT_DEST);
      PSENDX (MMI, bc_conf);
      return;
    } 

    if (cc_bearer_cap_decode((T_MNCC_bcconf *)&bc_req->bcconf2, 
                             (T_MNCC_bcpara *)&bc_conf->bcpara2)
        EQ ERROR)
    {
      /* Bearer capabilities not supported */
      PFREE (bc_req);
      bc_conf->cause = CAUSE_MAKE(DEFBY_STD, 
                                ORIGSIDE_MS, 
                                MNCC_CC_ORIGINATING_ENTITY, 
                                MNCC_CAUSE_INCOMPAT_DEST);
      PSENDX (MMI, bc_conf);
      return;
    }
  }
  else
  {
    /* Transform parameter form into coded form */

    /* Copy input parameters */
    bc_conf->bcpara  = bc_req->bcpara;
    bc_conf->bcpara2 = bc_req->bcpara2;

    if (cc_bearer_cap_code(&bc_req->bcpara, 
                           &bc_conf->bcconf)
        EQ ERROR)
    {
      /* Bearer capabilities not supported */
      PFREE (bc_req);
      bc_conf->cause = CAUSE_MAKE(DEFBY_STD, 
                                ORIGSIDE_MS, 
                                MNCC_CC_ORIGINATING_ENTITY, 
                                MNCC_CAUSE_INCOMPAT_DEST);
      PSENDX (MMI, bc_conf);
      return;
    }

    if (cc_bearer_cap_code((T_MNCC_bcpara *)&bc_req->bcpara2,
                           (T_MNCC_bcconf *)&bc_conf->bcconf2)
        EQ ERROR)
    {
      /* Bearer capabilities not supported */
      PFREE (bc_req);
      bc_conf->cause = CAUSE_MAKE(DEFBY_STD, 
                                ORIGSIDE_MS, 
                                MNCC_CC_ORIGINATING_ENTITY, 
                                MNCC_CAUSE_INCOMPAT_DEST);
      PSENDX (MMI, bc_conf);
      return;
    }
  }

  bc_conf->cause = MNCC_CAUSE_SUCCESS; /* Positive result */
  PSENDX (MMI, bc_conf);
  PFREE (bc_req);
}

#endif /*SIM_TOOLKIT */


/* Implements Measure#  3 and streamline encoding*/
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_send_status             |
+--------------------------------------------------------------------+

  PURPOSE : Calls CCD Start and then cc_build_and_send_status 
            for sending status message
*/
GLOBAL void cc_send_status (USHORT cause)
{
  TRACE_FUNCTION ("cc_send_status()");

  CCD_START;
  {
    MCAST (status, B_STATUS);
    cc_build_status (status, CAUSE_MAKE(DEFBY_STD, 
                                      ORIGSIDE_MS, 
                                      MNCC_CC_ORIGINATING_ENTITY,
                                      cause));
    for_status (status);
  }
  CCD_END;
}

/* Implements Measure#  19 */ 
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                     |
| STATE   : code                ROUTINE : cc_send_release_cmp        |
+--------------------------------------------------------------------+

  PURPOSE : Send release complete message.

*/

LOCAL void cc_send_release_cmp (USHORT cause)
{
  GET_INSTANCE_DATA; 
  TRACE_FUNCTION ("cc_send_release_cmp()");
  
  /* Send RELEASE COMPLETE */
  CCD_START;
  {
    MCAST (rel_com, U_RELEASE_COMP);
    cc_build_release_complete (rel_com, cause);
    for_release_complete (rel_com);
  }
  CCD_END;

  /* Inform MMI */
  {
    PALLOC (release, MNCC_RELEASE_IND);
    release->ti    = cc_data->ti;
    release->cause = cause;
    release->c_raw_cause = cause;
    PSENDX (MMI, release);
  }

  /* Release MM connection */
  for_rel_req ();

  /* Next state is NULL */
  cc_set_state (M_CC_CS_0);

}

/* Implements Measure#  36, 48 */ 
/*
+--------------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CC_EST                           |
| STATE   : code                ROUTINE : cc_send_mncc_release_ind         |
+--------------------------------------------------------------------------+

  PURPOSE : Send release complete message with cause invalid ti.

*/

LOCAL void cc_send_mncc_release_ind(UBYTE  ti, USHORT cause)
{
  TRACE_FUNCTION ("cc_send_mncc_release_ind");  
  {
    PALLOC (release, MNCC_RELEASE_IND); 
    release->ti          = ti;
    release->cause       = cause;
    release->c_raw_cause = 0;
    PSENDX (MMI, release);
  }
}
#endif