view src/g23m-gprs/gmm/gmm_kernf.c @ 276:4221c724c664

R2D: preparations for adding LCD hardware suspend handling
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 07 Sep 2021 21:05:38 +0000
parents fa8dc04885d8
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;
}