view src/g23m-gprs/gmm/gmm_kernp.c @ 623:df3649549840

Leonardo target: targets/leonardo.{conf,h} created
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 22 Dec 2019 00:23:38 +0000
parents 219afcfc6250
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  GPRS (8441)
|  Modul   :  gmm_kernp.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 
|             functions to handles the incoming primitives as described in 
|             the SDL-documentation (KERN-statemachine)
+----------------------------------------------------------------------------- 
*/ 



#ifndef GMM_KERNP_C
#define GMM_KERNP_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_f.h"      /* to ger the gobal functions */
#include "gmm_kernl.h"      /* to ger the local functions */
#include "gmm_kernf.h"      /* to ger the local functions */
#include "gmm_rdys.h"      /* to get some signals */
#include  <string.h>    /* to get memcpy */
#include "gmm_txs.h"    /* to get some signals */
#include "gmm_syncs.h"
#include "gmm_em.h"     /* To get Engineering Mode functions */

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

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

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

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

/*
+------------------------------------------------------------------------------
| Function    : kern_t3302
+------------------------------------------------------------------------------
| Description : Handles expiry of timer T3302. This function is called from
|               pei_primitive().
|               Timeout for Attach or RAU failure
| Parameters  : none
|
+------------------------------------------------------------------------------
*/
GLOBAL void  kern_t3302(void)
{
  GMM_TRACE_FUNCTION( "kern_t3302" );
  TRACE_0_INFO("TIMEOUT T3302");
  sig_kern_rdy_stop_t3302_req();
  /*
   * reset attach attempt counter
   * <R.GMM.ATTACH.M.010>
   */
  /*
   * reset rau attempt counter
   * <R.GMM.ATTACH.M.010>
   */


  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_DEREG_SUSPENDING:
    case KERN_GMM_DEREG_SUSPENDED:
      gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau=FALSE;
      break;
    case KERN_GMM_REG_SUSPENDING:
      gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau=FALSE;
      SET_STATE(GU,GU_UPDATE_NEEDED);
      break;
    case KERN_GMM_REG_RESUMING:
    case KERN_GMM_REG_SUSPENDED:
      gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau=FALSE;
      SET_STATE(GU,GU_UPDATE_NEEDED);
      break;
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
      kern_attach_reset();
      kern_attach ();
      break;
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:
      kern_attach_reset();

      if (PERIODIC_RAU == gmm_data->kern.attach_cap.update_proc_type)
      {
        /* 44.2.3.3.2 */
        kern_periodic_rau();
      }
      else
      {
        kern_rau_limited();
      }

      break;
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
      /*
       * GPRS is still attached (normal service)
       * so we need to resume LLC again
       */
      kern_attach_reset();
      kern_rau();
      break;
    default:
      TRACE_ERROR( "kern_t3302 unexpected" );
      break;
  }
  GMM_RETURN;
  
} /* kern_t3302 */

/*
+------------------------------------------------------------------------------
| Function    : kern_t3310
+------------------------------------------------------------------------------
| Description : Handles expiry of timer T3310. This function is called from
|               pei_primitive().
|               Timeout for ATTACH
| Parameters  : none
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_t3310 (void)
{
  GMM_TRACE_FUNCTION( "kern_t3310" );
  TRACE_0_INFO("TIMEOUT T3310");

  gmm_data->kern.attach_cap.t3310_value=0;

  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_REG_INITIATED:
      /************************************************************************
       * MSC: 3.8 Attach
       *
       * MSC: 3.8.1 Normal Attach
       * MSC: 3.8.1.4 Abnormal cases
       * MSC: 3.8.1.4.3 c) T3310 time-out
       ************************************************************************/
      if ( gmm_data->kern.ct3310 < MAX_CT3310 )
      {
        /*
         * ATTACH
         * <R.GMM.AGABNORM.M.007>
         */
        kern_gmmreg_detach (  GMMREG_DT_GPRS,  
            GMMCS_NET_FAIL, /* TCS 2.1 */
            GMMREG_SEARCH_RUNNING,
            GMMCS_NET_FAIL);

        kern_attach();
      }
      else
      {
        /*
         * AAC
         *<R.GMM.AGABNORM.M.008>
         */
        kern_aac(GMMCS_NO_SERVICE); /* TCS 2.1 */
      }

      break;
    case KERN_GMM_RAU_INITIATED:
      /************************************************************************
       * MSC: 3.10 RAU
       *
       * MSC: 3.10.1 Normal and periodic RAU initiation
       * MSC: 3.10.1.4 Abnormal cases
       * MSC: 3.10.1.4.3 c) T3310 time-out
       *
       ************************************************************************/
      /* 
       * I reused the timer T3310 instead of T3330 
       */
      if ( gmm_data->kern.ct3310 < MAX_CT3310 )
      {
        if (PERIODIC_RAU == gmm_data->kern.attach_cap.update_proc_type)
        {
          /* 44.2.3.3.2 */
          kern_periodic_rau();
        }
        else
        {
          kern_rau_limited();
        }
      }
      else
      {
        /*
         * AAC
         */
        kern_aac(GMMCS_NO_SERVICE); /* TCS 2.1 */
      }
      break;
    /* START PATCH UBUOB ISSUE 8274 */
    case KERN_GMM_REG_RESUMING:
    case KERN_GMM_REG_SUSPENDING:
    case KERN_GMM_REG_SUSPENDED:
      gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = FALSE;
      SET_STATE(GU,GU_UPDATE_NEEDED);
      break;
    /* END PATCH UBUOB ISSUE 8274 */
    case KERN_GMM_REG_LIMITED_SERVICE:
      TRACE_EVENT("T3310 ignored in limited mode"); 
      break;
    default:
      TRACE_ERROR( "kern_t3310 unexpected" );
      break;
  }
  GMM_RETURN;
} /* kern_t3310 */
/*
+------------------------------------------------------------------------------
| Function    : kern_t3311
+------------------------------------------------------------------------------
| Description : Handles expiry of timer T3310. This function is called from
|               pei_primitive().
|               Timeout for ATTACH or RAU Reject
| Parameters  : none
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_t3311 (void)
{
  GMM_TRACE_FUNCTION( "kern_t3311" );
  TRACE_0_INFO("TIMEOUT T3311");
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
      kern_attach ();
      break;
    case  KERN_GMM_REG_NORMAL_SERVICE:
      /*
       * <R.GMM.RNABNORM.M.022> 
       */
      kern_periodic_rau();
      break;
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
      kern_llgmm_suspend(LLGMM_RAU);
      /*FALLTHROUGH*/
      //lint -fallthrough
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:
      kern_rau_limited ();
      break;
    /* START PATCH UBUOB ISSUE 8893 */
    case KERN_GMM_DEREG_SUSPENDING:
    case KERN_GMM_DEREG_SUSPENDED:
    case KERN_GMM_DEREG_RESUMING:
    /* END PATCH UBUOB ISSUE 8893 */
    case KERN_GMM_REG_RESUMING:
    /* START PATCH UBUOB ISSUE 8273 */
    case KERN_GMM_REG_SUSPENDING:
    case KERN_GMM_REG_SUSPENDED:
      gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = FALSE;
      SET_STATE(GU,GU_UPDATE_NEEDED);
      break;
    /* END PATCH UBUOB ISSUE 8273 */
    default:
      TRACE_ERROR( "kern_t3311 unexpected" );
      break;
  }
  
  GMM_RETURN;
} /* kern_t3311 */
/*
+------------------------------------------------------------------------------
| Function    : kern_t3312
+------------------------------------------------------------------------------
| Description : Handles expiry of timer T3312. This function is called from
|               pei_primitive().

|               Periodic RAU timer
| Parameters  : none
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_t3312 (void)
{
  GMM_TRACE_FUNCTION( "kern_t3312" );
  TRACE_0_INFO("TIMEOUT T3312");
  switch( GET_STATE( KERN ) )
  {
    
    case KERN_GMM_REG_NORMAL_SERVICE:
      if (GMM_GRR_STATE_CR==gmm_data->kern.attach_cap.grr_state)
      {
         gmm_data->kern.timeout_t3312 = TRUE;
         SET_STATE(GU,GU_UPDATE_NEEDED);
      }
      else
      {
        kern_periodic_rau();
      }
      break;
    case KERN_GMM_REG_NO_CELL_AVAILABLE:
      /*
       * 24.008 ch 4.7.2.2. at the end:
       *
       * If the MS is both IMSI attached for GPRS and non-GPRS services in a network that
       * operates in network operation mode I, and if the MS has camped on a cell that does
       * not support GPRS, and timer T3312 expires, then the MS shall start an MM location
       * updating procedure. In addition, the MS shall perform a combined routing area update
       * procedure indicating "combined RA/LA updating with IMSI attach" when the MS enters
       * a cell that supports GPRS and indicates that the network is in operation mode I.
       */
      gmm_data->kern.timeout_t3312 = TRUE;
      SET_STATE(GU,GU_UPDATE_NEEDED);
      
      if (GMM_MM_DEREG != GET_STATE(MM)
      && GMMRR_LA_INVALID!=gmm_data->kern.sig_cell_info.env.rai.lac)
      {
        SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING);
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING);
#endif
        kern_llgmm_suspend(LLGMM_CALL); /* in no cell availble LLC is alread susended */
        kern_gmmrr_suspend(GMMRR_NOT_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LAU);
      }      
      break;


    case KERN_GMM_REG_LIMITED_SERVICE:
    case KERN_GMM_REG_IMSI_DETACH_INITIATED:
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
    case KERN_GMM_REG_RESUMING:
    case KERN_GMM_REG_SUSPENDING:
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:
    case KERN_GMM_REG_SUSPENDED:
        /* no break; */
        /*
         * <R.GMM.RAUTIMER.M.009>
         */
      gmm_data->kern.timeout_t3312 = TRUE;
      SET_STATE(GU,GU_UPDATE_NEEDED);
      break;
    default:
      break;
  }
  
  GMM_RETURN;
} /* kern_t3312 */
/*
+------------------------------------------------------------------------------
| Function    : kern_t3321
+------------------------------------------------------------------------------
| Description : Handles expiry of timer T3321. This function is called from
|               pei_primitive().
|               Timeout for DETACH
|
|               MSC: 3.9 GPRS detach procedure
|               
|               MCS: 3.9.3 Abnormal cases
|               MSC: 3.9.3.1 a) Timeout of timer T3321
|
| Parameters  : none
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_t3321 (void)
{

#ifdef REL99
  T_gmobile_identity gmobile_identity; /* TCS 4.0 */
#endif

  GMM_TRACE_FUNCTION( "kern_t3321" );
  TRACE_0_INFO("TIMEOUT T3321");
  /*
   * MSC: 3.9 GPRS detach procedure
   *
   * MCS: 3.9.3 Abnormal cases
   * MSC: 3.9.3.1 a) Timeout of timer T3321
   */
  if ( ++gmm_data->kern.ct3321 < 5 )
  {
    MCAST (u_detach_request, U_DETACH_REQUEST);
    
      TRACE_EVENT ("  START T3321" );
      sig_kern_rdy_start_timer_req ( kern_T3321, gmm_data->kern.t3321_val );
    
      u_detach_request->u_detach_type.u_type_of_detach 
                          = gmm_data->kern.detach_cap.detach_type,
      u_detach_request->u_detach_type.power_off = PO_NORMAL_DETACH;


#ifdef REL99
    /* Detach request sent to a Release 99 network has two addional
     * parameters. PTMSI and PTMSI signature  
     */        
    switch (gmm_data->kern.sig_cell_info.sgsnr_flag)/*!gmm_data->release99 =>old code*/ /* TCS 4.0 */
    {
      default:
      case PS_SGSN_UNKNOWN:
      case PS_SGSN_98_OLDER:
        u_detach_request->v_gmobile_identity = FALSE; /* TCS 4.0 */
        u_detach_request->v_p_tmsi_signature_2 = FALSE; /* TCS 4.0 */
        break;
      case PS_SGSN_99_ONWARDS:      
        /* 
         * PTMSI
         */
        kern_ulong2mobile_identity( gmm_data->ptmsi.current, &gmobile_identity ); /* TCS 4.0 */
        u_detach_request->v_gmobile_identity = TRUE; /* TCS 4.0 */
        u_detach_request->gmobile_identity   = gmobile_identity; /* TCS 4.0 */
        
        /* 
         * PTMSI Signature
         */
        if(gmm_data->ptmsi_signature.available) /* TCS 4.0 */
        { /* TCS 4.0 */
          u_detach_request->v_p_tmsi_signature_2 =TRUE; /* TCS 4.0 */
          u_detach_request->p_tmsi_signature_2.p_tmsi_signature_value /* TCS 4.0 */
                             = gmm_data->ptmsi_signature.value; /* TCS 4.0 */
        } /* TCS 4.0 */
        else  /* TCS 4.0 */
        { /* TCS 4.0 */
          u_detach_request->v_p_tmsi_signature_2=FALSE; /* TCS 4.0 */
        } /* TCS 4.0 */
        break;
      }
#endif


      switch ( gmm_data->kern.detach_cap.detach_type )
      {
        case GMMREG_DT_GPRS:
          u_detach_request->u_detach_type.u_type_of_detach 
                          = DT_GPRS;
          break;
        case GMMREG_DT_IMSI:
          u_detach_request->u_detach_type.u_type_of_detach 
                          = DT_IMSI;
          break;
        case GMMREG_DT_COMB:
          u_detach_request->u_detach_type.u_type_of_detach 
                          = DT_COMB;
          break;
        case GMMREG_DT_SIM_REMOVED:
          if ( GMM_MM_DEREG != GET_STATE(MM) )
          {
            u_detach_request->u_detach_type.u_type_of_detach 
                          = DT_COMB;
          }
          else
          {
            u_detach_request->u_detach_type.u_type_of_detach 
                          = DT_GPRS;
          }
          break;
        default:
          TRACE_ERROR ("unexpexted GMMREG_DT_TYPE");
          break;
      }
      kern_mm_detach_started ();    
      sig_kern_tx_data_req ( CURRENT_TLLI, U_DETACH_REQUEST);
  }
  else
  {    
    switch( GET_STATE( KERN ) )
    {
      case KERN_GMM_DEREG_INITIATED:
        kern_local_detach( GMMCS_INT_NOT_PRESENT, FALSE, GMM_LOCAL_DETACH_PROC_ENTER_DEREG); /* TCS 2.1 */
        break;  
      case KERN_GMM_REG_IMSI_DETACH_INITIATED:
        /*
         * <R.GMM.DMABNORM.M.020>
         */
        kern_local_detach( GMMCS_INT_NOT_PRESENT, FALSE, GMM_LOCAL_DETACH_PROC_ENTER_REG_NORMAL); /* TCS 2.1 */
        break;
      default:
        TRACE_ERROR( "kern_t3321 unexpected" );
        break;
    }
  }
  GMM_RETURN;
} /* kern_t3321 */
/*
+------------------------------------------------------------------------------
| Function    : kern_tpower_off
+------------------------------------------------------------------------------
| Description : Handles expiry of timer Tpower_off. This function is called from
|               pei_primitive().
|               Timeout for power_off after sending DETACH message
| Parameters  : none
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_tpower_off (void)
{
  GMM_TRACE_FUNCTION( "kern_tpower_off" );
  TRACE_0_INFO("TIMEOUT TPOWER_OFF");
  kern_local_detach( GMMCS_POWER_OFF, FALSE, /* TCS 2.1 */
                GMMREG_DT_SOFT_OFF==gmm_data->kern.detach_cap.detach_type?
                GMM_LOCAL_DETACH_PROC_SOFT_OFF:
                GMM_LOCAL_DETACH_PROC_POWER_OFF);

  GMM_RETURN;
  
} /* kern_tpower_off */

/*
+------------------------------------------------------------------------------
| Function    : kern_tlocal_detach
+------------------------------------------------------------------------------
| Description : Handles expiry of timer Tlocal_detach. This function is called from
|               pei_primitive().
|               function local_detach is called to locally detach the MS.
|               GRR and LLC can not unassigned immediately. So GMM waits untill 
|               the tlocal_detach timer has been expired or either CGRLC_TRIGGER_IND
|               has been received or GMMRR_SUSPEND_CNF has been received.
| Parameters  : none
|
+------------------------------------------------------------------------------
*/
GLOBAL void  kern_tlocal_detach (void)
{
  GMM_TRACE_FUNCTION( "kern_tlocal_detach" );


  switch( GET_STATE( KERN ) )
  {
    default:
      TRACE_ERROR("tlocal_detach not in state DEREG_SUSPENDING");
      /* NO break; */
    case KERN_GMM_DEREG_SUSPENDING:
      kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_NORMAL_RELEASE, 
                GMM_SUSP_UNKNOWN);  

      break;
  }

  GMM_RETURN  ;
} /* kern_tlocal_detach */




/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_net_req
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMREG_NET_REQ
|
|          MSC: 3.20 MM Interface
|          MSC: 3.20.2 Network selection
|
| Parameters  : *gmmreg_net_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_net_req ( T_GMMREG_NET_REQ *gmmreg_net_req )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmreg_net_req" );

  PFREE (gmmreg_net_req);
  kern_mm_net_req();
  GMM_RETURN;
} /* kern_gmmreg_net_req() */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_plmn_res
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMREG_PLMN_RES
|
|          MSC: 3.20 MM Interface
|          MSC: 3.20.2 Network selection
|
| Parameters  : *gmmreg_plmn_res - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_plmn_res ( T_GMMREG_PLMN_RES *gmmreg_plmn_res )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmreg_plmn_res" );

  gmm_data->kern.attach_cap.network_selection_mode=MODE_MAN;
  kern_remove_plmn_from_forbidden_list(gmmreg_plmn_res->plmn);
    
  /* START PATCH UBUOB ISSUE 8276 */
  /* T3302 should not be stopped here, because this is dangerous if the */
  /* user selection does not lead to a different PLMN */
  /*vsi_t_stop  ( GMM_handle, kern_T3302);*/
  /*sig_kern_rdy_start_t3302_req();*/
  /* END PATCH UBUOB ISSUE 8276 */

  /* When we receive manual mode network selection stop TSYNC timer */
  vsi_t_stop  ( GMM_handle, sync_TSYNC);

  gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = FALSE;
  /*
   * attach_cap.gmmreg sets the caller of the attach procedure to MMI
   */
  gmm_data->kern.attach_cap.gmmreg = TRUE;
  /*
   * if the moble has been rejected with cause #11,#12, or #13 it has to igored
   * when user wanted the moile explicitly to try to attach
   * TC 44.2.1.1.4.3.2
   */
  gmm_data->kern.detach_cap.error_cause=GMMCS_INT_NOT_PRESENT; /* TCS 2.1 */

  /* Setting mm_status to FULL Service immediately on receiving PLMN Response creates a false display 
   * on MMI if selecting forbidden PLMN second time in a row. However, it is necessary in case of Normal PLMN selection
   * for an early indication to ACI. Hence setting mm_status to Full Service only if the selected PLMN was not rejected by 
   * the N/W in the same power cycle.
   */
  if((memcmp(gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[0].mcc,gmmreg_plmn_res->plmn.mcc, SIZE_MCC) NEQ 0) AND
     (memcmp(gmm_data->kern.attach_cap.list_of_forbidden_plmns_for_gprs_service[0].mnc,gmmreg_plmn_res->plmn.mnc, SIZE_MNC)NEQ 0))
  {
    gmm_data->kern.sig_cell_info.mm_status = MMGMM_FULL_SERVICE;
    sig_kern_sync_set_mm_state(MMGMM_FULL_SERVICE);
  }

#ifndef NTRACE
  /*
   * My assumption is, that I have to know the class if plmn_res comes as power 
   * on primitive with AT+COPS=1,2,"001001". There are no possabilities  to 
   * change the classes. a class change is handeled with attach_req
   */
  if(gmm_data->kern.attach_cap.mobile_class!=gmmreg_plmn_res->mobile_class)
  {
    TRACE_ERROR("class change not expected: NO DETACH_REQ will be send!");
  }
#endif
  gmm_data->kern.attach_cap.plmn_requested  = gmmreg_plmn_res->plmn; 
  gmm_data->kern.attach_cap.mobile_class = gmmreg_plmn_res->mobile_class;  
  gmm_data->kern.attach_cap.attach_type = gmmreg_plmn_res->attach_type;
#ifndef NTRACE      
  switch ( gmm_data->kern.attach_cap.mobile_class )
  {
    case GMMREG_CLASS_CC:
      TRACE_0_PARA ("MS class CC");
      break;
    case GMMREG_CLASS_CG:
      TRACE_0_PARA ("MS class CG");
      break;
    case GMMREG_CLASS_B:
      TRACE_0_PARA ("MS class B");
      break;
    case GMMREG_CLASS_BG:
      TRACE_0_PARA ("MS class BG");
      break;
    case GMMREG_CLASS_BC:
      TRACE_0_PARA ("MS class BC");
      break;
    case GMMREG_CLASS_A:
      TRACE_0_PARA ("MS class A");
      break;
    default:
      TRACE_ERROR ("unknown mobile class");
      break;
  }
  switch (gmm_data->kern.attach_cap.attach_type)
  {
    case GMMREG_AT_IMSI:
      TRACE_EVENT ("----- GSM only attach -----");
      break;
    case GMMREG_AT_GPRS:
      TRACE_EVENT ("----- GPRS attach -----");
      break;
    case GMMREG_AT_COMB:
      TRACE_EVENT ("----- GSM and GPRS attach -----");
      break;
    default:
      TRACE_ERROR ("unknown attach type");
      break;
  }

#endif
  {
    PALLOC ( mmgmm_plmn_res, MMGMM_PLMN_RES);
      mmgmm_plmn_res->plmn = gmmreg_plmn_res->plmn;
      mmgmm_plmn_res->reg_type = REG_CELL_SEARCH_ONLY;
      PFREE (gmmreg_plmn_res);

    switch( GET_STATE( KERN ) )
    {
      case KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ:
      case KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ:           
        mmgmm_plmn_res->reg_type = REG_GPRS_INACTIVE;
        break;
      case KERN_GMM_NULL_NO_IMSI:
        if (GMMREG_CLASS_CC==gmm_data->kern.attach_cap.mobile_class
        || GMMREG_AT_IMSI== gmm_data->kern.attach_cap.attach_type)
        {
          /* NO state change */
        }
        else
        {
          SET_STATE ( KERN, KERN_GMM_DEREG_NO_IMSI);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_DEREG_NO_IMSI);
#endif
        }
        mmgmm_plmn_res->reg_type = REG_GPRS_INACTIVE;

        break;

      case KERN_GMM_DEREG_RESUMING:
      case KERN_GMM_REG_RESUMING:
      case KERN_GMM_DEREG_NO_IMSI:
        break;
      /*
       * GMM-DEREGISTERED
       */
      case KERN_GMM_DEREG_SUSPENDING:
        /* 
         * not reachable beause of save in pei 
         */
      case KERN_GMM_DEREG_SUSPENDED:
        kern_resume_grr_der();
        /* NO break;*/
      case KERN_GMM_DEREG_PLMN_SEARCH:
      case KERN_GMM_DEREG_LIMITED_SERVICE:
      case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
      case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
        if (GMMREG_CLASS_CC==gmm_data->kern.attach_cap.mobile_class
        || GMMREG_AT_IMSI== gmm_data->kern.attach_cap.attach_type)
        {
          SET_STATE ( KERN, KERN_GMM_NULL_PLMN_SEARCH);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_NULL_PLMN_SEARCH);
#endif
          mmgmm_plmn_res->reg_type = REG_GPRS_INACTIVE;
        }
        else
        {
          SET_STATE ( KERN, KERN_GMM_DEREG_PLMN_SEARCH);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_DEREG_PLMN_SEARCH);
#endif
        }

        break;

      case KERN_GMM_NULL_PLMN_SEARCH:
      case KERN_GMM_NULL_IMSI:          
       
        if (GMMREG_CLASS_CC==gmm_data->kern.attach_cap.mobile_class
        || GMMREG_AT_IMSI== gmm_data->kern.attach_cap.attach_type)
        {
          SET_STATE ( KERN, KERN_GMM_NULL_PLMN_SEARCH);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_NULL_PLMN_SEARCH);
#endif
          mmgmm_plmn_res->reg_type = REG_GPRS_INACTIVE;
        }
        else
        {
          SET_STATE ( KERN, KERN_GMM_DEREG_PLMN_SEARCH);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_DEREG_PLMN_SEARCH);
#endif
          kern_gmmrr_enable();
        }

        break;

      case KERN_GMM_REG_NORMAL_SERVICE:

      case KERN_GMM_REG_NO_CELL_AVAILABLE:
      case KERN_GMM_REG_LIMITED_SERVICE:
      case KERN_GMM_RAU_INITIATED:
      case KERN_GMM_REG_INITIATED:
      case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
      case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:  
        break;
      case KERN_GMM_REG_SUSPENDING:
        /* 
         * not reachablebeause of save in pei 
         */
      case KERN_GMM_REG_SUSPENDED:
        /*
         * Attach requests in suspended mode will be handled after resumption
         * by triggering form GRR with GMMRR_CELL_IND
         */

        /*
         * The user is not allowed to change the mobile class or establish a 
         * voice call the same time manuall network search is started. it would 
         * not be nice
         */
        kern_resume_grr_reg();

        TRACE_ERROR("I hoped, that this never is happened, ...");
        break;
      default:
        TRACE_ERROR( "GMMREG_PLMN_RES unexpected" );
        break;
       
    }
      mmgmm_plmn_res->mobile_class=gmm_data->kern.attach_cap.mobile_class;  
    PSEND ( hCommMM, mmgmm_plmn_res );
  }
  GMM_RETURN;
} /* kern_gmmreg_plmn_res() */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_plmn_mode_req
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMREG_PLMN_MODE_REQ
|
|          MSC: 3.20 MM Interface
|          MSC: 3.20.1 Change of PLMN Mode
|
| Parameters  : *gmmreg_plmn_mode_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_plmn_mode_req ( T_GMMREG_PLMN_MODE_REQ *gmmreg_plmn_mode_req )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmreg_plmn_mode_req" );
  {
    PPASS ( gmmreg_plmn_mode_req, mmgmm_plmn_mode_req, MMGMM_PLMN_MODE_REQ );
      /* 
       * PATCH UBUOB 11.3.02: if we change from MANUAL to AUTOMATC or vice versa,
       * then we need to clear the limited_service flag
       * Problem was: Bouyg SIM, manual registration on SFR upon return to
       * auto mode, first GPRS ATTACH
       
      if (gmm_data->kern.attach_cap.network_selection_mode 
          != gmmreg_plmn_mode_req->net_selection_mode)
      {
         gmm_data->kern.sig_cell_info.mm_status = MMGMM_FULL_SERVICE;
         sig_kern_sync_set_mm_state(MMGMM_FULL_SERVICE);
      }
      */
      /*
       * PLMN mode set to manual mode with PLMN_RES only
        gmm_data->kern.attach_cap.network_selection_mode = 
        gmmreg_plmn_mode_req->net_selection_mode;
       */
     if (GMMREG_NET_SEL_MODE_AUTO == gmmreg_plmn_mode_req->net_selection_mode)
     {
       gmm_data->kern.attach_cap.network_selection_mode = 
         gmmreg_plmn_mode_req->net_selection_mode;
     }
     else
     {
      TRACE_0_INFO ("manual mode ignored. will be set with PLMN_RES");
     }

    PSEND ( hCommMM, mmgmm_plmn_mode_req );
  }
  GMM_RETURN;
} /* kern_gmmreg_plmn_mode_req () */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_config_req
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMREG_CONFIG_REQ
|
| Parameters  : *gmmreg_config_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_config_req ( T_GMMREG_CONFIG_REQ *gmmreg_config_req )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmreg_config_req" );
  gmm_data->config.cipher_on 
                  = gmmreg_config_req->cipher_on;
  PFREE (gmmreg_config_req);
  GMM_RETURN;
} /* kern_gmmreg_plmn_mode_req () */
/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_detach_req
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMREG_DETACH_REQ
|
| Parameters  : *gmmreg_detach_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_detach_req ( T_GMMREG_DETACH_REQ *gmmreg_detach_req )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmreg_detach_req" );

  /*
   * RAU may interrupt detach procedure, so we have to store the detach type
   */
  gmm_data->kern.detach_cap.detach_type=gmmreg_detach_req->detach_type;
  gmm_data->kern.detach_cap.gmmreg=TRUE;
  
  switch (gmmreg_detach_req->detach_type)
  {
    case GMMREG_DT_GPRS:
      switch(gmm_data->kern.attach_cap.attach_type)
      {
        case GMMREG_AT_GPRS:
        case GMMREG_AT_NOT_KNOWN:
          gmm_data->kern.attach_cap.attach_type=GMMREG_AT_NOT_KNOWN;
          break;
        default:
        case GMMREG_AT_IMSI:
        case GMMREG_AT_COMB:
          gmm_data->kern.attach_cap.attach_type=GMMREG_AT_IMSI;
          break;
      }
      TRACE_EVENT ("Para: GPRS detach");
      break;
    case GMMREG_DT_IMSI:
      gmm_data->kern.attach_cap.attach_type=
        (GMMREG_CLASS_CC == gmm_data->kern.attach_cap.mobile_class?
            GMMREG_AT_NOT_KNOWN:
            GMMREG_AT_GPRS);
      TRACE_EVENT ("Para: IMSI detach");
      break;
    case GMMREG_DT_POWER_OFF:
      /*
       * TMSI reset to remove TMSI in GRR when gmmrr_assign_req will
       * be sent
       */
      gmm_data->tmsi = GMMRR_TMSI_INVALID;
      gmm_data->kern.attach_cap.attach_type=GMMREG_AT_NOT_KNOWN;
      gmm_data->kern.attach_cap.network_selection_mode=MODE_AUTO;
      TRACE_EVENT ("Para: Power OFF");
      break;
    case GMMREG_DT_SOFT_OFF:
      /*
       * TMSI reset to remove TMSI in GRR when gmmrr_assign_req will
       * be sent
       */
      gmm_data->tmsi = GMMRR_TMSI_INVALID;
      gmm_data->kern.attach_cap.attach_type=GMMREG_AT_NOT_KNOWN;
      TRACE_EVENT ("Para: Soft OFF");
      break;
    case GMMREG_DT_COMB:
      gmm_data->kern.attach_cap.service_mode=SERVICE_MODE_LIMITED;
      gmm_data->kern.attach_cap.attach_type=GMMREG_AT_NOT_KNOWN;
      TRACE_EVENT ("Para: GMMREG_DT_COMB");
      break;
    case GMMREG_DT_SIM_REMOVED:
      gmm_data->kern.attach_cap.attach_type=GMMREG_AT_NOT_KNOWN;
      TRACE_EVENT ("Para: GMMREG_DT_SIM_REMOVED");
      break;
    case GMMREG_DT_DISABLE_GPRS:
      TRACE_EVENT ("Para: GMMREG_DT_DISABLE_GPRS");
      break;
    case GMMREG_DT_LIMITED_SERVICE:
      gmm_data->kern.attach_cap.service_mode=SERVICE_MODE_LIMITED;
      TRACE_EVENT ("Para: GMMREG_DT_LIMITED_SERVICE");
      break;
    default:
      gmm_data->kern.attach_cap.attach_type=
        (GMMREG_CLASS_CG == gmm_data->kern.attach_cap.mobile_class?
            GMMREG_AT_NOT_KNOWN:
            GMMREG_AT_IMSI);
      vsi_o_ttrace(VSI_CALLER TC_ERROR,"Error: Unknown detach_type = %x", gmmreg_detach_req->detach_type);
    break;


  }

  gmm_data->kern.detach_cap.detach_type = gmmreg_detach_req->detach_type;  

  gmm_data->kern.detach_cap.gmmreg = TRUE;
  gmm_data->kern.attach_cap.gmmreg = FALSE;
#ifndef GMM_TCS4  
  gmm_data->kern.attach_cap.gmmsm  = FALSE;
#endif
  
  PFREE ( gmmreg_detach_req );

  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_REG_LIMITED_SERVICE:
    case KERN_GMM_REG_NO_CELL_AVAILABLE:
    case KERN_GMM_REG_TEST_MODE:  
    case KERN_GMM_REG_TEST_MODE_NO_IMSI:  
      switch ( gmm_data->kern.detach_cap.detach_type )
      {
        case GMMREG_DT_IMSI:
        case GMMREG_DT_COMB:
        case GMMREG_DT_SIM_REMOVED:
          SET_STATE ( KERN, KERN_GMM_REG_SUSPENDED);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDED);
#endif
          kern_mm_imsi_detach();
          break;
        case GMMREG_DT_DISABLE_GPRS:
          kern_local_detach( GMMCS_INT_NOT_PRESENT, FALSE,
             GMM_LOCAL_DETACH_PROC_ENTER_NULL_IMSI); /* TCS 2.1 */
          break;
        case GMMREG_DT_GPRS:
          kern_local_detach( GMMCS_INT_NOT_PRESENT, FALSE,
             GMM_LOCAL_DETACH_PROC_ENTER_NULL_IMSI); /* TCS 2.1 */
          break;
        case GMMREG_DT_POWER_OFF:
          kern_local_detach( GMMCS_POWER_OFF, FALSE, /* TCS 2.1 */
                GMM_LOCAL_DETACH_PROC_POWER_OFF);
          break;
        case GMMREG_DT_SOFT_OFF:
          kern_local_detach( GMMCS_POWER_OFF, FALSE, /* TCS 2.1 */
                GMM_LOCAL_DETACH_PROC_SOFT_OFF);

          break;
        default:
          TRACE_ERROR ("Unexpected detach type in primitive GMMREG_DETACH_REQ");
          break;
      }
      break;
    case KERN_GMM_REG_INITIATED:
      /* 
       * This cause is abnormal, because the normal and not the local detach 
       * procedure is started on power off 
       *
       * MSC: 3.8.1.4.7 g) Power off
       * <R.GMM.AGABNORM.M.015>,
       * <R.GMM.AGABNORM.M.031>
       */
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
      kern_gmmrr_attach_finished();
      /* NO break;*/

    case KERN_GMM_REG_NORMAL_SERVICE:
      switch ( gmm_data->kern.detach_cap.detach_type )
      {
        case GMMREG_DT_IMSI:
        case GMMREG_DT_COMB:
        case GMMREG_DT_SIM_REMOVED:
          switch (gmm_data->kern.sig_cell_info.net_mode)
          {
            case GMMRR_NET_MODE_I:
              kern_detach( );
              break;
            case GMMRR_NET_MODE_II:
              SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING);
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING);
#endif
              kern_llgmm_suspend(LLGMM_CALL);
              kern_gmmrr_suspend(GMMRR_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_IMSI_DETACH);
              break;
            case GMMRR_NET_MODE_III:
              kern_detach( );
              break;
            default:
              TRACE_ERROR ("unknown net mode");
              break;
          }
          break;
        case GMMREG_DT_DISABLE_GPRS:
        case GMMREG_DT_GPRS:
        case GMMREG_DT_POWER_OFF:
        case GMMREG_DT_SOFT_OFF:
          kern_detach( );
          break;

        default:
          TRACE_ERROR ("Unexpected detach type in primitive GMMREG_DETACH_REQ");
          break;
      }
      break;
    
    case KERN_GMM_REG_IMSI_DETACH_INITIATED:
      switch ( gmm_data->kern.detach_cap.detach_type )
      {
        case GMMREG_DT_DISABLE_GPRS:
          gmm_data->kern.attach_cap.mobile_class = GMMREG_CLASS_CC;
          /* NO break */
        default:
          kern_detach( );
          break;
      }
      break;
 
    case KERN_GMM_REG_SUSPENDED:
      switch ( gmm_data->kern.detach_cap.detach_type )
      {
        case GMMREG_DT_IMSI:
        case GMMREG_DT_COMB:
        case GMMREG_DT_SIM_REMOVED:
          kern_mm_imsi_detach();
          break;
        case GMMREG_DT_DISABLE_GPRS:
          gmm_data->kern.attach_cap.mobile_class = GMMREG_CLASS_CC;
          /* NO break; */
        case GMMREG_DT_GPRS:
          /*
           * Wait untill GSM is finished
           */
          break;
        case GMMREG_DT_POWER_OFF:
          kern_local_detach( GMMCS_POWER_OFF, FALSE, /* TCS 2.1 */
                GMM_LOCAL_DETACH_PROC_POWER_OFF);
          break;
        case GMMREG_DT_SOFT_OFF:
          kern_local_detach( GMMCS_POWER_OFF, FALSE, /* TCS 2.1 */
                GMM_LOCAL_DETACH_PROC_SOFT_OFF);
          break;
       default:
          TRACE_ERROR ("Unexpected detach type in primitive GMMREG_DETACH_REQ");
          break;
      }
      break;
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_REG_RESUMING:
      TRACE_ERROR ("prim should be saved by pei");
      /* NO break */
    case KERN_GMM_REG_SUSPENDING:
      switch ( gmm_data->kern.detach_cap.detach_type )
      {
        case GMMREG_DT_IMSI:
        case GMMREG_DT_COMB:
        case GMMREG_DT_SIM_REMOVED:
          gmm_data->kern.suspension_type |= GMM_SUSP_IMSI_DETACH;
          break;
        case GMMREG_DT_DISABLE_GPRS:
          gmm_data->kern.attach_cap.mobile_class = GMMREG_CLASS_CC;
          /* NO break; */
        case GMMREG_DT_GPRS:
          /*
           * Wait untill GSM is finished
           */
          break;
        case GMMREG_DT_POWER_OFF:
        case GMMREG_DT_SOFT_OFF:
          SET_STATE ( KERN, KERN_GMM_REG_SUSPENDED);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDED);
#endif
          kern_resume_grr_reg();
          break;
        default:
          TRACE_ERROR ("Unexpected detach type in primitive GMMREG_DETACH_REQ");
          break;
      }
      break;
  
    case KERN_GMM_NULL_NO_IMSI:
    case KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ:
      switch ( gmm_data->kern.detach_cap.detach_type )
      {
        case GMMREG_DT_IMSI:
        case GMMREG_DT_COMB:
          if ( GMM_MM_DEREG != GET_STATE(MM) )
          {
            kern_mm_imsi_detach();
            break;
          }
          /* else NO break;*/
        case GMMREG_DT_SIM_REMOVED:
        case GMMREG_DT_GPRS:
        {  
          PALLOC (gmmreg_detach_cnf, GMMREG_DETACH_CNF);
            gmmreg_detach_cnf->detach_type = gmm_data->kern.detach_cap.detach_type;
          PSEND ( hCommMMI, gmmreg_detach_cnf );  
          break;
        }
        case GMMREG_DT_POWER_OFF:
          SET_STATE ( KERN, KERN_GMM_NULL_NO_IMSI );
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI );
#endif
          /* NO break*/
        case GMMREG_DT_SOFT_OFF:
            kern_mm_imsi_detach_ind (GMMCS_INT_NOT_PRESENT, /* TCS 2.1 */
                  GET_STATE(MM)==GMM_MM_DEREG?
                    MMGMM_DETACH_DONE:
                    MMGMM_PERFORM_DETACH,
                    gmm_data->kern.detach_cap.detach_type);

          break;
        case GMMREG_DT_DISABLE_GPRS:
          gmm_data->kern.attach_cap.mobile_class = GMMREG_CLASS_CC;
          {  
            PALLOC (gmmreg_detach_cnf, GMMREG_DETACH_CNF);
              gmmreg_detach_cnf->detach_type = gmm_data->kern.detach_cap.detach_type;
            PSEND ( hCommMMI, gmmreg_detach_cnf );  
          }
          break;

        default:
          TRACE_ERROR ("Unexpected detach type in primitive GMMREG_DETACH_REQ");
          break;
      }
      break;
 

    case KERN_GMM_NULL_IMSI:
    case KERN_GMM_NULL_PLMN_SEARCH:
    case KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ:
      switch ( gmm_data->kern.detach_cap.detach_type )
      {
        case GMMREG_DT_IMSI:
        case GMMREG_DT_COMB:
          if ( GMM_MM_DEREG != GET_STATE(MM) )
          {
            kern_mm_imsi_detach_ind (GMMCS_INT_NOT_PRESENT, MMGMM_PERFORM_DETACH,
                                     GMMREG_DT_SIM_REMOVED); 

            break;
          }
          /* else NO break;*/
        case GMMREG_DT_GPRS:
        {  
          PALLOC (gmmreg_detach_cnf, GMMREG_DETACH_CNF);
            gmmreg_detach_cnf->detach_type = gmm_data->kern.detach_cap.detach_type;
          PSEND ( hCommMMI, gmmreg_detach_cnf );  
          break;
        }
        case GMMREG_DT_SOFT_OFF:
          SET_STATE ( KERN, KERN_GMM_NULL_IMSI );
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI );
#endif
          kern_mm_imsi_detach_ind (GMMCS_INT_NOT_PRESENT, /* TCS 2.1 */
                  GET_STATE(MM)==GMM_MM_DEREG?
                    MMGMM_DETACH_DONE:
                    MMGMM_PERFORM_DETACH,gmm_data->kern.detach_cap.detach_type);

          break;
        case GMMREG_DT_SIM_REMOVED:
        case GMMREG_DT_POWER_OFF:
          SET_STATE ( KERN, KERN_GMM_NULL_NO_IMSI );
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI );
#endif
          kern_mm_imsi_detach_ind (GMMCS_INT_NOT_PRESENT, /* TCS 2.1 */
                  GET_STATE(MM)==GMM_MM_DEREG?
                    MMGMM_DETACH_DONE:
                    MMGMM_PERFORM_DETACH,
                    gmm_data->kern.detach_cap.detach_type);

          break;
        case GMMREG_DT_DISABLE_GPRS:
          gmm_data->kern.attach_cap.mobile_class = GMMREG_CLASS_CC;
          {  
            PALLOC (gmmreg_detach_cnf, GMMREG_DETACH_CNF);
              gmmreg_detach_cnf->detach_type = gmm_data->kern.detach_cap.detach_type;
            PSEND ( hCommMMI, gmmreg_detach_cnf );  
          }
          break;
        default:
          TRACE_ERROR ("Unexpected detach type in primitive GMMREG_DETACH_REQ");
          break;
      }
      break;

    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
      kern_gmmrr_attach_finished();
    
      /* NO break; */

    case KERN_GMM_DEREG_NO_IMSI:
    case KERN_GMM_DEREG_PLMN_SEARCH:
    case KERN_GMM_DEREG_LIMITED_SERVICE:
    case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
    case KERN_GMM_DEREG_INITIATED:

    case KERN_GMM_DEREG_SUSPENDED:
    case KERN_GMM_DEREG_SUSPENDING:
      
      switch ( gmm_data->kern.detach_cap.detach_type )
      {
        case GMMREG_DT_IMSI:
        case GMMREG_DT_COMB:
          if ( GMM_MM_DEREG != GET_STATE(MM) )
          {
            switch ( GET_STATE( KERN ) )
            {
              case KERN_GMM_DEREG_SUSPENDING:
                gmm_data->kern.suspension_type |= GMM_SUSP_IMSI_DETACH;
                break;
              default:
                kern_imsi_detach_der_susp ();
                break;
            }
          }
          /* NO break;*/
        case GMMREG_DT_GPRS:
        {  
          PALLOC (gmmreg_detach_cnf, GMMREG_DETACH_CNF);
            gmmreg_detach_cnf->detach_type = gmm_data->kern.detach_cap.detach_type;
          PSEND ( hCommMMI, gmmreg_detach_cnf );  
          break;
        }
        case GMMREG_DT_SOFT_OFF:
          kern_local_detach( GMMCS_POWER_OFF, FALSE, GMM_LOCAL_DETACH_PROC_SOFT_OFF); /* TCS 2.1 */
          break;
        case GMMREG_DT_POWER_OFF:
          kern_local_detach( GMMCS_POWER_OFF, FALSE, GMM_LOCAL_DETACH_PROC_POWER_OFF); /* TCS 2.1 */
          break;
        case GMMREG_DT_DISABLE_GPRS:
        case GMMREG_DT_SIM_REMOVED:
          kern_local_detach( GMMCS_INT_PROTOCOL_ERROR, FALSE, /* TCS 2.1 */
            GMM_LOCAL_DETACH_PROC_ENTER_DEREG );
          break;
        default:
          TRACE_ERROR ("Unexpected detach type in primitive GMMREG_DETACH_REQ");
          break;
      }
      break;

    case KERN_GMM_RAU_INITIATED:
    case KERN_GMM_RAU_WAIT_FOR_NPDU_LIST:
      /*
       * DETACH whilst RAU
       */
      break;

    default:
      TRACE_ERROR( "GMMREG_DETACH_REQ unexpected" );
      break;
  }
  GMM_RETURN;
} /* kern_gmmreg_detach_req() */


/*
+------------------------------------------------------------------------------
| Function    : kern_gmmsms_reg_state_req
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMSMS_REG_STATE_REQ
|
|          MSC: 3.21 Interaction with SMS
|
| Parameters  : *gmmsms_reg_state_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmsms_reg_state_req ( T_GMMSMS_REG_STATE_REQ *gmmsms_reg_state_req )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmsms_reg_state_req" );

  PFREE (gmmsms_reg_state_req);
  {
    PALLOC ( gmmsms_reg_state_cnf, GMMSMS_REG_STATE_CNF );
    gmmsms_reg_state_cnf->radio_priority_level = 
      gmm_data->kern.attach_cap.sms_radio_priority_level;
    switch( GET_STATE( KERN ) )
    {
      case KERN_GMM_NULL_NO_IMSI:
      case KERN_GMM_NULL_IMSI:
      case KERN_GMM_DEREG_NO_IMSI:
      case KERN_GMM_REG_SUSPENDED:
      case KERN_GMM_REG_RESUMING:
      case KERN_GMM_DEREG_SUSPENDED:
      case KERN_GMM_DEREG_RESUMING:
      case KERN_GMM_DEREG_PLMN_SEARCH:
      case KERN_GMM_DEREG_LIMITED_SERVICE:
      case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
      case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
      case KERN_GMM_DEREG_INITIATED:
      case KERN_GMM_REG_INITIATED:
      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_RAU_INITIATED:
        
        gmmsms_reg_state_cnf->reg_state = SMS_RS_DEREGISTERED;
        break;
   
      case KERN_GMM_REG_NORMAL_SERVICE:
        
        gmmsms_reg_state_cnf->reg_state = SMS_RS_REGISTERED;
        break;
      default:
        TRACE_ERROR( "GMMSMS_REG_STATE_REQ unexpected" );
        break;
    }
    PSEND(hCommSMS,gmmsms_reg_state_cnf);
  }/* PALLOC*/
  GMM_RETURN;
} /* kern_gmmsms_reg_state_req() */



/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_page_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMRR_PAGE_IND
|
| Parameters  : *gmmrr_page_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_page_ind ( T_GMMRR_PAGE_IND *gmmrr_page_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmrr_page_ind" );

  
  switch( GET_STATE( KERN ) )
  {
    /* 
     * case GMM-DEREG
     * If the MS is not GPRS attached when it receives a paging for
     * GPRS services, the MS shall ignore the paging.
     * <R.GMM.PAGNGPRS.M.17> 
     */
    case KERN_GMM_REG_NORMAL_SERVICE:
      switch ( gmmrr_page_ind->page_id )
      {
        case GMMRR_IMSI:
          TRACE_EVENT("paged with IMSI");
          PFREE ( gmmrr_page_ind );
          gmm_data->gu                        = GU2_NOT_UPDATED;
          kern_sim_del_locigprs ();
          kern_sim_gmm_update ();
          /*
           * <R.GMM.PGPIMSI.M.004>, <R.GMM.PGPIMSI.M.005>,
           * <R.GMM.PGPIMSI.M.008>
           */
          gmm_data->kern.detach_cap.detach_type = GMM_DT_RE_ATTACH;
          kern_local_detach( GMMCS_INT_PROTOCOL_ERROR, /* TCS 2.1 */
          FALSE, GMM_LOCAL_DETACH_PROC_RE_ATTACH);
          /* 
           * goto LABEL ATTACH
           *
           * <R.GMM.PGPIMSI.M.009>
           * GMM-DEREG.NORMAL-SERVICE
           *
          kern_attach_reset();
          kern_attach();
           */
          break;
        case GMMRR_PTMSI:
          TRACE_EVENT("paged with P-TMSI");
          PFREE ( gmmrr_page_ind );
        {
          /* 
           * <R.GMM.PGPPTMS.M.007> 
           */
          PALLOC (llgmm_trigger_req, LLGMM_TRIGGER_REQ);
            llgmm_trigger_req->trigger_cause = LLGMM_TRICS_PAGE_RESPONSE;
          PSEND ( hCommLLC, llgmm_trigger_req );
          break;
        }
        default:
          PFREE ( gmmrr_page_ind );
          TRACE_ERROR( "IMSI or PTMSI page ID expected" );
          break;
      }
      break;
    default:
      PFREE ( gmmrr_page_ind );
      TRACE_ERROR( "GMMRR_PAGE_IND unexpected" );
      break;
  }
  GMM_RETURN;
} /* kern_gmmrr_page_ind() */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_cs_page_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMRR_CS_PAGE_IND
|
| Parameters  : *gmmrr_cs_page_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_cs_page_ind ( T_GMMRR_CS_PAGE_IND *gmmrr_cs_page_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmrr_cs_page_ind" );

  PFREE ( gmmrr_cs_page_ind );

  
  {
    PALLOC ( gmmrr_cs_page_res, GMMRR_CS_PAGE_RES );

    switch (gmm_data->kern.attach_cap.mobile_class)
    {
      case GMMRR_CLASS_CG:
        gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
        gmmrr_cs_page_res->susp_gprs = GMMRR_NOT_SUSP_GPRS;
        break;

/* PATCH JPS 26.10.02: with class BX, we can have BC in NMOIII */
      case GMMREG_CLASS_BG:
        if (GMMRR_NET_MODE_III==gmm_data->kern.sig_cell_info.net_mode)
        {
          gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
          gmmrr_cs_page_res->susp_gprs = GMMRR_NOT_SUSP_GPRS;
          break;
        }
        /* NO break; */
      case GMMREG_CLASS_BC:
      case GMMREG_CLASS_B:
/* PATCH JPS 26.10.02 END */
        switch( GET_STATE( KERN ) )
        {
          case KERN_GMM_DEREG_RESUMING:
          case KERN_GMM_REG_RESUMING:
            TRACE_ERROR ("prim should be saved by pei");
            break;
          case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
            gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = TRUE;
            /* NO break;*/
          case KERN_GMM_DEREG_NO_IMSI:
          case KERN_GMM_DEREG_SUSPENDED:
          case KERN_GMM_DEREG_LIMITED_SERVICE:
          
          case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
          case KERN_GMM_DEREG_PLMN_SEARCH:
          case KERN_GMM_DEREG_INITIATED:
          case KERN_GMM_REG_INITIATED:
            if (GMM_MM_DEREG != GET_STATE(MM)
            &&  MMGMM_LIMITED_SERVICE!=gmm_data->kern.sig_cell_info.mm_status
            )
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_CNF;
              SET_STATE ( KERN, KERN_GMM_DEREG_SUSPENDED );
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDED );
#endif
            }
            else
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
            }             
            gmmrr_cs_page_res->susp_gprs = GMMRR_NOT_SUSP_GPRS;
            break;
          case KERN_GMM_REG_SUSPENDED:
          case KERN_GMM_REG_LIMITED_SERVICE:
          case KERN_GMM_REG_NO_CELL_AVAILABLE:
            if (GMM_MM_DEREG != GET_STATE(MM)
            && MMGMM_LIMITED_SERVICE!=gmm_data->kern.sig_cell_info.mm_status)              
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_CNF;
              SET_STATE ( KERN, KERN_GMM_REG_SUSPENDED );
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDED );
#endif
              kern_llgmm_suspend(LLGMM_CALL);
            }
            else
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
            }              
            gmmrr_cs_page_res->susp_gprs = GMMRR_NOT_SUSP_GPRS;

            break;
          case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:
            if (GMM_MM_DEREG != GET_STATE(MM)
            &&  MMGMM_LIMITED_SERVICE!=gmm_data->kern.sig_cell_info.mm_status)
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_CNF;
              gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = TRUE;
              SET_STATE ( KERN, KERN_GMM_REG_SUSPENDED );
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDED );
#endif
              kern_llgmm_suspend(LLGMM_CALL);
            }
            else
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
            }
            gmmrr_cs_page_res->susp_gprs = GMMRR_SUSP_GPRS;
            /*
             * kern_llgmm_unassign();
             */
            break;
          case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
            /* IOT: Combined RA/LA is accepted with network cause 16
             * MSC temporarily unavailable. MM state is reset to GMM_MM_DEREG
             * From the IOT, it was observed that after GMM moves to NMOII, MM
             * was able to perform LAU successfully, but not combined RAU. Hence
             * in this state we should be able to make and receive CS calls
             * Also network is able to reach us through paging */
            if (/*GMM_MM_DEREG != GET_STATE(MM)
            && */ MMGMM_LIMITED_SERVICE!=gmm_data->kern.sig_cell_info.mm_status)
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_CNF;
              gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = TRUE;
              SET_STATE ( KERN, KERN_GMM_REG_SUSPENDED );
              kern_llgmm_suspend(LLGMM_CALL);
            }
            else
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
            }
            gmmrr_cs_page_res->susp_gprs = GMMRR_SUSP_GPRS;
            /*
             * kern_llgmm_unassign();
             */
            break;
          case KERN_GMM_RAU_INITIATED:
          case KERN_GMM_REG_NORMAL_SERVICE:
            if (GMM_MM_DEREG != GET_STATE(MM)
            && MMGMM_LIMITED_SERVICE!=gmm_data->kern.sig_cell_info.mm_status)
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_CNF;
              SET_STATE ( KERN, KERN_GMM_REG_SUSPENDED );
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDED );
#endif
              kern_llgmm_suspend(LLGMM_CALL);
            }
            else
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
            }
            gmmrr_cs_page_res->susp_gprs = GMMRR_SUSP_GPRS;
            /*
             * kern_llgmm_unassign();
             */
            break;
          case KERN_GMM_NULL_IMSI:
            /*
             * in state KERN_GMM_NULL_IMSI MS is doing a GPRS detach
             * and GMM has informed MM to act as GSM only mobile but
             * before MM processes the message, GMM receives CS_PAGE_IND
             * GMM must reject the CS_PAGE as MM will take care of the
             * next CS_PAGE_IND after processing MMGMM_REG_REQ to act as
             * GSM only mobile. if GMM accepts the CS_PAGE, GRR will be
             * suspended and after coming out of dedicated mode MM will
             * not inform GMM about CS connection release and GRR will
             * not be resumed. This is to prevent such a race condition.
             */

            TRACE_EVENT("CS Call Received To GMM In GMM_NULL_IMSI state");
            gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
            gmmrr_cs_page_res->susp_gprs = GMMRR_NOT_SUSP_GPRS;
            break;
          case KERN_GMM_NULL_PLMN_SEARCH:
            if (GMM_MM_DEREG != GET_STATE(MM)
            && MMGMM_LIMITED_SERVICE!=gmm_data->kern.sig_cell_info.mm_status)
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_CNF;
            }
            else
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
            }
            gmmrr_cs_page_res->susp_gprs = GMMRR_NOT_SUSP_GPRS;
            break;
          default:
            if (GMM_MM_DEREG != GET_STATE(MM)
            && MMGMM_LIMITED_SERVICE!=gmm_data->kern.sig_cell_info.mm_status)
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_CNF;
            }
            else
            {
              gmmrr_cs_page_res->response = GMMRR_CS_PAGE_REJ;
            }       
            gmmrr_cs_page_res->susp_gprs = GMMRR_NOT_SUSP_GPRS;
            TRACE_ERROR( "GMMRR_CS_PAGE_IND unexpected" );
            break;
        }  
        break;
      case GMMRR_CLASS_A:
      case GMMRR_CLASS_CC:
        gmmrr_cs_page_res->response = GMMRR_CS_PAGE_CNF;
        gmmrr_cs_page_res->susp_gprs = GMMRR_NOT_SUSP_GPRS; /* GMM1903A */
        break;
      default:
        TRACE_ERROR( "unknown MS class");
        break;
    }
    /* START PATCH UBUOB ISSUE 8379 */
    if (gmmrr_cs_page_res->response == GMMRR_CS_PAGE_CNF)
    {
      gmm_data->kern.gmmrr_resume_sent = FALSE;
    }
    /* END PATCH UBUOB ISSUES 8379 */
    PSEND ( hCommGRR, gmmrr_cs_page_res );
  }
  GMM_RETURN;
} /* kern_gmmrr_cs_page_ind() */

/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_cr_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMRR_CR_IND
|
| Parameters  : *gmmrr_cr_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_cr_ind ( T_GMMRR_CR_IND *gmmrr_cr_ind )
{     
  GMM_TRACE_FUNCTION( "kern_gmmrr_cr_ind" );

  PFREE ( gmmrr_cr_ind );
  if ( GMM_GRR_STATE_ON == gmm_data->kern.attach_cap.grr_state)
  /*
   * If GRR is suspended state should be kept.
   */
  {
    gmm_data->kern.attach_cap.grr_state = GMM_GRR_STATE_CR;
  }

  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_REG_INITIATED:
    case KERN_GMM_RAU_INITIATED:
      /*
       * store timer value to be able to restart timer after cell reselection
       */
      gmm_data->kern.attach_cap.t3310_value=0;
      if (VSI_OK == vsi_t_status ( GMM_handle , kern_T3310, &(gmm_data->kern.attach_cap.t3310_value))
      &&  gmm_data->kern.attach_cap.t3310_value>0)
      { 
        vsi_t_stop ( GMM_handle , kern_T3310);
      }
      
      TRACE_1_INFO ("TIMER t3310 = %dmsec stopped - waiting for CELL_IND",gmm_data->kern.attach_cap.t3310_value);
      break;
    default:
      break;
  }
  GMM_RETURN;
}/* kern_gmmrr_cr_ind */


/*
+------------------------------------------------------------------------------
| Function    : kern_cgrlc_status_ind (TCS 2.1)
+------------------------------------------------------------------------------
| Description : Handles the primitive CGRLC_STATUS_IND (TCS 2.1)
|
| Parameters  : *cgrlc_status_ind - Ptr to primitive payload (TCS 2.1)
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_cgrlc_status_ind ( T_CGRLC_STATUS_IND *cgrlc_status_ind ) /* TCS 2.1 */
{ 
  GMM_TRACE_FUNCTION( "kern_cgrlc_status_ind" ); /* TCS 2.1 */

  switch (cgrlc_status_ind->failure) /* TCS 2.1 */
  {
  case CGRLC_ACCESS_2_NETWORK_NOT_ALLOWED: /* TCS 2.1 */
    TRACE_EVENT ("Access to the network is not allowed");
    break;
  case CGRLC_PACKET_ACCESS_FAILURE: /* TCS 2.1 */
    TRACE_EVENT("Failure during packet access procedure, e.g. T3162 expired");
    break;
  case CGRLC_RLC_MAC_ERROR: /* TCS 2.1 */
    TRACE_EVENT("T3168 expires during contention resolution");
    break;
  case CGRLC_TLLI_MISMATCH: /* TCS 2.1 */
    TRACE_EVENT ("TLLI mismatch has occurred");
    break;
  case CGRLC_TBF_ESTABLISHMENT_FAILURE: /* TCS 2.1 */
    TRACE_EVENT ("T3164 expires or failure occurs due to any other reason");
    break;
  case CGRLC_RESUMPTION_FAILURE: /* TCS 2.1 */
    TRACE_EVENT ("resumption failure after dedicated mode was left");
    break;
  case CGRLC_CONTENTION_RESOLUTION_FAILED: /* TCS 2.1 */
    TRACE_EVENT ("Contantion Resolution has failed"); /* TCS 2.1 */
    break; /* TCS 2.1 */
  default:
    TRACE_ERROR ("unknown failure");
    break;
  }

  PFREE (cgrlc_status_ind); /* TCS 2.1 */
  
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_REG_INITIATED:
    case KERN_GMM_RAU_INITIATED:
      /************************************************************************
       * MSC: 3.8 Attach
       *
       * MSC: 3.8.1 Normal Attach
       * MSC: 3.8.1.4 Abnormal cases
       * MSC: 3.8.1.4.2 b) Lower layer failure before the ATTACH ACCEPT or
       *                   ATTACH REJECT 
       *                   message is received
       ************************************************************************
       *
       *<R.GMM.AGABNORM.M.004>, <R.GMM.LOWERFAIL.M.001>
       */
      kern_aac( /*llgmm_status_ind->error_cause*/ 0);
      break;
    case KERN_GMM_DEREG_INITIATED:
      /************************************************************************
       * MSC: 3.9 GPRS detach procedure
       *
       * MCS: 3.9.3 Abnormal cases
       * MSC: 3.9.3.2 b) Lower layer failure
       ************************************************************************/
      kern_local_detach ( GMMCS_INT_PROTOCOL_ERROR, FALSE, GMM_LOCAL_DETACH_PROC_ENTER_DEREG); /* TCS 2.1 */
      break;
    case KERN_GMM_REG_IMSI_DETACH_INITIATED:
      /* 
       * <R.GMM.DMABNORM.M.021> 
       */
      /************************************************************************
       * MSC: 3.9 GPRS detach procedure
       *
       * MCS: 3.9.3 Abnormal cases
       * MSC: 3.9.3.2 b) Lower layer failure
       ************************************************************************/
       gmm_data->kern.detach_cap.detach_type = GMMREG_DT_IMSI;
       kern_local_detach( GMMCS_INT_PROTOCOL_ERROR, FALSE, GMM_LOCAL_DETACH_PROC_ENTER_REG_NORMAL); /* TCS 2.1 */
       break;
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_DEREG_SUSPENDED:
    case KERN_GMM_REG_RESUMING:
    case KERN_GMM_REG_SUSPENDED:
      TRACE_ERROR( "CGRLC_STATUS_IND unexpected" ); /* TCS 2.1 */
      break;
    default:
      break;
  }
  GMM_RETURN;
} /* kern_cgrlc_status_ind() */ /* TCS 2.1 */
/*
+------------------------------------------------------------------------------
| Function    : kern_llgmm_status_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive LLGMM_STATUS_IND
|
| Parameters  : *llgmm_status_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_llgmm_status_ind ( T_LLGMM_STATUS_IND *llgmm_status_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_llgmm_status_ind" );

  PFREE (llgmm_status_ind);
  
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_REG_INITIATED:
    case KERN_GMM_RAU_INITIATED:
      /************************************************************************
       * MSC: 3.8 Attach
       *
       * MSC: 3.8.1 Normal Attach
       * MSC: 3.8.1.4 Abnormal cases
       * MSC: 3.8.1.4.2 b) Lower layer failure before the ATTACH ACCEPT or
       *                   ATTACH REJECT 
       *                   message is received
       ************************************************************************
       *
       *<R.GMM.AGABNORM.M.004>, <R.GMM.LOWERFAIL.M.001>
       */
      kern_aac( /*llgmm_status_ind->error_cause*/ GMMCS_NO_SERVICE); /* TCS 2.1 */
      break;
    case KERN_GMM_DEREG_INITIATED:
      /************************************************************************
       * MSC: 3.9 GPRS detach procedure
       *
       * MCS: 3.9.3 Abnormal cases
       * MSC: 3.9.3.2 b) Lower layer failure
       ************************************************************************/
       kern_local_detach( GMMCS_INT_PROTOCOL_ERROR, FALSE, GMM_LOCAL_DETACH_PROC_ENTER_DEREG); /* TCS 2.1 */
       break;
    case KERN_GMM_REG_IMSI_DETACH_INITIATED:
      /* 
       * <R.GMM.DMABNORM.M.021> 
       */
      /************************************************************************
       * MSC: 3.9 GPRS detach procedure
       *
       * MCS: 3.9.3 Abnormal cases
       * MSC: 3.9.3.2 b) Lower layer failure
       ************************************************************************/
       gmm_data->kern.detach_cap.detach_type = GMMREG_DT_IMSI;
       kern_local_detach( GMMCS_INT_PROTOCOL_ERROR, FALSE, GMM_LOCAL_DETACH_PROC_ENTER_REG_NORMAL); /* TCS 2.1 */
      
       break;
    default:
      TRACE_ERROR( "LLGMM_STATUS_IND unexpected" );
      break;
  }
  GMM_RETURN;
} /* kern_llgmm_status_ind() */

/*
+------------------------------------------------------------------------------
| Function    : kern_llgmm_tlli_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive LLGMM_TLLI_IND
|
| Parameters  : *llgmm_status_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_llgmm_tlli_ind ( T_LLGMM_TLLI_IND *llgmm_tlli_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_llgmm_tlli_ind" );
  TRACE_1_PARA ("TLLI: 0x%x", llgmm_tlli_ind->new_tlli);

  GMM_TRACE_GMM_DATA(GMM_DEBUG_PRINT_MASK_TLLI);
  
  switch( GET_STATE( KERN ) )
  {
    default:
    case KERN_GMM_NULL_NO_IMSI:
    case KERN_GMM_NULL_IMSI:
    case KERN_GMM_NULL_PLMN_SEARCH:
    case KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ:
    case KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ:
      TRACE_ERROR("LLGMM_TLLI_IND unexpected");
      break;

    case KERN_GMM_DEREG_INITIATED:
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
    case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
    case KERN_GMM_DEREG_LIMITED_SERVICE:
    case KERN_GMM_DEREG_NO_IMSI:
    case KERN_GMM_DEREG_PLMN_SEARCH:
    case KERN_GMM_DEREG_SUSPENDED:
    case KERN_GMM_REG_INITIATED:
    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_ATTEMPTING_TO_UPDATE:
    case KERN_GMM_REG_SUSPENDED:
    case KERN_GMM_REG_NORMAL_SERVICE:
    case KERN_GMM_RAU_INITIATED:
    case KERN_GMM_RAU_WAIT_FOR_NPDU_LIST:
    case KERN_GMM_REG_IMSI_DETACH_INITIATED:
    case KERN_GMM_REG_RESUMING:
    case KERN_GMM_DEREG_SUSPENDING:
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_REG_SUSPENDING:
    case KERN_GMM_REG_TEST_MODE:
    case KERN_GMM_REG_TEST_MODE_NO_IMSI:

      if ( llgmm_tlli_ind->new_tlli != gmm_data->tlli.current)
      {
         TRACE_ERROR("TLLI value not expected");
      }
      
      TRACE_0_OUT_PARA("Unassign Old PTMSI");
        
      gmm_data->tlli.old  = GMMRR_TLLI_INVALID;
      gmm_data->ptmsi.old = GMMRR_TMSI_INVALID;
  
      GMM_TRACE_GMM_DATA(GMM_DEBUG_PRINT_MASK_TLLI | GMM_DEBUG_PRINT_MASK_PTMSI);
      /*
       * LLC should know about unassigning itself
       */
      kern_gmmrr_assign();
      break;
  }

  PFREE (llgmm_tlli_ind);

  GMM_RETURN;
} /* kern_llgmm_tlli_ind() */

/*
+------------------------------------------------------------------------------
| Function    : kern_sim_gmm_insert_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive SIM_GMM_INSERT_IND
|      
|               MSC: 3.2   SIM
|
| Parameters  : *sim_gmm_insert_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_sim_gmm_insert_ind ( T_SIM_GMM_INSERT_IND *sim_gmm_insert_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_sim_gmm_insert_ind" );
  /*
   * Set IMSI
   */

  kern_read_imsi ( sim_gmm_insert_ind ) ;

  GMM_TRACE_GMM_DATA(GMM_DEBUG_PRINT_MASK_IMSI);

  kern_read_loc_info (sim_gmm_insert_ind);

  GMM_TRACE_GMM_DATA(GMM_DEBUG_PRINT_MASK_CID);
  GMM_TRACE_GMM_DATA(GMM_DEBUG_PRINT_MASK_KERN_ATTACH);

  gmm_data->acc_contr_class = sim_gmm_insert_ind->acc_ctrl.acc[0] * 256 +
                               sim_gmm_insert_ind->acc_ctrl.acc[1];
  gmm_data->kern.sim_op_mode = sim_gmm_insert_ind->op_mode;
  kern_read_kc_cksn   (sim_gmm_insert_ind);

  PFREE ( sim_gmm_insert_ind );

  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_NULL_NO_IMSI:
    case KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ:
    case KERN_GMM_DEREG_NO_IMSI:
      /*
       *  MSC: 3.2   SIM
       *
       *  MSC: 3.2.1 SIM is inserted and valid
       */
      /*
       * SIM is considered as invalid until SIM removed or switching off
       */
      gmm_data->sim_gprs_invalid = FALSE;
      /*
       * reset the attach attampt counter and the rau attempt counter
       * <R.GMM.ATTACH.M.007>
       */
      gmm_data->kern.aac = 0;

      switch( GET_STATE( KERN ) )
      {
        case KERN_GMM_NULL_NO_IMSI:
          /* 
           * <R.GMM.DOTHCASE.M.001>
           * SET_STATE ( KERN, KERN_GMM_DEREG_PLMN_SEARCH );
           *
           * state GMM-DEREGISTERED.IMSI discribes the state GMM-NULL.IMSI-VALID
           */
       
          SET_STATE ( KERN, KERN_GMM_NULL_IMSI );
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI );
#endif
          break;
        case KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ:
          SET_STATE (KERN, KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);
#endif
          break;
        case KERN_GMM_DEREG_NO_IMSI:
          /*
           * GMM enters state NULL_IMSI beause GMM is waiting for a new attach 
           * prim from GACI (COPS=0)
           */
          SET_STATE ( KERN, KERN_GMM_NULL_IMSI );
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI );
#endif
          break;
        default:
          TRACE_ERROR( "State unexpected" );
          break;
      }
      break;
    default:
      TRACE_ERROR( "SIM_GMM_INSERT_IND unexpected" );
      break;
  }
  GMM_RETURN;
} /* kern_sim_gmm_insert_ind() */



/*
+------------------------------------------------------------------------------
| Function    : kern_sim_remove_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive SIM_REMOVE_IND
|
| Parameters  : *sim_remove_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_sim_remove_ind ( T_SIM_REMOVE_IND *sim_remove_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_sim_remove_ind" );

  PFREE ( sim_remove_ind );

  gmm_data->sim_gprs_invalid = TRUE;
  gmm_data->kern.detach_cap.detach_type = GMMREG_DT_SIM_REMOVED;
  /*
   * multiple outstanding SIM_AUTHENTICATION_REQ messages reset the 
   * counter whenever SIM is removed
   */
  gmm_data->kern.auth_cap.last_auth_req_id = NOT_PRESENT_8BIT;
  
  switch( GET_STATE( KERN ) )
  {
    /*
     * MSC: 3.2 SIM
     *
     * MSC: 3.2.2. No SIM present or SIM not valid
     * MSC: 3.2.2.2 State GMM-REG
     */

    /*
     * MSC: 3.2.2.2.1 Network not reachable
     * state GMM_REG
     */
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_DEREG_SUSPENDED:
    case KERN_GMM_REG_RESUMING:
    case KERN_GMM_REG_SUSPENDED:
      if (GMM_GRR_STATE_SUSPENDED==gmm_data->kern.attach_cap.grr_state)
      /*
       * wait for MMGMM_CM_RELEASE_IND
       */
      {
        break;
      }
      /* NO break;*/
    case KERN_GMM_REG_LIMITED_SERVICE:
    case KERN_GMM_REG_NO_CELL_AVAILABLE:
    {
      kern_local_detach (GMMCS_SIM_REMOVED, FALSE,GMM_LOCAL_DETACH_PROC_SIM_REMOVED); /* TCS 2.1 */
      break;
    }
    case KERN_GMM_REG_TEST_MODE:  
      {
        PALLOC (cgrlc_test_end_req, CGRLC_TEST_END_REQ); /* TCS 2.1 */
        SET_STATE (KERN, KERN_GMM_REG_TEST_MODE_NO_IMSI);
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_REG_TEST_MODE_NO_IMSI);
#endif
        PSEND (hCommGRLC, cgrlc_test_end_req); /* TCS 2.1 */
       }
      break;
    /*
     * MSC: 3.2.2.2.2 Network reachable
     * state GMM_REG.NORMAL_SERVICE
     */
    case KERN_GMM_RAU_INITIATED:
    case KERN_GMM_RAU_WAIT_FOR_NPDU_LIST:
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:
    case KERN_GMM_REG_NORMAL_SERVICE:
      /*
       * <R.GMM.DSUBFANO.M.003>
       */
 
      kern_detach ();
      break;
    /*
     * MSC: 3.2 SIM
     *
     * MSC: 3.2.2. No SIM present or SIM not valid
     * MSC: 3.2.2.1 State GMM-DEREG
     */

    /*
     * state GMM_DEREG
     */
    case KERN_GMM_DEREG_PLMN_SEARCH:
    case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
    case KERN_GMM_DEREG_LIMITED_SERVICE:
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
    case KERN_GMM_REG_INITIATED:
    case KERN_GMM_DEREG_INITIATED:

      kern_mm_imsi_detach_ind ( GMMCS_SIM_REMOVED, MMGMM_PERFORM_DETACH,
                                gmm_data->kern.detach_cap.detach_type); /* TCS 2.1 */
      /*
       * <R.GMM.ODNOIMSI.M.001>
       */
      SET_STATE ( KERN, KERN_GMM_DEREG_NO_IMSI );
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_DEREG_NO_IMSI );
#endif
      break;
    
    case KERN_GMM_NULL_IMSI:
    
      kern_mm_imsi_detach_ind ( GMMCS_SIM_REMOVED, MMGMM_PERFORM_DETACH,
                                gmm_data->kern.detach_cap.detach_type  );  /* TCS 2.1 */
      /*
       * <R.GMM.ODNOIMSI.M.001>
       */
      SET_STATE ( KERN, KERN_GMM_NULL_NO_IMSI );
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI );
#endif
      break;

    default:
      kern_mm_imsi_detach_ind ( GMMCS_SIM_REMOVED, MMGMM_PERFORM_DETACH,
                                gmm_data->kern.detach_cap.detach_type); /* TCS 2.1 */
      TRACE_ERROR( "SIM_REMOVE_IND unexpected" );
      break;
  }
  GMM_RETURN;
} /* kern_sim_remove_ind() */


/*
+------------------------------------------------------------------------------
| Function    : kern_gmmrr_suspend_cnf
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMRR_SUSPEND_CNF
|
|               GRR confirms that GRR is successful suspended and RR is
|               activated.
|
| Parameters  : *gmmrr_suspend_cnf - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmrr_suspend_cnf ( T_GMMRR_SUSPEND_CNF *gmmrr_suspend_cnf )
{ 
  GMM_TRACE_FUNCTION( "kern_gmmrr_suspend_cnf" );
  PFREE(gmmrr_suspend_cnf);
  gmm_data->kern.attach_cap.grr_state = GMM_GRR_STATE_SUSPENDED;

  TRACE_1_PARA ("susp_type: %x", gmm_data->kern.suspension_type);
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_DEREG_SUSPENDING:
      SET_STATE (KERN, KERN_GMM_DEREG_SUSPENDED);
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDED);
#endif
     if(gmm_data->kern.detach_cap.detach_type EQ GMMREG_DT_GPRS)
     	{
        if ( GET_STATE(MM) != GMM_MM_REG_NORMAL_SERVICE)
            /*
                      * The state of MM is forwarded to MMI 
                      */
            {
              gmm_data->kern.detach_cap.detach_type = GMMREG_DT_COMB;  
            }
            if ( kern_lau_needed())
            {
              /* 
                          * see also kern_enter_der ()
                          */
              kern_gmmreg_detach (gmm_data->kern.detach_cap.detach_type, GMMCS_INT_NOT_PRESENT,
                                GMMREG_SEARCH_RUNNING, GMMCS_INT_NOT_PRESENT);
            }
            else
            {
              kern_gmmreg_detach (gmm_data->kern.detach_cap.detach_type, GMMCS_INT_NOT_PRESENT,
                                GMMREG_SEARCH_NOT_RUNNING,GMMCS_INT_NOT_PRESENT);
            }
     	}

      kern_call_undone_mm_proc_der();
      break;

    case KERN_GMM_REG_SUSPENDING:
      SET_STATE (KERN, KERN_GMM_REG_SUSPENDED);
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDED);
#endif
      kern_call_undone_mm_proc_reg();
      break;

    case KERN_GMM_NULL_NO_IMSI:
      kern_local_detach ( GMMCS_POWER_OFF,    /* TCS 2.1 */
        FALSE, GMM_LOCAL_DETACH_PROC_NOTHING);
      break;
    default:
      TRACE_ERROR( "GMMRR_SUSPNED_CNF unexpected" );
      break;
  }
  GMM_RETURN;
} /* kern_gmmrr_suspend_cnf() */
/*
+------------------------------------------------------------------------------
| Function    : kern_cgrlc_test_mode_cnf (TCS 2.1)
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMRR_SUSPEND_CNF
|
|               GRR confirms that the test mode is finished
|
| Parameters  : *cgrlc_test_mode_cnf - Ptr to primitive payload (TCS 2.1)
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_cgrlc_test_mode_cnf ( T_CGRLC_TEST_MODE_CNF *cgrlc_test_mode_cnf ) /* TCS 2.1 */
{ 
  GMM_TRACE_FUNCTION( "kern_cgrlc_test_mode_cnf" ); /* TCS 2.1 */
  PFREE (cgrlc_test_mode_cnf); /* TCS 2.1 */

  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_REG_TEST_MODE:
      kern_enter_reg_normal();
      break;
    case KERN_GMM_REG_TEST_MODE_NO_IMSI:
      /*
       * <R.GMM.DSUBFANO.M.003>
       */

      gmm_data->kern.detach_cap.detach_type = GMMREG_DT_SIM_REMOVED;
      kern_detach ();
      break;
    default:
      TRACE_ERROR( "CGRLC_TEST_MODE_CNF unexpected" ); /* TCS 2.1 */
      break;
  }
  GMM_RETURN;
} /* kern_cgrlc_test_mode_cnf() */ /* TCS 2.1 */

/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_lup_needed_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive MMGMM_LUP_NEEDED_IND
|
|          MSC: 3.20.8 MMGMM LUP NEEDED IND
|
| Parameters  : *mmgmm_lup_needed_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_lup_needed_ind ( T_MMGMM_LUP_NEEDED_IND *mmgmm_lup_needed_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_lup_needed_ind" );
#ifndef NTRACE
  switch (mmgmm_lup_needed_ind->reason) /* TCS 2.1 */
  {
    case MMGMM_T3212:
      TRACE_EVENT("T3212 has expired");
      break;
    case MMGMM_T_ACCEPT:
      TRACE_EVENT("T_ACCEPT has expired");
      break;
    case MMGMM_IMSI_IN_VLR:
      TRACE_EVENT("IMSI unknown in VLR received");
      break;
    case MMGMM_RXLEV_JUMP:
      TRACE_EVENT("RR indicated an increased RX level");
      break;
    case MMGMM_REG_TIMER:
      TRACE_EVENT("Registration timer in MM expired");
      break;
    default:
      TRACE_ERROR("GPRS indicator is out of range");
      break;
  }
#endif
  switch (GET_STATE( KERN ))
  {
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_DEREG_SUSPENDED:
    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_DEREG_INITIATED:
    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_SUSPENDING:
    case KERN_GMM_REG_NO_CELL_AVAILABLE:
      break;
    default:
      if( GMMRR_NET_MODE_I==gmm_data->kern.sig_cell_info.net_mode
      &&  MMGMM_T3212==mmgmm_lup_needed_ind->reason) /* TCS 2.1 */
      /*
       * <R.GMM.MMGMMONE.M.002>, <R.GMM.MMGMMONE.M.003>
       */
      {
        PFREE (mmgmm_lup_needed_ind);
        GMM_RETURN;  
      }
      break;
  }


  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:
      /*
       * After deregistration MM will receive mmgmm_reg_req
       * automatically
       */
      break;
    case KERN_GMM_DEREG_NO_IMSI:
      /* PLU also if #7 */
      /*NO break;*/
    case KERN_GMM_DEREG_PLMN_SEARCH:    

    case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
    case KERN_GMM_DEREG_LIMITED_SERVICE:
    case KERN_GMM_REG_INITIATED:
      SET_STATE ( KERN, KERN_GMM_DEREG_SUSPENDING );
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDING );
#endif
      kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LAU);  
      break;

    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
      gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = TRUE;
      SET_STATE ( KERN, KERN_GMM_DEREG_SUSPENDING );
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDING );
#endif
      kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LAU);  
      break;
    case KERN_GMM_DEREG_INITIATED:
    case KERN_GMM_DEREG_RESUMING:      
    case KERN_GMM_DEREG_SUSPENDED:
    case KERN_GMM_REG_SUSPENDED:
    case KERN_GMM_REG_RESUMING:
    case KERN_GMM_RAU_INITIATED:
    case KERN_GMM_RAU_WAIT_FOR_NPDU_LIST:
    case KERN_GMM_REG_IMSI_DETACH_INITIATED:
      SET_STATE(MM, GMM_MM_REG_UPDATE_NEEDED);
      break;
      
    case KERN_GMM_REG_SUSPENDING:
    case KERN_GMM_DEREG_SUSPENDING:
      gmm_data->kern.suspension_type |= GMM_SUSP_LAU;
      break;

    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:
      gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau=TRUE;
      SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING );
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING );
#endif
      kern_llgmm_suspend(LLGMM_CALL);
      kern_gmmrr_suspend (GMMRR_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LAU);  
      break;
    case KERN_GMM_REG_LIMITED_SERVICE:
    case KERN_GMM_REG_NO_CELL_AVAILABLE:
      if(gmm_data->kern.gmmrr_resume_sent)
      /*
       * GMM is waiting for GMMRR_CELL_IND. So I rememmber to attach MM with
       * seting mm_imsi_attached to update_needed
       */
      {
        SET_STATE(MM,GMM_MM_REG_UPDATE_NEEDED);        
      }
      else
      {
        SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING );
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING );
#endif
        kern_llgmm_suspend(LLGMM_CALL);
        kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LAU);  
      }
      break;
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
    case KERN_GMM_REG_NORMAL_SERVICE:
      if( GMMRR_NET_MODE_I==gmm_data->kern.sig_cell_info.net_mode)
      {
        kern_rau();
      }
      else
      {
        SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING );
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING );
#endif
        kern_llgmm_suspend(LLGMM_CALL);
        kern_gmmrr_suspend (GMMRR_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LAU);  
      }
      break;
    case KERN_GMM_REG_TEST_MODE_NO_IMSI:
    case KERN_GMM_REG_TEST_MODE:
      break;
    default:
      TRACE_ERROR ("Unexpexcted state");   
      break;
  }
  
  PFREE (mmgmm_lup_needed_ind);
  GMM_RETURN;  
} /* kern_mmgmm_lup_needed_ind() */


/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_lup_accept_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive MMGMM_LUP_ACCEPT_IND
|
|          MSC: 3.20.3 IMSI attach/detach
|
| Parameters  : *mmgmm_lup_accept_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_lup_accept_ind ( T_MMGMM_LUP_ACCEPT_IND *mmgmm_lup_accept_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_lup_accept_ind" );
 
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_NULL_PLMN_SEARCH:
    case KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ:
    case KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ:
    case KERN_GMM_NULL_NO_IMSI:
    
    case KERN_GMM_NULL_IMSI:
    case KERN_GMM_DEREG_NO_IMSI:
    case KERN_GMM_DEREG_LIMITED_SERVICE:
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
    case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
    case KERN_GMM_DEREG_PLMN_SEARCH:
    case KERN_GMM_REG_INITIATED:

    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_DEREG_SUSPENDED:
    case KERN_GMM_DEREG_SUSPENDING:
      if ( GMMRR_NET_MODE_III==gmm_data->kern.sig_cell_info.net_mode
      && GMMREG_CLASS_BC==  gmm_data->kern.attach_cap.mobile_class )
      {
        kern_mmgmmreg_attach_cnf (GMMREG_AT_IMSI, SEARCH_NOT_RUNNING, (T_MMGMM_REG_CNF*)mmgmm_lup_accept_ind);
      }
      else
      {
        kern_mmgmmreg_attach_cnf (GMMREG_AT_IMSI, SEARCH_RUNNING, (T_MMGMM_REG_CNF*)mmgmm_lup_accept_ind);
      }
      break;                                      
    case KERN_GMM_REG_NORMAL_SERVICE:
    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_DEREG_INITIATED:
    case KERN_GMM_RAU_INITIATED:

    case KERN_GMM_REG_RESUMING:
    case KERN_GMM_REG_SUSPENDED:
      kern_mmgmmreg_attach_cnf (GMMREG_AT_COMB, SEARCH_RUNNING, (T_MMGMM_REG_CNF*)mmgmm_lup_accept_ind);
      break;
    default:
      TRACE_ERROR ("Unexpexcted state");   
      break;
  }
  PFREE ( mmgmm_lup_accept_ind );
  GMM_RETURN;  
} /* kern_mmgmm_lup_accept_ind() */
/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_lup_accept_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive MMGMM_INFO_IND
|
|          MSC: 3.20.6 MM Information
|
| Parameters  : *mmgmm_info_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_info_ind ( T_MMGMM_INFO_IND *mmgmm_info_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_info_ind" );
  {
    PPASS (mmgmm_info_ind, gmmreg_info_ind, GMMREG_INFO_IND);
    PSEND ( hCommMMI, gmmreg_info_ind );
  }  
  GMM_RETURN;
} /* kern_mmgmm_info_ind() */

/*
+------------------------------------------------------------------------------
| Function    : kern_sim_authentication_cnf
+------------------------------------------------------------------------------
| Description : The function kern_sim_authentication_cnf
|       
| Parameters  : *sim_authentication_cnf - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_sim_authentication_cnf ( T_SIM_AUTHENTICATION_CNF *
                                        sim_authentication_cnf )
{ 
  GMM_TRACE_FUNCTION( "kern_sim_authentication_cnf" );
  
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_REG_NORMAL_SERVICE:
    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_INITIATED:
    case KERN_GMM_DEREG_INITIATED:
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
    case KERN_GMM_RAU_INITIATED:
    case KERN_GMM_REG_IMSI_DETACH_INITIATED: 
      /*
       * PATCH ubuob 19.7.02: multiple outstanding AUTHENTICATION REQ messages
       * reduce the count of outstanding requests
       */

      /*
       * only use this SIM answer if there are no other outstanding SIM_AUTHENTICATION_REQ messages!
       */

      if (gmm_data->kern.auth_cap.last_auth_req_id == sim_authentication_cnf->req_id)


      if (gmm_data->kern.auth_cap.last_auth_req_id == sim_authentication_cnf->req_id)
      {
         MCAST (authentication_and_ciphering_response,
          AUTHENTICATION_AND_CIPHERING_RESPONSE);
            authentication_and_ciphering_response->a_c_reference_number
            .a_c_reference_number_value 
            = gmm_data->kern.auth_cap.a_c_reference_number;
        
          authentication_and_ciphering_response
           ->v_authentication_parameter_sres = TRUE;
          authentication_and_ciphering_response
            ->authentication_parameter_sres.sres_value.l_sres_value = MAX_SRES*8;
          authentication_and_ciphering_response
            ->authentication_parameter_sres.sres_value.o_sres_value = 0;
          memcpy (authentication_and_ciphering_response->
            authentication_parameter_sres.sres_value.b_sres_value, 
            sim_authentication_cnf->sres, MAX_SRES);  
        
          memcpy ( gmm_data->kern.auth_cap.kc, sim_authentication_cnf->kc,
            MAX_KC ) ;
        
#ifdef GMM_TCS4
        gmm_data->kern.auth_cap.last_auth_req_id = NOT_PRESENT_8BIT;
#endif
          
        PFREE (sim_authentication_cnf);
        /*
         * <R.GMM.AUTH_RES.M.006>
         */
        {
          PALLOC ( llgmm_assign_req, LLGMM_ASSIGN_REQ );
            llgmm_assign_req->old_tlli = LLGMM_TLLI_INVALID;
            llgmm_assign_req->new_tlli = gmm_data->tlli.current;
            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 
              = gmm_data->kern.auth_cap.ciphering_algorithm;
      
          PSEND ( hCommLLC, llgmm_assign_req );
        }
        
        
        if (IMEISV_REQUESTED == gmm_data->kern.auth_cap.imeisv_requested)
        {
          authentication_and_ciphering_response->v_gmobile_identity = TRUE;
          kern_get_imeisv (
            &authentication_and_ciphering_response->gmobile_identity);
        }
        else
        {
          authentication_and_ciphering_response->v_gmobile_identity = FALSE;     
        }
        sig_kern_tx_data_req (CURRENT_TLLI,AUTHENTICATION_AND_CIPHERING_RESPONSE);
      }
      else
      {  
        PFREE (sim_authentication_cnf);
         /* 
          * mutliple  authentication request problem occurred!!!!
          * ignore this SIM answer because another request has already been sent to
          * the SIM again and this overwrote the A&C reference number
          */
         TRACE_0_INFO ("error: Authentication received twice, SIM ignored");
      }
      /* end patch ubuob */
      break;

    default:

      PFREE (sim_authentication_cnf);
      TRACE_1_INFO ("state: %x", GET_STATE( KERN ));
      TRACE_ERROR("A&C RES unexpected");
      break;
  }
  GMM_RETURN;    
} /* kern_sim_authentication_cnf() */


/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_nreg_cnf
+------------------------------------------------------------------------------
| Description : Handles the primitive MMGMM_NREG_CNF
|
|          MSC: 3.20.3 IMSI attach/detach
|
| Parameters  : *mmgmm_nreg_cnf - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_nreg_cnf ( T_MMGMM_NREG_CNF *mmgmm_nreg_cnf )
{ 
  UBYTE detach_type;
  GMM_TRACE_FUNCTION( "kern_mmgmm_nreg_cnf" );

  if (gmm_data->kern.attach_cap.mobile_class_changed
  && GMM_GRR_STATE_ON == gmm_data->kern.attach_cap.grr_state)
  {
    gmm_data->kern.attach_cap.mobile_class_changed=FALSE;
    kern_gmmrr_enable();
  }

  switch (mmgmm_nreg_cnf->detach_cause) /* TCS 2.1 */
  {
    case CS_SIM_REM:
      detach_type = GMMREG_DT_SIM_REMOVED;
      TRACE_EVENT ("SIM is removed");
      break;
    case CS_POW_OFF:
      detach_type = GMMREG_DT_POWER_OFF;
      TRACE_EVENT ("Power is switched off");
      break;
    case CS_SOFT_OFF:
      detach_type = GMMREG_DT_SOFT_OFF;
      TRACE_EVENT ("Power is soft switched off");
      break;      
    case CS_DISABLE:
      detach_type = GMMREG_DT_IMSI;
      TRACE_EVENT ("GSM switched off");
      break;
    default:
      detach_type = GMMREG_DT_POWER_OFF;
      TRACE_EVENT ("unknown detach type in MMGMM_NREG_CNF");
      break;
  }
  SET_STATE( MM, GMM_MM_DEREG );
  sig_kern_sync_set_mm_state(MMGMM_CELL_SELECTED);

  if (gmm_data->sim_gprs_invalid && gmm_data->kern.cell_id.lac  == GMMREG_LA_INVALID && mmgmm_nreg_cnf->detach_cause == CS_SIM_REM)
  {
      switch ( GET_STATE (KERN) )
      {
          case KERN_GMM_DEREG_PLMN_SEARCH:
          case KERN_GMM_DEREG_SUSPENDED:
             SET_STATE(KERN,KERN_GMM_DEREG_NO_IMSI);
#ifdef FF_EM_MODE
             EM_GMM_SET_STATE(KERN_GMM_DEREG_NO_IMSI);
#endif
             break;
          case KERN_GMM_REG_IMSI_DETACH_INITIATED:
             kern_enter_reg_normal();
             break;
          case KERN_GMM_DEREG_NO_IMSI:
             SET_STATE(KERN,KERN_GMM_NULL_NO_IMSI);
#ifdef FF_EM_MODE
             EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI);
#endif
             break;
          default:
              break;
      }
      PFREE ( mmgmm_nreg_cnf );
      GMM_RETURN;
  }
  switch ( GET_STATE (KERN) )
  {
    case KERN_GMM_DEREG_PLMN_SEARCH:
      switch(mmgmm_nreg_cnf->detach_cause) /* TCS 2.1 */
      {
        case CS_SOFT_OFF:
        case CS_POW_OFF:
          kern_gmmreg_detach (GMMREG_DT_POWER_OFF,
                              GMMCS_POWER_OFF, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_POWER_OFF);
          break;
        case CS_SIM_REM:
          SET_STATE(KERN,KERN_GMM_DEREG_NO_IMSI);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_DEREG_NO_IMSI);
#endif
          kern_gmmreg_detach (GMMREG_DT_SIM_REMOVED,
                              GMMCS_SIM_REMOVED, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_SIM_REMOVED);
          break;
        default:
          kern_gmmreg_detach (GMMREG_DT_COMB,
                              /* START UBUOB PATCH ISSUE 8381 */
                              GMMCS_NET_CAUSE_NOT_PRESENT, /* TCS 2.1 */
                              /* END UBUOB PATCH ISSUE 8381 */
                              SEARCH_RUNNING,
                              GMMCS_NET_CAUSE_NOT_PRESENT);
          kern_mm_activate_rr();
          break;
      }

      break;

    case KERN_GMM_NULL_NO_IMSI:
    case KERN_GMM_NULL_IMSI:
      /*
       * POWER OFF
       */
      if( CS_DISABLE==mmgmm_nreg_cnf->detach_cause) /* TCS 2.1 */
      {
        detach_type=GMMREG_DT_IMSI;
      }
      kern_gmmreg_detach (detach_type,
                              gmm_data->kern.detach_cap.error_cause, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              gmm_data->kern.detach_cap.error_cause);                          
          
      break;
    case KERN_GMM_DEREG_SUSPENDED:
      switch(mmgmm_nreg_cnf->detach_cause) /* TCS 2.1 */
      {
        case CS_SOFT_OFF:
          kern_gmmreg_detach (GMMREG_DT_SOFT_OFF,
                              GMMCS_POWER_OFF, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_POWER_OFF);
          break;
        case CS_POW_OFF:
          kern_gmmreg_detach (GMMREG_DT_POWER_OFF,
                              GMMCS_POWER_OFF, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_POWER_OFF);
          break;
        case CS_SIM_REM:
          SET_STATE(KERN,KERN_GMM_DEREG_NO_IMSI);
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_DEREG_NO_IMSI);
#endif
          kern_gmmreg_detach (GMMREG_DT_SIM_REMOVED,
                              GMMCS_SIM_REMOVED, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_SIM_REMOVED);
          break;
        default:
          /* ACI can not handle SEARCH RUNNING to show GSM detached */
          if (GMMRR_NET_MODE_III==gmm_data->kern.sig_cell_info.net_mode
          && GMMREG_CLASS_BG==  gmm_data->kern.attach_cap.mobile_class )
          {
            kern_gmmreg_detach (GMMREG_DT_COMB,
                              GMMCS_NET_CAUSE_NOT_PRESENT, /* TCS 2.1 */
                              SEARCH_RUNNING,
                              GMMCS_NET_CAUSE_NOT_PRESENT);
          }
          else
          { 
            kern_gmmreg_detach (GMMREG_DT_COMB,
                              GMMCS_NET_CAUSE_NOT_PRESENT, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_NET_CAUSE_NOT_PRESENT);
          }
          break;
      }
      kern_call_undone_mm_proc_der();
      break;
    case KERN_GMM_REG_SUSPENDED:
      switch(mmgmm_nreg_cnf->detach_cause) /* TCS 2.1 */
      {
        case CS_SOFT_OFF:
             kern_gmmreg_detach (GMMREG_DT_SOFT_OFF,
                              GMMCS_POWER_OFF, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_POWER_OFF);
          break;
        case CS_POW_OFF:
          kern_gmmreg_detach (GMMREG_DT_POWER_OFF,
                              GMMCS_POWER_OFF, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_POWER_OFF);
          break;
        case CS_DISABLE:
          if (GMMREG_DT_IMSI == gmm_data->kern.detach_cap.detach_type)
          {
             kern_gmmreg_detach (GMMREG_DT_IMSI,
                              GMMCS_NET_CAUSE_NOT_PRESENT, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_NET_CAUSE_NOT_PRESENT);
             break;
          }
          /*
           * else: wait for gprs detach to be finished
           * FALLTHROUGH
           */
        case CS_SIM_REM:
          if (GMMRR_NET_MODE_III!=gmm_data->kern.sig_cell_info.net_mode)
          {

            /*
             * Wait until GPRS is deregistered
             */
            break;
          }
          /*
           * else NO break;
           * we are ms class BG and have switched off GSM
           */
        default:
          kern_gmmreg_detach (GMMREG_DT_IMSI,
                              GMMCS_NET_CAUSE_NOT_PRESENT, /* TCS 2.1 */
                              SEARCH_NOT_RUNNING,
                              GMMCS_NET_CAUSE_NOT_PRESENT);
          break;
      }
      kern_call_undone_mm_proc_reg();
      break;
    case KERN_GMM_REG_IMSI_DETACH_INITIATED:
       kern_enter_reg_normal();
      if(GMMRR_NET_MODE_I!=gmm_data->kern.sig_cell_info.net_mode)
      /*
       * In NMO I gmmreg_detach_cnf was sent before requesting 
       * mmgmm_net_req
       */
      {
        kern_gmmreg_detach (detach_type,
                            GMMCS_NET_CAUSE_NOT_PRESENT, /* TCS 2.1 */
                            GMMREG_SEARCH_NOT_RUNNING,
                            GMMCS_NET_CAUSE_NOT_PRESENT);
      }
      break;
    case KERN_GMM_REG_NORMAL_SERVICE:
      break;
    case KERN_GMM_DEREG_NO_IMSI:
      SET_STATE(KERN,KERN_GMM_NULL_NO_IMSI);
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI);
#endif
      kern_gmmreg_detach (detach_type,
                      GMMCS_INT_NOT_PRESENT, /* TCS 2.1 */
                      GMMREG_SEARCH_NOT_RUNNING,
                      GMMCS_INT_NOT_PRESENT);            
      break;
    default:
        TRACE_ERROR( "MMGMM_NREG_CNF unexpected" );
      break;
  } 
  PFREE ( mmgmm_nreg_cnf );

#ifdef TRACE_FUNC  
#ifdef IDENTATION
  if (gmm_data->deep<=0) {
    /*
     * after power off deep is set to 0 in kern_init so we need here normal 
     * return
     */
    return;
  } 
  else
  {
    GMM_RETURN;
  }
#endif
#endif
} /* kern_mmgmm_nreg_cnf() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_auth_rej_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive MMGMM_AUTH_REJ_IND
|
| Parameters  : *mmgmm_auth_rej_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_auth_rej_ind ( T_MMGMM_AUTH_REJ_IND *mmgmm_auth_rej_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_auth_rej_ind" );
  PFREE (mmgmm_auth_rej_ind);

  gmm_data->sim_gprs_invalid = TRUE;
  gmm_data->kern.detach_cap.detach_type = GMMREG_DT_SIM_REMOVED;
  kern_sim_del_locigprs ();
  gmm_data->gu  = GU3_ROAMING_NOT_ALLOWED;
  kern_sim_gmm_update ();
  
  GMM_RETURN;
} /* kern_mmgmm_auth_rej_ind() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_t3212_val_ind
|
| Description : Handles the primitive MMGMM_T3212_VAL  _IND
|
| Parameters  : *mmgmm_t3212_val_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_t3212_val_ind ( T_MMGMM_T3212_VAL_IND *mmgmm_t3212_val_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_t3212_val_ind" );

#ifdef REL99
  switch (gmm_data->kern.sig_cell_info.sgsnr_flag)/*!gmm_data->release99 =>old code*/ /* TCS 4.0 */
  {
    default:
    case PS_SGSN_UNKNOWN:
    case PS_SGSN_98_OLDER:
#endif

    /*
     * see GSM04.08 ch. 11.2.2 NOTE 4
     */
    gmm_data->kern.t3302_val = mmgmm_t3212_val_ind->t3212_val;
    /*
     * Boeser Hack wegen Faulheit, signal should be taken
     */
    gmm_data->sync.mm_cell_info.t3212_val = gmm_data->kern.t3302_val;

#ifdef REL99
      break;
    case PS_SGSN_99_ONWARDS:
      break;
  }
#endif

  PFREE ( mmgmm_t3212_val_ind );
  GMM_RETURN;
} /* kern_mmgmm_t3212_val_ind() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_cm_establish_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive MMGMM_CM_ESTABLISH_IND
|
| Parameters  : *mmgmm_cm_establish_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_cm_establish_ind ( T_MMGMM_CM_ESTABLISH_IND *mmgmm_cm_establish_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_cm_establish_ind" );

  PFREE ( mmgmm_cm_establish_ind );

  if (gmm_data->kern.gmmrr_resume_sent)
  {
    kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
    GMM_RETURN;
  }
    
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_REG_RESUMING:
      TRACE_ERROR ("prim should be saved");
      break;
    case KERN_GMM_DEREG_SUSPENDING:
    case KERN_GMM_REG_SUSPENDING:
      gmm_data->kern.suspension_type |= GMM_SUSP_CALL;
      break;

    case KERN_GMM_DEREG_SUSPENDED:
    case KERN_GMM_NULL_IMSI:
      kern_mm_cm_establish_res (MMGMM_ESTABLISH_OK);
      break;
    case KERN_GMM_DEREG_LIMITED_SERVICE:
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
    case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
    case KERN_GMM_DEREG_PLMN_SEARCH:
    case KERN_GMM_DEREG_INITIATED:
    case KERN_GMM_REG_INITIATED:
      switch (gmm_data->kern.attach_cap.mobile_class)
      {
        case GMMREG_CLASS_A:
          if (GMMRR_NET_MODE_III == gmm_data->kern.sig_cell_info.net_mode)
          {
             kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
          }
          else
          {
            kern_mm_cm_establish_res (MMGMM_ESTABLISH_OK);
          }
          break;
        case GMMREG_CLASS_CG:
          kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
          break; 
        case GMMREG_CLASS_BG:
          if (GMMRR_NET_MODE_III == gmm_data->kern.sig_cell_info.net_mode)
          {
            kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
            break;
          }
          /* NO break */
        case GMMREG_CLASS_B:
        case GMMREG_CLASS_BC:
          /* START PATCH UBUOB ISSUE 8278 */
          switch (GET_STATE (KERN))
          {
            case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
              gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = TRUE;
              break;
            default:
              break;
          }
          /* END PATCH UBUOB ISSUE 8278 */

          if (GMM_MM_DEREG != GET_STATE(MM))
          {
            SET_STATE ( KERN, KERN_GMM_DEREG_SUSPENDING );
#ifdef FF_EM_MODE
            EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDING );
#endif
            /* START PATCH UBUOB ISSUE 8781 */
            /* kern_gmmreg_suspend (GMMREG_CS_CALL); */
            /* END PATCH UBUOB ISSUE 8781 */
            kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_ABNORMAL_RELEASE, GMM_SUSP_CALL);
            vsi_t_stop(GMM_handle, kern_T3321);
          }
          else
          {
            SET_STATE( KERN, KERN_GMM_DEREG_SUSPENDING);
#ifdef FF_EM_MODE
            EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDING);
#endif
            /*
             * kern_llgmm_unassign();
             */
            kern_llgmm_suspend(LLGMM_CALL);
            kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_ABNORMAL_RELEASE, GMM_SUSP_CALL);
          }
          break;  
        default:
          TRACE_ERROR( "unknown MS class");
          break;
      }
      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_RAU_INITIATED:
      switch (gmm_data->kern.attach_cap.mobile_class)
      {
        case GMMREG_CLASS_A:
          kern_mm_cm_establish_res (MMGMM_ESTABLISH_OK);
          break;
        case GMMREG_CLASS_CG:
          kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
          break; 
        case GMMREG_CLASS_BG:
          if (GMMRR_NET_MODE_III == gmm_data->kern.sig_cell_info.net_mode)
          {
            kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
            break;
          }
          /* NO break; */      
        case GMMREG_CLASS_B:
        case GMMREG_CLASS_BC:
          /* START PATCH UBUOB ISSUE 8278 */
          switch (GET_STATE (KERN))
          {
            case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:
              gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = TRUE;
              break;
            default:
              break;
          }
          /* END PATCH UBUOB ISSUE 8278 */
          SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING );
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING );
#endif
          kern_llgmm_suspend(LLGMM_CALL);
          kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_ABNORMAL_RELEASE, GMM_SUSP_CALL);
          break;
        default:
          TRACE_ERROR( "unknown MS class");
          break;
      }  
      break;

    case KERN_GMM_REG_NORMAL_SERVICE:
      switch (gmm_data->kern.attach_cap.mobile_class)
      {
        case GMMREG_CLASS_A:
          kern_mm_cm_establish_res (MMGMM_ESTABLISH_OK);
          break;
        case GMMREG_CLASS_CG:
          kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
          break; 
        case GMMREG_CLASS_BG:
          if (GMMRR_NET_MODE_III == gmm_data->kern.sig_cell_info.net_mode)
          {
            kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
            break;
          }
          /* NO break; */        
        case GMMREG_CLASS_B:
        case GMMREG_CLASS_BC:
          SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING );
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING );
#endif
          kern_llgmm_suspend(LLGMM_CALL);
          kern_gmmrr_suspend (GMMRR_SUSP_GPRS, GMMRR_ABNORMAL_RELEASE, GMM_SUSP_CALL);
          break;
        default:
          TRACE_ERROR( "unknown MS class");
          break;
      }  
      break;
    case KERN_GMM_REG_SUSPENDED:
      switch (gmm_data->kern.attach_cap.mobile_class)
      {
        case GMMREG_CLASS_A:
          kern_mm_cm_establish_res (MMGMM_ESTABLISH_OK);
          break;
        case GMMREG_CLASS_CG:
          kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
          break; 
        case GMMREG_CLASS_BG:
          if (GMMRR_NET_MODE_III == gmm_data->kern.sig_cell_info.net_mode)
          {
            kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
            break;
          }
          /* NO break; */        
        case GMMREG_CLASS_B:
        case GMMREG_CLASS_BC:
          /*
           * call is rejected because MM may establish the call by itself.
           * When state REG_RESUMING will be defined than GMM will return OK.
           * In case of waiting for GMMRR_CELL_IND after GMMRR_RESUME_REQ
           * the mobile will run into a dead lock situation otherwise.
           */
          kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
          break;
        default:
          TRACE_ERROR( "unknown MS class");
          break;
      }  
      break;
    case KERN_GMM_DEREG_NO_IMSI:
    case KERN_GMM_NULL_NO_IMSI:
      kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
      break;
    default:
      kern_mm_cm_establish_res (MMGMM_ESTABLISH_REJECT);
      TRACE_1_INFO ("state: %x", GET_STATE( KERN ));
      TRACE_ERROR( "MMGMM_CM_ESTABLISH_IND unexpected" );
      break;
  }
  GMM_RETURN;
} /* kern_mm_cm_establish_ind() */
/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_cm_emergency_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive MMGMM_CM_EMERGENCY_IND
|
| Parameters  : *mmgmm_cm_emergency_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_cm_emergency_ind ( T_MMGMM_CM_EMERGENCY_IND *mmgmm_cm_emergency_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_cm_emeregncy_ind" );

  PFREE ( mmgmm_cm_emergency_ind );

  if (GMMREG_CLASS_A == gmm_data->kern.attach_cap.mobile_class
  && GMMRR_NET_MODE_III != gmm_data->kern.sig_cell_info.net_mode)
  {
     kern_mm_cm_emergency_res (MMGMM_ESTABLISH_OK);
    GMM_RETURN;
  }
  
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_REG_RESUMING:
      TRACE_ERROR ("prim should be saved");
      break;

    case KERN_GMM_DEREG_SUSPENDING:
    case KERN_GMM_REG_SUSPENDING:
      gmm_data->kern.suspension_type |= GMM_SUSP_EM_CALL;
      break;
    case KERN_GMM_DEREG_SUSPENDED:
    case KERN_GMM_REG_SUSPENDED:
    case KERN_GMM_NULL_IMSI:
    case KERN_GMM_NULL_NO_IMSI:
    case KERN_GMM_NULL_PLMN_SEARCH:
    case KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ:
    case KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ:
      kern_mm_cm_emergency_res (MMGMM_ESTABLISH_OK);
      break;
    case KERN_GMM_DEREG_NO_IMSI:
      if (gmm_data->kern.detach_cap.gmmreg)
      /* 
       * The mobile is switching off this moment. Thera are no power anymore
       */
      {
        kern_mm_cm_emergency_res (MMGMM_ESTABLISH_REJECT);
      }
      break;

    case KERN_GMM_DEREG_PLMN_SEARCH:
    case KERN_GMM_DEREG_LIMITED_SERVICE:
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
    case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
    case KERN_GMM_DEREG_INITIATED:
    case KERN_GMM_REG_INITIATED:
      SET_STATE ( KERN, KERN_GMM_DEREG_SUSPENDING );
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDING );
#endif
      kern_llgmm_suspend(LLGMM_CALL);
      kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_ABNORMAL_RELEASE, GMM_SUSP_EM_CALL);
      break;
    case KERN_GMM_RAU_WAIT_FOR_NPDU_LIST:
    case KERN_GMM_REG_IMSI_DETACH_INITIATED:
    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_RAU_INITIATED:
      SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING);
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING);
#endif
      kern_llgmm_suspend(LLGMM_CALL);
      kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_ABNORMAL_RELEASE, GMM_SUSP_EM_CALL);
      break;
    case KERN_GMM_REG_NORMAL_SERVICE:
      SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING );
#ifdef FF_EM_MODE
      EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING );
#endif
      /*
       * kern_llgmm_unassign();
       */
      kern_llgmm_suspend(LLGMM_CALL);
      kern_gmmrr_suspend (GMMRR_SUSP_GPRS, GMMRR_ABNORMAL_RELEASE, GMM_SUSP_EM_CALL);
      break;
    default:
      TRACE_ERROR( "MMGMM_CM_EMERGENCY_IND unexpected" );
      break;
  }
  GMM_RETURN;
} /* kern_mm_cm_emergency_ind() */
/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_cm_release_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive MMGMM_CM_RELEASE_IND
|
| Parameters  : *mmgmm_cm_release_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_cm_release_ind ( T_MMGMM_CM_RELEASE_IND *mmgmm_cm_release_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_cm_release_ind" );

  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_REG_SUSPENDED:
      /*
       * resume with cell_ind
       */
      if (MMGMM_RESUMPTION_OK!=mmgmm_cm_release_ind->resumption)
      {
        TRACE_EVENT("Para: resumption failure: RAU needed");
        SET_STATE(GU,GU_UPDATE_NEEDED);
      }
      else
      {
        TRACE_EVENT("OPar: resumption OK.");
      }
      PFREE ( mmgmm_cm_release_ind );
      kern_call_undone_mm_proc_reg();
      break;
    case KERN_GMM_DEREG_SUSPENDED:
      PFREE ( mmgmm_cm_release_ind );
      kern_call_undone_mm_proc_der();
      break;
    case KERN_GMM_DEREG_SUSPENDING:
    case KERN_GMM_REG_SUSPENDING:
      gmm_data->kern.suspension_type &= ~ (GMM_SUSP_CALL|GMM_SUSP_EM_CALL);

      PFREE ( mmgmm_cm_release_ind );
      break;
    
    default:

      if (GMMREG_CLASS_A!=gmm_data->kern.attach_cap.mobile_class)
      {
        TRACE_ERROR( "MMGMM_CM_RELEASE_IND unexpected" );
      }    
      PFREE ( mmgmm_cm_release_ind );
      break;
  }
  GMM_RETURN;
} /* kern_mm_cm_release_ind() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_plmn_ind
+------------------------------------------------------------------------------
| Description : Handles the primitive MMGMM_PLMN_IND
|
|          MSC: 3.20 MM Interface
|          MSC: 3.20.2 Network selection
|
| Parameters  : *mmgmm_plmn_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_plmn_ind ( T_MMGMM_PLMN_IND *mmgmm_plmn_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_plmn_ind" );
  {
    PPASS (mmgmm_plmn_ind, gmmreg_plmn_ind, GMMREG_PLMN_IND);
    PSEND ( hCommMMI, gmmreg_plmn_ind );
  }
  GMM_RETURN;
} /* kern_mm_plmn_ind() */


/*
+------------------------------------------------------------------------------
| Function    : kern_gmmreg_attach_req
+------------------------------------------------------------------------------
| Description : Handles the the primitive GMMREG_ATTACH_REQ
|
|               This signal passed the attach_type from MMI to 
|               the service KERN
|
|         MSC : 3.4 MMI-initiated normal/combined GPRS attach
|
| Parameters  : *gmmreq_attach_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmreg_attach_req ( T_GMMREG_ATTACH_REQ *gmmreg_attach_req ) 
{ 
  U8 attach_type_changed = FALSE;
  GMM_TRACE_FUNCTION( "kern_gmmreg_attach_req" );
  TRACE_EVENT ("hp_gmm_24473#1#24473"); /* TCS 2.1 */

  /* Changes for Boot Time Speedup. GMM will get dummy GMMREG_ATTACH_REQ indicating QUICK_REG. 
   * GMM will send MMGMM_REG_REQ indicating QUICK_REG. No need to process this request as it is 
   * dummy request and GMM will get other GMMREG_ATTACH_REQ indicating NORMAL_REG
   */
  if (gmmreg_attach_req->bootup_act EQ QUICK_REG)
  {
    kern_mm_reg_req (REG_GPRS_INACTIVE, QUICK_REG);
    return ;
  }
  vsi_t_stop  ( GMM_handle, kern_T3302);
  sig_kern_rdy_stop_t3302_req();
  gmm_data->kern.attach_cap.enter_attempting_to_update_after_lau = FALSE;
  /*
   * attach_cap.gmmreg sets the caller of the attach procedure to MMI
   */
  gmm_data->kern.attach_cap.gmmreg = TRUE;
  gmm_data->kern.detach_cap.gmmreg = FALSE;

  gmm_data->kern.attach_cap.service_mode = gmmreg_attach_req->service_mode;
  

  if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
  {
    /*
     * I expect that limited service means emergency call over GSM only
     * CLASS_CC can be set, because service mode is changed via 
     * GMMREG_ATTACH_REQ only, so that the wanted mobile class is giveb again
     */
    gmm_data->kern.attach_cap.mobile_class = GMMREG_CLASS_CC;    
    gmm_data->kern.attach_cap.attach_type = GMMREG_AT_IMSI;

  }
  else
  {
     /*
      *PATCH TB 26/10/02 <
      * Inform GRR of the new MS class
      */
     attach_type_changed = 
        (  gmm_data->kern.attach_cap.mobile_class != gmmreg_attach_req->mobile_class
        || gmm_data->kern.attach_cap.attach_type!= gmmreg_attach_req->attach_type);
     
     if (GMM_GRR_STATE_OFF != gmm_data->kern.attach_cap.grr_state
     && (gmm_data->kern.attach_cap.mobile_class != gmmreg_attach_req->mobile_class))
     {
       if (GMMRR_NET_MODE_III==gmm_data->kern.sig_cell_info.net_mode)
       {
          gmm_data->kern.attach_cap.mobile_class_changed = TRUE;
          gmm_data->kern.attach_cap.mobile_class = gmmreg_attach_req->mobile_class;
          /*
           * inform GRR after switch (mmgmm_nreg_cnf xor kern _enter_der)
           * kern_gmmrr_enable();
           */
       }
       else
       {
          gmm_data->kern.attach_cap.mobile_class = gmmreg_attach_req->mobile_class;
          kern_gmmrr_enable();
       }
     }     
     /* PATCH TB 26/10/02 > */


     gmm_data->kern.attach_cap.mobile_class = gmmreg_attach_req->mobile_class;
      /*
       * if MMI wants to detach, then detach is expected or class change
       */
     gmm_data->kern.attach_cap.attach_type = 
       (GMMREG_CLASS_CG == gmmreg_attach_req->mobile_class?
        GMMREG_AT_GPRS:
        gmm_data->kern.attach_cap.attach_type|gmmreg_attach_req->attach_type);

  }
   

  
  #ifndef NTRACE      
  switch (gmmreg_attach_req->service_mode)
  {
    case SERVICE_MODE_LIMITED:
      TRACE_EVENT ("Limited Service");
      break;
    case SERVICE_MODE_FULL:
      TRACE_EVENT ("Full Service");
      break;
    default:
      TRACE_ERROR ("wrong Service requested");
  }
  switch ( gmm_data->kern.attach_cap.mobile_class )
  {
    case GMMREG_CLASS_CC:
      TRACE_0_PARA("MS class CC");
      break;
    case GMMREG_CLASS_CG:
      TRACE_0_PARA("MS class CG");
      break;
    case GMMREG_CLASS_B:
      TRACE_0_PARA("MS class B");
      break;
    case GMMREG_CLASS_BG:
      TRACE_0_PARA("MS class BG");
      break;
    case GMMREG_CLASS_BC:
      TRACE_0_PARA("MS class BC");
      break;
    case GMMREG_CLASS_A:
      TRACE_0_PARA("MS class A");
      break;
    default:
      TRACE_ERROR ("unknown mobile class");
      break;
  }
  switch (gmm_data->kern.attach_cap.attach_type)
  {
    case GMMREG_AT_IMSI:
      TRACE_0_PARA("GSM only attach");
      break;
    case GMMREG_AT_GPRS:
      TRACE_0_PARA("GPRS attach");
      break;
    case GMMREG_AT_COMB:
      TRACE_0_PARA("GSM and GPRS attach");
      break;
    default:
      TRACE_ERROR ("unknown attach type");
      TRACE_1_PARA("%d",gmm_data->kern.attach_cap.attach_type);
      break;
  }
#endif

  if (gmm_data->sim_gprs_invalid
  && GMMREG_CLASS_CG == gmm_data->kern.attach_cap.mobile_class)
  /* 
   * i.e. error cause 7: gprs not allowed
   */
  {
    PREUSE(gmmreg_attach_req,gmmreg_attach_rej,GMMREG_ATTACH_REJ );
      gmmreg_attach_rej->detach_type = 
        (GMM_MM_REG_NORMAL_SERVICE == GET_STATE(MM)?GMMREG_DT_GPRS:GMMREG_DT_COMB),
      gmmreg_attach_rej->search_running = GMMREG_SEARCH_NOT_RUNNING,
      gmmreg_attach_rej->cause = GMMCS_GPRS_NOT_ALLOWED; /* TCS 2.1 */
      gmmreg_attach_rej->service = GMMCS_GPRS_NOT_ALLOWED;
      gmm_data->kern.attach_cap.gmmreg = FALSE;
      
    PSEND ( hCommMMI, gmmreg_attach_rej );
    GMM_RETURN;
  }
 
  
  PFREE ( gmmreg_attach_req );
  
  switch( GET_STATE( KERN ) )
  {
    /*
     * GMM-DEREGISTERED
     */
    case KERN_GMM_DEREG_RESUMING:
    case KERN_GMM_REG_RESUMING:
      TRACE_ERROR ("prim should be saved");
      break;
 
    case KERN_GMM_DEREG_PLMN_SEARCH:
    case KERN_GMM_DEREG_LIMITED_SERVICE:
    case KERN_GMM_DEREG_NO_CELL_AVAILABLE:
    case KERN_GMM_DEREG_ATTEMPTING_TO_ATTACH:
    
    case KERN_GMM_DEREG_SUSPENDING:
    case KERN_GMM_DEREG_SUSPENDED:
      if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
      {
        SET_STATE ( KERN, KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);
#endif
        kern_gmmrr_disable();
        kern_mm_activate_mm();
        break;
      }

      if (GMMREG_CLASS_CC==gmm_data->kern.attach_cap.mobile_class
      || GMMREG_AT_IMSI== gmm_data->kern.attach_cap.attach_type)
      {
        SET_STATE ( KERN, KERN_GMM_NULL_IMSI );
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI );
#endif
        kern_gmmrr_disable();
        kern_mm_activate_mm();
        if ( GMM_MM_REG_NORMAL_SERVICE == GET_STATE(MM) )
        {
          kern_gmmreg_attach_cnf( GMMREG_AT_IMSI);
        }
        break;
      }

      switch ( gmm_data->kern.attach_cap.mobile_class )
      {
        case GMMREG_CLASS_CG:
          if ( GMM_MM_DEREG != GET_STATE(MM) )
          {
            switch( GET_STATE( KERN ) )
            {
              case KERN_GMM_DEREG_SUSPENDED:
                /*
                 * Case GMMREG_CLASS_CG.
                 * The detach procedure for cs is only possible after receiving
                 * GMMRR_CELL_IND
                 */
                break;
              case KERN_GMM_DEREG_SUSPENDING:
                gmm_data->kern.suspension_type |=GMM_SUSP_IMSI_DETACH;
                break;
              default:
                if (kern_lai_changed() )
                {
                  SET_STATE ( KERN, KERN_GMM_DEREG_SUSPENDING );
#ifdef FF_EM_MODE
                  EM_GMM_SET_STATE(KERN_GMM_DEREG_SUSPENDING );
#endif
                  kern_gmmrr_suspend (GMMRR_NOT_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LAU);
                }
                else 
                {
                  kern_imsi_detach_der_susp();
                }
                GMM_RETURN;
            }
          }
          break;
        default:
          break;
      }

      switch( GET_STATE( KERN ) )
      {
        case KERN_GMM_DEREG_SUSPENDED:
          gmm_data->kern.attach_cap.mm_lau_attempted=TRUE;
          gmm_data->kern.suspension_type &= ~GMM_SUSP_LAU;
          break;
        case KERN_GMM_DEREG_SUSPENDING:
          gmm_data->kern.suspension_type |=GMM_SUSP_LAU;
          break;
        default:          
          {
            kern_mm_reg_req (REG_CELL_SEARCH_ONLY, NORMAL_REG);
          }
          break;
          
      }
      break;
    case KERN_GMM_NULL_PLMN_SEARCH:
      if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
      {
        SET_STATE (KERN,KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);
#endif
        kern_mm_activate_mm ();
        break;
      }

      if (GMMREG_CLASS_CC==gmm_data->kern.attach_cap.mobile_class
      || GMMREG_AT_IMSI== gmm_data->kern.attach_cap.attach_type)
      {
        kern_mm_activate_mm ();
        break;
      }


      switch ( gmm_data->kern.attach_cap.mobile_class )
      {
        case GMMREG_CLASS_CG:
          if ( GMM_MM_DEREG != GET_STATE(MM) )
          {
            SET_STATE(KERN, KERN_GMM_DEREG_PLMN_SEARCH);
#ifdef FF_EM_MODE
            EM_GMM_SET_STATE(KERN_GMM_DEREG_PLMN_SEARCH);
#endif
            /*
             * MM enters autmaticly gprs cell search mode so that GMM 
             * need not to send mmgmm_reg_req (cell_search_only)
             */
            kern_mm_imsi_detach();
          }
          else
          {
            SET_STATE ( KERN, KERN_GMM_DEREG_PLMN_SEARCH );
#ifdef FF_EM_MODE
            EM_GMM_SET_STATE(KERN_GMM_DEREG_PLMN_SEARCH );
#endif
            kern_mm_activate_rr();
          }
          break;
        default:
          /*
           * class A and B
           */
          SET_STATE ( KERN, KERN_GMM_DEREG_PLMN_SEARCH );
#ifdef FF_EM_MODE
          EM_GMM_SET_STATE(KERN_GMM_DEREG_PLMN_SEARCH );
#endif
          kern_mm_activate_rr();
        break;
      }
      break;
    /*
     * GPRS will be enabled
     */
    case KERN_GMM_NULL_IMSI:          
      if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
      {
        SET_STATE (KERN,KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ);
#endif
        kern_mm_activate_mm ();
        break;
      }
      if (GMM_MM_DEREG != GET_STATE(MM) 
      && GMMREG_CLASS_CC == gmm_data->kern.attach_cap.mobile_class)
      {
        TRACE_EVENT ("GMMREG_ATTACH_REQ has been come twice and is ignored!");
        /*
         * the funcion is not alled because mm_plmn is used.
         */
       
        kern_gmmreg_attach_cnf(GMMREG_AT_IMSI);
        gmm_data->kern.attach_cap.gmmreg = FALSE;

       break;
      }
      /* NO break */
    case KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ:           
      if (SERVICE_MODE_LIMITED != gmm_data->kern.attach_cap.service_mode)
      {
        gmm_data->kern.sig_cell_info.gmm_status = GMMRR_SERVICE_UNKNOWN ; /* Initalize gmm status value */
        switch ( gmm_data->kern.attach_cap.mobile_class )
        {
          case GMMREG_CLASS_CC:
            if (KERN_GMM_NULL_IMSI_LIMITED_SERVICE_REQ==GET_STATE(KERN)
            || GMM_MM_DEREG == GET_STATE(MM))
            {
              SET_STATE ( KERN, KERN_GMM_NULL_PLMN_SEARCH );
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_NULL_PLMN_SEARCH );
#endif
              kern_mm_activate_mm();
            }
            else
            {
              SET_STATE(KERN,KERN_GMM_NULL_IMSI);
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_NULL_IMSI);
#endif
              kern_gmmreg_attach_cnf( GMMREG_AT_IMSI);
            }
            break;
          case GMMREG_CLASS_CG:
            if ( GMM_MM_DEREG != GET_STATE(MM) )
            {
              switch(GET_STATE(KERN))
              {
                case KERN_GMM_NULL_IMSI:
                  SET_STATE ( KERN, KERN_GMM_DEREG_PLMN_SEARCH);
#ifdef FF_EM_MODE
                  EM_GMM_SET_STATE(KERN_GMM_DEREG_PLMN_SEARCH);
#endif
                  /*
                   * MM enters autmaticly gprs cell search mode so that GMM 
                   * need not to send mmgmm_reg_req (cell_search_only)
                   */
                  kern_mm_imsi_detach();
                  break;
                default:
                  break;
              }
            }
            else
            {
              SET_STATE ( KERN, KERN_GMM_DEREG_PLMN_SEARCH );
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_DEREG_PLMN_SEARCH );
#endif
              kern_mm_activate_rr();
            }
            break;
          default:
            /*
             * class A and B
             */
            if (GMMREG_AT_IMSI== gmm_data->kern.attach_cap.attach_type)
            {
              SET_STATE ( KERN, KERN_GMM_NULL_PLMN_SEARCH );
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_NULL_PLMN_SEARCH );
#endif
              kern_mm_activate_mm();
            }
            else
            {
              SET_STATE ( KERN, KERN_GMM_DEREG_PLMN_SEARCH );
#ifdef FF_EM_MODE
              EM_GMM_SET_STATE(KERN_GMM_DEREG_PLMN_SEARCH );
#endif

              kern_mm_activate_rr();
            }
          break;
        }
      }  
      break;
    /* end case KERN_GMM_NULL_IMSI */

    case KERN_GMM_DEREG_NO_IMSI:
      /*
       * this state is not necessary, it is the same as NULL_NO_IMSI
       * and will be romoved soon
       */

      if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
      {
        SET_STATE (KERN,KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ);
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ);
#endif
      }
      else
      {
        SET_STATE (KERN,KERN_GMM_NULL_NO_IMSI);
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI);
#endif
      }
      kern_gmmrr_disable();
      kern_mm_activate_mm(); 
      break;
     
    case KERN_GMM_NULL_NO_IMSI:
      /*
       * Attach Rejected for the first time to enable POWER_OFF
       */
      if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
      {
        SET_STATE (KERN,KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ);
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ);
#endif
      }
      kern_mm_activate_mm();
      break;
    case KERN_GMM_NULL_NO_IMSI_LIMITED_SERVICE_REQ:
      if ( SERVICE_MODE_LIMITED != gmm_data->kern.attach_cap.service_mode)
      {
        SET_STATE (KERN,KERN_GMM_NULL_NO_IMSI);
#ifdef FF_EM_MODE
        EM_GMM_SET_STATE(KERN_GMM_NULL_NO_IMSI);
#endif
      }
      kern_mm_activate_mm();
      break;
    case KERN_GMM_REG_NORMAL_SERVICE:
      if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
      {
        kern_l_sim_rem_reg();
      }
      else
      {
        switch ( gmm_data->kern.attach_cap.mobile_class )
        {
          case GMMREG_CLASS_CC:
            if ( GMM_MM_REG_NORMAL_SERVICE == GET_STATE(MM) )
            {
              kern_gmmreg_attach_cnf ( GMMREG_AT_IMSI );
            }
            kern_disable();
            break;
          case GMMREG_CLASS_CG:
            if (GMM_MM_DEREG != GET_STATE(MM))
            {
              if (kern_lai_changed() )
              {
                switch (gmm_data->kern.sig_cell_info.net_mode)
                {
                  case GMMRR_NET_MODE_I:
                    kern_rau();
                    break;
                  default:
                    SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING );
#ifdef FF_EM_MODE
                    EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING );
#endif
                    kern_llgmm_suspend(LLGMM_CALL);
                    kern_gmmrr_suspend (GMMRR_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LAU);
                    break;
                }
              }
              else 
              {
                switch (gmm_data->kern.sig_cell_info.net_mode)
                {
                  case GMMRR_NET_MODE_I:
                    gmm_data->kern.detach_cap.detach_type = GMMREG_DT_IMSI;
                    kern_detach();
                    break;
                  default:
                    kern_imsi_detach_reg_susp();
                    break;
                }
              }
              GMM_RETURN;
            }
            /*
             * <R.GMM.AGACCEPT.M.027>,
             * <R.GMM.PATTCNF.M.001>
             */
            else
            {
              kern_gmmreg_attach_cnf ( GMMREG_AT_GPRS );
            }
            break;
          default:
            if (attach_type_changed)
            {
              /*
               * class A and B
               */
              if ( GMM_MM_REG_NORMAL_SERVICE == GET_STATE(MM) )
              {
                kern_gmmreg_attach_cnf ( GMMREG_AT_COMB );
              }
              else
              {
                /*
                 * Combined RAU procedure is established
                 * if GPRS is attached and IMSI should attached
                 */
              
                kern_rau();
              }
            }
            else
            {
              kern_mm_reg_req (REG_CELL_SEARCH_ONLY, NORMAL_REG);
            }
            break;
        }
      }
      break;
    case KERN_GMM_REG_SUSPENDED:
    case KERN_GMM_REG_SUSPENDING:
      if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
      {
        kern_l_sim_rem_reg_lim ();
        break;
      }
      /*
       * Attach requests in suspended mode will be handled after resumption
       * by triggering form GRR with GMMRR_CELL_IND
       */
      break;
    
    case KERN_GMM_REG_NO_CELL_AVAILABLE:
    case KERN_GMM_REG_LIMITED_SERVICE:
      if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
      {
        kern_l_sim_rem_reg_lim ();
        break;
      }
      /* NO break */
    case KERN_GMM_RAU_INITIATED:
    case KERN_GMM_REG_INITIATED:
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
    case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:  
    
      if (SERVICE_MODE_LIMITED == gmm_data->kern.attach_cap.service_mode)
      {
        kern_l_sim_rem_reg ();
      }
      else
      {
        switch ( gmm_data->kern.attach_cap.mobile_class )
        {
          case GMMREG_CLASS_CC:

            gmm_data->kern.detach_cap.detach_type = GMMREG_DT_DISABLE_GPRS;

            kern_local_detach( GMMCS_INT_PROTOCOL_ERROR, FALSE, GMM_LOCAL_DETACH_PROC_ENTER_NULL_IMSI); /* TCS 2.1 */
            if ( GMM_MM_REG_NORMAL_SERVICE == GET_STATE(MM) )
            {
              kern_gmmreg_attach_cnf ( GMMREG_AT_IMSI );
            }
            kern_enter_der();
            break;
          case GMMREG_CLASS_CG:
            if (GMM_MM_DEREG != GET_STATE(MM))
            {
              if (kern_lai_changed() )
              {
                switch(GET_STATE(KERN))
                {
                  case KERN_GMM_REG_NO_CELL_AVAILABLE:
                  case KERN_GMM_RAU_INITIATED:
                  case KERN_GMM_REG_ATTEMPTING_TO_UPDATE_MM:
                  case KERN_GMM_REG_ATTEMPTING_TO_UPDATE:  
                    kern_llgmm_suspend(LLGMM_CALL);
                    break;
                  default:
                    break;
                }

                SET_STATE ( KERN, KERN_GMM_REG_SUSPENDING );
#ifdef FF_EM_MODE
                EM_GMM_SET_STATE(KERN_GMM_REG_SUSPENDING );
#endif

                
                kern_gmmrr_suspend (GMMRR_SUSP_GPRS, GMMRR_NORMAL_RELEASE, GMM_SUSP_LAU);
              }
              else 
              {
                kern_imsi_detach_reg_susp();
              }
              GMM_RETURN;
            }
            else
            /*
             * <R.GMM.AGACCEPT.M.027>,
             * <R.GMM.PATTCNF.M.001>
             */
            {
              if (KERN_GMM_REG_INITIATED!=GET_STATE(KERN))
              {
                kern_gmmreg_attach_cnf ( GMMREG_AT_GPRS );
              }
            }
            break;
          default:
            
            {
              kern_mm_reg_req (REG_CELL_SEARCH_ONLY, NORMAL_REG);
            }
            break;
          }
        }
      break;  
    default:
      TRACE_ERROR( "GMMREG_ATTACH_REQ unexpected" );
      break;
     
  }
  GMM_RETURN;
} /* kern_gmmreg_attach_req() */


/*
+------------------------------------------------------------------------------
| Function    : kern_gmmsm_sequence_res
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMSM_SEQENCE_RES
|
| Parameters  : *gmmsm_sequence_res - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
#ifdef GMM_TCS4
GLOBAL void kern_gmmsm_sequence_res ( T_MMPM_SEQUENCE_RES *gmmsm_sequence_res )
#else
GLOBAL void kern_gmmsm_sequence_res ( T_GMMSM_SEQUENCE_RES *gmmsm_sequence_res )
#endif
{ 
  GMM_TRACE_FUNCTION( "kern_gmmsm_sequence_res" );

  
  switch( GET_STATE( KERN ) )
  {
    case KERN_GMM_RAU_WAIT_FOR_NPDU_LIST:
    { 
      int i=0;
      MCAST (routing_area_update_complete, ROUTING_AREA_UPDATE_COMPLETE);
      routing_area_update_complete->v_receive_n_pdu_number_list = TRUE;
      routing_area_update_complete->receive_n_pdu_number_list.
        c_receive_n_pdu_number_list_val = gmmsm_sequence_res->c_npdu_list;
      
      for (i=0;i<routing_area_update_complete->receive_n_pdu_number_list.c_receive_n_pdu_number_list_val;i++)
      {
        routing_area_update_complete
          ->receive_n_pdu_number_list.receive_n_pdu_number_list_val[i]
          .nsapi 
          =  gmmsm_sequence_res->npdu_list[i].nsapi;
          
        routing_area_update_complete
          ->receive_n_pdu_number_list.receive_n_pdu_number_list_val[i]
          .receive_n_pdu_number_val
           
          =  gmmsm_sequence_res->npdu_list[i].receive_n_pdu_number_val;

      }
      
      PFREE (gmmsm_sequence_res);
      kern_rau_complete (gmm_data->kern.attach_cap.result_type);
      
      break;
    }
    default:
      PFREE (gmmsm_sequence_res);
      TRACE_ERROR( "GMMSM_SEQUENCE_RES received in an unusual state." );
      break;
  }
  GMM_RETURN;
} /* kern_gmmsm_sequence_res() */

 /*TI DK primitive*/
#ifdef REL99
/*+------------------------------------------------------------------------------
| Function    : kern_gmmsm_pdp_status_req
+------------------------------------------------------------------------------
| Description : Handles the primitive GMMSM_PDP_STATUS_REQ
|
| Parameters  : *gmmsm_pdp_status_req - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_gmmsm_pdp_status_req ( T_MMPM_PDP_CONTEXT_STATUS_REQ *gmmsm_pdp_status_req )

{ 
  GMM_TRACE_FUNCTION( "kern_gmmsm_pdp_status_req" );

  /* Store the data in context */  
  gmm_data->kern.attach_cap.pdp_context_status = 
                                    gmmsm_pdp_status_req->nsapi_set;
  
  GMM_RETURN;
} /* kern_gmmsm_pdp_status_req() */
#endif

/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_ciphering_ind
+------------------------------------------------------------------------------
| Description : forwards the ciphering indicator of GSM to MMI
|
| Parameters  : *mmgmm_ciphering_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_ciphering_ind ( T_MMGMM_CIPHERING_IND *mmgmm_ciphering_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_ciphering_ind" );
  {
    PALLOC (gmmreg_ciphering_ind, GMMREG_CIPHERING_IND);
    gmmreg_ciphering_ind->gsm_ciph = mmgmm_ciphering_ind->ciph;
    /* 
     * do not include the ciphering status of gprs purposely to have the
     * behaviour for GSM and for GPRS (do not remember the status of the other!)
     */
    gmmreg_ciphering_ind->gprs_ciph = CIPH_NA;
    PFREE ( mmgmm_ciphering_ind );
    PSEND ( hCommMMI, gmmreg_ciphering_ind );
  }
  GMM_RETURN;
} /* kern_mmgmm_ciphering_ind() */
/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_tmsi_ind
+------------------------------------------------------------------------------
| Description : forwards the TMSI received in MM  to GMM
|
| Parameters  : *mmgmm_tmsi_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_tmsi_ind ( T_MMGMM_TMSI_IND *mmgmm_tmsi_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_tmsi_ind" );
  gmm_data->tmsi = mmgmm_tmsi_ind->tmsi;
  TRACE_1_PARA("TMSI %x", gmm_data->tmsi  );
  PFREE ( mmgmm_tmsi_ind );
  GMM_RETURN;
} /* kern_mmgmm_ciphering_ind() */

/*
+------------------------------------------------------------------------------
| Function    : kern_mmgmm_ahplmn_ind
+------------------------------------------------------------------------------
| Description : forwards the ahplmn indicator to MMI
|
| Parameters  : *mmgmm_ahplmn_ind - Ptr to primitive payload
|
+------------------------------------------------------------------------------
*/
GLOBAL void kern_mmgmm_ahplmn_ind ( T_MMGMM_AHPLMN_IND *mmgmm_ahplmn_ind )
{ 
  GMM_TRACE_FUNCTION( "kern_mmgmm_ahplmn_ind" );
  {
    PPASS (mmgmm_ahplmn_ind, gmmreg_ahplmn_ind, GMMREG_AHPLMN_IND);
    PSEND ( hCommMMI, gmmreg_ahplmn_ind );
  }
  GMM_RETURN;
} /* kern_mmgmm_ahplmn_ind() */