view src/g23m-gprs/gmm/gmm_kernf.c @ 662:8cd8fd15a095

SIM speed enhancement re-enabled and made configurable TI's original code supported SIM speed enhancement, but Openmoko had it disabled, and OM's disabling of speed enhancement somehow caused certain SIM cards to start working which didn't work before (OM's bug #666). Because our FC community is much smaller in year 2020 than OM's community was in their day, we are not able to find one of those #666-affected SIMs, thus the real issue they had encountered remains elusive. Thus our solution is to re-enable SIM speed enhancement and simply wait for if and when someone runs into a #666-affected SIM once again. We provide a SIM_allow_speed_enhancement global variable that allows SIM speed enhancement to be enabled or disabled per session, and an /etc/SIM_spenh file in FFS that allows it to enabled or disabled on a non-volatile basis. SIM speed enhancement is now enabled by default.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 24 May 2020 05:02:28 +0000
parents 219afcfc6250
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GPRS (8441)
|  Modul   :  gmm_kernf.c
+----------------------------------------------------------------------------- 
|  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 is part of the entity GMM and implements all 
|             procedures and functions as described in the 
|             SDL-documentation (KERN-statemachine)
+----------------------------------------------------------------------------- 
*/ 


#ifndef GMM_KERNF_C
#define GMM_KERNF_C
#endif

#define ENTITY_GMM

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

#include "typedefs.h"    /* to get Condat data types */
#include "vsi.h"        /* to get a lot of macros */
#include "macdef.h"
#include "gprs.h"
#include "gsm.h"        /* to get a lot of macros */
#include "ccdapi.h"     /* to get CCD API */
#include "cnf_gmm.h"    /* to get cnf-definitions */
#include "mon_gmm.h"    /* to get mon-definitions */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "gmm.h"        /* to get the global entity definitions */

#include "gmm_kernf.h"  /* to get some local definitions */
#include "gmm_kernl.h"  /* to get some local definitions */
#include "gmm_f.h"
#include <string.h>     /* to get memset */
#include "pcm.h"
#include "gmm_rxf.h"
#include "gmm_rxs.h"
#include "gmm_txf.h"
#include "gmm_rdyf.h"
#include "gmm_syncs.h"
#include "gmm_kernp.h"
#include "gmm_rdys.h"
#include "gmm_syncf.h"
#include "gmm_em.h"     /* To get Engineering Mode functions */

#ifdef _TARGET_
#include "ffs/ffs.h"
#endif

#include "cl_imei.h"  /* IMEI common library */

#include <stdlib.h>

#include <stdio.h>      /* for sprintf */

/*==== CONST ================================================================*/

/*==== LOCAL VARS ===========================================================*/

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

/*==== PUBLIC FUNCTIONS =====================================================*/
/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_info_ind
+------------------------------------------------------------------------------
| Description : The function kern_gmmreg_info_ind forwards the info comming
|               from the net to the MMI entity
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_info_ind ( void)
{ 
  GMM_TRACE_FUNCTION( "kern_gmmreg_info_ind" );
  {
	  MCAST(gmm_information, GMM_INFORMATION);
    /* Agilent Issue OMAPS00148436 WA */
    if (!gmm_information->v_full_network_name && !gmm_information->v_short_network_name 
        && !gmm_information->v_time_zone && !gmm_information->v_time_zone_and_time)
    { 
      TRACE_EVENT ("GMM_INFORMATION message doesn't contain valid information"); 
      GMM_RETURN; 
    } 
    {

    PALLOC (gmmreg_info_ind, GMMREG_INFO_IND); /* T_GMMREG_INFO_IND */
  
    /* 
     * Set PLMN, this will be used if network name is given
     */
    gmmreg_info_ind->plmn.v_plmn = TRUE;       
    memcpy (gmmreg_info_ind->plmn.mcc, gmm_data->kern.attach_cap.rai_accepted.mcc, SIZE_MCC);
    memcpy (gmmreg_info_ind->plmn.mnc, gmm_data->kern.attach_cap.rai_accepted.mnc, SIZE_MNC);

    /*
     * Set full network name, if present
     */

      if (gmm_information->v_full_network_name) 
      {
        gmmreg_info_ind->full_net_name_gmm.v_name     = TRUE;
        gmmreg_info_ind->full_net_name_gmm.dcs /* TCS 2.1 */
            = gmm_information->full_network_name.code;
        gmmreg_info_ind->full_net_name_gmm.add_ci    
         = gmm_information->full_network_name.add_ci;
        gmmreg_info_ind->full_net_name_gmm.num_spare  = 
          gmm_information->full_network_name.nr_sparebits;
        memset(gmmreg_info_ind->full_net_name_gmm.text, 0, MMR_MAX_TEXT_LEN);
        gmmreg_info_ind->full_net_name_gmm.c_text = 
          MINIMUM (MMR_MAX_TEXT_LEN, gmm_information->full_network_name.c_text_string);
        memcpy (gmmreg_info_ind->full_net_name_gmm.text,
            gmm_information->full_network_name.text_string,
            gmmreg_info_ind->full_net_name_gmm.c_text);
      }
      else
      {
        gmmreg_info_ind->full_net_name_gmm.v_name = FALSE;
      }
      /* Set short network name, if present */
      if (gmm_information->v_short_network_name) 
      {
        gmmreg_info_ind->short_net_name_gmm.v_name    = TRUE;
        gmmreg_info_ind->short_net_name_gmm.dcs       = gmm_information->short_network_name.code;  /* TCS 2.1 */
        gmmreg_info_ind->short_net_name_gmm.add_ci    = gmm_information->short_network_name.add_ci;
        gmmreg_info_ind->short_net_name_gmm.num_spare = 
        gmm_information->short_network_name.nr_sparebits;
        memset(gmmreg_info_ind->short_net_name_gmm.text, 0, MMR_MAX_TEXT_LEN);
        gmmreg_info_ind->short_net_name_gmm.c_text = 
        MINIMUM (MMR_MAX_TEXT_LEN, gmm_information->short_network_name.c_text_string);
        memcpy (gmmreg_info_ind->short_net_name_gmm.text,
          gmm_information->short_network_name.text_string,
          gmmreg_info_ind->short_net_name_gmm.c_text);
      }
      else
      {
        gmmreg_info_ind->short_net_name_gmm.v_name = FALSE;
      }
      /* Set network time zone, if present */
      if (gmm_information->v_time_zone)
      {
        gmmreg_info_ind->net_time_zone.v_time_zone = TRUE;
        gmmreg_info_ind->net_time_zone.time_zone 
            = gmm_information->time_zone.time_zone_value;
      }
      else
      {
        gmmreg_info_ind->net_time_zone.v_time_zone = FALSE;
      }
      /* Set network time zone and time, if present */
      if (gmm_information->v_time_zone_and_time)
      {
        gmmreg_info_ind->net_time_zone.v_time_zone = TRUE;
        gmmreg_info_ind->net_time_zone.time_zone   
            = gmm_information->time_zone_and_time.time_zone_value;
        gmmreg_info_ind->net_time.v_time = TRUE;

        gmmreg_info_ind->net_time.year = 
          10 * gmm_information->time_zone_and_time.year[0] + 
               gmm_information->time_zone_and_time.year[1];
        gmmreg_info_ind->net_time.month = 
          10 * gmm_information->time_zone_and_time.month[0] + 
               gmm_information->time_zone_and_time.month[1];
        gmmreg_info_ind->net_time.day = 
          10 * gmm_information->time_zone_and_time.day[0] +
               gmm_information->time_zone_and_time.day[1];
        gmmreg_info_ind->net_time.hour = 
          10 * gmm_information->time_zone_and_time.hour[0] + 
               gmm_information->time_zone_and_time.hour[1];
        gmmreg_info_ind->net_time.minute =
          10 * gmm_information->time_zone_and_time.minute[0] +
               gmm_information->time_zone_and_time.minute[1];
        gmmreg_info_ind->net_time.second = 
          10 * gmm_information->time_zone_and_time.second[0] +
               gmm_information->time_zone_and_time.second[1];
      }
      else
      {
        gmmreg_info_ind->net_time.v_time = FALSE;
      }

#ifdef REL99
      if (gmm_information->v_daylight_save_time) /* TCS 4.0 */
      { /* TCS 4.0 */
        gmmreg_info_ind->net_daylight_save_time =  /* TCS 4.0 */
          gmm_information->daylight_save_time.save_time_value; /* TCS 4.0 */
      } /* TCS 4.0 */
      else /* TCS 4.0 */
      { /* TCS 4.0 */
        gmmreg_info_ind->net_daylight_save_time = GMMREG_ADJ_NO; /* TCS 4.0 */
      } /* TCS 4.0 */
#endif

    PSEND ( hCommMMI, gmmreg_info_ind);
	}
  }
  GMM_RETURN;
} /* kern_gmmreg_info_ind() */
/*
+------------------------------------------------------------------------------
| Function    : kern_calculate_digits
+------------------------------------------------------------------------------
| Description : Derives tm mobile identiti for the AIR
|
| COPIED FROM : MM    mm_mmf.c : mm_calculate_digits
|               
| Parameters  : mobile_identity   - used in the AIR message
|
+------------------------------------------------------------------------------
*/
LOCAL UBYTE kern_calculate_digits (UBYTE *digits)
{
  UBYTE i = 0;

  GMM_TRACE_FUNCTION ("kern_calculate_digits()");

  while (digits[i] < 0x0A AND i < 16)
    i++;

  GMM_RETURN_ (i);
}
/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmmreg_attach_cnf
+------------------------------------------------------------------------------
| Description : This procedure sends the gmmreg_attach_cnf primitiv to ACI
|
| Parameters  : attach_type - attach type
|               mmgmm_reg_req - the primitiv
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmmreg_attach_cnf ( UBYTE attach_type, UBYTE search_running,
                                      T_MMGMM_REG_CNF * mmgmm_reg_cnf )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmmreg_attach_cnf" );

    TRACE_1_INFO ("Info: MM  lac: %x", mmgmm_reg_cnf->lac);

  switch (gmm_data->kern.sig_cell_info.gmm_status)
  {
    case GMMRR_SERVICE_LIMITED:
    case GMMRR_SERVICE_NONE:
      search_running=SEARCH_NOT_RUNNING;
      break;
    default:
    case GMMRR_SERVICE_FULL:
      break;
  }


  gmm_data->kern.mm_cell_env.cid = mmgmm_reg_cnf->cid;
  gmm_data->kern.mm_cell_env.rai.lac = mmgmm_reg_cnf->lac;
  gmm_data->kern.mm_cell_env.rai.plmn = mmgmm_reg_cnf->plmn;

  GMM_TRACE_GMM_DATA(GMM_DEBUG_PRINT_MASK_CID);

  {
    PALLOC ( gmmreg_attach_cnf, GMMREG_ATTACH_CNF );
      gmmreg_attach_cnf->attach_type = attach_type;
      /*
       * gmmreg_attach_cnf->plmn = gmm_data->mm_plmn= mmgmm_reg_cnf->plmn;
       */
      gmmreg_attach_cnf->plmn = mmgmm_reg_cnf->plmn;
      gmmreg_attach_cnf->search_running = search_running;
      gmmreg_attach_cnf->lac = mmgmm_reg_cnf->lac;
      gmmreg_attach_cnf->rac =  gmm_data->kern.sig_cell_info.env.rai.rac;
      //gmmreg_attach_cnf->cid = gmm_data->kern.sig_cell_info.env.cid; // #HM#
      gmmreg_attach_cnf->cid = mmgmm_reg_cnf->cid; // #HM#
      gmmreg_attach_cnf->gprs_indicator = gmm_data->kern.sig_cell_info.gmm_status;
      gmmreg_attach_cnf->bootup_cause = REG_END;
#ifdef GMM_TCS4
      gmmreg_attach_cnf->rt = gmm_data->kern.sig_cell_info.rt; // TCS 4.0
#endif
#ifdef TRACE_EVE
      {
        switch (attach_type)
        {
          case GMMREG_AT_COMB:
            TRACE_EVENT ("MS is combined attached.");
            break;
          case GMMREG_AT_IMSI:
            TRACE_EVENT ("MS is GSM-only attached.");
            break;
          case GMMREG_AT_GPRS:
            TRACE_EVENT ("MS is GPRS-only attached.");
            break;
          default:
            TRACE_ERROR ("MS is attached with wrong attach type.");
            break;
        }
      TRACE_7_PARA("%x%x%x, %x%x%x, lac %x", 
          gmmreg_attach_cnf->plmn.mcc[0],
          gmmreg_attach_cnf->plmn.mcc[1],
          gmmreg_attach_cnf->plmn.mcc[2],
          gmmreg_attach_cnf->plmn.mnc[0],
          gmmreg_attach_cnf->plmn.mnc[1],
          gmmreg_attach_cnf->plmn.mnc[2],
          gmmreg_attach_cnf->lac);
     }
#endif
   
    PSEND ( hCommMMI, gmmreg_attach_cnf );
    
    gmm_data->kern.attach_cap.gmmreg = FALSE;
  }
  GMM_RETURN;
} /* kern_mmgmmreg_attach_cnf () */
/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_attach_cnf
+------------------------------------------------------------------------------
| Description : This procedure sends the gmmreg_attach_cnf primitiv to ACI
|
| Parameters  : attach_type - attach type
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_attach_cnf ( UBYTE attach_type)
{ 
  GMM_TRACE_FUNCTION( "kern_gmmreg_attach_cnf" );
  kern_gmmreg_attach_cnf_sr(attach_type,SEARCH_NOT_RUNNING);
  GMM_RETURN;
} /* kern_gmmreg_attach_cnf () */
/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_attach_cnf_sr
+------------------------------------------------------------------------------
| Description : This procedure sends the gmmreg_attach_cnf primitiv to ACI
|
| Parameters  : attach_type - attach type
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_attach_cnf_sr ( UBYTE attach_type, UBYTE search_running)
{ 
  GMM_TRACE_FUNCTION( "kern_gmmreg_attach_cnf_sr" );
  TRACE_2_OUT_PARA("%s, %s",
      search_running==SEARCH_RUNNING? "searching":"finished",
      attach_type==GMMREG_AT_COMB?    "comb":
      attach_type==GMMREG_AT_GPRS?"gprs":
      attach_type==GMMREG_AT_IMSI?"gsm":
                                   "unknown tpe"
     );

  {
    PALLOC ( gmmreg_attach_cnf, GMMREG_ATTACH_CNF );
      gmmreg_attach_cnf->attach_type = attach_type;
      gmmreg_attach_cnf->plmn.v_plmn = TRUE;
      gmmreg_attach_cnf->search_running= search_running;
      memcpy ( gmmreg_attach_cnf->plmn.mcc, gmm_data->kern.sig_cell_info.env.rai.plmn.mcc, SIZE_MCC);
      memcpy ( gmmreg_attach_cnf->plmn.mnc, gmm_data->kern.sig_cell_info.env.rai.plmn.mnc, SIZE_MNC);
      gmmreg_attach_cnf->lac = gmm_data->kern.sig_cell_info.env.rai.lac;
      gmmreg_attach_cnf->rac = gmm_data->kern.sig_cell_info.env.rai.rac;
      gmmreg_attach_cnf->cid = gmm_data->kern.sig_cell_info.env.cid;
      gmmreg_attach_cnf->gprs_indicator = gmm_data->kern.sig_cell_info.gmm_status;      
      gmmreg_attach_cnf->bootup_cause = REG_END;
#ifdef GMM_TCS4
      gmmreg_attach_cnf->rt = gmm_data->kern.sig_cell_info.rt; /* TCS 4.0 */
#endif
    PSEND ( hCommMMI, gmmreg_attach_cnf );
    
    gmm_data->kern.attach_cap.gmmreg = FALSE;

    /* 
     * ACI does not realize GSM detach if search running has been set
     * in kern_mmgmm_nreg_cnf 
     */
    if (GMMRR_NET_MODE_III==gmm_data->kern.sig_cell_info.net_mode
    && GMMREG_CLASS_BG==  gmm_data->kern.attach_cap.mobile_class
    && GMMREG_AT_GPRS==attach_type)
    {
      kern_gmmreg_detach (GMMREG_DT_IMSI,
                        GMMCS_LIMITED_SERVICE,  /* TCS 2.1 */
                        SEARCH_NOT_RUNNING,
                        GMMCS_LIMITED_SERVICE);
    }
  }
  GMM_RETURN;
} /* kern_gmmreg_attach_cnf_sr () */
/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_detach
+------------------------------------------------------------------------------
| Description : This procedure sends the gmmreg_detach primitiv to ACI
|
| Parameters  : detach_type    - detach type
|                cause           - error cause
|               search_running - cell search still running or not
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_detach ( UBYTE detach_type, 
                                 USHORT service,
                                 UBYTE search_running,
                                 USHORT cause)
{
  UBYTE mm_state;

  GMM_TRACE_FUNCTION( "kern_gmmreg_detach" );

  mm_state = GET_STATE(MM);

  if (GMMREG_DT_GPRS==detach_type
  &&  (  GMM_MM_DEREG==mm_state
      || GMM_MM_REG_NO_CELL_AVAILABLE==mm_state
      || GMM_MM_REG_INITATED_VIA_GPRS==mm_state
      || MMGMM_LIMITED_SERVICE==gmm_data->kern.sig_cell_info.mm_status )
  )
  {
    detach_type = GMMREG_DT_COMB;
  }

  TRACE_3_OUT_PARA("%s, cause: 0x%x, %s",
        detach_type==GMMREG_DT_COMB?    "comb":
        detach_type==GMMREG_DT_IMSI?    "gsm":
        detach_type==GMMREG_DT_GPRS?"gprs":
        detach_type==GMMREG_DT_POWER_OFF?"power off":
        detach_type==GMMREG_DT_SIM_REMOVED?"sim removed":
        detach_type==GMMREG_DT_LIMITED_SERVICE?"limited":
        detach_type==GMMREG_DT_SOFT_OFF?"soft off":
                                            "unknown type"
          , cause,
       (search_running==GMMREG_SEARCH_RUNNING?"searching":"finished"));

  if ( gmm_data->kern.detach_cap.gmmreg )
  {
    PALLOC ( gmmreg_detach_cnf, GMMREG_DETACH_CNF );
      gmmreg_detach_cnf->detach_type = gmm_data->kern.detach_cap.detach_type;
    PSEND ( hCommMMI, gmmreg_detach_cnf );
  }
  else
  {
    if ( gmm_data->kern.attach_cap.gmmreg )
    {
      if (GMMREG_CLASS_CG==gmm_data->kern.attach_cap.mobile_class
      && GMMREG_DT_IMSI==detach_type)
      {
        kern_gmmreg_attach_cnf_sr(GMMREG_AT_GPRS, search_running);
      }
      else
      {
        PALLOC ( gmmreg_attach_rej, GMMREG_ATTACH_REJ );
          gmmreg_attach_rej->detach_type = detach_type;
          gmmreg_attach_rej->cause = cause;
          gmmreg_attach_rej->search_running = search_running;
          gmmreg_attach_rej->service = service;
        PSEND ( hCommMMI, gmmreg_attach_rej );
      }
      if (GMMREG_SEARCH_NOT_RUNNING==search_running)
      {
        gmm_data->kern.attach_cap.gmmreg=FALSE;
      }

    }
    else /* if ! gmmreg */
    {
      /* 
       * If gmmsm == TRUE means, we are in GMM_REGISTERED_INITIATED state.
       * That means, if ACI did not send an attach request ACI need not
       * to be informed, otherwise we are attached in ACI has to be informed
       */
#ifndef GMM_TCS4
      if ( !gmm_data->kern.attach_cap.gmmsm )
#endif 
      {
        PALLOC ( gmmreg_detach_ind, GMMREG_DETACH_IND );
          gmmreg_detach_ind->detach_type = detach_type;
          gmmreg_detach_ind->cause = cause;
          gmmreg_detach_ind->search_running = search_running;
          gmmreg_detach_ind->service = service;
        PSEND ( hCommMMI, gmmreg_detach_ind );
      }
    }
  }
  gmm_data->kern.detach_cap.gmmreg=FALSE;
  /*
   * Clear data before Power Off
   */
  if (GMMREG_DT_POWER_OFF==detach_type)
  {
    /*
     * every servce i reinitilized that the test sysem may run
     * with out real power off
     */
    kern_init();
    rxgmm_init();
    txgmm_init();
    rdy_init();
    sync_gmm_init();

    /*
     * In kern_init the deep is set to 0 for MACRO GMM_RETURN
     */
    return;
  }
  GMM_RETURN;
} /* kern_gmmreg_detach () */

/*
+------------------------------------------------------------------------------
| Function    : kern_llgmm_assign_tlli
+------------------------------------------------------------------------------
| Description : This procedure assigned the given TLLI parameter to LLC 
|
| Parameters  : new_tlli_type - type of new TLLI (random, local ,..)
|               old_tlli_type - type of old TLLI
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_llgmm_assign_tlli ( T_TLLI_TYPE new_tlli_type,
                                     T_TLLI_TYPE old_tlli_type )
{ 
  GMM_TRACE_FUNCTION( "kern_llgmm_assign_tlli" );

  if( GMM_LLC_STATE_UNASSIGNED EQ gmm_data->kern.attach_cap.llc_state )
  {
    gmm_data->kern.attach_cap.llc_state = GMM_LLC_STATE_ASSIGNED;
  }
  {
    PALLOC ( llgmm_assign_req, LLGMM_ASSIGN_REQ );
      llgmm_assign_req->old_tlli = gmm_get_tlli ( old_tlli_type );
      if ( GMMRR_TMSI_INVALID == gmm_data->ptmsi.current )
      {
        /*
         * <R.GMM.TLLIUSE.M.005>
         */
        llgmm_assign_req->new_tlli = gmm_get_tlli (  RANDOM_TLLI );
      }
      else
      {
        llgmm_assign_req->new_tlli = gmm_get_tlli ( new_tlli_type );
      }
      if (NO_KEY== gmm_data->kern.auth_cap.cksn)
      {
        memset (llgmm_assign_req->llgmm_kc.key, 0x0, MAX_KC);
      }
      else
      {
        memcpy ( llgmm_assign_req->llgmm_kc.key, gmm_data->kern.auth_cap.kc, MAX_KC );
      }
      llgmm_assign_req->ciphering_algorithm = LLGMM_CIPHER_NA;
 
      TRACE_2_OUT_PARA("TLLI old: 0x%X, new: 0x%X",  llgmm_assign_req->old_tlli,llgmm_assign_req->new_tlli);

    PSEND ( hCommLLC, llgmm_assign_req );
  }
  GMM_RETURN;
} /* kern_llgmm_assign_tlli() */
/*
+------------------------------------------------------------------------------
| Function    : kern_llgmm_assign
+------------------------------------------------------------------------------
| Description : This procedure assigned the current TLLI parameter to LLC 
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_llgmm_assign ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_llgmm_assign" );
  kern_llgmm_assign_tlli ( CURRENT_TLLI, OLD_TLLI );
  GMM_RETURN;
} /* kern_llgmm_assign() */
/*
+------------------------------------------------------------------------------
| Function    : kern_gmmsm_establish_rej
+------------------------------------------------------------------------------
| Description : This procedure informs SM that gprs is off. 
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmsm_establich_rej ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmsm_stablich_rej" );

#ifdef GMM_TCS4 

  {
     PALLOC (mmpm_detach_ind, MMPM_DETACH_IND);
     mmpm_detach_ind->ps_cause = kern_make_new_cause();
     /*For reattach, overwrite the cause from kern_make_new_cause()*/
     if (GMM_DT_RE_ATTACH == gmm_data->kern.detach_cap.detach_type) {
       mmpm_detach_ind->ps_cause.ctrl_value = CAUSE_is_from_mm;
       mmpm_detach_ind->ps_cause.value.mm_cause = 
                                 (U16)CAUSE_MM_DETACH_WITH_REATTACH;
     }
     PSEND ( hCommSM, mmpm_detach_ind);
  }
  
#else  /*New TI DK primitive should be sent*/
 if ( gmm_data->kern.attach_cap.gmmsm )
  {
    PALLOC ( gmmsm_establish_rej, GMMSM_ESTABLISH_REJ );
      gmmsm_establish_rej->sm_cause = gmm_data->kern.detach_cap.error_cause; 
    PSEND ( hCommSM, gmmsm_establish_rej );
  }
  else // if !gmmsm 
  {
    
    //  <R.GMM.PRELIND.M.001>
    
    PALLOC ( gmmsm_release_ind, GMMSM_RELEASE_IND);
    PSEND ( hCommSM, gmmsm_release_ind );
  } 

#endif



  GMM_RETURN;
} /* kern_gmmsm_establish_rej() */


/*
+------------------------------------------------------------------------------
| Function    : kern_llgmm_unassign
+------------------------------------------------------------------------------
| Description : This procedure unassigned all TLLIs in LLC 
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_llgmm_unassign ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_llgmm_unassign" );

  switch (gmm_data->kern.attach_cap.llc_state)
  {
    case GMM_LLC_STATE_UNASSIGNED:
      GMM_RETURN;
    default:
    case GMM_LLC_STATE_ASSIGNED:
    case GMM_LLC_STATE_SUSPENED:
    case GMM_LLC_STATE_SUSPENED_RAU:
      gmm_data->kern.attach_cap.llc_state = GMM_LLC_STATE_UNASSIGNED;
      break;
  }



  /*
   * PTMSI is still valid for next attach
   * gmm_data->ptmsi.current = GMMRR_TMSI_INVALID;
   */
  gmm_data->ptmsi.new_grr = GMMRR_TMSI_INVALID;

  gmm_data->tlli.old=gmm_data->tlli.current;
  gmm_data->tlli.current_type = INVALID_TLLI;
  gmm_data->tlli.current=GMMRR_TMSI_INVALID;

  TRACE_0_OUT_PARA("Unassign");
  {
    PALLOC ( gmmrr_assign_req, GMMRR_ASSIGN_REQ );
      gmmrr_assign_req->old_tlli  = GMMRR_TLLI_INVALID;
      gmmrr_assign_req->new_tlli  = GMMRR_TLLI_INVALID;
      gmmrr_assign_req->old_ptmsi = GMMRR_TMSI_INVALID;
      gmmrr_assign_req->new_ptmsi = GMMRR_TMSI_INVALID;
      gmmrr_assign_req->imsi  = gmm_data->imsi;
      gmmrr_assign_req->rai.plmn.v_plmn=TRUE;
      memcpy (gmmrr_assign_req->rai.plmn.mcc, gmm_data->kern.attach_cap.rai_accepted.mcc, SIZE_MCC);
      memcpy (gmmrr_assign_req->rai.plmn.mnc, gmm_data->kern.attach_cap.rai_accepted.mnc, SIZE_MNC);
      gmmrr_assign_req->rai.lac = gmm_data->kern.attach_cap.rai_accepted.lac;
      gmmrr_assign_req->rai.rac = gmm_data->kern.attach_cap.rai_accepted.rac;
    PSEND ( hCommGRR, gmmrr_assign_req );
  }
  {
    PALLOC (llgmm_assign_req, LLGMM_ASSIGN_REQ);

    /* gmm_data->tlli.current_type=INVALID_TLLI; */
    
    llgmm_assign_req->old_tlli = LLGMM_TLLI_INVALID;
    llgmm_assign_req->new_tlli = LLGMM_TLLI_INVALID;

    memset (llgmm_assign_req->llgmm_kc.key,0, sizeof (llgmm_assign_req->llgmm_kc.key));
   
    llgmm_assign_req->ciphering_algorithm = LLGMM_CIPHER_NO_ALGORITHM;    
    kern_reset_cipher ();
    
    PSEND ( hCommLLC, llgmm_assign_req );
  }
 
  GMM_RETURN;     
} /* kern_llgmm_unassign() */
/*
+------------------------------------------------------------------------------
| Function    : kern_llgmm_suspend
+------------------------------------------------------------------------------
| Description : This procedure suspends  LLC 
|
| Parameters  : susp_cause - cause off suspension
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_llgmm_suspend ( UBYTE susp_cause)
{ 
  U8 cell_state=GMMREG_CS_CALL;
#ifdef GMM_TCS4 
  U8 mm_cause = CAUSE_MM_DEDICATED_MODE;      
#endif

  GMM_TRACE_FUNCTION( "kern_llgmm_suspend" );
  /*
   * if LLC is in suspended RAU it means that GRR has opned the GMM queue
   * so we have to remember.
   */
  switch (gmm_data->kern.attach_cap.llc_state)
  {
    case GMM_LLC_STATE_SUSPENED_RAU:
      GMM_RETURN;
    case GMM_LLC_STATE_UNASSIGNED:
      TRACE_ERROR ("suspending of LLC in state unassigned ignored");
      GMM_RETURN;
    default:
    case GMM_LLC_STATE_ASSIGNED:
    case GMM_LLC_STATE_SUSPENED:
      break;
  }

  switch (susp_cause)
  {
    case LLGMM_CALL:
      TRACE_0_OUT_PARA("call");
      
      cell_state=GMMREG_CS_CALL;
#ifdef GMM_TCS4
      mm_cause = CAUSE_MM_DEDICATED_MODE;      
#endif
      break;

    case LLGMM_LIMITED:      
      TRACE_0_OUT_PARA("limited");      
      cell_state=GMMREG_LIMITED_SERVICE;
#ifdef GMM_TCS4
      mm_cause = CAUSE_MM_LIMITED_SERVICE;      
#endif
      break;
      
    case LLGMM_NO_GPRS_SERVICE:
      TRACE_0_OUT_PARA("no_service");
      cell_state=GMMREG_GPRS_NOT_SUPPORTED;
#ifdef GMM_TCS4
      mm_cause = CAUSE_MM_NO_SERVICE;      
#endif
      break;

    case LLGMM_RAU:
      cell_state=GMMREG_TRY_TO_UPDATE;
#ifdef GMM_TCS4
      mm_cause = CAUSE_MM_TRY_TO_UPDATE;      
#endif

      if(GET_STATE(CU) EQ CU_CELL_RES_SENT
      || GET_STATE(CU) EQ CU_REQUESTED_CELL_RES_SENT)
      {
        susp_cause= LLGMM_PERIODIC_RAU;
        /* NO break; */
      }
      else
      {
        gmm_data->kern.attach_cap.llc_state=GMM_LLC_STATE_SUSPENED_RAU;
        TRACE_0_OUT_PARA("rau");          
        break;
      }
      /* GS, how would you solve it with V8?*/ 
    case LLGMM_PERIODIC_RAU:
      if (GMM_LLC_STATE_SUSPENED==gmm_data->kern.attach_cap.llc_state)
      {
        GMM_RETURN;
      }
      else
      {
        TRACE_0_OUT_PARA("periodic rau");
        cell_state=GMMREG_TRY_TO_UPDATE;
#ifdef GMM_TCS4
        mm_cause = CAUSE_MM_TRY_TO_UPDATE;      
#endif
      }
      break;
    default:
      TRACE_ERROR("llc_susp unexpected");
      break;
  }
  
  if (GMM_LLC_STATE_SUSPENED_RAU!=gmm_data->kern.attach_cap.llc_state)
  {
    gmm_data->kern.attach_cap.llc_state= GMM_LLC_STATE_SUSPENED;
  }
  
  {
    PALLOC (llgmm_suspend_req, LLGMM_SUSPEND_REQ);
      llgmm_suspend_req->susp_cause = susp_cause;
    PSEND  ( hCommLLC, llgmm_suspend_req );
  }

  {
    PALLOC(gmmreg_suspend_ind, GMMREG_SUSPEND_IND);
      gmmreg_suspend_ind->cell_state= cell_state;
    PSEND(hCommMMI,gmmreg_suspend_ind);
  }
#ifdef GMM_TCS4 
  {
    PALLOC(mmpm_suspend_ind, MMPM_SUSPEND_IND);
      mmpm_suspend_ind->ps_cause.ctrl_value = CAUSE_is_from_mm;      
      mmpm_suspend_ind->ps_cause.value.mm_cause = mm_cause;      
    PSEND(hCommSM,mmpm_suspend_ind);
  }
#endif 
  GMM_RETURN;     
} /* kern_llgmm_suspend() */
/*
+------------------------------------------------------------------------------
| Function    : kern_llgmm_resume
+------------------------------------------------------------------------------
| Description : This procedure resumes  LLC 
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_llgmm_resume ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_llgmm_resume" );
 
  switch(gmm_data->kern.attach_cap.llc_state)
  {
    case GMM_LLC_STATE_SUSPENED_RAU:
    case GMM_LLC_STATE_SUSPENED:
      {
        PALLOC (llgmm_resume_req, LLGMM_RESUME_REQ);
          gmm_data->kern.attach_cap.llc_state=GMM_LLC_STATE_ASSIGNED;
        PSEND  ( hCommLLC, llgmm_resume_req );
      }
      {
        PALLOC (gmmreg_resume_ind, GMMREG_RESUME_IND);
        PSEND  ( hCommMMI, gmmreg_resume_ind );
      }
    
#ifdef GMM_TCS4
      {
        PALLOC(mmpm_resume_ind, MMPM_RESUME_IND);
        PSEND(hCommSM,mmpm_resume_ind);
      }
#endif
      break;
    case GMM_LLC_STATE_ASSIGNED:
    default:
      break;
    case GMM_LLC_STATE_UNASSIGNED:
      TRACE_ERROR("resuming LLC in state unassigned");
      kern_llgmm_assign();
      break;
  }
  kern_gmmrr_stop_waiting_for_transmission();
  GMM_RETURN;     
} /* kern_llgmm_suspend() */


/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_enable
+------------------------------------------------------------------------------
| Description : The function kern_enable() 
|               disables GRR and activates MM to act as a class CC mobile.
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_enable ( void )
{
  GMM_TRACE_FUNCTION ("kern_gmmrr_enable()");
  gmm_data->kern.attach_cap.mobile_class_changed = FALSE;
  {
    PALLOC ( gmmrr_enable_req, GMMRR_ENABLE_REQ );
      TRACE_EVENT ("GRR is on");
      gmm_data->kern.attach_cap.grr_state = GMM_GRR_STATE_ON;
      gmmrr_enable_req->mobile_class = gmm_data->kern.attach_cap.mobile_class;
      gmmrr_enable_req->acc_contr_class = gmm_data->acc_contr_class;
      if (DRX_NOT_USED==gmm_data->drx_parameter.split_pg_cycle_code)
      {
         gmmrr_enable_req->split_pg_cycle = 704/* GMMREG_NO_DRX*/; 
      }
      else if (gmm_data->drx_parameter.split_pg_cycle_code<65)
      {
        gmmrr_enable_req->split_pg_cycle 
          = gmm_data->drx_parameter.split_pg_cycle_code; 
      } 
      else if (gmm_data->drx_parameter.split_pg_cycle_code<=98)
      {
        const USHORT cycle_array[] = 
        {
          71, 72, 74, 75, 77, 79, 80, 83, 86, 88, 90, 92, 96, 101, 103, 107,
          112,116, 118, 128, 141, 144, 150, 160, 171, 176, 192, 214, 224, 235, 
          256, 288, 320, 352 
        };
        
        gmmrr_enable_req->split_pg_cycle
           = cycle_array[gmm_data->drx_parameter.split_pg_cycle_code-65];
      }
      else
      {
        gmmrr_enable_req->split_pg_cycle = 1;
      } 

      if( gmm_data->drx_parameter.split_on_ccch EQ SPLIT_NO )
      {
        gmmrr_enable_req->spgc_ccch_supp = GMMRR_SPGC_CCCH_SUPP_NO;
      }
      else
      {
        gmmrr_enable_req->spgc_ccch_supp = GMMRR_SPGC_CCCH_SUPP_YES;
      }

      gmmrr_enable_req->gmmrr_non_drx_timer = gmm_data->drx_parameter.non_drx_timer;

    PSEND ( hCommGRR, gmmrr_enable_req );
  }
  GMM_RETURN;
} /* kern_gmmrr_ensable () */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_disable
+------------------------------------------------------------------------------
| Description : The function kern_gmmrr_disable switches off GRR
|
| Parameters  : cm_estasblish_res - OK or NOT to establish the CM
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_disable ( void )
{
  GMM_TRACE_FUNCTION ("kern_gmmrr_disable()");
  TRACE_EVENT ("GRR is off");

  /*gmm_data->kern.attach_cap.mobile_class = GMMREG_CLASS_CC;*/
  gmm_data->kern.attach_cap.attach_type &= ~GMMREG_AT_GPRS;

  gmm_data->kern.attach_cap.grr_state = GMM_GRR_STATE_OFF;
  gmm_data->kern.suspension_type &= ~GMM_SUSP_LOCAL_DETACH;

  /* This code is applicable only for Release 99 */
#ifdef REL99
  gmm_data->ptmsi_signature.available = FALSE;
  gmm_data->ptmsi_signature.value     = INVALID_PTMSI_SIGNATURE;
#endif

  kern_llgmm_unassign();


  {
    PALLOC ( gmmrr_disable_req, GMMRR_DISABLE_REQ );
    PSEND ( hCommGRR, gmmrr_disable_req );
  }
  /* kern_mm_activate_mm (); */
  GMM_RETURN;
} /* kern_gmmrr_disable () */
/*
+------------------------------------------------------------------------------
| Function    : kern_mm_cm_establish_res
+------------------------------------------------------------------------------
| Description : The function mm_cm_establish_res is a response whether a CS call
|                is possible or not
|
| Parameters  : cm_estasblish_res - OK or NOT to establish the CM
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_cm_establish_res ( UBYTE cm_establish_res  )
{
  GMM_TRACE_FUNCTION ("kern_mm_cm_establish_res ()");
  {
    PALLOC ( mmgmm_cm_establish_res, MMGMM_CM_ESTABLISH_RES);
      mmgmm_cm_establish_res->cm_establish_res = cm_establish_res;
      gmm_data->kern.suspension_type &= ~GMM_SUSP_CALL;
    PSEND ( hCommMM, mmgmm_cm_establish_res );
  }
  GMM_RETURN;
} /* kern_mm_establish_res () */
/*
+------------------------------------------------------------------------------
| Function    : kern_mm_cm_emergency_res
+------------------------------------------------------------------------------
| Description : The function mm_cm_emrgency_res is a response whether a
|               emergnecy call is possible or not
|
| Parameters  : cm_estasblish_res - OK or NOT to establish the CM
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_cm_emergency_res ( UBYTE cm_establish_res  )
{
  GMM_TRACE_FUNCTION ("kern_mm_cm_emergency_res ()");
  {
    PALLOC ( mmgmm_cm_emergency_res, MMGMM_CM_EMERGENCY_RES);
      mmgmm_cm_emergency_res->cm_establish_res = cm_establish_res;
    PSEND ( hCommMM, mmgmm_cm_emergency_res );
    gmm_data->kern.suspension_type &= ~GMM_SUSP_EM_CALL;
  }
  GMM_RETURN;
} /* kern_mm_emergency_res () */
/*
+------------------------------------------------------------------------------
| Function    : kern_mm_net_req
+------------------------------------------------------------------------------
| Description : The function kern_mm_net_req sends the promitve to MM
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_net_req ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_mm_net_req" );
  {
    PALLOC ( mmgmm_net_req, MMGMM_NET_REQ );
    PSEND ( hCommMM, mmgmm_net_req);
  }
  GMM_RETURN;
} /* kern_mm_net_req() */
/*
+------------------------------------------------------------------------------
| Function    : kern_mm_start_t3212
+------------------------------------------------------------------------------
| Description : This procedure is called: "If the detach type information
|               element value indicates "GPRS detach without switching off ?and
|               the MS is attached for GPRS and non-GPRS services and the 
|               network operates in network operation mode I, then if in the MS
|               the timer T3212 is not already running, the timer T3212 shall be
|               set to its initial value and restarted after the DETACH REQUEST
|               message has been sent."
|
|               <R.GMM.DINITM.M.007>
|    
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_start_t3212 ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_mm_start_t3212" );
  {  
    PALLOC ( mmgmm_start_t3212_req, MMGMM_START_T3212_REQ );
    PSEND ( hCommMM, mmgmm_start_t3212_req);
  }
  GMM_RETURN;
} /* kern_mm_start_t3212() */
/*
+------------------------------------------------------------------------------
| Function    : kern_ssim_authentication_req
+------------------------------------------------------------------------------
| Description : The function kern_sim_authentication_req
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_sim_authentication_req ( UBYTE *random, UBYTE cksn )
{ 
  GMM_TRACE_FUNCTION( "kern_sim_authentication_req" );
  {
    PALLOC (sim_authentication_req, SIM_AUTHENTICATION_REQ);
      sim_authentication_req->source = SRC_GMM;
#ifdef GMM_TCS4
      sim_authentication_req->req_id = gmm_data->kern.auth_cap.last_auth_req_id;
#endif
      memcpy ( 
        sim_authentication_req->rand, random, MAX_RAND);
        sim_authentication_req->cksn = cksn;
    PSEND (hCommSIM, sim_authentication_req);
  }
  GMM_RETURN;
} /* kern_mm_authentication_req() */
/*
+------------------------------------------------------------------------------
| Function    : kern_mm_attach_started
+------------------------------------------------------------------------------
| Description : The function kern_mm_attach_started sends the primitive 
|                mmgmm_attach_started_req to MM
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_attach_started ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_mm_attach_started" );

  SET_STATE ( MM, GMM_MM_REG_INITATED_VIA_GPRS);
  {  
    PALLOC ( mmgmm_attach_started_req, MMGMM_ATTACH_STARTED_REQ );
    PSEND ( hCommMM, mmgmm_attach_started_req);
  }
  GMM_RETURN;
} /* kern_mm_attach_started() */
/*
+------------------------------------------------------------------------------
| Function    : kern_mm_auth_rej
+------------------------------------------------------------------------------
| Description : The function kern_mm_atuth_rej sends the primitive 
|                mmgmm_auth_req to MM
|       
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_auth_rej ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_mm_auth_rej" );  
  {  
    PALLOC ( mmgmm_auth_rej_req, MMGMM_AUTH_REJ_REQ );
    PSEND ( hCommMM, mmgmm_auth_rej_req);  
  }
  GMM_RETURN;
} /* kern_mm_attach_rej() */
/*
+------------------------------------------------------------------------------
| Function    : kern_mm_attach_rej
+------------------------------------------------------------------------------
| Description : The function kern_mm_attach_rej sends the primitive 
|                mmgmm_attach_rej_req to MM.  The primitive is always sent if 
|               responce from MM is expected, .i.e no MMGMM_NREG_CNF
|       
| Parameters  : error_cause - the error cause given by the net or
|               MMGMM_AAC_OVER_5 if attach_attempt_counter is greater or equal 
|               than 5
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_attach_rej ( USHORT error_cause )
{ 
  GMM_TRACE_FUNCTION( "kern_mm_attach_rej" );

    //if (GMM_MM_REG_INITATED_VIA_GPRS==gmm_data->mm_imsi_attached)
    {
      PALLOC ( mmgmm_attach_rej_req, MMGMM_ATTACH_REJ_REQ );
        /*
         * Anite B2 TC 44.2.1.2.8
         */
      SET_STATE ( MM, GMM_MM_DEREG);

      mmgmm_attach_rej_req-> cause = error_cause;  /* TCS 2.1 */
      PSEND ( hCommMM, mmgmm_attach_rej_req);  
    }
    /*
    else
    {
        kern_mm_imsi_detach_ind ( error_cause, MMGMM_DETACH_DONE);
    }
    */
  GMM_RETURN;
} /* kern_mm_attach_rej() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mm_attach_acc
+------------------------------------------------------------------------------
| Description : The function kern_mm_attach_acc  sends the promitve to MM. 
|       
| Parameters  : mobile_identity -  TMSI given by the network
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_attach_acc ( BOOL                v_mobile_identity,  /* TCS 2.1 */
                                 T_mobile_identity * mobile_identity, /* TCS 2.1 */
                                 BOOL                v_eqv_plmn_list, /* TCS 2.1 */
                                 T_eqv_plmn_list   * eqv_plmn_list /* TCS 2.1 */
                               ) /* TCS 2.1 */
{ 
  GMM_TRACE_FUNCTION( "kern_mm_attach_acc" );
  /* 
   * HM: This catches never...
   * Patch HM 07-Aug-01, make GMM2503 pass >>>
   * GMM thinks it performs a combined attach in network mode I, 
   * but the truth is we came from network mode I and are now 
   * performing the non-combined procedures in network mode II.
   */
  if ( GMM_MM_REG_INITATED_VIA_GPRS == GET_STATE(MM)  )
  /* Patch HM 07-Aug-01, make GMM2503 pass <<< */
  {
    PALLOC ( mmgmm_attach_acc_req, MMGMM_ATTACH_ACC_REQ );

    sig_kern_sync_set_mm_state ( MMGMM_FULL_SERVICE );
    
    gmm_data->kern.mm_cell_env.rai.lac = gmm_data->kern.sig_cell_info.env.rai.lac;
    gmm_data->kern.mm_cell_env.rai.plmn = gmm_data->kern.sig_cell_info.env.rai.plmn;
    mmgmm_attach_acc_req->v_tmsi = v_mobile_identity;
    mmgmm_attach_acc_req->lac = gmm_data->kern.mm_cell_env.rai.lac;
    mmgmm_attach_acc_req->plmn.v_plmn = TRUE;
    memcpy(mmgmm_attach_acc_req->plmn.mnc,gmm_data->kern.mm_cell_env.rai.plmn.mnc,SIZE_MNC);  
    memcpy (mmgmm_attach_acc_req->plmn.mcc, gmm_data->kern.mm_cell_env.rai.plmn.mcc,SIZE_MCC);
    mmgmm_attach_acc_req->tmsi = 
      (v_mobile_identity?gmm_data->tmsi:MMGMM_TMSI_INVALID);
    mmgmm_attach_acc_req->v_equ_plmn_list = v_eqv_plmn_list; /* TCS 2.1 */
    if (v_eqv_plmn_list)  /* TCS 2.1 */
      memcpy(&mmgmm_attach_acc_req->equ_plmn_list, eqv_plmn_list, sizeof(T_equ_plmn_list)); /* TCS 2.1 */
    PSEND ( hCommMM, mmgmm_attach_acc_req);
  }
  else
  {
    PALLOC ( mmgmm_allowed_req, MMGMM_ALLOWED_REQ );
    mmgmm_allowed_req->lac = gmm_data->kern.attach_cap.rai_accepted.lac;
    mmgmm_allowed_req->plmn.v_plmn = TRUE;
    memcpy(mmgmm_allowed_req->plmn.mnc,gmm_data->kern.attach_cap.rai_accepted.mnc,SIZE_MNC);  
    memcpy (mmgmm_allowed_req->plmn.mcc, gmm_data->kern.attach_cap.rai_accepted.mcc,SIZE_MCC);
    mmgmm_allowed_req->v_equ_plmn_list = v_eqv_plmn_list; /* TCS 2.1 */
    if (v_eqv_plmn_list) /* TCS 2.1 */
      memcpy(&mmgmm_allowed_req->equ_plmn_list, eqv_plmn_list, sizeof(T_equ_plmn_list));   /* TCS 2.1 */
    PSEND ( hCommMM, mmgmm_allowed_req);
  }
  GMM_RETURN;
} /* kern_mm_attach_acc() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mm_reg_req
+------------------------------------------------------------------------------
| Description : The function kern_mm_reg_req sends the primitive 
|                MMGMM_REG_REQ to MM
|       
| Parameters  : 
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_reg_req (U8 reg_type, U8 bootup_act)
{ 
  GMM_TRACE_FUNCTION( "kern_mm_reg_req" );  
  {  
    PALLOC ( mmgmm_reg_req, MMGMM_REG_REQ ); /* T_MMGMM_REG_REQ */
    mmgmm_reg_req->reg_type     = reg_type;
    mmgmm_reg_req->service_mode = gmm_data->kern.attach_cap.service_mode;
    mmgmm_reg_req->mobile_class = gmm_data->kern.attach_cap.mobile_class;
    mmgmm_reg_req->bootup_act   = bootup_act;
    PSEND ( hCommMM, mmgmm_reg_req );
  }
  GMM_RETURN;
} /* kern_mm_attach_rej() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mm_activate_rr
+------------------------------------------------------------------------------
| Description : The MMGMM_ACTIVATE_REQ is used to initiate GPRS Cell Selection
|                in RR. Cell selection for CS only is triggered implicitly be 
|                activating MM (i.e. the MS is operates as a class CC mobile) by
|                sending the primitive discribed in function kern_mm_activate_mm
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_activate_rr ( void )
{
  GMM_TRACE_FUNCTION ("kern_mm_activate_rr()");

  if (gmm_data->kern.attach_cap.network_selection_mode EQ MODE_AUTO)
  {
    kern_mm_reg_req (REG_CELL_SEARCH_ONLY, NORMAL_REG);
  }
  else
  {
    PALLOC ( mmgmm_plmn_res, MMGMM_PLMN_RES ); /* T_MMGMM_PLMN_RES */
      mmgmm_plmn_res->plmn         = gmm_data->kern.attach_cap.plmn_requested;
      mmgmm_plmn_res->reg_type     = REG_CELL_SEARCH_ONLY;
      mmgmm_plmn_res->mobile_class = gmm_data->kern.attach_cap.mobile_class;
    PSEND ( hCommMM, mmgmm_plmn_res );
  }

  kern_gmmrr_enable();
  GMM_RETURN;
} /* kern_mm_activate_rr () */

/*
+------------------------------------------------------------------------------
| Function    : kern_mm_activate_mm
+------------------------------------------------------------------------------
| Description : The MM_ACTIVATE_MM_REQ is used to request MM to act as
|               an GSM-only mobile. 
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_activate_mm ( void )
{
  GMM_TRACE_FUNCTION ("kern_mm_activate_mm()");
  
  if (GMMREG_CLASS_CG!=gmm_data->kern.attach_cap.mobile_class)
  {
    /*
     * remember lau initiated
     */
     gmm_data->kern.attach_cap.mm_lau_attempted = TRUE;

     if (gmm_data->kern.attach_cap.network_selection_mode EQ MODE_AUTO)
     {
        kern_mm_reg_req (REG_GPRS_INACTIVE, NORMAL_REG);
     }
     else
     {
        PALLOC ( mmgmm_plmn_res, MMGMM_PLMN_RES ); /* T_MMGMM_PLMN_RES */
        mmgmm_plmn_res->plmn         = gmm_data->kern.attach_cap.plmn_requested;
        mmgmm_plmn_res->reg_type     = REG_GPRS_INACTIVE;
        mmgmm_plmn_res->mobile_class = gmm_data->kern.attach_cap.mobile_class;
        PSEND ( hCommMM, mmgmm_plmn_res );
     }
  }
  GMM_RETURN;
} /* kern_mm_activate_rr () */

/*
+------------------------------------------------------------------------------
| Function    : kern_local_detach_open_proc
+------------------------------------------------------------------------------
| Description : The function kern_local_detach_open_proc() calls all open 
|            issues to be done upon receiving GMMRR_SUSPEND_CNF
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_local_detach_open_proc (void )
{
  GMM_TRACE_FUNCTION( "kern_local_detach_open_proc" );

  TRACE_1_INFO ("open %d",gmm_data->kern.detach_cap.local_detach_open_proc);


  switch ( gmm_data->kern.detach_cap.local_detach_open_proc)
  {
    case GMM_LOCAL_DETACH_PROC_RESUME:
      kern_resume_grr_der();
      break;
    case GMM_LOCAL_DETACH_PROC_ENTER_NULL_IMSI:
      SET_STATE (KERN, KERN_GMM_NULL_IMSI);
      EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI);
      /* If GMM entered No Cell Available & after coming back to GSM only N/W, the user does a manual 
       * detach, then it is necessary for GMM to disable GRR & enable GSM only mode through MM */
      kern_gmmrr_disable();
      kern_mm_activate_mm();
      break;
    case GMM_LOCAL_DETACH_PROC_ENTER_NULL_NO_IMSI:
      SET_STATE (KERN, KERN_GMM_NULL_NO_IMSI);
      EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI);

      break;
    case GMM_LOCAL_DETACH_PROC_ENTER_NULL_IMSI_LIMITED_SERVICE_REQ:
      SET_STATE (KERN, KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);
      EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);

      break;
    case GMM_LOCAL_DETACH_PROC_ENTER_REG_NORMAL:
      kern_enter_reg_normal();
      break;
    case GMM_LOCAL_DETACH_PROC_ENTER_DEREG:
      kern_enter_der();
      break;
    case GMM_LOCAL_DETACH_PROC_UNASSIGN:
      kern_llgmm_unassign();
      kern_resume_grr_der();
      break;      
    case GMM_LOCAL_DETACH_PROC_SUSP_LAU:
      gmm_data->kern.suspension_type &= ~GMM_SUSP_LOCAL_DETACH;
      kern_mm_lau();
      break;
    case GMM_LOCAL_DETACH_PROC_RE_ATTACH:
    
      TRACE_0_OUT_PARA("Unassign");
      gmm_data->tlli.old=gmm_data->tlli.current;
      gmm_data->tlli.current_type = INVALID_TLLI;
      gmm_data->tlli.current=GMMRR_TMSI_INVALID;
      gmm_data->kern.attach_cap.llc_state = GMM_LLC_STATE_UNASSIGNED;
      {
        PALLOC (llgmm_assign_req, LLGMM_ASSIGN_REQ);

        gmm_data->tlli.current_type=INVALID_TLLI;
          
        llgmm_assign_req->old_tlli = LLGMM_TLLI_INVALID;
        llgmm_assign_req->new_tlli = LLGMM_TLLI_INVALID;

        memset (llgmm_assign_req->llgmm_kc.key,0, sizeof (llgmm_assign_req->llgmm_kc.key));
         
        kern_reset_cipher ();
        llgmm_assign_req->ciphering_algorithm = LLGMM_CIPHER_NO_ALGORITHM;
          
        PSEND ( hCommLLC, llgmm_assign_req );
      }

      kern_resume_grr_der();

      //kern_attach_reset();
      //kern_attach();

      break;
    case GMM_LOCAL_DETACH_PROC_RAU:
      kern_rau();
      break;
    case GMM_LOCAL_DETACH_PROC_DISABLE:
      if (gmm_data->sim_gprs_invalid)
      {
        SET_STATE ( KERN, KERN_GMM_NULL_NO_IMSI);
        EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI);

      }
      else
      {
        SET_STATE ( KERN, KERN_GMM_NULL_IMSI);
        EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI);

      }
      
      kern_gmmrr_disable();
      kern_mm_activate_mm ();
      break;
    case GMM_LOCAL_DETACH_PROC_COMB_DISABLE:
      SET_STATE ( KERN, KERN_GMM_NULL_NO_IMSI);
      EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI);
      gmm_data->kern.attach_cap.attach_type = GMMREG_AT_NOT_KNOWN;
      kern_gmmrr_disable();
      kern_mm_activate_mm ();
      break;
    case GMM_LOCAL_DETACH_PROC_AUTH_FAILED:
      SET_STATE ( KERN, KERN_GMM_DEREG_NO_IMSI);
      EM_GMM_SET_STATE(KERN_GMM_DEREG_NO_IMSI);
      gmm_data->kern.attach_cap.attach_type = GMMREG_AT_NOT_KNOWN;
      kern_gmmrr_disable();
      kern_mm_imsi_detach_ind ( GMMCS_AUTHENTICATION_REJECTED,  /* TCS 2.1 */
        GET_STATE(MM)==GMM_MM_DEREG?
          MMGMM_DETACH_DONE:
          MMGMM_PERFORM_DETACH,			  
          gmm_data->kern.detach_cap.detach_type  );
      break;
    case GMM_LOCAL_DETACH_PROC_SIM_REMOVED:
      SET_STATE ( KERN, KERN_GMM_DEREG_NO_IMSI);
      EM_GMM_SET_STATE(KERN_GMM_DEREG_NO_IMSI);
      gmm_data->kern.attach_cap.attach_type = GMMREG_AT_NOT_KNOWN;
      kern_gmmrr_disable();
      kern_mm_imsi_detach_ind ( GMMCS_SIM_REMOVED,  /* TCS 2.1 */
        GET_STATE(MM)==GMM_MM_DEREG?
          MMGMM_DETACH_DONE:
          MMGMM_PERFORM_DETACH,
          gmm_data->kern.detach_cap.detach_type);

      break;
    case GMM_LOCAL_DETACH_PROC_POWER_OFF:
      SET_STATE (KERN, KERN_GMM_DEREG_NO_IMSI);
      EM_GMM_SET_STATE(KERN_GMM_DEREG_NO_IMSI);
      vsi_t_stop  ( GMM_handle, kern_TPOWER_OFF);
      kern_gmmrr_disable();
      kern_mm_imsi_detach_ind ( GMMCS_POWER_OFF,  /* TCS 2.1 */
        GET_STATE(MM)==GMM_MM_DEREG?
          MMGMM_DETACH_DONE:
          MMGMM_PERFORM_DETACH,
          gmm_data->kern.detach_cap.detach_type);

      break;
    case GMM_LOCAL_DETACH_PROC_SOFT_OFF:
      
      if (gmm_data->sim_gprs_invalid)
      {
        SET_STATE (KERN, KERN_GMM_DEREG_NO_IMSI);
        EM_GMM_SET_STATE(KERN_GMM_DEREG_NO_IMSI);
      }
      else
      {
          SET_STATE (KERN, KERN_GMM_NULL_IMSI);
          EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI);
      }
      vsi_t_stop  ( GMM_handle, kern_TPOWER_OFF);
      kern_gmmrr_disable();
      kern_mm_imsi_detach_ind ( GMMCS_POWER_OFF,  /* TCS 2.1 */
        GET_STATE(MM)==GMM_MM_DEREG?
          MMGMM_DETACH_DONE:
          MMGMM_PERFORM_DETACH,
          gmm_data->kern.detach_cap.detach_type);

      break;

    case GMM_LOCAL_DETACH_PROC_NOT_CHANGED:
    case GMM_LOCAL_DETACH_PROC_NOTHING:
    default:
      if (GMM_GRR_STATE_SUSPENDED==gmm_data->kern.attach_cap.grr_state)
      {
        kern_resume_grr_der();
      }
      break;
  }
  gmm_data->kern.detach_cap.local_detach_open_proc=GMM_LOCAL_DETACH_PROC_NOTHING;
  GMM_RETURN;
} /* kern_kern_local_detach_open_proc () */

/*
+------------------------------------------------------------------------------
| Function    : kern_local_detach
+------------------------------------------------------------------------------
| Description : The function kern_local_detach() .... 
|
| Parameters  : error_cause - error cause
|
|               gmm_data->kern.detach_cap.detach_type MUST be set !
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_local_detach ( USHORT error_cause, BOOL det_acc_sent, T_LOCAL_DETACH_PROC local_detach_open_proc )
{
  /* 
   * compiler cl470.exe test: replace local variable detach_type with 
   *                          gmm_data...detach_type
   * => you may get an assembler error (because switch condition
   *    modified within case statement ??)
   */
  UBYTE detach_type = gmm_data->kern.detach_cap.detach_type;
  UBYTE kern_gmm_save_state = GET_STATE(KERN);

  GMM_TRACE_FUNCTION( "kern_local_detach" );

  if (GMM_LOCAL_DETACH_PROC_NOT_CHANGED!=local_detach_open_proc)
  {
    gmm_data->kern.detach_cap.local_detach_open_proc=local_detach_open_proc;
  }
  else
  {
    if(GMM_LOCAL_DETACH_PROC_NOTHING EQ gmm_data->kern.detach_cap.local_detach_open_proc)
    {
      TRACE_ERROR ("GMM_LOCAL_DETACH_PROC_NOTHING called");
    }
  }
  
  if ( gmm_data->kern.local_detached)
  /*local_detach_done */
  {
    TRACE_0_INFO ("kern_local_detach() called already");
    gmm_data->kern.local_detached = FALSE;
    kern_local_detach_open_proc();
    GMM_RETURN;
  }
  gmm_data->kern.local_detached = TRUE;
  
  switch (detach_type)
  {
    case GMMREG_DT_IMSI:
      break;
    case GMMREG_DT_POWER_OFF:
      SET_STATE ( KERN, KERN_GMM_DEREG_SUSPENDING );
      EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDING );

      kern_gmmsm_establich_rej();

      if (det_acc_sent)
      {
        gmm_data->kern.suspension_type            |= GMM_SUSP_LOCAL_DETACH;
        sig_kern_rdy_start_timer_req( kern_TPOWER_OFF, TPOWER_OFF_VALUE);
      }
      else
      {
        vsi_t_start ( GMM_handle , kern_TPOWER_OFF, TPOWER_OFF_VALUE);
        kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LOCAL_DETACH);
      }
      break;
    default:
      SET_STATE ( KERN, KERN_GMM_DEREG_SUSPENDING );
      EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDING );
      kern_gmmsm_establich_rej();

      if (det_acc_sent)
      {
        gmm_data->kern.suspension_type            |= GMM_SUSP_LOCAL_DETACH;
        sig_kern_rdy_start_timer_req( kern_TLOCAL_DETACH, TLOCAL_DETACH_VALUE);
      }
      else
      {
        kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LOCAL_DETACH);
      }
      break;
  }  
  /*
   * LABEL UNASSIGN_GMMREG
   */

  vsi_t_stop ( GMM_handle , kern_T3321);

  switch ( detach_type )
  {
    case GMM_DT_RE_ATTACH:
      GMM_RETURN;
    case GMMREG_DT_LIMITED_SERVICE:
    case GMMREG_DT_SIM_REMOVED:
      gmm_data->kern.detach_cap.local_detach_open_proc=
        (GMMCS_AUTHENTICATION_REJECTED== error_cause? /* TCS 2.1 */
                   GMM_LOCAL_DETACH_PROC_AUTH_FAILED:
                   GMM_LOCAL_DETACH_PROC_SIM_REMOVED);
      kern_gmmreg_detach (gmm_data->kern.detach_cap.detach_type, error_cause,
                          GMMREG_SEARCH_NOT_RUNNING, error_cause);

      break;
    case GMMREG_DT_POWER_OFF:
    case GMMREG_DT_SOFT_OFF:
     /* If GPRS is already suspended and power switch off is to be done, 
      * kern_local_detach_open_proc() will not be called as GMM will not receive
      * GMMRR_SUSPEND_CNF from GRR, as GRR is already suspended */
      if (kern_gmm_save_state EQ KERN_GMM_REG_SUSPENDED)
      {
          gmm_data->kern.local_detached = FALSE;
          kern_local_detach_open_proc();
      }
      break;
    case GMMREG_DT_IMSI:
      kern_mm_attach_rej ( error_cause );
      kern_gmmreg_detach (gmm_data->kern.detach_cap.detach_type, error_cause,
                          GMMREG_SEARCH_NOT_RUNNING, error_cause);
      gmm_data->kern.local_detached = FALSE;
      kern_local_detach_open_proc();

      break;
    case GMMREG_DT_COMB:
      kern_mm_attach_rej ( error_cause );
      kern_gmmreg_detach (gmm_data->kern.detach_cap.detach_type, error_cause,
                          GMMREG_SEARCH_NOT_RUNNING, error_cause);
      break;
    case GMMREG_DT_DISABLE_GPRS:
      gmm_data->kern.attach_cap.mobile_class = GMMREG_CLASS_CC;
      gmm_data->kern.attach_cap.attach_type &= ~GMMREG_AT_GPRS;
      /* NO break; */
    case GMMREG_DT_GPRS:
      break;
    default:
      TRACE_ERROR ( "Unexpected detach_type in DETACH LABEL" );
      break;
  }

  GMM_RETURN;   
} /* kern_local_detach() */


/*
+------------------------------------------------------------------------------
| Function    : kern_get_imeisv
+------------------------------------------------------------------------------
| Description : The function kern_get_imeisv
|               copied from MM: void csf_read_imei (T_imsi *imei) 
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_get_imeisv (T_gmobile_identity *imei)
{
  UBYTE buf[CL_IMEI_SIZE];


  GMM_TRACE_FUNCTION( "kern_get_imeisv" );
#ifdef TDSGEN
  imei->identity_digit[0]        = 0x04;
  imei->identity_digit[1]        = 0x04;
  imei->identity_digit[2]        = 0x06;
  imei->identity_digit[3]        = 0x00;
  imei->identity_digit[4]        = 0x01;
  imei->identity_digit[5]        = 0x09;
  imei->identity_digit[6]        = 0x01;
  imei->identity_digit[7]        = 0x09;
  imei->identity_digit[8]        = 0x07;
  imei->identity_digit[9]        = 0x05;
  imei->identity_digit[10]       = 0x00;
  imei->identity_digit[11]       = 0x07;
  imei->identity_digit[12]       = 0x05;
  imei->identity_digit[13]       = 0x09;
  imei->identity_digit[14]       = 0x00;
  imei->identity_digit[15]       = 0x00;/* Software Version Number */

#else /* TDSGEN */
  /*
   * Get IMEISV from IMEI common library
   */
  cl_get_imeisv(CL_IMEI_SIZE, buf, CL_IMEI_GET_SECURE_IMEI);
  imei->identity_digit[0]  = (buf [0] >> 4) & 0x0F; /* TAC 8 byte */
  imei->identity_digit[1]  =  buf [0] & 0x0F;
  imei->identity_digit[2]  = (buf [1] >> 4) & 0x0F;
  imei->identity_digit[3]  =  buf [1] & 0x0F;
  imei->identity_digit[4]  = (buf [2] >> 4) & 0x0F;
  imei->identity_digit[5]  =  buf [2] & 0x0F;
  imei->identity_digit[6]  = (buf [3] >> 4) & 0x0F;
  imei->identity_digit[7]  =  buf [3] & 0x0F;
  imei->identity_digit[8]  = (buf [4] >> 4) & 0x0F; /* SNR 6 byte */
  imei->identity_digit[9]  =  buf [4] & 0x0F;
  imei->identity_digit[10] = (buf [5] >> 4) & 0x0F;
  imei->identity_digit[11] =  buf [5] & 0x0F;
  imei->identity_digit[12] = (buf [6] >> 4) & 0x0F;
  imei->identity_digit[13] =  buf [6] & 0x0F;
  imei->identity_digit[14] = (buf [7] >> 4) & 0x0F; /* SV 2 byte */
  imei->identity_digit[15] =  buf [7] & 0x0F;
  TRACE_EVENT_P8("GMM INFO IMEI: TAC %1x%1x%1x%1x%1x%1x%1x%1x",
                  imei->identity_digit[0], imei->identity_digit[1],
                  imei->identity_digit[2], imei->identity_digit[3],
                  imei->identity_digit[4], imei->identity_digit[5],
                  imei->identity_digit[6], imei->identity_digit[7]);
  TRACE_EVENT_P6("GMM INFO IMEI: SNR %1x%1x%1x%1x%1x%1x",
                  imei->identity_digit[8],  imei->identity_digit[9],
                  imei->identity_digit[10], imei->identity_digit[11],
                  imei->identity_digit[12], imei->identity_digit[13]);
  TRACE_EVENT_P2("GMM INFO IMEI: SV  %1x%1x", imei->identity_digit[14],
                                              imei->identity_digit[15]);

#endif /* not defined TDSGEN */

  imei->v_identity_digit = TRUE;
  imei->c_identity_digit =  16;
  
  imei->type_of_identity = ID_TYPE_IMEISV;
  imei->odd_even   = 0;

  GMM_RETURN;
} /* kern_get_imeisv() */
/*
+------------------------------------------------------------------------------
| Function    : kern_get_imei
+------------------------------------------------------------------------------
| Description : The function kern_get_imei
|               copied from MM: void csf_read_imei (T_imsi *imei) 
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_get_imei (T_gmobile_identity *imei)
{   
  GMM_TRACE_FUNCTION( "kern_get_imei" );
  kern_get_imeisv(imei);

  /*
     * get imeisv returns 16 digits, but imei has only 14 digits
     * thus clear last byte:
     */
    imei->identity_digit[14] =  0;
    imei->identity_digit[15] =  0;
    imei->v_identity_digit   = TRUE;
    imei->c_identity_digit   = 15;


  imei->type_of_identity = ID_TYPE_IMEI;
  imei->odd_even   = 1;
  GMM_RETURN;
} /* kern_get_imei() */
/*
+------------------------------------------------------------------------------
| Function    : kern_read_pcm
+------------------------------------------------------------------------------
| Description : The function kern_read_pcm
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/

GLOBAL void kern_read_pcm ( void )
{
#ifdef _TARGET_    
  T_GMM_FFS ffsBuffer;
  T_FFS_SIZE size = ffs_fread("/GPRS/gmm", &ffsBuffer, sizeof(ffsBuffer));
  TRACE_FUNCTION( "kern_read_pcm" );

  
  if ( size != sizeof(ffsBuffer) )
  {
    if ( size < 0 )
    {
      TRACE_EVENT_P1("FFS can not read \"/GPRS/gmm\" (%d)", size);
    }
    else
    {
      TRACE_EVENT_P2("FFS contains old file of \"/GPRS/gmm\": %dBytes long, but %dBytes expected",
                      size, sizeof(ffsBuffer));
    }
  }
  else
  {
    gmm_data->config.cipher_on = ffsBuffer.cipher_on;
    
    TRACE_1_INFO("GEA2=%d", (gmm_data->config.cipher_on & 0x02)>0);
    TRACE_1_INFO("GEA3=%d", (gmm_data->config.cipher_on & 0x04)>0);
    TRACE_1_INFO("GEA4=%d", (gmm_data->config.cipher_on & 0x08)>0);
    TRACE_1_INFO("GEA5=%d", (gmm_data->config.cipher_on & 0x10)>0);
    TRACE_1_INFO("GEA6=%d", (gmm_data->config.cipher_on & 0x20)>0);
    TRACE_1_INFO("GEA7=%d", (gmm_data->config.cipher_on & 0x40)>0);
    
  }
#endif /* NOT DEFINED _SIMULATION_ */
  return;
}

/*
+------------------------------------------------------------------------------
| Function    : kern_build_ms_network_capability
+------------------------------------------------------------------------------
| Description : The function kern_build_ms_network_capability() .... 
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_build_ms_network_capability (T_ms_network_capability *ms_network_capability)
{
  T_mob_class_2 mob_class_2;
  EXTERN  void rr_csf_get_classmark2 (T_mob_class_2 *mob_class_2);

  GMM_TRACE_FUNCTION ("kern_build_ms_network_capability()");

  rr_csf_get_classmark2 (&mob_class_2);

#ifdef REL99
  // HM 20-Jun-2003 Release 1999 >>>
  // Ensure these IEs are not accidently included in the uplink message
  // until Release 1999 is completely implemented in GMM
  memset (ms_network_capability, 0, sizeof (T_ms_network_capability));
  // HM 20-Jun-2003 Release 1999 <<<
#endif

  if (gmm_data->config.cipher_on)
  {
    ms_network_capability->gea_1                  = GEA_1_YES;
    TRACE_EVENT ("ciphering on requested");
  }
  else
  {
    ms_network_capability->gea_1                  = GEA_1_NO;
    TRACE_EVENT ("ciphering off requested");
  }

  ms_network_capability->ss_screening_indicator = mob_class_2.ss_screen;
  ms_network_capability->sm_capabilities_gsm    = mob_class_2.mt_pp_sms;
  ms_network_capability->sm_capabilities_gprs   = SM_CAP_GPRS_YES;
  ms_network_capability->ucs2_support           = UCS2_YES;
  /* 
   * R99 definitions must be set to 0
   */

    ms_network_capability->solsa_capability       = NO;
#ifdef REL99
    ms_network_capability->rev_level_ind          = REV_LEVEL_IND_99_YES;
    ms_network_capability->pfc_feature_mode       = YES;
#else
	ms_network_capability->rev_level_ind          = REV_LEVEL_IND_99_NO;
    ms_network_capability->pfc_feature_mode       = NO;
#endif
  /* 
   * end of R99 definitions
   */
  ms_network_capability->ext_gea_bits.gea_2     = (gmm_data->config.cipher_on & 0x02)>0;
  ms_network_capability->ext_gea_bits.gea_3     = (gmm_data->config.cipher_on & 0x04)>0;
  ms_network_capability->ext_gea_bits.gea_4     = (gmm_data->config.cipher_on & 0x08)>0;
  ms_network_capability->ext_gea_bits.gea_5     = (gmm_data->config.cipher_on & 0x10)>0;
  ms_network_capability->ext_gea_bits.gea_6     = (gmm_data->config.cipher_on & 0x20)>0;
  ms_network_capability->ext_gea_bits.gea_7     = (gmm_data->config.cipher_on & 0x40)>0;

#ifdef TDSGEN
  ms_network_capability->sm_capabilities_gsm    = SM_CAP_GSM_NO;
  ms_network_capability->ss_screening_indicator = 0;
#endif

  GMM_RETURN;
} /* kern_build_ms_network_capability () */

/*
+------------------------------------------------------------------------------
| Function    : kern_init
+------------------------------------------------------------------------------
| Description : The function kern_init() .... 
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_init ( void )
{ 
  int i;
  TRACE_FUNCTION( "kern_init" );

  /*gmm_data->gprs_enabled = TRUE;*/
  /*
   * Initialise service KERN with state KERN_READY.
   */
  INIT_STATE ( KERN, KERN_GMM_NULL_NO_IMSI );

#ifdef TRACE_FUNC
#ifdef IDENTATION
  gmm_data->deep=0;
#endif
#endif
  gmm_data->anite               = FALSE;
  gmm_data->tlli.current        = LLGMM_TLLI_INVALID;
  gmm_data->tlli.old            = LLGMM_TLLI_INVALID;
  gmm_data->kern.local_detached = FALSE; 
  gmm_data->tlli.current_type   = INVALID_TLLI;
  INIT_STATE ( MM, GMM_MM_DEREG);
  gmm_data->gu                  = GU3_ROAMING_NOT_ALLOWED;
  gmm_data->acc_contr_class     = 0;
  gmm_data->kern.gprs_indicator  = GMM_GPRS_SUPP_NO;
#ifdef GMM_TCS4
  gmm_data->sync.sig_cell_info.rt = RT_GSM; /* TCS 4.0 */
#endif
 
  gmm_data->kern.attach_cap.attach_acc_after_po = FALSE;
  TRACE_EVENT ("GRR is off");
  gmm_data->kern.attach_cap.grr_state = GMM_GRR_STATE_OFF;
  /* 
   * set all kc values to 0xff
   */
  memset (gmm_data->kern.auth_cap.kc, 0x00, MAX_KC);

  gmm_data->kern.auth_cap.ciphering_algorithm = LLGMM_CIPHER_NO_ALGORITHM;
  /*
   * multiple outstanding SIM_AUTHENTICATION_REQ messages reset the counter
   */
  gmm_data->kern.auth_cap.last_auth_req_id = NOT_PRESENT_8BIT;
  gmm_data->config.cipher_on = 0x01;
  gmm_data->cipher = FALSE;
  gmm_data->config.preuse_off = FALSE;
  
  gmm_data->ptmsi.new_grr = GMMRR_TMSI_INVALID;
  gmm_data->ptmsi.current  = GMMRR_TMSI_INVALID;
  gmm_data->ptmsi.old  = GMMRR_TMSI_INVALID;
  gmm_data->tmsi  = GMMRR_TMSI_INVALID;
  gmm_data->config.nmo = 0xff;
  /*
   * set the dafault timer vlaues needed in service kern
   */
  gmm_data->kern.t3310_val      = T3310_VALUE;
  gmm_data->kern.t3311_val      = T3311_VALUE;
  gmm_data->kern.t3321_val      = T3321_VALUE;

  /*
   * T3302 is loaded with the same value which is used to load T3212.
   */ 
  gmm_data->kern.t3302_val      = T3302_VALUE;

  gmm_data->kern.timeout_t3312  = FALSE;

  vsi_t_stop  ( GMM_handle, kern_T3310);
  vsi_t_stop  ( GMM_handle, kern_T3311);
  vsi_t_stop  ( GMM_handle, kern_T3321);
  vsi_t_stop  ( GMM_handle, kern_TPOWER_OFF);
  vsi_t_stop  ( GMM_handle, kern_TLOCAL_DETACH);

  /*
   * which kind of attach will be used is unknown this time
   * nobody requested an attach 
   */
  
  gmm_data->kern.attach_cap.mobile_class    = GMMREG_CLASS_BG;
  gmm_data->kern.attach_cap.mobile_class_changed = FALSE;
  gmm_data->kern.attach_cap.attach_type     = GMMREG_AT_NOT_KNOWN;
  gmm_data->kern.attach_cap.service_mode    = SERVICE_MODE_LIMITED;
  gmm_data->kern.attach_cap.gmmreg          = FALSE;
#ifndef GMM_TCS4
  gmm_data->kern.attach_cap.gmmsm           = FALSE;
#endif 
  gmm_data->kern.detach_cap.network         = FALSE;
  gmm_data->kern.detach_cap.gmmreg          = FALSE;        
  gmm_data->kern.detach_cap.local_detach_open_proc=GMM_LOCAL_DETACH_PROC_NOTHING;
  gmm_data->kern.detach_cap.error_cause     = GMMCS_INT_NOT_PRESENT; /* TCS 2.1 */
  gmm_data->kern.suspension_type            = GMM_SUSP_NONE;
  /*
   * the DRX parameter are hardware dependend 
   * TI is not supporting DRX
   * <R.GMM.AGINIT.M.006>
   */

#ifdef _SIMULATION_
  gmm_data->drx_parameter.split_pg_cycle_code = 92 /* 95 DRX_NOT_USED */;
#ifdef TDSGEN
  gmm_data->drx_parameter.split_pg_cycle_code = 16;
#endif

#else  /* #ifdef _SIMULATION_ */
  gmm_data->drx_parameter.split_pg_cycle_code = 16 /* 95 DRX_NOT_USED */;
#endif /* #ifdef _SIMULATION_ */

  gmm_data->drx_parameter.split_on_ccch       = SPLIT_NO;
  gmm_data->drx_parameter.non_drx_timer       = DRX_2_SEC;


  /*
   * resets the attach and rau attempt counter
   */
  gmm_data->kern.aac = 0;
  gmm_data->kern.attach_cap.rau_initiated = GMM_NO_RAU;
  gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau=FALSE;

  gmm_data->kern.sig_cell_info.env.rai.rac = GMMREG_RA_INVALID;
  gmm_data->kern.sig_cell_info.env.rai.lac = GMMRR_LA_INVALID;
  gmm_data->kern.sig_cell_info.gmm_status = GMMRR_SERVICE_UNKNOWN ; /* Initalize gmm status value */
  
#ifdef _SIMULATION_
  gmm_data->kern.mm_cell_env.rai.rac = GMMREG_RA_INVALID;
  gmm_data->kern.mm_cell_env.rai.lac = GMMRR_LA_INVALID;
  gmm_data->kern.detach_cap.detach_type = VAL_DETACH_TYPE___DEF;
#endif

  /*
   * Cel ID
   */
  gmm_data->kern.cell_id.lac  = (USHORT)GMMREG_LA_INVALID;
  gmm_data->kern.cell_id.rac  = (UBYTE)GMMREG_RA_INVALID;


  INIT_STATE (CU,CU_CELL_RES_SENT);
  gmm_data->kern.attach_cap.llc_state=GMM_LLC_STATE_UNASSIGNED;
  gmm_data->kern.gmmrr_resume_sent = FALSE;
  gmm_data->kern.attach_cap.grr_via_llc_suspended=FALSE;
  gmm_data->kern.attach_cap.mm_lau_attempted=FALSE;
  
  for(i=0; i<MAX_LIST_OF_FORBIDDEN_PLMNS_FOR_GPRS_SERVICE; i++)
  {
    memset(gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[i].mcc, 0xFF, SIZE_MCC);
    memset(gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[i].mnc, 0xFF, SIZE_MNC);
  }
  kern_read_pcm();

#ifdef REL99
  /* Used to indicate to LLC if it should use NULL frame for
   * performing cell updates. Cell notification is disabled by
   * default. This field is changed only if the SGSN indicates
   * that it supports cell notification
   */
   gmm_data->cell_notification = NO_CELL_NOTIFY; /* TCS 4.0 */
  /* Initialise all the pdp context status to invalid untill GMM gets a valid status from SM */
  gmm_data->kern.attach_cap.pdp_context_status = INVALID_PDP_CONTEXT_STATUS; /* TCS 4.0 */
#endif

  return;
} /* kern_init() */


/*
+------------------------------------------------------------------------------
| Function    : kern_attach_reset
+------------------------------------------------------------------------------
| Description : This procedure is called in cell updatingn procedure, if RA 
|               was changed an the ATTACH procedurehas to re-initialized. 
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_attach_reset ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_attach_reset" );
  
  /*
   * resets the counter for TIMER t3310
   */
  gmm_data->kern.ct3310 = 0;

  /* 
   * I reuse timer T3310 also for T3330
   */
  vsi_t_stop  ( GMM_handle, kern_T3310);
  vsi_t_stop  ( GMM_handle, kern_T3311);


  gmm_data->kern.aac = 0;
  gmm_data->kern.detach_cap.network = FALSE;
  GMM_RETURN; 
} /* kern_attach_reset() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mm_detach_started
+------------------------------------------------------------------------------
| Description : The function kern_mm_detach_started indicates MM that the 
|                GSM detach procedure is started by GMM. MM has to enter state
|               MM-IMSI-DETACH-PENDING.
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_detach_started ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_mm_detach_started" );

  switch( gmm_data->kern.detach_cap.detach_type)
  {
    case GMMREG_DT_SIM_REMOVED :
      if (GMM_MM_DEREG == GET_STATE(MM))
      {
        break;
      }
      /* NO break;*/
    case GMMREG_DT_IMSI:
    case GMMREG_DT_COMB:
      if (GMMRR_NET_MODE_I==gmm_data->kern.sig_cell_info.net_mode)
      {
        PALLOC ( mmgmm_detach_started_req, MMGMM_DETACH_STARTED_REQ);
        PSEND ( hCommMM, mmgmm_detach_started_req ); 
      }
      break;
    default:
      break;
  }
  GMM_RETURN;
} /* kern_detach_started() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mm_imsi_detach_ind
+------------------------------------------------------------------------------
| Description : The function kern_mm_imsi_detach()handles the IMSI detach. 
|      
| Parameters  : detach_done -  indicates whether GMM has already done the IMSI
|                detach or not.
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_imsi_detach_ind ( USHORT error_cause, BOOL detach_done, UBYTE detach_type )
{ 
  GMM_TRACE_FUNCTION( "kern_mm_imsi_detach_ind" );
 
  {
    PALLOC ( mmgmm_nreg_req, MMGMM_NREG_REQ); /* T_MMGMM_NREG_REQ */
      mmgmm_nreg_req->cause = error_cause; /* TCS 2.1 */
      mmgmm_nreg_req->detach_done = detach_done;
      SET_STATE ( MM, GMM_MM_DEREG );

      TRACE_1_OUT_PARA("detach_done %d",detach_done);
      
      switch ( detach_type )
      {
        case GMMREG_DT_SIM_REMOVED:
          mmgmm_nreg_req->detach_cause = CS_SIM_REM; /* TCS 2.1 */
          break;
        case GMMREG_DT_POWER_OFF:
          mmgmm_nreg_req->detach_cause = CS_POW_OFF; /* TCS 2.1 */
          break;
        case GMMREG_DT_SOFT_OFF:
          mmgmm_nreg_req->detach_cause = CS_SOFT_OFF; /* TCS 2.1 */
          break;
        default:
          mmgmm_nreg_req->detach_cause = CS_DISABLE; /* TCS 2.1 */
          break;
      }
      gmm_data->kern.suspension_type &= ~GMM_SUSP_IMSI_DETACH;
    PSEND ( hCommMM, mmgmm_nreg_req );   
  }
  GMM_RETURN;                  
} /* kern_imsi_detach_ind () */
/*
+------------------------------------------------------------------------------
| Function    : kern_mm_imsi_detach
+------------------------------------------------------------------------------
| Description : The function kern_mm_imsi_detach()handles the IMSI detach. 
|      
| Parameters  : detach_done -  indicates whether GMM has already done the IMSI
|                detach or not.
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_imsi_detach ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_mm_imsi_detach" );
  kern_mm_imsi_detach_ind (GMMCS_INT_NOT_PRESENT, MMGMM_PERFORM_DETACH,
                           gmm_data->kern.detach_cap.detach_type); /* TCS 2.1 */
  GMM_RETURN;
} /* kern_imsi_detach() */


/*
+------------------------------------------------------------------------------
| Function    : kern_mm_lau
+------------------------------------------------------------------------------
| Description : This procedure start the LAU procedure in entity MM
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mm_lau ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_mm_lau" );

  gmm_data->kern.attach_cap.mm_lau_attempted=TRUE;
  gmm_data->kern.suspension_type &= ~GMM_SUSP_LAU;

  if (gmm_data->kern.attach_cap.network_selection_mode EQ MODE_AUTO)
  {
    kern_mm_reg_req (REG_REMOTE_CONTROLLED, NORMAL_REG);
  }
  else
  {
    PALLOC ( mmgmm_plmn_res, MMGMM_PLMN_RES ); /* T_MMGMM_PLMN_RES */
      mmgmm_plmn_res->plmn         = gmm_data->kern.attach_cap.plmn_requested;
      mmgmm_plmn_res->reg_type = REG_REMOTE_CONTROLLED;
      mmgmm_plmn_res->mobile_class = gmm_data->kern.attach_cap.mobile_class;
    PSEND ( hCommMM, mmgmm_plmn_res );
  }

  GMM_RETURN;
} /* kern_mm_lau() */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_assign
+------------------------------------------------------------------------------
| Description : The function kern_gmmrr_assign() 
|               
|               This procedure assigned the current TLLI parameter to GRR
|               entities 
|
| Parameters  : void
|              
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_assign ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmrr_assign" );
  
  {
    PALLOC ( gmmrr_assign_req, GMMRR_ASSIGN_REQ );
      gmmrr_assign_req->new_tlli  = gmm_get_tlli ( CURRENT_TLLI );
      gmmrr_assign_req->old_tlli  = gmm_get_tlli ( OLD_TLLI );      
      
      if (GMMRR_TLLI_INVALID==gmmrr_assign_req->new_tlli)
      {
        gmmrr_assign_req->old_ptmsi = GMMRR_TMSI_INVALID;
        gmmrr_assign_req->new_ptmsi = GMMRR_TMSI_INVALID;
      }
      else
      {
        gmmrr_assign_req->old_ptmsi = gmm_data->ptmsi.old;
        gmmrr_assign_req->new_ptmsi = gmm_data->ptmsi.new_grr;

      }
    gmmrr_assign_req->imsi  = gmm_data->imsi;
    gmmrr_assign_req->rai.plmn.v_plmn=TRUE;
    memcpy (gmmrr_assign_req->rai.plmn.mcc, gmm_data->kern.attach_cap.rai_accepted.mcc, SIZE_MCC);
    memcpy (gmmrr_assign_req->rai.plmn.mnc, gmm_data->kern.attach_cap.rai_accepted.mnc, SIZE_MNC);
    gmmrr_assign_req->rai.lac = gmm_data->kern.attach_cap.rai_accepted.lac;
    gmmrr_assign_req->rai.rac = gmm_data->kern.attach_cap.rai_accepted.rac;

    TRACE_3_OUT_PARA("PTMSI old: 0x%X new: 0x%X,curent:0x%X ",gmmrr_assign_req->old_ptmsi, 
    gmmrr_assign_req->new_ptmsi, gmm_data->ptmsi.current);
    PSEND ( hCommGRR, gmmrr_assign_req );
  }
  GMM_RETURN;
} /* kern_gmmrr_assign() */

/*
+------------------------------------------------------------------------------
| Function    : kern_local_atach
+------------------------------------------------------------------------------
| Description : The function kern_local_attach() 
|               
|               This procedure assigned the given TLLI parameter to the other
|               entities 
|
| Parameters  : new_tlli_type - type of new TLLI (random, local ,..)
|               old_tlli_type - type of old TLLI
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_local_attach ( T_TLLI_TYPE new_tlli_type, T_TLLI_TYPE old_tlli_type )
{ 
  GMM_TRACE_FUNCTION( "kern_local_attach" );
  
  kern_llgmm_assign_tlli ( new_tlli_type, old_tlli_type );
  kern_gmmrr_assign();
  GMM_RETURN;
} /* kern_local_attach() */

/*
+------------------------------------------------------------------------------
| Function    : kern_ptmsi_negotiated
+------------------------------------------------------------------------------
| Description : This procedure is called if an AIR message is received which 
|               contains an optional PTMSI IE. i.e. in the ATTACH_ACCEPT or 
|               RAU_ACCEPT message. It stores the P-TMSI and the
|               P-TMSI Signature, if available into the SIM and changes the
|               update state to GU1 UPDATED and triggers the cell update
|               procedure by calling LLGMM_TRIGGER_REQ, if needed. Otherwise,
|               if P-TMSI was negotiated CU is triggered outside of this
|               procedure by transmitting CONFIRM message. At the end of this
|               procedure the new genereted TLLI is passed to the other layers
|
| Parameters  : v_mobile_identity  - flag from AIR  if ptmsi is available
|               mobile_identity    - ptmsi from AIR
|               v_ptmsi_signature  - flag from AIR if psignature is available
|               ptmsi_signature   - ptmsi signature from AIR
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_tmsi_negotiated ( BOOL v_tmsi, 
                                   T_mobile_identity *tmsi,
                                   BOOL v_ptmsi, 
                                   T_gmobile_identity *ptmsi,
                                   BOOL v_ptmsi_signature,
                                   T_p_tmsi_signature *p_tmsi_signature
                                 ) 
{
  GMM_TRACE_FUNCTION ("kern_tmsi_negotiated()");

  /*
   * save the available flags
   */
  gmm_data->ptmsi_signature.available = v_ptmsi_signature;
  if ( v_ptmsi )
  {
    if ( !ptmsi->v_tmsi )
    {
      TRACE_ERROR ( "PTMSI IE received from air without ptmsi value, perhaps IMSI reseived" );
      sig_kern_rx_gmm_status(ERRCS_IE_INVALID);
    }
    else
    {
      /*
       * store the given PTMSI
       */
      gmm_data->ptmsi.old     = gmm_data->ptmsi.current,
  
      gmm_data->ptmsi.new_grr 
       = gmm_data->ptmsi.current = kern_get_tmsi ((T_mobile_identity *)ptmsi );

    }
  }
  if ( v_tmsi )
  {
    if ( !tmsi->v_tmsi )
    {
      TRACE_EVENT ( "TMSI IE received from air without ptmsi value, perhaps IMSI reseived" );
      /* 
       * <R.GMM.ACSUBOTH.M.011>
       * If the message contains an IMSI (i.e. the MS is not allocated any TMSI)
       * than the MS shall delete any TMSI.
       */
      gmm_data->tmsi =MMGMM_TMSI_INVALID;

    }
    else
    {
    /*
     * store the given TMSI
     */
      gmm_data->tmsi = kern_get_tmsi ((T_mobile_identity *)tmsi );
    }
  }
  /*
   * After the rocedure the local TLLI have to be used
   *
   * set all TLLIs and saves the current TLLI as old TLLI
   */
  gmm_set_current_tlli ( LOCAL_TLLI ) ;


  if ( v_ptmsi_signature ) 
  {
    /*
     * <R.GMM.AGACCEPT.M.020>, <R.GMM.AGACCEPT.M.021>,
     * <R.GMM.AGACCEPT.M.022>, <R.GMM.RNACCEPT.M.014>
     */
    gmm_data->ptmsi_signature.value 
                           = p_tmsi_signature->p_tmsi_signature_value;
  }
  /*
   * <R.GMM.AGACCEPT.M017>, <R.GMM.AGACCEPT.M019>, 
   * <R.GMM.AGACCEPT.M022>,<R.GMM.AGACCEPT.M023>
   */
  gmm_data->gu                = GU1_UPDATED;

  kern_sim_gmm_update();
  vsi_o_ttrace(VSI_CALLER TC_EVENT,"Info: GU: %i", gmm_data->gu+1);

  
  if ( 
     GMM_PERIODIC_RAU    != gmm_data->kern.attach_cap.rau_initiated
   || ptmsi->v_tmsi
   || tmsi->v_tmsi
  )
  {
    /*
     * in attach and RAU the TLLI as to change from foreign to local tlli
     */
    kern_local_attach ( CURRENT_TLLI, OLD_TLLI );
  }
  else
  {
    /* 
     * AniteB2 44.2.3.1.5
     * RR has to transmit the last assigned RAI with GPRS resumption
     */
    kern_gmmrr_assign();
  }
  GMM_RETURN;

} /* kern_ptmsi_negotiated */

/*
+------------------------------------------------------------------------------
| Function    : kern_sim_del_locigprs
+------------------------------------------------------------------------------
| Description : This procedure resets all location infos on sim
|               
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_sim_del_locigprs ( void ) 
{
  GMM_TRACE_FUNCTION ("kern_sim_del_locigprs()");

  gmm_data->ptmsi.current           = GMMRR_TMSI_INVALID;
  gmm_data->ptmsi.new_grr           = GMMRR_TMSI_INVALID;
  gmm_data->ptmsi.old               = GMMRR_TMSI_INVALID;
  gmm_data->ptmsi_signature.available = FALSE;
  gmm_data->ptmsi_signature.value      = INVALID_PTMSI_SIGNATURE; 

  gmm_data->kern.attach_cap.rai_accepted.lac = 0xfffe;           /* INVALID */
  gmm_data->kern.attach_cap.rai_accepted.rac = 0xff;           /* INVALID */
  memset (gmm_data->kern.auth_cap.kc, 0xFF, MAX_KC);
  gmm_data->kern.auth_cap.cksn       = NO_KEY;
  GMM_RETURN;
} /* kern_sim_del_locigprs */

/*
+------------------------------------------------------------------------------
| Function    : kern_sim_gmm_update
+------------------------------------------------------------------------------
| Description : This procedure sends the primitive SIM_GU_UPDATE_REQ to SIM.
|               The primitive is allocated within this function and the
|               parameters of the primitive are filled in with the actually
|               set global variables of GMM.
|               
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_sim_gmm_update () 
{
  GMM_TRACE_FUNCTION ("kern_sim_gmm_update()");
  {
    PALLOC ( sim_gmm_update_req, SIM_GMM_UPDATE_REQ );
      kern_set_loc_info   (sim_gmm_update_req);
      kern_set_kc_cksn    (sim_gmm_update_req);
      sim_gmm_update_req->att_status 
        = gmm_data->kern.attach_cap.attach_acc_after_po;    
    PSEND ( hCommSIM, sim_gmm_update_req );
  }
  GMM_RETURN;
} /* kern_sim_gmm_update */

/*
+------------------------------------------------------------------------------
| Function    : kern_read_imsi
+------------------------------------------------------------------------------
| Description : This procedure reads the imsi from primitive 
|               sim_gmm_insert_ind
|               
|               copied from mm_regF.c in MM
|               
| Parameters  : sim_gmm_insert_ind - primitiv pointer
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_read_imsi (T_SIM_GMM_INSERT_IND *sim_gmm_insert_ind)
{
  USHORT i;
  UBYTE  digit;
  UBYTE  length;
  ULONG  init_value=25;
#ifdef NEW_FRAME
  T_TIME  time_val;
#else /* NEW_FRAME */
  T_VSI_TVALUE  time_val;
#endif /* NEW_FRAME */

  GMM_TRACE_FUNCTION ("kern_read_imsi ()");

  
  gmm_data->imsi.v_mid    = TRUE;
  gmm_data->imsi.id_type  = TYPE_IMSI;
  gmm_data->imsi.tmsi_dig = 0;


  length = (sim_gmm_insert_ind->imsi_field.c_field-1)*2;
  if (sim_gmm_insert_ind->imsi_field.field[0] & 0x08)
  {
    length++;
  }

  for (i = 0; i < length; i++)
  {
    digit = (i & 1) ?
        sim_gmm_insert_ind->imsi_field.field[(i + 1) / 2] & 0x0f :
       (sim_gmm_insert_ind->imsi_field.field[(i + 1) / 2] & 0xf0) >> 4;
    gmm_data->imsi.id[i] = digit;
    init_value += digit*digit; 
  }
  gmm_data->imsi.id[i] = 0xff;

  vsi_t_time (VSI_CALLER &time_val); 
  srand ((USHORT)(init_value*time_val));
  GMM_RETURN;
} /*kern_read_imsi*/ 
/*
+------------------------------------------------------------------------------
| Function    : kern_get_tmsi
+------------------------------------------------------------------------------
| Description : This procedure translate the timer value given by ACI to
|               an air message struct  
|               
|               
| Parameters  : mobile_identity - PTMSI received from AIR
|
+------------------------------------------------------------------------------
*/

GLOBAL ULONG kern_get_tmsi (T_mobile_identity * mobile_identity )
{ 
  ULONG ptmsi;
  GMM_TRACE_FUNCTION( "kern_get_tmsi" );
  
  ptmsi = (mobile_identity->tmsi.b_tmsi[0] << 24)+
                    (mobile_identity->tmsi.b_tmsi[1] << 16)+
                    (mobile_identity->tmsi.b_tmsi[2] << 8)+
                     mobile_identity->tmsi.b_tmsi[3];
  GMM_RETURN_ (ptmsi);

} /* kern_get_tmsi */

/*
+------------------------------------------------------------------------------
| Function    : kern_get_mobile_identity
+------------------------------------------------------------------------------
| Description : Derives the mobile identiti for the AIR
|
| COPIED FROM : MM    mm_mmf.c : mm_fill_identity
|               
| Parameters  : type_of_identity  - tpe of identity
|                gmobile_identity   - used in the AIR message
|
+------------------------------------------------------------------------------
*/

GLOBAL void kern_get_mobile_identity ( 
  UBYTE type_of_identity,
  T_gmobile_identity* gmobile_identity )
{
  GMM_TRACE_FUNCTION ("kern_get_mobile_identity()");
 
  memset (gmobile_identity, 0, sizeof (T_mobile_identity));

  switch (type_of_identity)
  {
    case ID_TYPE_IMEISV:
      kern_get_imeisv ( gmobile_identity);
      break;
    case ID_TYPE_IMEI:
      kern_get_imei ( gmobile_identity);
      break;
    case ID_TYPE_TMSI:
      kern_ulong2mobile_identity (gmm_data->ptmsi.current, gmobile_identity);
      break;
    default:
      TRACE_ERROR ("undefined type of Identity");
      /*
       * NO break;
       */
    case ID_TYPE_IMSI:
      gmobile_identity->v_tmsi = FALSE;
      gmobile_identity->type_of_identity  = ID_TYPE_IMSI;
      gmobile_identity->v_identity_digit = TRUE;
      gmobile_identity->c_identity_digit 
        = kern_calculate_digits (gmm_data->imsi.id);
      gmobile_identity->odd_even    = gmobile_identity->c_identity_digit & 1;
      memcpy (gmobile_identity->identity_digit, gmm_data->imsi.id, 16);
      break;
  }
  GMM_RETURN;
} /* kern_get_mobile_identity() */
/*
+------------------------------------------------------------------------------
| Function    : kern_read_kc_cksn
+------------------------------------------------------------------------------
| Description : Reads the location information delivered by the SIM card
|               into the registration memory structures.
|
| COPIED FROM : MM    mm_regf.c : reg_read_kc_cksn
|               
| Parameters  : T_loc_info - the the loc_inf field from sim_gmm_inserted_ind
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_read_kc_cksn (T_SIM_GMM_INSERT_IND *sim_gmm_insert_ind)
{
  GMM_TRACE_FUNCTION ("kern_read_kc_cksn ()");
  
  switch (gmm_data->gu)
  {
    case GU2_NOT_UPDATED:
      /*
       * GSM: 04.08, Ch.4.1.3.2 GPRS update status
       * 
       *   GU2: NOT UPDATED
       *     The last GPRS attach or routing area updating attempt failed procedurally,
       *     i.e. no response was received from the network. This includes the cases of
       *     failures or congestion inside the network.
       *     In this case, the SIM may contain the RAI of the routing area (RA) to which
       *     the subscriber was attached, and possibly also a valid P-TMSI,
       *     GPRS GSM ciphering key, GPRS UMTS ciphering key, GPRS UMTS integrity key
       *     and GPRS ciphering key sequence number. For compatibility reasons, all these
       *     fields shall be set to the "deleted" value if the RAI is deleted. However, the
       *     presence of other values shall not be considered an error by the MS. 
       */
      if ( GMMRR_LA_INVALID != gmm_data->kern.attach_cap.rai_accepted.lac) 
      {
        break;
      }
      /* NO break */
    case GU3_ROAMING_NOT_ALLOWED:
    case GU3_PLMN_NOT_ALLOWED:
      /*
       * GSM: 04.08, Ch.4.3.2.4:
       * "When the deletion of the sequence number is described this also means
       * that the associated key shall be considered as invalid."
       * GSM: 04.08, Ch.4.7.7.4:
       * "If the sequence number is deleted,
       *  the associated key shall be considered as invalid."
       */

      gmm_data->kern.auth_cap.cksn = NO_KEY;
      memset (gmm_data->kern.auth_cap.kc, 0xFF, MAX_KC);
      break;
    default:
       gmm_data->kern.auth_cap.cksn = sim_gmm_insert_ind->kc_n.kc[MAX_KC];
      if (NO_KEY == gmm_data->kern.auth_cap.cksn)
      {
        memset (gmm_data->kern.auth_cap.kc, 0xFF, MAX_KC);
      }
      else
      {  
        /*
         * copy parameter from SIM card
         */
        memcpy (gmm_data->kern.auth_cap.kc, sim_gmm_insert_ind->kc_n.kc, MAX_KC);      
      }
      break;
  }
  GMM_RETURN;
}
/*
+------------------------------------------------------------------------------
| Function    : kern_set_kc_cksn
+------------------------------------------------------------------------------
| Description : sets the kc and cksn delivered by the SIM card
|               into the registration memory structures.
|
| COPIED FROM : MM    mm_regf.c : reg_read_kc_cksn
|               
| Parameters  : T_loc_info - the the loc_inf field from sim_gmm_inserted_ind
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_set_kc_cksn (T_SIM_GMM_UPDATE_REQ *sim_gmm_update_req)
{
  GMM_TRACE_FUNCTION ("kern_set_kc_cksn ()");

  sim_gmm_update_req->cksn = gmm_data->kern.auth_cap.cksn;
  memcpy (sim_gmm_update_req->kc, gmm_data->kern.auth_cap.kc, MAX_KC);
  GMM_RETURN;
}

/*
+------------------------------------------------------------------------------
| Function    : kern_read_log_info
+------------------------------------------------------------------------------
| Description : Reads the location information delivered by the SIM card
|               into the registration memory structures.
|
| COPIED FROM : MM    mm_regf.c : reg_read_log_info
|               
| Parameters  : T_loc_info - the the loc_inf field from sim_gmm_inserted_ind
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_read_loc_info (T_SIM_GMM_INSERT_IND *sim_gmm_insert_ind)
{
  GMM_TRACE_FUNCTION ("kern_read_loc_info ()");
  
  gmm_data->tmsi =  (sim_gmm_insert_ind->loc_info.loc[0] << 24) +
                    (sim_gmm_insert_ind->loc_info.loc[1] << 16) +
                    (sim_gmm_insert_ind->loc_info.loc[2] <<  8) +
                      sim_gmm_insert_ind->loc_info.loc[3];

  gmm_data->ptmsi.new_grr =
  gmm_data->ptmsi.current =     (sim_gmm_insert_ind->gprs_loc_info.loc[0] << 24) +
                        (sim_gmm_insert_ind->gprs_loc_info.loc[1] << 16) +
                        (sim_gmm_insert_ind->gprs_loc_info.loc[2] <<  8) +
                         sim_gmm_insert_ind->gprs_loc_info.loc[3];


  gmm_data->ptmsi_signature.value =  
                        (sim_gmm_insert_ind->gprs_loc_info.loc[4] << 16) +
                        (sim_gmm_insert_ind->gprs_loc_info.loc[5] <<  8) +
                         sim_gmm_insert_ind->gprs_loc_info.loc[6];  
  gmm_data->ptmsi_signature.available = TRUE;
   
  gmm_data->kern.attach_cap.rai_accepted.mcc[0] = sim_gmm_insert_ind->gprs_loc_info.loc[7] & 0x0f;
  gmm_data->kern.attach_cap.rai_accepted.mcc[1] = sim_gmm_insert_ind->gprs_loc_info.loc[7] >> 4;
  gmm_data->kern.attach_cap.rai_accepted.mcc[2] = sim_gmm_insert_ind->gprs_loc_info.loc[8] & 0x0f;
  gmm_data->kern.attach_cap.rai_accepted.mnc[2] = sim_gmm_insert_ind->gprs_loc_info.loc[8] >> 4;
  gmm_data->kern.attach_cap.rai_accepted.mnc[0] = sim_gmm_insert_ind->gprs_loc_info.loc[9] & 0x0f;
  gmm_data->kern.attach_cap.rai_accepted.mnc[1] = sim_gmm_insert_ind->gprs_loc_info.loc[9] >> 4;
  gmm_data->kern.attach_cap.rai_accepted.lac    = sim_gmm_insert_ind->gprs_loc_info.loc[10] * 256 +
                         sim_gmm_insert_ind->gprs_loc_info.loc[11];
  gmm_data->kern.attach_cap.rai_accepted.rac    = sim_gmm_insert_ind->gprs_loc_info.loc[12];

  gmm_data->gu        = sim_gmm_insert_ind->gprs_loc_info.loc[13]; 

  if ( GMMRR_LA_INVALID == gmm_data->kern.attach_cap.rai_accepted.lac)
  {
     kern_sim_del_locigprs ();
  } 
  TRACE_9_PARA("TMSI %x, PTMSI %x, lac %x, rac %x, MCC: %x%x%x, MNC: %x%x", 
    gmm_data->tmsi,
    gmm_data->ptmsi.current,          
    gmm_data->kern.attach_cap.rai_accepted.lac,
    gmm_data->kern.attach_cap.rai_accepted.rac,
    gmm_data->kern.attach_cap.rai_accepted.mcc[0],
    gmm_data->kern.attach_cap.rai_accepted.mcc[1],
    gmm_data->kern.attach_cap.rai_accepted.mcc[2],
    gmm_data->kern.attach_cap.rai_accepted.mnc[0],
    gmm_data->kern.attach_cap.rai_accepted.mnc[1]
  );
 
  if (gmm_data->gu > GU3_ROAMING_NOT_ALLOWED)
  {
    gmm_data->gu = GU2_NOT_UPDATED;
  }
  GMM_RETURN;
}

/*
+------------------------------------------------------------------------------
| Function    : kern_set_loc_info
+------------------------------------------------------------------------------
| Description : derives the log_info field for for sim inserted
|
| COPIED FROM : MM    mm_regf.c : reg_set_log_info
|               
| Parameters  : sim_gmm_update_req - the primitive
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_set_loc_info (T_SIM_GMM_UPDATE_REQ *sim_gmm_update_req)
{

  GMM_TRACE_FUNCTION ("kern_set_loc_info ()");
  sim_gmm_update_req->gprs_loc_info.c_loc = MAX_LOCIGPRS;

  sim_gmm_update_req->gprs_loc_info.loc[0]  = (UBYTE)(gmm_data->ptmsi.current >> 24);
  sim_gmm_update_req->gprs_loc_info.loc[1]  = (UBYTE)(gmm_data->ptmsi.current >> 16);
  sim_gmm_update_req->gprs_loc_info.loc[2]  = (UBYTE)(gmm_data->ptmsi.current >> 8);
  sim_gmm_update_req->gprs_loc_info.loc[3]  = (UBYTE)gmm_data->ptmsi.current;
  
  sim_gmm_update_req->gprs_loc_info.loc[4]  = (UBYTE)(gmm_data->ptmsi_signature.value >> 16);
  sim_gmm_update_req->gprs_loc_info.loc[5]  = (UBYTE)(gmm_data->ptmsi_signature.value >> 8);
  sim_gmm_update_req->gprs_loc_info.loc[6]  = (UBYTE)gmm_data->ptmsi_signature.value;
  
  sim_gmm_update_req->gprs_loc_info.loc[7]  = gmm_data->kern.attach_cap.rai_accepted.mcc[1] << 4;
  sim_gmm_update_req->gprs_loc_info.loc[7] += gmm_data->kern.attach_cap.rai_accepted.mcc[0];

  sim_gmm_update_req->gprs_loc_info.loc[8]  = gmm_data->kern.attach_cap.rai_accepted.mnc[2] << 4;
  sim_gmm_update_req->gprs_loc_info.loc[8] += gmm_data->kern.attach_cap.rai_accepted.mcc[2];
  
  sim_gmm_update_req->gprs_loc_info.loc[9]  = gmm_data->kern.attach_cap.rai_accepted.mnc[1] << 4;
  sim_gmm_update_req->gprs_loc_info.loc[9] += gmm_data->kern.attach_cap.rai_accepted.mnc[0];
  sim_gmm_update_req->gprs_loc_info.loc[10]  = gmm_data->kern.attach_cap.rai_accepted.lac >> 8;
  sim_gmm_update_req->gprs_loc_info.loc[11]  = gmm_data->kern.attach_cap.rai_accepted.lac & 0xff;
  sim_gmm_update_req->gprs_loc_info.loc[12]  = gmm_data->kern.attach_cap.rai_accepted.rac;
  
  sim_gmm_update_req->gprs_loc_info.loc[13] = gmm_data->gu;
  GMM_RETURN;
}
/*
+------------------------------------------------------------------------------
| Function    : kern_ulong2mobile_identity
+------------------------------------------------------------------------------
| Description : Derives tm mobile identiti for the AIR
|
| COPIED FROM : MM    mm_mmf.c : mm_fill_identity
|               
| Parameters  : mobile_identity   - used in the AIR message
|
+------------------------------------------------------------------------------
*/

GLOBAL void kern_ulong2mobile_identity ( ULONG ptmsi, T_gmobile_identity* gmobile_identity )
{
  GMM_TRACE_FUNCTION ("kern_ulong2mobile_identity()");
 
  memset (gmobile_identity, 0, sizeof (T_mobile_identity));

  
  
  if ( GMMRR_TMSI_INVALID == gmm_data->ptmsi.current )
  {
    /*
     * IMSI
     * <R.GMM.AGINIT.M.005>
     */
    gmobile_identity->v_tmsi      = FALSE;

    kern_get_mobile_identity ( ID_TYPE_IMSI, gmobile_identity );
  }  
  else /* !ptmsi.available */
  { 
    /* 
     * PTMSI
     * <R.GMM.AGINIT.M.002>
     */
    gmobile_identity->odd_even    = EVEN;
    gmobile_identity->v_tmsi      = TRUE;
    gmobile_identity->type_of_identity = ID_TYPE_TMSI;
    gmobile_identity->v_identity_digit = FALSE;
    gmobile_identity->tmsi.l_tmsi = 32;
  
  
    ccd_codeByte (gmobile_identity->tmsi.b_tmsi,  0, 8, (UBYTE)(ptmsi >> 24));
    ccd_codeByte (gmobile_identity->tmsi.b_tmsi,  8, 8, (UBYTE)(ptmsi >> 16));
    ccd_codeByte (gmobile_identity->tmsi.b_tmsi, 16, 8, (UBYTE)(ptmsi >> 8));
    ccd_codeByte (gmobile_identity->tmsi.b_tmsi, 24, 8, (UBYTE) ptmsi);
  }
  GMM_RETURN; 
  
} /* kern_ulong2mobile_identity() */
/*
+------------------------------------------------------------------------------
| Function    : kern_kern_cell_changed
+------------------------------------------------------------------------------
| Description : Returns TRUE if cell was changed.
|               
| Parameters  : void
|
+------------------------------------------------------------------------------
*/

GLOBAL BOOL kern_cell_changed ( void )
{
  GMM_TRACE_FUNCTION ("kern_cell_changed()");

  if ( gmm_data->kern.sig_cell_info.env.cid != gmm_data->kern.old_sig_cell_info.env.cid)
  {
    TRACE_EVENT("Info: cid changed");
    GMM_RETURN_ (TRUE);
  }
  else 
  {
    GMM_RETURN_ (kern_ra_crossed());
  }
} /* kern_lai_changed() */

/*
+------------------------------------------------------------------------------
| Function    : kern_kern_lai_changed
+------------------------------------------------------------------------------
| Description : Returns TRUE if LA was changed.
|               
| Parameters  : void
|
+------------------------------------------------------------------------------
*/

GLOBAL BOOL kern_lai_changed ( void )
{
  GMM_TRACE_FUNCTION ("kern_lai_changed()");

  if ( gmm_data->kern.attach_cap.rai_accepted.lac != gmm_data->kern.sig_cell_info.env.rai.lac)
  {
    TRACE_3_INFO ("Info: LAI changed: changed lac: %x (%x) -> %x",            
    gmm_data->kern.attach_cap.rai_accepted.lac,
    gmm_data->kern.old_sig_cell_info.env.rai.lac,
    gmm_data->kern.sig_cell_info.env.rai.lac);
    GMM_RETURN_ (TRUE);
  }
  else 
  {
    if (kern_plmn_changed()) 
    {
      GMM_RETURN_ (TRUE);
    }
  }

  GMM_RETURN_ (FALSE);
} /* kern_lai_changed() */

/*
+------------------------------------------------------------------------------
| Function    : kern_kern_lau_needed
+------------------------------------------------------------------------------
| Description : Returns TRUE if LAU is needed
|               
| Parameters  : void
|
+------------------------------------------------------------------------------
*/

GLOBAL BOOL kern_lau_needed ( void )
{
  UBYTE mm_state;

  GMM_TRACE_FUNCTION ("kern_lau_needed()");

  mm_state = GET_STATE(MM);

  TRACE_1_PARA ("sig_cell_info.mm_status %d", gmm_data->kern.sig_cell_info.mm_status);

  switch (gmm_data->kern.attach_cap.attach_type)
  {
    case GMMREG_AT_IMSI:
    case GMMREG_AT_COMB:                    
      GMM_RETURN_ (
        (   GMM_MM_DEREG              == mm_state
          || GMM_MM_REG_UPDATE_NEEDED == mm_state
          || MMGMM_WAIT_FOR_UPDATE    == gmm_data->kern.sig_cell_info.mm_status
             
          ||  gmm_data->kern.sig_cell_info.env.rai.lac != gmm_data->kern.mm_cell_env.rai.lac
          || (memcmp (gmm_data->kern.sig_cell_info.env.rai.plmn.mnc, 
                      gmm_data->kern.mm_cell_env.rai.plmn.mnc, SIZE_MNC) != 0)
          || (memcmp (gmm_data->kern.sig_cell_info.env.rai.plmn.mcc, 
                      gmm_data->kern.mm_cell_env.rai.plmn.mcc, SIZE_MCC) != 0)
        )
        
        &&  ( MMGMM_LIMITED_SERVICE != gmm_data->kern.sig_cell_info.mm_status)
      );
      /* break; */
    default:
      GMM_RETURN_ (FALSE);
      /* break; */
  }
} /* kern_lau_needed() */


/*
+------------------------------------------------------------------------------
| Function    : kern_ra_crossed
+------------------------------------------------------------------------------
| Description : Returns TRUE if RA was crossed.
|               
| Parameters  : void
|
+------------------------------------------------------------------------------
*/

GLOBAL BOOL kern_ra_crossed ( void )
{
  GMM_TRACE_FUNCTION ("kern_ra_crossed?");
  
  if (gmm_data->kern.sig_cell_info.env.rai.rac != gmm_data->kern.old_sig_cell_info.env.rai.rac
    || gmm_data->kern.sig_cell_info.env.rai.lac != gmm_data->kern.old_sig_cell_info.env.rai.lac )
  {
    TRACE_EVENT("Info: RA crossed");
    GMM_RETURN_ (TRUE);
  }
  GMM_RETURN_(FALSE);
} /* kern_rai_changed() */

/*
+------------------------------------------------------------------------------
| Function    : kern_rai_changed
+------------------------------------------------------------------------------
| Description : Returns TRUE if RA was changed.
|               
| Parameters  : void
|
+------------------------------------------------------------------------------
*/

GLOBAL BOOL kern_rai_changed ( void )
{
  GMM_TRACE_FUNCTION ("kern_rai_changed()");
  
  if ( gmm_data->kern.sig_cell_info.env.rai.rac != gmm_data->kern.attach_cap.rai_accepted.rac )
  {
    TRACE_0_INFO("RAI changed");
    GMM_RETURN_ (TRUE);
  }
  GMM_RETURN_ (kern_lai_changed());
} /* kern_rai_changed() */

/*
+------------------------------------------------------------------------------
| Function    : kern_plmn_changed
+------------------------------------------------------------------------------
| Description : Returns TRUE if PLMN was changed.
|               
| Parameters  : void
|
+------------------------------------------------------------------------------
*/

GLOBAL BOOL kern_plmn_changed ( void )
{
  GMM_TRACE_FUNCTION ("kern_plmn_changed()");

  if ( (memcmp (gmm_data->kern.sig_cell_info.env.rai.plmn.mnc, gmm_data->kern.attach_cap.rai_accepted.mnc, SIZE_MNC) != 0)
    || (memcmp (gmm_data->kern.sig_cell_info.env.rai.plmn.mcc, gmm_data->kern.attach_cap.rai_accepted.mcc, SIZE_MCC) != 0)
    )
  {
    TRACE_0_INFO ("PLMN changed");
    GMM_RETURN_ (TRUE);
  }
  else
  {
    GMM_RETURN_ (FALSE);
  } 
} /* kern_plmn_changed() */
/*
+------------------------------------------------------------------------------
| Function    : kern_set_rai
+------------------------------------------------------------------------------
| Description : This Procedure sets the old rai and the new rai.
|               
| Parameters  : rai 
|
+------------------------------------------------------------------------------
*/

GLOBAL void kern_set_rai ( T_routing_area_identification * rai)
{
  GMM_TRACE_FUNCTION ("kern_set_rai()");

  /*
   * gmm_data->kern.attach_cap.rai_accepted has to be always the last valid assigned RAI
   * gmm_data->rai includes the last updated lac and or rac depending
   * on the net mode and the oroiginator:
   * net modeII: lac may only chaged by MM so that we know
   * whether we have to update LA or not either upon cell_ind(lac) or
   * activate_ind(lac) dependinig on what receives first. . 
   * That means gmm_data->rai MUST NOT sent to the  network it
   * can be wrong, i.e. new LAC but old RAC! Use always gmm_data->kern.attach_cap.rai_accepted
   * for transmission o the AIR.
   */
  gmm_data->kern.attach_cap.rai_accepted = *rai;

  if (GMMRR_NET_MODE_I==gmm_data->kern.sig_cell_info.net_mode)
  {
    memcpy (gmm_data->kern.mm_cell_env.rai.plmn.mcc, rai->mcc, SIZE_MCC);
    memcpy (gmm_data->kern.mm_cell_env.rai.plmn.mnc, rai->mnc, SIZE_MNC);

    gmm_data->kern.mm_cell_env.rai.lac     = rai->lac;
    gmm_data->kern.mm_cell_env.rai.rac     = rai->rac;
    gmm_data->kern.mm_cell_env.cid         = gmm_data->kern.sig_cell_info.env.cid;
  }
  GMM_RETURN;
} /* kern_set_rai() */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_suspend
+------------------------------------------------------------------------------
| Description : The function kern_gmmrr_suspend()
|       
|               This procedure suspends GRR
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_suspend ( UBYTE susp_gprs, UBYTE gmmrr_susp_cause, UBYTE susp_type)
{ 
  GMM_TRACE_FUNCTION( "kern_gmmrr_suspend" );

  gmm_data->kern.suspension_type            |= susp_type;
  TRACE_1_OUT_PARA ("susp_type: %x", gmm_data->kern.suspension_type);

  if (GMM_GRR_STATE_CR==gmm_data->kern.attach_cap.grr_state)
  {
    TRACE_0_INFO("suspension delayed untill cell_ind is received");
  }
  else
  {
    PALLOC ( gmmrr_suspend_req, GMMRR_SUSPEND_REQ);
      gmmrr_suspend_req->susp_gprs = susp_gprs;
      gmmrr_suspend_req->gmmrr_susp_cause= gmmrr_susp_cause;
      /* START PATCH UBUOB ISSUE 8379 */
      gmm_data->kern.gmmrr_resume_sent = FALSE;
      gmm_data->kern.attach_cap.grr_state = GMM_GRR_STATE_SUSPENDING;
      /* END PATCH UBUOB ISSUE 8379 */
    PSEND ( hCommGRR, gmmrr_suspend_req );
  }

  GMM_RETURN;
} /* kern_gmmrr_suspend() */
/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_stop_waiting_for_transmission
+------------------------------------------------------------------------------
| Description : The function kern_gmmrr_stop_waiting_for_transmission()
|       
|            Is sent after gmmrr_cell_ind if no RAU is needed.
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_stop_waiting_for_transmission (void)
{ 
  GMM_TRACE_FUNCTION( "kern_gmmrr_stop_waiting_for_transmission" );
  switch(GET_STATE(CU))
  {
    case CU_NOT_REQUESTED:
      {
        PALLOC (gmmrr_cell_res, GMMRR_CELL_RES);
          gmmrr_cell_res->cu_cause=GMMRR_RA_DEFAULT;
          SET_STATE (CU, CU_CELL_RES_SENT);
        PSEND (hCommGRR, gmmrr_cell_res);
      }
      break;
    case CU_REQUESTED:
      {
        PALLOC (gmmrr_cell_res, GMMRR_CELL_RES);
          gmmrr_cell_res->cu_cause=GMMRR_RA_CU;
        PSEND (hCommGRR, gmmrr_cell_res);
      }
      /* NO break; */
    case CU_REQUESTED_CELL_RES_SENT:
      SET_STATE (CU, CU_CELL_RES_SENT);
      kern_send_llgmm_trigger_req();
      break;
    default:
    case CU_CELL_RES_SENT:
      break;
  }
  GMM_RETURN;
} /* kern_gmmrr_suspend() */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_attach_started
+------------------------------------------------------------------------------
| Description : The function kern_attach_started()
|       |
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
          /*
           * GMMRR_ATTACH_STARTED_REQ is used to inform GRR that routing area upodate or 
           * attach procedure is started. This time span is closed with 
           * GMMRR_ATTACH_FINISHED_REQ
           * GSM 04.60, ch. 5.5.1.5 Discontinuous reception (DRX):
           * "When initiating the MM procedures for GPRS attach and routeing area update 
           * defined in 3GPP TS 04.08, the mobile station shall enter the MM non- DRX mode 
           * period. This period ends when either of  the messages GPRS ATTACH ACCEPT, 
           * GPRS ATTACH REJECT, ROUTING AREA UPDATE ACCEPT or ROUTING AREA UPDATE REJECT 
           * is received by the mobile station. This period also ends after timeout 
           * waiting for any of these messages."
           */

GLOBAL void kern_gmmrr_attach_started (void)
{ 
  GMM_TRACE_FUNCTION( "kern_gmmrr_attach_started" );
  {
    PALLOC (gmmrr_attach_started_req, GMMRR_ATTACH_STARTED_REQ);
    gmm_data->kern.attach_cap.gmmrr_attach_finished_sent=FALSE;
    PSEND (hCommGRR, gmmrr_attach_started_req);
  }
  GMM_RETURN;
} /* kern_gmmrr_attach_finished() */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_attach_finished
+------------------------------------------------------------------------------
| Description : The function kern_attach_finished()
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_attach_finished (void)
{ 
  GMM_TRACE_FUNCTION( "kern_gmmrr_attach_finished" );
  if(!gmm_data->kern.attach_cap.gmmrr_attach_finished_sent )
  {
    PALLOC (gmmrr_attach_finished_req, GMMRR_ATTACH_FINISHED_REQ);
    gmm_data->kern.attach_cap.gmmrr_attach_finished_sent=TRUE;
    PSEND (hCommGRR, gmmrr_attach_finished_req);
  }
  GMM_RETURN;
} /* kern_gmmrr_attach_finished() */

/*
+------------------------------------------------------------------------------
| Function    : kern_is_cell_forbidden
+------------------------------------------------------------------------------
| Description : The function kern_is_cell_forbidden checks whether cell is 
|            forbidden for GPRS or not
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL BOOL kern_is_cell_forbidden (void)
{ 
  BOOL forbidden = (GMMRR_SERVICE_LIMITED== gmm_data->kern.sig_cell_info.gmm_status);
  
  int i;
  GMM_TRACE_FUNCTION( "kern_is_cell_forbidden" );

  if (MMGMM_LIMITED_SERVICE == gmm_data->kern.sig_cell_info.mm_status)
  {
    TRACE_0_INFO ("mm is in limited");
    GMM_RETURN_ (TRUE);
  }



  if(MODE_AUTO EQ gmm_data->kern.attach_cap.network_selection_mode
    /* START PATCH UBUOB ISSUE 8781 */
    || !gmm_data->kern.attach_cap.gmmreg)
    /* END PATCH UBUOB ISSUE 8781 */
  {
    for(i=0;!forbidden && (i<MAX_LIST_OF_FORBIDDEN_PLMNS_FOR_GPRS_SERVICE); i++)
    {
      forbidden =
       forbidden
       ||
       (
             (memcmp 
             (gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[i].mcc,
                        gmm_data->kern.sig_cell_info.env.rai.plmn.mcc, SIZE_MCC) 
                        == 0
               )
             &&
              (memcmp 
              (gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[i].mnc,
                        gmm_data->kern.sig_cell_info.env.rai.plmn.mnc, SIZE_MNC) 
                        == 0
               )
        );
    }
  }
  TRACE_1_INFO ("cell %s",forbidden?"forbidden":"allowed");
  
  GMM_RETURN_(forbidden);         
      

} /* kern_gmmrr_attach_finished() */

/*
+------------------------------------------------------------------------------
| Function    : kern_remove_plmn_from_forbidden_list
+------------------------------------------------------------------------------
| Description : The function kern_remove_plmn_from_forbidden_list
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_remove_plmn_from_forbidden_list (T_plmn plmn)
{ 
  int i;
  GMM_TRACE_FUNCTION( "kern_remove_plmn_from_forbidden_list" );
  
  for(i=0; i<MAX_LIST_OF_FORBIDDEN_PLMNS_FOR_GPRS_SERVICE; i++)
  {
    BOOL forbidden =
     ((memcmp 
     (gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[i].mcc,
                plmn.mcc, SIZE_MCC) 
                == 0
       )
     &&
      (memcmp 
      (gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[i].mnc,
                plmn.mnc, SIZE_MNC) 
                == 0
       )
      );
    if (forbidden)
    {
      memset(gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[i].mcc, 0xFF, SIZE_MCC);
      memset(gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[i].mnc, 0xFF, SIZE_MNC);
    }
  }
    
  GMM_RETURN;         
      

} /* kern_gmmrr_attach_finished() */

/*
+------------------------------------------------------------------------------
| Function    : kern_send_gmmreg_cell_ind
+------------------------------------------------------------------------------
| Description : The function kern_send_gmmreg_cell_ind informs MMI 
|            that cell has changed or that we GSM is in full service again
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_send_gmmreg_cell_ind (void)
{ 
  BOOL attach_cnf_to_be_sent;
  GMM_TRACE_FUNCTION( "kern_send_gmmreg_cell_ind" );

  attach_cnf_to_be_sent = (MMGMM_FULL_SERVICE == gmm_data->kern.sig_cell_info.mm_status
      && (
          (
            (
              kern_cell_changed() 
              || gmm_data->kern.attach_cap.gmmreg
            )
            && 
            (
              GMMRR_SERVICE_NONE != gmm_data->kern.sig_cell_info.gmm_status
              || GMMRR_SERVICE_NONE == gmm_data->kern.old_sig_cell_info.gmm_status
            )
          )
                                            /* OLD !!! */
          || MMGMM_FULL_SERVICE != gmm_data->kern.old_sig_cell_info.mm_status
        )
      );
  
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_NULL_NO_IMSI:
    case KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ:
    case KERN_GMM_NULL_IMSI:
    case KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ:
    case KERN_GMM_NULL_PLMN_SEARCH:

    case KERN_GMM_DEREG_NO_IMSI:
    case KERN_GMM_DEREG_PLMN_SEARCH:    
    case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
    case KERN_GMM_DEREG_LIMITED_SERVICE:
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_DEREG_SUSPENDING:
    case KERN_GMM_DEREG_SUSPENDED:

      if (attach_cnf_to_be_sent)
      {
        if ( GMMRR_NET_MODE_III==gmm_data->kern.sig_cell_info.net_mode
        && GMMREG_CLASS_BC==  gmm_data->kern.attach_cap.mobile_class
        && !kern_lau_needed())
        {
          kern_gmmreg_attach_cnf_sr(GMMREG_AT_IMSI, 
                                SEARCH_NOT_RUNNING);
        }
        else
        {          
          switch (gmm_data->kern.sig_cell_info.gmm_status)
          {
            case GMMRR_SERVICE_LIMITED:
            case GMMRR_SERVICE_NONE:
              kern_gmmreg_attach_cnf_sr(GMMREG_AT_IMSI, 
                    SEARCH_NOT_RUNNING);
              break;
            default:
            case GMMRR_SERVICE_FULL:
              kern_gmmreg_attach_cnf_sr(GMMREG_AT_IMSI, 
                     (UBYTE)(gmm_data->sim_gprs_invalid?
                    SEARCH_NOT_RUNNING:SEARCH_RUNNING));
              break;
          }
        }
      }
      break;

    case KERN_GMM_DEREG_INITIATED:
      break;
    case KERN_GMM_REG_INITIATED:
      if (attach_cnf_to_be_sent)
      {
        kern_gmmreg_attach_cnf_sr(GMMREG_AT_IMSI,SEARCH_RUNNING);
      }
      break;
    default:
      TRACE_ERROR ("Unexpexcted state");
      /* NO break */
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:
    case KERN_GMM_REG_NO_CELL_AVAILABLE:
    case KERN_GMM_REG_LIMITED_SERVICE:
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
    case KERN_GMM_REG_RESUMING:
    case KERN_GMM_REG_SUSPENDED:
    case KERN_GMM_REG_SUSPENDING:
    case KERN_GMM_REG_IMSI_DETACH_INITIATED:
    
    case KERN_GMM_REG_TEST_MODE_NO_IMSI:
    case KERN_GMM_REG_TEST_MODE:
    case KERN_GMM_RAU_INITIATED:
    case KERN_GMM_RAU_WAIT_FOR_NPDU_LIST:

      if (attach_cnf_to_be_sent)
      {
        kern_gmmreg_attach_cnf(GMMREG_AT_COMB);
      }
      break;
    case KERN_GMM_REG_NORMAL_SERVICE:
      if (attach_cnf_to_be_sent)
      {
        kern_gmmreg_attach_cnf(GMMREG_AT_COMB);

#ifdef REL99
        if (gmm_data->kern.sig_cell_info.sgsnr_flag!= gmm_data->kern.old_sig_cell_info.sgsnr_flag) 
        {
          PALLOC (mmpm_attach_ind, MMPM_ATTACH_IND);
          PSEND ( hCommSM, mmpm_attach_ind );
        }
#endif  

      break;
      }
  }
  GMM_RETURN;
} /* kern_gmmreg_cell_ind */
/*
+------------------------------------------------------------------------------
| Function    : kern_send_llgmm_trigger_req
+------------------------------------------------------------------------------
| Description : Sends trigger request with the correct cause value
|
| Parameters  : None
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_send_llgmm_trigger_req(void)
{
   
  GMM_TRACE_FUNCTION ("kern_send_llgmm_trigger_req()");
  {   
    PALLOC (llgmm_trigger_req, LLGMM_TRIGGER_REQ);

#ifdef REL99
    /* 
     * If SGSN supports cell notification indicate that LLC
     * can use NULL frame for performing cell updates.
     * The first cell notification shouldn't use LLC NULL 
     * frame. The following logic takes care of it. 
     */
     switch (gmm_data->cell_notification) /* TCS 4.0 */
      { /* TCS 4.0 */
        case FIRST_CELL_NOTIFY: /* TCS 4.0 */
          /*
           * Next cell update can use LLC NULL frame
           */
          gmm_data->cell_notification = NOT_FIRST_CELL_NOTIFY; /* TCS 4.0 */
           /*
            * This cell update should not use LLC NULL frame
            */
           llgmm_trigger_req->trigger_cause = LLGMM_TRICS_CELL_UPDATE;
          break; /* TCS 4.0 */
        case NOT_FIRST_CELL_NOTIFY:  /* TCS 4.0 */
          /* 
           * Cell notification supported and this is not the first cell update.
           * So LLC NULL frame can be used
           */
          llgmm_trigger_req->trigger_cause = LLGMM_TRICS_CELL_UPDATE_NULL_FRAME;      /* TCS 4.0 */
          break; /* TCS 4.0 */
        default: /* TCS 4.0 */
          /*
           * cell notification not supported by SGSN 
           */
         llgmm_trigger_req->trigger_cause = LLGMM_TRICS_CELL_UPDATE; /* TCS 4.0 */
     } /* TCS 4.0 */
#else
         llgmm_trigger_req->trigger_cause = LLGMM_TRICS_CELL_UPDATE; /* TCS 4.0 */
#endif

     PSEND ( hCommLLC, llgmm_trigger_req );
  }
  GMM_RETURN;
} /* kern_send_llgmm_trigger_req */
/*
+------------------------------------------------------------------------------
| Function    : kern_attach_rau_init
+------------------------------------------------------------------------------
| Description : The function kern_attach_rau_init initilize RAU and attach procedure
|       
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_attach_rau_init (void)
{ 
  GMM_TRACE_FUNCTION( "kern_attach_rau_init" );
  /*
   * PATCH UBUOB 22.7.07: multiple outstanding SIM_AUTHENTICATION_REQ messages
   * for safety reset the counter whenever a new attachment is started
   */

  gmm_data->kern.auth_cap.last_auth_req_id = NOT_PRESENT_8BIT;


  /* START PATCH UBUOB ISSUE 8284 */
  gmm_data->kern.detach_cap.error_cause = GMMCS_INT_NOT_PRESENT; /* TCS 2.1 */
  /* END PATCH UBUOB ISSUE 8284 */

  gmm_data->kern.attach_cap.t3310_value=0;
  vsi_t_stop ( GMM_handle , kern_T3310);

  /* #5899 */
  /*
   * PATCH UBUOB 25.3.02: Stop timer T3302 when you are trying to ATTACH again
   * otherwise it may timeout in the middle of the procedure. Also this ATTACH
   * procedure may be successful and then T3302 also needs to be stopped.
   */
  vsi_t_stop ( GMM_handle , kern_T3302);
  /* end patch */

  /* 
   * PATCH UBUOB 25.10.02: there are cases where T3311 also needs to be stopped:
   * GMM receives CGRLC_STATUS_IND(access not allowed due to cell change), starts T3311 (TCS 2.1)
   * GMMRR_CELL_IND(cell changed), RAU restarted, but forgot to stop T3311
   * trace 25a_night_cell_change_no_patch
   */
  vsi_t_stop ( GMM_handle , kern_T3311);
  /* end patch ubuob 25.10.02 */
  sig_kern_rdy_stop_t3302_req();

  /* 
   * patch ubuob 23.10.02: flag needs to be cleared when initiating RAU or ATTACH
   * and not at end
   */
  SET_STATE (GU,GU_UPDATE_NOT_NEEDED);
  /* end patch ubuob */

  GMM_RETURN;         
      

} /* kern_attach_rau_init */

/*
+------------------------------------------------------------------------------
| Function    : kern_make_cause
+------------------------------------------------------------------------------
| Description : The function kern_make_cause()
|       
|            An internal 16 bit cause is generated from the cause received
|            from the network. The reject causes indicating a retry in a new
|            cell are translated to a single value. In case no cause was sent 
|            by the network a special internal value is returned to handle this.
|
| Parameters  : valid flag, network cause value
|
+------------------------------------------------------------------------------
*/
GLOBAL USHORT kern_make_cause (BOOL cause_valid, UBYTE network_cause)
{
  GMM_TRACE_FUNCTION ("kern_make_cause");
  
  if (cause_valid)
  {
    if (network_cause >= 0x30 AND /* TCS 2.1 */
        network_cause <= 0x3F) /* TCS 2.1 */
    { /* TCS 2.1 */
      GMM_RETURN_ (GMMCS_RETRY_IN_NEW_CELL); /* TCS 2.1 */
    } /* TCS 2.1 */
    else /* TCS 2.1 */
    { /* TCS 2.1 */
      GMM_RETURN_ (CAUSE_MAKE (DEFBY_STD, /* TCS 2.1 */
                         ORIGSIDE_NET, /* TCS 2.1 */
                         GMM_ORIGINATING_ENTITY, /* TCS 2.1 */
                         network_cause)); /* TCS 2.1 */
    } /* TCS 2.1 */
  }
  else
  {
    GMM_RETURN_ (GMMCS_NET_CAUSE_NOT_PRESENT);
  }
}
#ifdef GMM_TCS4
/*
+------------------------------------------------------------------------------
| Function    : kern_make_new_cause
+------------------------------------------------------------------------------
| Description : The function kern_make_new_cause()
|       
|            An internal 16 bit cause is generated from the cause received
|            from the network. The reject causes indicating a retry in a new
|            cell are translated to a single value. In case no cause was sent 
|            by the network a special internal value is returned to handle this.
|
| Parameters  : valid flag, network cause value
|
+------------------------------------------------------------------------------
*/
GLOBAL T_CAUSE_ps_cause kern_make_new_cause ( void )
{
  T_CAUSE_ps_cause ps_cause;
  GMM_TRACE_FUNCTION ("kern_make_cause");
  ps_cause.ctrl_value = CAUSE_is_from_mm;
    
  switch (gmm_data->kern.detach_cap.error_cause)
  {
    case GMMCS_INT_NOT_PRESENT:
    case GMMCS_NET_CAUSE_NOT_PRESENT    :
    case MMCS_INT_NOT_PRESENT:
      ps_cause.value.mm_cause = CAUSE_MM_NO_ERROR;
      break;
    default:
      ps_cause.ctrl_value = CAUSE_is_from_nwmm;
      ps_cause.value.nwmm_cause = gmm_data->kern.detach_cap.error_cause&0xff; /* TCS 4.0 */
      break;
    case MMCS_UNSPECIFIED:
    case GMMCS_INT_PROTOCOL_ERROR:
      ps_cause.value.mm_cause = CAUSE_MM_PROTOCOL_ERROR;
      break;
    case GMMCS_SUCCESS:
      ps_cause.value.mm_cause = CAUSE_MM_SUCCESS;
      break;
    case GMMCS_AAC_UNDER_5:
    case GMMCS_AAC_OVER_5:
      ps_cause.value.mm_cause = CAUSE_MM_TRY_TO_UPDATE;
      break;
    case MMCS_AUTHENTICATION_REJECTED:
    case GMMCS_AUTHENTICATION_REJECTED:
      ps_cause.value.mm_cause = CAUSE_MM_AUTHENTICATION_REJECTED;
      break;
    case MMCS_SIM_REMOVED:
    case GMMCS_SIM_REMOVED:
      ps_cause.value.mm_cause = CAUSE_MM_SIM_REMOVED;
      break;
    case GMMCS_POWER_OFF:
      ps_cause.value.mm_cause = CAUSE_MM_POWER_OFF;
      break;
    case GMMCS_LIMITED_SERVICE:
      ps_cause.value.mm_cause = CAUSE_MM_LIMITED_SERVICE;
      break;
    case MMCS_SUCCESS:
      ps_cause.value.mm_cause = CAUSE_MM_SUCCESS;
      break;
    case MMCS_NO_REGISTRATION:
      ps_cause.value.mm_cause = CAUSE_MM_NO_REGISTRATION;
      break;      
    case MMCS_TIMER_RECOVERY:
      ps_cause.value.mm_cause = CAUSE_MM_TIMER_RECOVERY;
      break;      
    case MMCS_NO_REESTABLISH:
      ps_cause.value.mm_cause = CAUSE_MM_NO_REESTABLISH;
      break;      
    case MMCS_INT_PREEM:
      ps_cause.value.mm_cause = CAUSE_MM_INT_PREEM;
      break;      
    case MMCS_PLMN_NOT_IDLE_MODE:
      ps_cause.value.mm_cause = CAUSE_MM_PLMN_NOT_IDLE_MODE;
      break;   


  }
  GMM_RETURN_ (ps_cause);
}
#endif

/*
+------------------------------------------------------------------------------
| Function    : kern_call_undone_mm_proc_der 
+------------------------------------------------------------------------------
| Description : This function starts all undone MM procedures after finishing the last 
|            MM procedure
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_call_undone_mm_proc_der ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_call_undone_mm_proc_der" );
  if (!gmm_data->kern.suspension_type)
  /*
   * default branch
   */
  {
    kern_resume_grr_der(); 
    GMM_RETURN;
  }


  if (GMM_SUSP_EM_CALL & gmm_data->kern.suspension_type)
  {
    kern_mm_cm_emergency_res(MMGMM_ESTABLISH_OK);
  }
  else if (GMM_SUSP_LAU & gmm_data->kern.suspension_type)
  {
    kern_mm_lau();
  }
  else if (GMM_SUSP_CALL & gmm_data->kern.suspension_type)
  {
    kern_mm_cm_establish_res(MMGMM_ESTABLISH_OK);
  }
  else if (GMM_SUSP_IMSI_DETACH & gmm_data->kern.suspension_type)
  {
    kern_mm_imsi_detach();
  }
  else if (GMM_SUSP_LOCAL_DETACH & gmm_data->kern.suspension_type)
  {
    kern_local_detach ( GMMCS_INT_NOT_PRESENT, FALSE, GMM_LOCAL_DETACH_PROC_NOT_CHANGED); /* TCS 2.1 */

  }
  GMM_RETURN;
}
/*
+------------------------------------------------------------------------------
| Function    : kern_call_undone_mm_proc_reg 
+------------------------------------------------------------------------------
| Description : This function starts all undone MM procedures after finishing the last 
|            MM procedure
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_call_undone_mm_proc_reg ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_call_undone_mm_proc_reg" );
  if (GMM_SUSP_NONE == gmm_data->kern.suspension_type)
  /*
   * default branch
   */
  {
    kern_resume_grr_reg(); 
    GMM_RETURN;
  }


  if (GMM_SUSP_EM_CALL & gmm_data->kern.suspension_type)
  {
    kern_mm_cm_emergency_res(MMGMM_ESTABLISH_OK);
  }
  else if (GMM_SUSP_LAU & gmm_data->kern.suspension_type)
  {
    kern_mm_lau();
  }
  else if (GMM_SUSP_CALL & gmm_data->kern.suspension_type)
  {
    kern_mm_cm_establish_res(MMGMM_ESTABLISH_OK);
  }
  else if (GMM_SUSP_IMSI_DETACH & gmm_data->kern.suspension_type)
  {
    kern_mm_imsi_detach();
  }
  else if (GMM_SUSP_LOCAL_DETACH & gmm_data->kern.suspension_type)
  {
    kern_local_detach ( GMMCS_INT_NOT_PRESENT, FALSE, GMM_LOCAL_DETACH_PROC_NOT_CHANGED); /* TCS 2.1 */
  }
  GMM_RETURN;
}

/*
+------------------------------------------------------------------------------
| Function    : kern_reset_cipher
+------------------------------------------------------------------------------
| Description : This function deletes the ciphering parameters
|
| Parameters  : void
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_reset_cipher ( void )
{ 
  GMM_TRACE_FUNCTION( "kern_reset_cipher" );
  
  /*
   * 3GPP,24.008:
   * 4.7.7.2   Authentication and ciphering response by the MS
   *
   * The RAND and RES values stored in the mobile station shall be deleted:
   * - if the mobile station enters the GMM states GMM-DEREGISTERED or GMM-NULL.
   */
  /* 
   * 3GPP,24.008:
   * 4.7.7.4  GPRS ciphering key sequence number
   *
   * If the GPRS ciphering key sequence number is deleted, the associated GPRS GSM 
   * ciphering key , GPRS UMTS ciphering key and GPRS UMTS integrity key shall be deleted 
   * (i.e. the established GSM security context or the UMTS security context is no longer
   * valid).  
   */
  TRACE_EVENT ("ciphering OFF");
  gmm_data->cipher = FALSE;

  GMM_RETURN;
}