view src/g23m-gsm/cc/cc_est.c @ 383:43dbedde9d80

doc/C1xx-Howto written
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 14 Jan 2018 20:45:51 +0000
parents 27a4235405c6
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