diff src/g23m-gsm/mm/mm_mmf.c @ 1:fa8dc04885d8

src/g23m-*: import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 06:25:50 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/g23m-gsm/mm/mm_mmf.c	Fri Oct 16 06:25:50 2020 +0000
@@ -0,0 +1,3933 @@
+/* 
++----------------------------------------------------------------------------- 
+|  Project :  GSM-PS (8410)
+|  Modul   :  MM_MMF
++----------------------------------------------------------------------------- 
+|  Copyright 2002 Texas Instruments Berlin, AG 
+|                 All rights reserved. 
+| 
+|                 This file is confidential and a trade secret of Texas 
+|                 Instruments Berlin, AG 
+|                 The receipt of or possession of this file does not convey 
+|                 any rights to reproduce or disclose its contents or to 
+|                 manufacture, use, or sell anything it may describe, in 
+|                 whole, or in part, without the specific written consent of 
+|                 Texas Instruments Berlin, AG. 
++----------------------------------------------------------------------------- 
+|  Purpose :  This Modul defines the functions for the mob. management
+|             capability of the module Mobility Management.
++----------------------------------------------------------------------------- 
+*/ 
+
+#ifndef MM_MMF_C
+#define MM_MMF_C
+
+#define ENTITY_MM
+
+/*==== INCLUDES ===================================================*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include "typedefs.h"
+#include "pcm.h"
+#include "pconst.cdg"
+#include "mconst.cdg"
+#include "message.h"
+#include "ccdapi.h"
+#include "vsi.h"
+#include "custom.h"
+#include "gsm.h"
+#include "prim.h"
+#include "cnf_mm.h"
+#include "mon_mm.h"
+#include "pei.h"
+#include "tok.h"
+#include "mm.h"
+#ifdef _SIMULATION_
+  #include "ffs_pc_api.h"
+#else
+  #include "ffs/ffs.h"
+#endif
+#include "mm_em.h"
+
+
+
+
+/*==== EXPORT =====================================================*/
+BOOL poor_quality_network = FALSE; /* Hack, maybe needed by CC */
+
+/*==== TEST =====================================================*/
+
+/*==== VARIABLES ==================================================*/
+
+/*==== FUNCTIONS ==================================================*/
+GLOBAL T_FFS_RET ffs_mkdir(const char *name);
+
+/*==== PRIVAT =====================================================*/
+LOCAL BOOL mm_handle_ffs_read_result  (T_FFS_SIZE status_read);
+LOCAL BOOL mm_handle_ffs_write_result (T_FFS_RET status_write);
+LOCAL BOOL mm_create_ffs_dirs         (const char *name);
+LOCAL BOOL mm_check_ffs_dirs          (void);
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_fill_identity           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function fills the mobile identity structure with
+            the desired identity, this maybe the IMSI, the IMSISV,
+            the IMEI or the TMSI.
+
+*/
+
+LOCAL void mm_fill_identity (T_mob_id *mob_ident, UBYTE id_type)
+{
+  GET_INSTANCE_DATA;
+  T_imsi_struct imei_struct;
+  TRACE_FUNCTION ("mm_fill_identity()");
+
+  memset (mob_ident, 0, sizeof (T_mob_id));
+
+  switch (id_type)
+  {
+    case ID_TYPE_IMSI:
+      mob_ident->ident_type  = id_type;
+      mob_ident->v_ident_dig = TRUE;
+      mob_ident->c_ident_dig = mm_calculate_digits (mm_data->reg.imsi_struct.id);
+      mob_ident->odd_even    = mob_ident->c_ident_dig & 1;
+      memcpy (mob_ident->ident_dig, mm_data->reg.imsi_struct.id, 16);
+      break;
+    
+    case ID_TYPE_IMEI:
+      csf_read_imei (&imei_struct);
+      mob_ident->ident_type  = id_type;
+      mob_ident->v_ident_dig = TRUE;
+      mob_ident->c_ident_dig = 15;
+      mob_ident->odd_even    = 1; 
+      memcpy (mob_ident->ident_dig, imei_struct.id, 14);
+      mob_ident->ident_dig[14] = 0;
+      break;
+    
+    case ID_TYPE_IMEISV:
+      csf_read_imei (&imei_struct);
+      mob_ident->ident_type  = id_type;
+      mob_ident->v_ident_dig = TRUE;
+      mob_ident->c_ident_dig = 16;
+      mob_ident->odd_even    = 0;
+      memcpy (mob_ident->ident_dig, imei_struct.id, 16);
+      break;
+    
+    case ID_TYPE_TMSI:
+      mob_ident->ident_type  = id_type;
+      mob_ident->v_ident_dig = FALSE;
+      mob_ident->tmsi.l_tmsi = 32;
+      mob_ident->v_tmsi      = TRUE;
+      ccd_codeByte (mob_ident->tmsi.b_tmsi, 0, 8, 
+        (UBYTE)(mm_data->reg.tmsi >> 24));
+      ccd_codeByte (mob_ident->tmsi.b_tmsi, 8, 8, 
+        (UBYTE)(mm_data->reg.tmsi >> 16));
+      ccd_codeByte (mob_ident->tmsi.b_tmsi, 16, 8, 
+        (UBYTE)(mm_data->reg.tmsi >> 8));
+      ccd_codeByte (mob_ident->tmsi.b_tmsi, 24, 8, 
+        (UBYTE)(mm_data->reg.tmsi));
+      break;
+
+    default: 
+      TRACE_ERROR ("No such mobile identity");
+      break;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_fill_ident_for_est      |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functinon fills the mobile identity for an 
+            establishment message and uses the appropriate identity
+            for this purpose. The function returns the used mobile
+            identity type.
+
+*/
+
+LOCAL UBYTE mm_fill_ident_for_est (T_mob_id *mob_ident)
+{
+  GET_INSTANCE_DATA;
+  UBYTE id_type;
+
+  TRACE_FUNCTION ("mm_fill_ident_for_est()");
+
+  if (mm_data->reg.op.sim_ins EQ SIM_NO_INSRT)
+  {
+    /* No SIM present */
+    id_type = ID_TYPE_IMEI;
+  }
+  else
+  {
+    /* SIM present */
+    if (mm_data->reg.tmsi EQ TMSI_INVALID_VALUE)
+    {
+      /* No TMSI present */
+      id_type = ID_TYPE_IMSI;
+    }
+    else
+    {
+      /* TMSI present */
+      id_type = ID_TYPE_TMSI;
+    }
+  }
+
+  mm_fill_identity (mob_ident, id_type);
+
+  return id_type;
+}
+
+/*==== VARIABLES ==================================================*/
+
+/*==== FUNCTIONS ==================================================*/
+
+/*
+ * -------------------------------------------------------------------
+ * Procedures
+ * -------------------------------------------------------------------
+ */
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_abort_connection        |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function sends the RR_ABORT_REQ primitive.
+
+*/
+
+GLOBAL void mm_abort_connection (UBYTE abcs)
+{
+  TRACE_FUNCTION ("mm_abort_connection ()");
+  
+  assert (abcs EQ ABCS_SIM_REM OR 
+          abcs EQ ABCS_NORM);
+  
+  {
+    PALLOC ( rr_abort_req, RR_ABORT_REQ); /* T_RR_ABORT_REQ */
+    rr_abort_req->abcs = abcs;
+    PSENDX (RR, rr_abort_req);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_attach_loc_upd          |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function starts an IMSI ATTACH location update.
+
+*/
+
+GLOBAL void mm_attach_loc_upd (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_attach_loc_upd ()");
+
+  if (mm_lup_allowed_by_gmm())
+  {
+    mm_start_loc_upd (IMSI_ATTACH_LUP);
+  }
+  else
+  {
+    SET_STATE (STATE_MM, MM_IDLE_LUP_NEEDED);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_normal_loc_upd          |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function starts a normal location update procedure.
+
+*/
+
+GLOBAL void mm_normal_loc_upd (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_normal_loc_upd ()");
+
+  if (mm_lup_allowed_by_gmm())
+  {
+    mm_start_loc_upd (NORMAL_LUP);
+  }
+  else
+  {
+    SET_STATE (STATE_MM, MM_IDLE_LUP_NEEDED);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_periodic_loc_upd        |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function starts a periodic location update.
+
+*/
+
+GLOBAL void mm_periodic_loc_upd (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_periodic_loc_upd ()");
+  if (mm_lup_allowed_by_gmm())
+  {
+    mm_start_loc_upd (PERIODIC_LUP);
+  }
+  else
+  {
+    SET_STATE (STATE_MM, MM_IDLE_LUP_NEEDED);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_build_auth_res          |
++--------------------------------------------------------------------+
+
+  PURPOSE : In this function the AUTHENTICATION RESPONSE message is 
+            built.
+
+*/
+
+GLOBAL void mm_build_auth_res (T_SIM_AUTHENTICATION_CNF *sim_auth_cnf,
+                               T_U_AUTH_RES             *auth_res)
+{
+  TRACE_FUNCTION ("mm_build_auth_res ()");
+  auth_res->msg_type = U_AUTH_RES;
+  auth_res->auth_sres.l_auth_sres = MAX_SRES << 3;
+  auth_res->auth_sres.o_auth_sres = 0;
+  memcpy (auth_res->auth_sres.b_auth_sres, sim_auth_cnf->sres, MAX_SRES);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_build_ident_res         |
++--------------------------------------------------------------------+
+
+  PURPOSE : In this function the IDENTITY RESPONSE message is built.
+
+*/
+
+GLOBAL void mm_build_ident_res (UBYTE         id_type, 
+                                T_U_IDENT_RES *ident_res)
+{
+  TRACE_FUNCTION ("mm_build_ident_res ()");
+  ident_res->msg_type = U_IDENT_RES;
+  mm_fill_identity (&ident_res->mob_id, id_type);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_build_mm_status         |
++--------------------------------------------------------------------+
+
+  PURPOSE : In this function the MM STATUS message is built.
+
+*/
+
+GLOBAL void mm_build_mm_status (UBYTE         cause,
+                                T_B_MM_STATUS *mm_status)
+{
+  TRACE_FUNCTION ("mm_build_mm_status ()");
+  mm_status->msg_type  = B_MM_STATUS;
+  mm_status->rej_cause = cause;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_build_rr_sync_req_cause |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is used to synchronize RR information 
+            with changed information in MM.
+            The function mm_build_rr_sync_req_cause() is used especially
+            if the registration has failed for some reason, e.g. 
+            authentication failure. Cause value is given, 
+            ciphering information and tmsi are not present if this 
+            function is called.
+
+*/
+
+GLOBAL void mm_build_rr_sync_req_cause (USHORT cause)
+{
+  GET_INSTANCE_DATA;
+  PALLOC (rr_sync_req, RR_SYNC_REQ); /* T_RR_SYNC_REQ */
+
+  TRACE_FUNCTION ("mm_build_rr_sync_req_cause ()");
+
+  rr_sync_req->op.v_op    = V_OP_NOT_PRES;
+  rr_sync_req->cksn       = CKSN_NOT_PRES;
+  rr_sync_req->kcv.v_kc   = V_KC_NOT_PRES;
+  rr_sync_req->tmsi_struct.v_mid = V_MID_NOT_PRES;
+  rr_sync_req->plmn.v_plmn = V_PLMN_NOT_PRES;
+  rr_sync_req->synccs     = cause;
+  rr_sync_req->accc       = mm_data->reg.acc_class;
+  rr_sync_req->eq_plmn_list.v_eq_plmn = FALSE;
+
+  TRACE_EVENT_P1 ("sync_cause = %04x", cause);
+
+  switch (cause)
+  {
+    case SYNCCS_LAI_ALLOW:
+    case SYNCCS_LAI_NOT_ALLOW:
+    case SYNCCS_LAI_NOT_ALLOW_FOR_ROAMING:
+      rr_sync_req->plmn.v_plmn = V_PLMN_PRES;
+      memcpy (rr_sync_req->plmn.mcc, mm_data->mm.lai.mcc, SIZE_MCC);
+      memcpy (rr_sync_req->plmn.mnc, mm_data->mm.lai.mnc, SIZE_MNC);
+      rr_sync_req->lac = mm_data->mm.lai.lac;
+      break;
+    case SYNCCS_EPLMN_LIST:
+      rr_sync_req->eq_plmn_list.v_eq_plmn = TRUE;
+      memcpy(&rr_sync_req->eq_plmn_list.eq_plmn, 
+             &mm_data->reg.eqv_plmns.eqv_plmn_list, 
+             EPLMNLIST_SIZE*UBYTES_PER_PLMN);
+      break;
+    default: /* eg. SYNCCS_ACCC */
+      break;
+  }
+  PSENDX (RR, rr_sync_req);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_build_rr_sync_req       |
++--------------------------------------------------------------------+
+
+  PURPOSE : The function unifies the functions mm_build_rr_sync_req_mode()
+            and mm_build_rr_sync_req_ciph() and is used to synchronize 
+            RR information with changed information in MM. The parameter
+            'ciph' decides whether the ciphering parameters are to be 
+            set.
+*/
+
+GLOBAL void mm_build_rr_sync_req (T_MSG_TYPE ciph)
+{
+  GET_INSTANCE_DATA;
+  PALLOC (rr_sync_req, RR_SYNC_REQ); /* T_RR_SYNC_REQ */
+
+  TRACE_FUNCTION ("mm_build_rr_sync_req()");
+  rr_sync_req->tmsi_struct.v_mid   = V_MID_NOT_PRES;
+  rr_sync_req->synccs              = NOT_PRESENT_16BIT;
+  rr_sync_req->accc                = mm_data->reg.acc_class;
+  rr_sync_req->plmn.v_plmn         = V_PLMN_NOT_PRES;
+
+  if( ciph EQ MSG_MM_CIPH)
+  {
+    rr_sync_req->op.v_op           = V_OP_NOT_PRES;
+    rr_sync_req->cksn              = mm_data->reg.cksn;
+    rr_sync_req->kcv.v_kc          = V_KC_PRES;
+    memcpy (rr_sync_req->kcv.kc, mm_data->reg.kc, MAX_KC);
+  }
+  else
+  {
+    memcpy (&rr_sync_req->op, &mm_data->reg.op, sizeof (T_op));
+    rr_sync_req->cksn              = NOT_PRESENT_8BIT;
+    rr_sync_req->kcv.v_kc          = V_KC_NOT_PRES;
+  }
+  PSENDX (RR, rr_sync_req);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_build_rr_sync_req_tmsi  |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is used to synchronize RR information 
+            with changed information in MM.
+            The function mm_build_rr_sync_req_tmsi() is used especially
+            to inform RR about a change in the ciphering parameter 
+            tmsi.
+            
+*/
+
+GLOBAL void mm_build_rr_sync_req_tmsi (void)
+{
+  GET_INSTANCE_DATA;
+  PALLOC (rr_sync_req, RR_SYNC_REQ); /* T_RR_SYNC_REQ */
+
+  TRACE_FUNCTION ("mm_build_rr_sync_req_tmsi ()");
+
+  rr_sync_req->op.v_op           = V_OP_NOT_PRES;
+  rr_sync_req->cksn              = CKSN_RES;
+  rr_sync_req->kcv.v_kc          = V_KC_NOT_PRES;
+  rr_sync_req->plmn.v_plmn       = V_PLMN_NOT_PRES;
+  rr_sync_req->synccs            = NOT_PRESENT_16BIT;
+  rr_sync_req->accc              = mm_data->reg.acc_class;
+
+  memset (rr_sync_req->tmsi_struct.id, 0, 
+          sizeof (rr_sync_req->tmsi_struct.id));  /* IMSI digits */
+  rr_sync_req->tmsi_struct.v_mid    = V_MID_PRES;
+  rr_sync_req->tmsi_struct.id_type  = TYPE_TMSI;
+  rr_sync_req->tmsi_struct.tmsi_dig = mm_data->reg.tmsi;
+
+  PSENDX (RR, rr_sync_req);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_build_rr_sync_hplmn_req |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is used to synchronize RR information 
+            with changed AHPLMN in MM.
+            The function mm_build_rr_sync_hplmn_req() is used especially
+            to inform RR about the change of the status of RPLMN to AHPLMN.            
+            
+*/
+
+GLOBAL void mm_build_rr_sync_hplmn_req (void)
+{
+  GET_INSTANCE_DATA;
+
+  PALLOC (rr_sync_hplmn_req, RR_SYNC_HPLMN_REQ); /* T_RR_SYNC_HPLMN_REQ */
+
+  TRACE_FUNCTION ("mm_build_rr_sync_hplmn_req()");
+
+  rr_sync_hplmn_req->plmn.v_plmn = mm_data->reg.acting_hplmn.v_plmn;
+  memcpy(&rr_sync_hplmn_req->plmn.mcc, &mm_data->reg.acting_hplmn.mcc, SIZE_MCC);
+  memcpy(&rr_sync_hplmn_req->plmn.mnc, &mm_data->reg.acting_hplmn.mnc, SIZE_MNC);
+
+  PSENDX(RR,rr_sync_hplmn_req);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_check_critical_error    |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function checks wheter a critical error has been 
+            detected in the air message. Critical errors which prevent 
+            the treatment of an air message are 
+            - invalid Message ID
+            - mandatory IE missing
+            - IE coded as comprehension required missing
+*/
+
+GLOBAL BOOL mm_check_critical_error (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_check_critical_error ()");
+  if (mm_data->error EQ RC_INVALID_MAND_MESSAGE     OR 
+      mm_data->error EQ RC_MESSAGE_TYPE_NOT_IMPLEM  OR
+      mm_data->error EQ RC_CONDITIONAL_IE           OR
+      mm_data->error EQ RC_SERVICE_NOT_SUPPORTED    OR
+      mm_data->error EQ RC_MESSAGE_INCOMPAT         OR
+      mm_data->error EQ RC_MESSAGE_TYPE_INCOMPAT)
+  {
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_send_status             |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function checks wheter a critical error has been 
+            detected requiring 
+            - to abort the AIM processing and
+            - to send a STATUS message.
+            The error can be detected by CCD or within the AIM processing itself.
+            If any, the message is send, using the value found in mm_data->error as cause.
+*/
+
+GLOBAL BOOL mm_send_status_on_error (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_send_status_on_error ()");
+  if (mm_check_critical_error())
+  {
+
+/* Implements Measure 29 and streamline encoding */
+    mm_send_status(mm_data->error);
+    mm_for_set_error (0);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_check_error_flag        |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function checks wheter a critical error has been 
+            detected in the air message. Critical errors which prevent 
+            the treatment of an air message are all errors except 
+            an error in an optional information element.
+            [In calls of this function it is checked whether the 
+             error is an RC_INVALID_MAND_MESSAGE, only this case is 
+             treated as error in the caller's code. The code could be 
+             simplified here if mm_check_error_flag() was a function 
+             returning a BOOLEAN, indicating whether the message is valid
+             or not. This is done this way in the CC entitity.]
+
+*/
+
+GLOBAL void mm_check_error_flag (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_check_error_flag ()");
+  if (mm_data->error NEQ 0 AND 
+      mm_data->error NEQ OPTIONAL_INFO_ERROR)
+  {
+/* Implements Measure 29 and streamline encoding */
+    mm_send_status(mm_data->error);
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_clear_mob_ident         |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function zeroes out the mobile identity. 
+
+
+*/
+
+GLOBAL void mm_clear_mob_ident (T_imsi_struct*mob_ident)
+{
+  TRACE_FUNCTION ("mm_clear_mob_ident ()");
+  
+  memset (mob_ident, 0, sizeof (T_imsi_struct));
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_clear_reg_data          |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function clears some variables in the registration 
+            data. This is done in a way that the SIM data is not lost, 
+            the SIM data is only disabled by setting a software flag
+            indicating MM shall not use the SIM data until it is 
+            requested to do so by upper layers.
+
+*/
+
+GLOBAL void mm_clear_reg_data (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_clear_reg_data ()");
+ 
+  mm_data->reg.op.func = FUNC_LIM_SERV_ST_SRCH;
+  mm_data->reg.op.sim_ins = SIM_NO_INSRT;
+  mm_data->first_attach = TRUE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_copy_rr_act_cnf_data    |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function copies the data delivered by RR_ACTIVATE_CNF
+            or RR_ACTIVATE_IND into the internal MM data structures.
+
+*/
+
+GLOBAL void mm_copy_rr_act_cnf_data (T_RR_ACTIVATE_CNF *rr_activate_cnf)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_copy_rr_act_cnf_data ()");
+
+  mm_data->mm.mm_info = rr_activate_cnf->mm_info; /* Stucture copy */
+  memcpy (mm_data->mm.lai.mcc, rr_activate_cnf->plmn.mcc, SIZE_MCC);
+  memcpy (mm_data->mm.lai.mnc, rr_activate_cnf->plmn.mnc, SIZE_MNC);
+  mm_data->mm.lai.lac = rr_activate_cnf->lac;
+  mm_data->mm.cid = rr_activate_cnf->cid;
+
+  EM_CELL_SELECTION_RESELECTION;
+
+#ifdef GPRS
+  mm_data->mm.gprs_indication= rr_activate_cnf->gprs_indication;
+#endif /* GPRS */
+
+  // Write-only variable, eliminated HM 20.07.00
+  // mm_data->mm.lac = rr_activate_cnf->lac;
+
+  /*
+   * Until now we have only knowledge that chinese networks
+   * seem to have special problems we have to deal with,
+   * but maybe other countries have these special problems, too.
+   */
+  poor_quality_network =
+    ((rr_activate_cnf->plmn.mcc[0] EQ 4) AND
+     (rr_activate_cnf->plmn.mcc[1] EQ 6) AND
+     (rr_activate_cnf->plmn.mcc[2] EQ 0));
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_count_connections       |
++--------------------------------------------------------------------+
+
+  PURPOSE : Count the number of connections which connection state 
+            equals to the parameter conn_type. In case conn_type 
+            is CM_NOT_IDLE, all connections not idle are counted.
+
+*/
+
+GLOBAL SHORT mm_count_connections (UBYTE conn_type)
+{
+  GET_INSTANCE_DATA;
+  UBYTE cm;
+  UBYTE ti;
+  SHORT count = 0;
+    
+  TRACE_FUNCTION ("mm_count_connections ()");
+  
+  for (cm = 0; cm < NUM_OF_CM_ENT; cm++)
+  {
+    for (ti = 0; ti < NUM_OF_CONN_PER_CM_ENT; ti++)
+    {
+      if (((conn_type EQ CM_NOT_IDLE) AND (CMSTATE(cm, ti) NEQ CM_IDLE)) OR
+          (CMSTATE(cm, ti) EQ conn_type))
+      {
+#if defined (WIN32)
+        (void)CM_GET_STATE(cm, ti);
+#endif
+        count++;
+      }
+    }
+  }
+  return (count);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_create_est_message      |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functinon creates the establishment message, 
+            either for MM services or for CM services. 
+            If the entitity requiring service is a CM component, 
+            the CM entitity will be remembered in mm_data->last_comp.
+
+*/
+
+GLOBAL void mm_create_est_message (USHORT    est_cause,
+                                   UBYTE     service,
+                                   UBYTE     ti,
+                                   USHORT    *bit_size_message)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_create_est_message ()");
+
+  TRACE_EVENT_P1 ("  ESTCS = %x", est_cause);
+  TRACE_EVENT_P7 ("  REG: MCC=%X%X%X MNC=%X%X%X LAC=%04X",
+                  mm_data->reg.lai.mcc[0],
+                  mm_data->reg.lai.mcc[1],
+                  mm_data->reg.lai.mcc[2],
+                  mm_data->reg.lai.mnc[0],
+                  mm_data->reg.lai.mnc[1],
+                  mm_data->reg.lai.mnc[2],
+                  mm_data->reg.lai.lac);
+  TRACE_EVENT_P7 ("  MM: MCC=%X%X%X MNC=%X%X%X LAC=%04X",
+                  mm_data->mm.lai.mcc[0],
+                  mm_data->mm.lai.mcc[1],
+                  mm_data->mm.lai.mcc[2],
+                  mm_data->mm.lai.mnc[0],
+                  mm_data->mm.lai.mnc[1],
+                  mm_data->mm.lai.mnc[2],
+                  mm_data->mm.lai.lac);
+
+  if (est_cause NEQ ESTCS_SERV_REQ_BY_MM)
+  {
+    UBYTE comp;
+
+    /*
+     * Set the CM component requiring CM service 
+     */
+    switch (service)
+    {
+      case CALL_SERVICE:
+      case EMERGENCY_SERVICE:
+        comp = CC_COMP;
+        break;
+
+      case SS_SERVICE:
+        comp = SS_COMP;
+        break;
+
+      case SMS_SERVICE:
+        comp = SMS_COMP;
+        break;
+
+      default: /* Request for MM service */
+        TRACE_ERROR ("Illegal service");
+        comp = CC_COMP; /* Just to say something */
+        break;
+    }
+
+    mm_data->pend_conn.ti   = ti;
+    mm_data->pend_conn.comp = comp;
+    mm_data->pend_conn.service = service;
+    mm_data->pend_conn.cause = est_cause;
+    if (est_cause EQ ESTCS_CAL_REEST)
+    {
+      CM_SET_STATE (comp, ti, CM_REEST_PENDING);
+    }
+    else
+    {
+      CM_SET_STATE (comp, ti, CM_PENDING);
+    }
+  }
+
+  mm_data->rej_cause = 0;
+
+  switch (est_cause)
+  {
+    case ESTCS_CAL_REEST:
+      {
+        MCAST (cm_reestab_req, U_CM_REESTAB_REQ); /* T_U_CM_REESTAB_REQ */
+
+        *bit_size_message = BSIZE_U_CM_REESTAB_REQ;
+        cm_reestab_req->msg_type = U_CM_REESTAB_REQ;
+        cm_reestab_req->ciph_key_num.key_seq = mm_data->reg.cksn;
+        cm_reestab_req->v_loc_area_ident = FALSE;
+
+        csf_read_mobile_class_2 (&cm_reestab_req->mob_class_2);
+        cm_reestab_req->mob_class_2.rf_pow_cap = mm_data->rf_power;
+
+        if (mm_fill_ident_for_est (&cm_reestab_req->mob_id) EQ ID_TYPE_TMSI)
+        {
+          /* TMSI used. Include also location area to make this unambiguous */
+          cm_reestab_req->v_loc_area_ident = TRUE;
+          cm_reestab_req->loc_area_ident = mm_data->reg.lai; /* Struct copy */
+        }
+      }
+      break;
+
+    case ESTCS_SERV_REQ_BY_MM:
+      {
+        MCAST (loc_upd_req, U_LOC_UPD_REQ); /* T_U_LOC_UPD_REQ */
+
+        *bit_size_message = BSIZE_U_LOC_UPD_REQ;
+        loc_upd_req->msg_type = U_LOC_UPD_REQ;
+        loc_upd_req->loc_upd_type = mm_data->loc_upd_type; /* Struct copy */
+        loc_upd_req->ciph_key_num.key_seq = mm_data->reg.cksn;
+        loc_upd_req->loc_area_ident = mm_data->reg.lai; /* Struct copy */
+        if (loc_upd_req->loc_area_ident.mnc[2] EQ 0xF)
+          loc_upd_req->loc_area_ident.c_mnc = 2;
+        csf_read_mobile_class_1 (&loc_upd_req->mob_class_1);
+        loc_upd_req->mob_class_1.rf_pow_cap = mm_data->rf_power;
+        mm_fill_ident_for_est (&loc_upd_req->mob_id);
+      }
+      break;
+
+    default:
+      {
+        MCAST (cm_serv_req, U_CM_SERV_REQ); /* T_U_CM_SERV_REQ */
+
+        EM_CM_SERVICE_REQUESTED;
+
+#if defined (WIN32)
+        {
+          char buf [40];
+          sprintf (buf, "detected power = %d", mm_data->rf_power);
+          TRACE_FUNCTION (buf);
+        }
+#endif
+
+        *bit_size_message = BSIZE_U_CM_SERV_REQ;
+        cm_serv_req->msg_type = U_CM_SERV_REQ;
+        cm_serv_req->cm_serv_type = service;
+        cm_serv_req->ciph_key_num.key_seq = mm_data->reg.cksn;
+
+        csf_read_mobile_class_2 (&cm_serv_req->mob_class_2);
+        cm_serv_req->mob_class_2.rf_pow_cap = mm_data->rf_power;
+
+        mm_fill_ident_for_est (&cm_serv_req->mob_id);
+      }
+      break;
+  }
+}
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)    MODULE  : MM_MM                         |
+| STATE   : code             ROUTINE : mm_create_imsi_detach_message |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function creates the IMSI DETACH message. This may 
+            either be forwarded to the network by the means of 
+            RR_ESTABLISH_REQ or RR_DATA_REQ if a network connection 
+            already exists.
+
+*/
+
+GLOBAL void mm_create_imsi_detach_message (void)
+{
+  GET_INSTANCE_DATA;
+  MCAST (imsi_detach, U_IMSI_DETACH_IND);
+
+  TRACE_FUNCTION ("mm_create_imsi_detach_message ()");
+
+  imsi_detach->msg_type = U_IMSI_DETACH_IND;
+  csf_read_mobile_class_1 (&imsi_detach->mob_class_1);
+  imsi_detach->mob_class_1.rf_pow_cap = mm_data->rf_power;
+  mm_fill_ident_for_est (&imsi_detach->mob_id);
+
+  EM_IMSI_DETACH;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_delete_entry            |
++--------------------------------------------------------------------+
+
+  PURPOSE :   The purpose of this function is to delete a stored entry
+              previously written by the mm_write_entry() function.
+              There are some types of entries which may be stored in
+              the T_STORE data structure.
+              - Establish attempts by the CM sublayer (MMXX_ESTABLISH_REQ)
+              - Net requests by MMI (MMXXX_NET_REQ, AT+COPS=?)
+              - Expired timers (TIMEOUT)
+              - primitives incoming
+              In case the content type is set to PRIMITIVE_ENTRY currently
+              nothing is done, because no delete case was necessary so far.
+
+*/
+
+GLOBAL void mm_delete_entry (UBYTE comp, UBYTE ti)
+{
+  GET_INSTANCE_DATA;
+  USHORT  i;
+  USHORT  j;
+
+  TRACE_FUNCTION ("mm_delete_entry ()");
+
+  /*
+   * Find stored entry in table
+   */
+  for (i = 0; i < MAX_STORE_ENTRIES; i++)
+  {
+    if (mm_data->store[i].content_type EQ EVENT_ENTRY)
+    {
+
+      if (mm_data->store[i].use NEQ ENTRY_FREE AND
+          mm_data->store[i].content.event.comp EQ comp AND
+          mm_data->store[i].content.event.ti   EQ ti)
+      {
+        TRACE_EVENT_P2 ("Delete entry: comp=%d, ti=%d", comp, ti);
+        
+        for (j = i; j < MAX_STORE_ENTRIES - 1; j++)
+        {
+          mm_data->store[j] = mm_data->store[j + 1]; /* Struct copy */
+        }        
+          mm_data->store[MAX_STORE_ENTRIES - 1].use = ENTRY_FREE;
+          mm_data->store[MAX_STORE_ENTRIES - 1].content_type = NO_ENTRY;
+          
+        if (comp < NUM_OF_CM_ENT)
+        {
+            /* Establish request for any CM entity has been deleted */
+            CM_SET_STATE(comp, ti, CM_IDLE);
+        } 
+        return;
+      } /*IF comp ti*/
+    } /*IF content_type*/
+  } /*FOR*/
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_set_follow_on_request   |
++--------------------------------------------------------------------+
+
+  PURPOSE : set the follow on request if at least one connection 
+            attempt is stored.
+
+*/
+
+GLOBAL BOOL mm_set_follow_on_request (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_set_follow_on_request()");
+
+  if (mm_count_connections (CM_STORE) NEQ 0 AND mm_cm_est_allowed())
+  {
+    mm_data->loc_upd_type.follow = FOR_PENDING_YES;
+    return TRUE;
+  }
+  else
+  {
+    mm_data->loc_upd_type.follow = FOR_PENDING_NO;
+    return FALSE;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_init                    |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function initializes the MM data structures.
+
+*/
+
+GLOBAL void mm_init (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_init()");
+
+  TIMERSTOP (T_REGISTRATION);
+  TIMERSTOP (T3210);
+  TIMERSTOP (T3211);
+  TIMERSTOP (T3212);  
+  mm_data->t3212_timeout = FALSE;
+  TIMERSTOP (T3213);
+  mm_data->t3213_restart = 0;
+  TIMERSTOP (T3220);
+  TIMERSTOP (T3230);
+  TIMERSTOP (T3240);
+#ifdef REL99
+  TIMERSTOP (T3241);
+#endif
+
+  memset (mm_data, 0, sizeof (T_MM_DATA));
+  mm_data->limited_cause = MMCS_SIM_REMOVED; /* MMCS_SIM_INVAL_NOSIM */
+
+  mm_data->last_auth_req_id = NOT_PRESENT_8BIT;
+  mm_data->first_attach = TRUE;
+  mm_data->first_attach_mem = FALSE;
+
+  mm_data->t3212_cfg_counter = 0;
+  mm_data->idle_entry = RRCS_INT_NOT_PRESENT;
+  mm_data->ciphering_on = CIPH_NOT_PRES; /* Initialize ciphering indicator */
+
+  
+  mm_data->reg.length_mnc = 2;
+  mm_data->net_search_count = 0;
+  mm_data->ef_indicator = 0; /* Initialize for EF indication to SIM */
+  mm_data->reg.is_cingular_sim = FALSE; /*This flag is specially for cingular n/w*/
+  
+  reg_init ();
+
+  poor_quality_network = FALSE;
+
+#ifdef GPRS
+  SET_STATE (STATE_REG_TYPE, REG_GPRS_INACTIVE);
+  SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EST_IDLE);
+#endif /* GPRS */
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_calculate_digits        |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function calculates the length of the IMSI. 
+            (The digits delivered to this function are the digits of
+            an IMSI, but this doesn't become obvious from the function's
+            or parameter's name.)
+
+*/
+
+GLOBAL UBYTE mm_calculate_digits (const UBYTE *digits)
+{
+  UBYTE i = 0;
+
+  TRACE_FUNCTION ("mm_calculate_digits()");
+
+  while (digits[i] < 0x0A AND i < 16)
+    i++;
+
+  return i;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_loc_upd_rej             |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is called if LOCATION UPDATING REJECT has 
+            been received and then after the RR connection has been 
+            released or aborted, after leaving MM_LUP_REJECTED state.
+            It is also used if MMGMM_ATTACH_REJ_REQ is received by GMM.
+            It is also used if MMGMM_NREG_REQ is received with
+            cs EQ CS_DISABLE and certain mmgmm_error_cause values.
+            Maybe the name "mm_network_rejected()" would be a 
+            better name for the function now.
+
+            NOTE: For MM's own location updating, every non-defined 
+                  cause is mapped into RC_SERVICE_ORDER (0x22). 
+                  If the network sends some GPRS only defined cause 
+                  by means of the LOCATION UPDATING REJECT message, 
+                  we catch this in the default.
+
+*/
+
+GLOBAL void mm_loc_upd_rej (void)
+{
+  GET_INSTANCE_DATA;
+  T_plmn hplmn;
+
+  TRACE_FUNCTION ("mm_loc_upd_rej ()");
+
+  reg_extract_hplmn (&hplmn);
+
+  TRACE_EVENT_P1 ("rej_cause = %04X", mm_data->rej_cause);
+
+  /* 
+   * T3212 is stopped if a LOCATION UPDATING ACCEPT or 
+   * LOCATION UPDATING REJECT message is received.
+   * [GSM 04.08 subclause 4.4.2]
+   * Exception: MMGMM_ERRCS_GPRS_NOT_ALLOWED_IN_PLMN as this shall not
+   * have any influence on T3212.
+   */
+#ifdef GPRS
+  if (mm_data->rej_cause NEQ GMMCS_GPRS_NOT_ALLOWED_IN_PLMN)
+#endif /* #ifdef GPRS */
+  {
+    TIMERSTOP (T3212);
+    mm_data->t3212_timeout = FALSE;
+  }
+
+  switch (mm_data->rej_cause)
+  {
+    case MMCS_PLMN_NOT_ALLOWED: /* #11 + Ofs */
+#ifdef GPRS
+    case GMMCS_PLMN_NOT_ALLOWED:
+#endif /* #ifdef GPRS */
+      mm_data->attempt_cnt = 0;
+      mm_data->loc_upd_type.lut = NOT_RUNNING;
+      if (reg_plmn_equal_hplmn (&mm_data->reg.actual_plmn) EQ FALSE)
+      {
+        /*
+         * The PLMN is only added to forbidden list if not the HPLMN.
+         * An internal error of the HPLMN would otherwise invalidate
+         * the SIM for the HPLMN even after SIM removal/SIM insertion.
+         */
+        reg_plmn_add_bad (mm_data->reg.forb_plmn, 
+                          MAX_FORB_PLMN_ID,
+                          &mm_data->reg.actual_plmn);
+        mm_build_rr_sync_req_cause (SYNCCS_LIMITED_SERVICE);
+        mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL);
+
+        /* Delete EPLMN List */
+        if (reg_clear_plmn_list (mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE))
+          mm_build_rr_sync_req_cause(SYNCCS_EPLMN_LIST);
+#ifdef REL99
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED, FALSE);
+#else
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED);
+#endif
+        /* Set the new MM state before calling reg_mm_failure() */
+        SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE);
+        reg_mm_failure (FORB_PLMN_INCLUDED);
+      }
+      else
+      {
+        /* 
+         * Cause #11 for the HPLMN. This is a network failure.
+         */
+
+        // Call mm_lup_restart() instead? Makes no sense this way...
+
+        mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL);
+
+        /* Delete EPLMN List */
+        if (reg_clear_plmn_list (mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE))
+          mm_build_rr_sync_req_cause(SYNCCS_EPLMN_LIST);
+        
+#ifdef REL99
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED, FALSE);
+#else
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED);
+#endif
+        /* Set the new MM state before calling reg_mm_failure() */
+        SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE);
+        reg_mm_failure (FORB_PLMN_NOT_INCLUDED);
+      }
+
+      USE_STORED_ENTRIES();
+      break;
+
+    case MMCS_LA_NOT_ALLOWED: /* #12 + Ofs */
+#ifdef GPRS
+    case GMMCS_LA_NOT_ALLOWED:
+#endif /* #ifdef GPRS */
+      /* 
+       * There is no list of "forbidden location areas for regional
+       * provision of service" supported by G23. Compare this with the 
+       * requirements of GSM 04.08 subclause 4.4.4.7.
+       * The non-implementation of this list should not cause any 
+       * harm for cause #12.
+       */
+      mm_data->attempt_cnt = 0;
+      mm_build_rr_sync_req_cause (SYNCCS_LAI_NOT_ALLOW);
+      mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL);
+
+      mm_data->loc_upd_type.lut = NOT_RUNNING;
+#ifdef REL99
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED, FALSE);
+#else
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED);
+#endif
+      /* Set the new MM state before calling reg_mm_failure() */
+      SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE);
+      reg_mm_failure (FORB_PLMN_NOT_INCLUDED);
+      USE_STORED_ENTRIES();
+      break;
+
+    
+#ifdef GPRS
+    case GMMCS_ROAMING_NOT_ALLOWED:
+#ifdef REL99
+      /* Invalidate the TMSI, CKSN, KC in RR */
+      mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL);
+      case GMMCS_ROAMING_NOT_ALLOWED_WITH_RAU_REJ: /* #13 + Ofs GMM sent for GPRS RAU rejected case*/
+      /* GMM sent cause value 13 becauseof 'Normal/periodic RAU Rejected' or 
+       * 'Combined RAU Rejected by the network'.*/
+      /*FALLTHROUGH*/
+#endif
+      /*FALLTHROUGH*/
+      //lint -fallthrough
+#endif /* #ifdef GPRS */
+    case MMCS_ROAMING_NOT_ALLOWED: /* #13 + Ofs */
+      /* MM received cause value 13 because of 'LU rejected' by the network*/
+      /*
+       * For the cause 13 handling as per the specification 24.008 v3.15.0,
+       * If Cause value 13 received because of 'LU rejected' or 'Normal/periodic RAU
+       * Rejected' or 'Combined RAU Rejected by the network' MM will
+       *   - store the LAI in the list of "forbidden location areas for roaming".
+       *   - set the update status to U3 ROAMING NOT ALLOWED and shall reset the
+       *     location update attempt counter
+       *   - The mobile station shall perform a PLMN selection instead of a cell
+       *     selection when back to the MM IDLE state according to 3GPP TS 23.122.
+       *
+       * If cause value 13 received because of 'GPRS attach rejected' or 'Combined
+       * GPRS rejected' or 'Network initiated GPRS detach' MM will
+       *   - Do the above steps
+       *   - Additionally MM will any TMSI and ciphering key sequence number.
+       */
+      mm_data->attempt_cnt = 0;
+      mm_data->loc_upd_type.lut = NOT_RUNNING;
+
+      /* Remember the PLMN which sent this reject cause, it's low prio now */
+      mm_data->reg.low_prio_plmn = mm_data->reg.actual_plmn; /* Struct copy */
+      
+      /* Enter the location area in RR into the list of 
+       * "forbidden location areas for roaming" for reject cause #13.
+       * This list is maintained in RR */
+      mm_build_rr_sync_req_cause (SYNCCS_LAI_NOT_ALLOW_FOR_ROAMING);
+
+      /* Inform RR about the limited service condition */
+      mm_build_rr_sync_req_cause (SYNCCS_LIMITED_SERVICE);
+
+      /* As RR_SYNC_REQ (SYNCCS_LIMITED_SERVICE) clears the PLMN in RR, 
+       * we do the same with the actual PLMN in MM. */
+      reg_clear_plmn (&mm_data->reg.actual_plmn);
+#ifndef REL99
+      /* Invalidate the TMSI, CKSN, KC in RR */
+      mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL);
+#endif
+      /* Delete EPLMN List */
+      if (reg_clear_plmn_list (mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE))
+        mm_build_rr_sync_req_cause(SYNCCS_EPLMN_LIST);
+
+#ifdef REL99
+#ifdef GPRS
+      /* Following will check if the TMSI, CKSN, KC needs to be deleted */
+      if(mm_data->rej_cause EQ GMMCS_ROAMING_NOT_ALLOWED)
+      {
+        /*
+         * Update the MM state with invalidate the TMSI, CKSN, KC in MM
+         * and send indication to SIM.
+         */
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED, FALSE);
+      }
+      else
+#endif /* #ifdef GPRS */
+      {
+        /*
+         * update the MM state but don't delete the TMSI, CKSN, KC 
+         * and send indication to SIM.
+         */
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED, TRUE);
+      }
+
+#else
+      /* Inform the SIM */
+      reg_invalidate_upd_state (MS_LA_NOT_ALLOWED);
+#endif
+      /* Set the new MM state before calling reg_mm_failure() */
+      SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE);
+      reg_mm_failure (FORB_PLMN_NOT_INCLUDED);
+      USE_STORED_ENTRIES();
+      break;
+
+#ifdef REL99
+#ifdef GPRS
+    case GMMCS_NO_SUITABLE_CELL_IN_LA: /* #15 + Ofs GMM sent for GPRS attach rejected case*/
+      /* GMM sent cause value 15 because of 'GPRS attach rejected' or 'Combined GPRS rejected'
+       * or 'Network initiated GPRS detach'.*/
+      /* Invalidate the TMSI, CKSN, KC in RR */
+      mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL);
+      /*FALLTHROUGH*/
+    case GMMCS_NO_SUITABLE_CELL_IN_LA_WITH_RAU_REJ: /* #15 + Ofs GMM sent for GPRS RAU rejected case*/
+      /* GMM sent cause value 15 because of 'Normal/periodic RAU Rejected' or 
+       * 'Combined RAU Rejected by the network'.*/
+      /*FALLTHROUGH*/
+      //lint -fallthrough
+#endif
+    case MMCS_NO_SUITABLE_CELL_IN_LA: /* #15 + Ofs MM received in LU rejected message*/
+      /*MM received cause value 15 because of 'LU rejected' by the network*/
+      /*
+       * For cause 15 handling as per the specification 24.008 v3.15.0,
+       * If Cause value 15 received because of 'LU rejected' or 'Normal/periodic RAU
+       * Rejected' or 'Combined RAU Rejected by the network' MM will
+       *   - store the LAI in the list of "forbidden location areas for roaming".
+       *   - set the update status to U3 ROAMING NOT ALLOWED and shall reset the
+       *     location update attempt counter
+       *   - The MS shall search for a suitable cell in another location area in
+       *     the same PLMN according to 3GPP TS 03.22 and 3GPP TS 25.304.
+       * If cause value 15 received because of 'GPRS attach rejected' or 'Combined
+       * GPRS rejected' or 'Network initiated GPRS detach' MM will
+       *   - Do the above steps
+       *   - Additionally will delete any TMSI and ciphering key sequence number.
+       */
+      mm_data->attempt_cnt = 0;
+      mm_data->loc_upd_type.lut = NOT_RUNNING;
+      /*
+       * Enter the location area in RR into the list of "forbidden location areas for roaming"
+       * for reject cause #15. This list is maintained in RR.
+       */
+      mm_build_rr_sync_req_cause (SYNCCS_LAI_NOT_ALLOW_FOR_ROAMING);
+
+      /* Set the new MM state MM_IDLE_LIMITED_SERVICE*/
+      SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE);
+      /* Following will check if the TMSI, CKSN, KC needs to be deleted */
+#ifdef GPRS
+      if(mm_data->rej_cause EQ GMMCS_NO_SUITABLE_CELL_IN_LA)
+      {
+        /*
+         * Update the MM state with invalidate the TMSI, CKSN, KC in MM
+         * and send indication to SIM.
+         */
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED, FALSE);
+      }
+      else
+#endif /* #ifdef GPRS */
+      {
+        /*
+         * update the MM state but don't delete the TMSI, CKSN, KC
+         * and send indication to SIM.
+         */
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED, TRUE);
+      }
+
+      /* MM should send primitive MMGMM_REG_REJ to GMM only in case if cause 15 is received
+       * because of its own failure i.e if there was either a RR failure or a MM failure
+       * (e.g. LOCATION UPDATING reject). It should then inform GMM about failure. Upon
+       * reception of MMGMM_REG_REJ primitive, GMM send failure information to MMI.
+       */
+      if(GET_CAUSE_ORIGIN_ENTITY (mm_data->rej_cause) EQ MM_ORIGINATING_ENTITY)
+      {
+        /* MM sends primitive MMGMM_REG_REJ to GMM */
+        mm_mmgmm_nreg_ind (NREG_LIMITED_SERVICE,
+                          SEARCH_RUNNING,
+                          FORB_PLMN_NOT_INCLUDED);
+      }
+      else
+      {
+        /*Do not send NREG Indication. GMM is already unregistered*/
+      }
+      /*
+       * Start PLMN serch, try the PLMN in the list i.e. search
+       * another location area in the same PLMN.
+       */
+      mm_mmr_reg_req (FUNC_PLMN_SRCH);
+
+      /*Responce back with confirmation if MMGMM_NREG_REQ was received.*/
+      if (mm_data->nreg_request)
+      {
+        mm_mmgmm_nreg_cnf (mm_data->nreg_cause);
+      }
+
+      USE_STORED_ENTRIES();
+      break;
+#endif
+
+    case MMCS_IMSI_IN_HLR: /* #2 + Ofs */
+#ifdef GPRS
+    case GMMCS_IMSI_UNKNOWN:
+      if (!mm_lup_allowed_by_gmm())
+      {
+        /* 
+         * The "IMSI unknown in HLR" was received by a GMM request and 
+         * not by a LOCATION UPDATING REJECT message.
+         * MM must not enter MM_IDLE_NO_IMSI here, as the SIM 
+         * is still valid for the GPRS side and MM still has to deliver
+         * some services for GMM which it cannot deliver in service state 
+         * "NO IMSI". The relevant testcases here are (Release 1999):
+         * GSM 11.10 subclause 44.2.1.2.2, GSM 11.10 subclause 44.2.3.2.3.
+         * What is tested there is that after an ATTACH ACCEPT/
+         * ROUTING AREA UPDATING ACCEPT message the mobile doesn't 
+         * respond to packet paging with IMSI anymore and that no DETACH 
+         * is performed for GSM.
+         * What is not tested is that the mobile station doesn't respond to 
+         * paging with IMSI on the old channels after entering an area where 
+         * we have network mode II/III or that the mobile rejects a manual 
+         * switch to mobile class CS without switch off. 
+         * What is done here may not be perfect, but should be sufficient.         
+         * In fact, #2 may never be seen in field, as the network providers
+         * may not want to sell GPRS subscriptions without GSM subscriptions.
+         */
+
+        /* Release all waiting CM requests */
+        mm_mmxx_rel_ind (mm_data->rej_cause, CM_NOT_IDLE);
+        
+        /* 
+         * Invalidate TMSI and ciphering parameters in RR. 
+         * RR remains in full service for GPRS.
+         */
+        mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL);
+
+        /* Delete EPLMN List */
+        if (reg_clear_plmn_list (mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE))
+          mm_build_rr_sync_req_cause(SYNCCS_EPLMN_LIST);
+
+        /* Invalidate the update state */
+#ifdef REL99
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED, FALSE);
+#else
+        reg_invalidate_upd_state (MS_LA_NOT_ALLOWED);
+#endif
+
+        /* If the deregistration was caused by a MMGMM_NREG_REQ, 
+         * confirm it properly */
+        if (mm_data->nreg_request) 
+          mm_mmgmm_nreg_cnf (mm_data->nreg_cause);
+
+        /* Next state is a parking state */
+        SET_STATE (STATE_MM, MM_IDLE_LUP_NEEDED);
+        break;
+      }
+      /* 
+       * However, if #2 is received by LOCATION UPDATING REJECT message,
+       * GSM 04.08 subclause 4.4.4.7 claims that the SIM shall be considered
+       * as invalid for "the mobile station" (and not only for the GSM part).
+       * There is no distinction between causes #2, #3 and #6 there.
+       */
+      /*FALLTHROUGH*/
+      //lint -fallthrough
+#endif /* #ifdef GPRS */
+    case MMCS_ILLEGAL_MS:  /* #3 + Ofs */
+    case MMCS_ILLEGAL_ME:  /* #6 + Ofs */
+#ifdef GPRS
+    case GMMCS_ILLEGAL_MS:
+    case GMMCS_ILLEGAL_ME:
+    case GMMCS_GSM_GPRS_NOT_ALLOWED: /* #8 + Ofs */
+#endif /* #ifdef GPRS */
+      mm_clear_mob_ident (&mm_data->reg.imsi_struct);
+      mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL_NO_PAG);
+
+      /* Delete EPLMN List */
+      if (reg_clear_plmn_list (mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE))
+        mm_build_rr_sync_req_cause(SYNCCS_EPLMN_LIST);
+
+      // Debug patch >>>
+      if (mm_data->mm_idle_no_imsi_marker EQ 0)
+        mm_data->mm_idle_no_imsi_marker = 19;
+      // End debug patch
+
+      mm_data->loc_upd_type.lut = NOT_RUNNING;
+#ifdef REL99
+      reg_invalidate_upd_state (MS_LA_NOT_ALLOWED, FALSE);
+#else
+      reg_invalidate_upd_state (MS_LA_NOT_ALLOWED);
+#endif
+      /* Invalidate SIM data after indirect call to reg_build_sim_update() */
+      mm_clear_reg_data ();
+      mm_data->reg.plmn_cnt = 0; /* Delete list of available PLMNs */
+      /* Set the new MM state before calling reg_mm_failure */
+      SET_STATE (STATE_MM, MM_IDLE_NO_IMSI);
+      reg_mm_failure (FORB_PLMN_NOT_INCLUDED);
+      USE_STORED_ENTRIES();
+      break;
+
+#ifdef GPRS
+    case GMMCS_GPRS_NOT_ALLOWED_IN_PLMN: /* #14 + Ofs */
+      /* 
+       * We assume this cause will not be sent by the HPLMN.
+       *
+       * "The MS shall store the PLMN identity in the "forbidden PLMNs for
+       * GPRS service" list. A GPRS MS operating in MS operation mode C 
+       * shall perform a PLMN selection instead of a cell selection."
+       * [3GPP TS 04.08 version 7.13.0 and others]
+       */
+      reg_plmn_add_bad (mm_data->reg.gprs_forb_plmn,
+                        MAX_GPRS_FORB_PLMN_ID,
+                        &mm_data->reg.actual_plmn);
+
+      if (mm_data->reg.op.m EQ MODE_AUTO AND
+          mm_data->gprs.mobile_class EQ MMGMM_CLASS_CG AND
+          !reg_plmn_equal_hplmn (&mm_data->reg.actual_plmn))
+      {
+        if (mm_data->reg.plmn_cnt EQ 0)
+        {
+          /* A PLMN list is not present */
+          reg_extract_hplmn (&mm_data->reg.actual_plmn);
+          mm_data->reg.plmn_cnt = 0; /* Delete list of available PLMNs */
+          mm_mmr_reg_req (FUNC_PLMN_SRCH);
+        }
+        else
+        {
+          /* A PLMN list is present */
+          if (mm_data->reg.plmn_cnt > mm_data->reg.plmn_index)
+          {
+            /* 
+             * There are still untried entries in the PLMN list. 
+             * Try the next PLMN in the list.
+             */
+            reg_unpack_plmn (&mm_data->reg.actual_plmn,
+                             mm_data->reg.plmn, mm_data->reg.plmn_index);
+            mm_data->reg.plmn_index++;
+            mm_data->attempt_cnt = 0;
+            mm_mmr_reg_req (FUNC_PLMN_SRCH);
+          }
+          else
+          {
+            /* 
+             * There is no signalization to signal the end of search to 
+             * GMM here. Maybe this has to be introduced.
+             */
+          }
+        }
+      }
+      break;
+#endif /* #ifdef GPRS */
+
+    case MMCS_NETWORK_FAILURE: /* #17 + Ofs */
+#ifdef GPRS
+    case GMMCS_NET_FAIL:
+#endif /* #ifdef GPRS */
+      /*FALLTHROUGH*/
+    default:
+
+      /* Delete EPLMN List */
+      if (reg_clear_plmn_list (mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE))
+        mm_build_rr_sync_req_cause(SYNCCS_EPLMN_LIST);
+
+      mm_lup_restart ();
+      break;
+  }
+}
+
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_lup_restart             |
++--------------------------------------------------------------------+
+
+  PURPOSE : The purpose of this function is to perform the actions
+            required after a location updating attempt has failed.
+            Either T3211 or T3212 are started by this function,
+            so a new location updating attempt will be started
+            after expiry.
+
+*/
+
+GLOBAL void mm_lup_restart (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_lup_restart ()");
+
+  mm_data->last_rej_cause = 0;
+  if (mm_data->attempt_cnt < 4)
+    mm_data->attempt_cnt++;
+  if (mm_data->attempt_cnt < 4 AND
+      mm_check_lai (&mm_data->reg.lai, &mm_data->mm.lai) AND
+      mm_data->reg.update_stat EQ MS_UPDATED)
+  {
+    /*
+     * - The update status is UPDATED, and the stored LAI is equal to the one
+     *   received on the BCCH from the current serving cell and the
+     *   attempt counter is smaller than 4:
+     *   
+     *   The mobile station shall keep the update status to UPDATED, the MM IDLE 
+     *   sub-state after the RR connection release is NORMAL SERVICE. 
+     * (GSM 04.08 4.4.4.9)
+     */ 
+    TIMERSTART (T3211, T_3211_VALUE);
+    SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE);
+
+#ifdef GPRS
+    if (mm_data->gprs.sim_physically_removed)
+    {
+      mm_sim_removed_gprs_active ();
+      return;
+    }
+#endif /* #ifdef GPRS */
+
+  }
+  else
+  {
+    /* 
+     * - Either the update status is different from UPDATED, or the stored 
+     *   LAI is different from the one received by the on the BCCH from the 
+     *   serving cell, or the attempt counter is greater or equal to 4:
+     * 
+     *   The mobile station shall delete any LAI, TMSI, ciphering key sequence
+     *   number stored in the SIM, set the update status to NOT UPDATED and 
+     *   enter the MM IDLE sub-state ATTEMPTING TO UPDATE or optionally the 
+     *   MM IDLE sub-state PLMN SEARCH in order to perform a PLMN selection 
+     *   according to 3GPP TS 23.122 when the RR connection is released. If 
+     *   the attempt counter is smaller than 4, the mobile station shall 
+     *   memorize that timer T3211 is to be started when the RR connection is 
+     *   released, otherwise it shall memorize that timer T3212 is to be started 
+     *   when the RR connection is released. 
+     * (GSM 24.008 4.4.4.9)
+     */
+    mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL);
+#ifdef REL99
+    reg_invalidate_upd_state (MS_NOT_UPDATED, FALSE);
+#else
+    reg_invalidate_upd_state (MS_NOT_UPDATED);
+#endif
+
+    /* Set the new state now, vital for reg_plmn_select() */
+    SET_STATE (STATE_MM, MM_IDLE_ATTEMPT_TO_UPDATE);
+
+#ifdef GPRS
+    if (mm_data->gprs.sim_physically_removed)
+    {
+      mm_sim_removed_gprs_active ();
+      return;
+    }
+#endif /* #ifdef GPRS */
+
+    if (mm_data->attempt_cnt < 4)
+    {
+      TIMERSTART (T3211, T_3211_VALUE);
+    }
+    else
+    {
+      mm_mmxx_rel_ind (MMCS_NO_REGISTRATION, CM_NOT_IDLE);
+      mm_start_t3212_bcch ();
+      mm_data->loc_upd_type.lut = NOT_RUNNING;
+
+      if (mm_lup_allowed_by_gmm())
+      {
+        if (mm_data->reg.plmn_cnt > mm_data->reg.plmn_index)
+        {
+          /*
+           * Select the next PLMN in the list, if available.
+           * This is recommended in GSM 03.22 subclause 4.4.4.
+           * "When in Automatic Network Selection mode and the MS is in the 
+           * "not updated" state with one or more suitable cells to camp on;
+           * then after the maximum allowed unsuccessful LR requests (controlled
+           * by the specific attempt counters) the MS may continue (or start if 
+           * not running) the user reselection procedure of 4.4.3.2 A."
+           */
+          reg_plmn_select (FORB_PLMN_NOT_INCLUDED);
+        }
+        else if (mm_data->reg.op.m EQ MODE_AUTO AND
+                 mm_data->reg.op.sim_ins EQ SIM_INSRT AND
+                 mm_data->reg.quick_hplmn_search EQ TRUE)
+        {
+          /* The state PLMN SEARCH is also entered in the following cases:
+           * - optionally, when the mobile station is in the ATTEMPTING TO UPDATE 
+           * state and is in Automatic Network Selection mode and location update 
+           * attempt counter is greater than or equal to 4.
+           * (GSM 24.008 4.2.1.2)
+           */
+          /* optionally the MM IDLE sub-state PLMN SEARCH in order to perform a 
+           * PLMN selection according to 3GPP TS 23.122
+           * (GSM 24.008 4.4.4.9)
+           */
+          mm_data->plmn_scan_mm = TRUE;
+          mm_data->reg.quick_hplmn_search = FALSE;
+          mm_mmgmm_nreg_ind (NREG_LIMITED_SERVICE, 
+                       SEARCH_RUNNING,
+                       FORB_PLMN_NOT_INCLUDED);
+          mm_func_mmgmm_net_req();
+        }
+        else
+      {
+          mm_mmgmm_nreg_ind (NREG_LIMITED_SERVICE, 
+                             SEARCH_NOT_RUNNING,
+                             FORB_PLMN_NOT_INCLUDED);
+          mm_data->reg.quick_hplmn_search = TRUE;
+      }
+      }
+      
+      
+      if (mm_data->reg.op.sim_ins EQ SIM_INSRT AND 
+          mm_data->reg.op.ts EQ TS_NO_AVAIL)
+      {
+        /*
+         * If there is no test SIM inserted and after 4 unsuccessfull 
+         * registration attempts, the registration timer is started.
+         * On timeout of the registration timer, *one* normal location 
+         * updating is started.
+         * Without this, MM may stay in MM_IDLE_ATTEMPT_TO_UPDATE 
+         * for an infinite time. (No call attempt, no cell selection, 
+         * no periodic location updating)
+         */
+        TIMERSTART (T_REGISTRATION, T_REG_VALUE);
+      }
+    }
+  }
+  reg_check_hplmn_tim (mm_data->reg.thplmn);
+  USE_STORED_ENTRIES();
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mdl_rel_req             |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function sends an MDL_RELEASE_REQ for SAPI 0 to the 
+            data link layer. Usually this is done after RR_RELEASE_IND 
+            or RR_ABORT_IND is received by RR. 
+            One really good question is why this is handled in MM and
+            not in RR. But this doesn't matter as it works the way it
+            is implemented.
+
+*/
+
+GLOBAL void mm_mdl_rel_req (void)
+{
+  PALLOC (mdl_release_req, MDL_RELEASE_REQ); /* T_MDL_RELEASE_REQ */
+  TRACE_FUNCTION ("mm_mdl_rel_req ()");
+
+  mdl_release_req->sapi = SAPI_0;
+  mdl_release_req->ch_type = NOT_PRESENT_8BIT;
+
+  PSENDX (DL, mdl_release_req);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mdl_rel_req_sapi_3      |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function sends an MDL_RELEASE_REQ for SAPI 3 to the 
+            data link layer. Usually this is done after RR_RELEASE_IND 
+            or RR_ABORT_IND is received by RR. 
+            One really good question is why this is handled in MM and
+            not in RR. But this doesn't matter as it works the way it
+            is implemented.
+
+*/
+
+GLOBAL void mm_mdl_rel_req_sapi_3 (void)
+{
+  PALLOC (mdl_release_req, MDL_RELEASE_REQ);
+
+  TRACE_FUNCTION ("mm_mdl_rel_req_sapi_3 ()");
+
+  mdl_release_req->sapi = SAPI_3;
+  mdl_release_req->ch_type = NOT_PRESENT_8BIT;
+
+  PSENDX (DL, mdl_release_req);
+}
+   
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmsms_rel_ind           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions releases the SMS connections (SAPI 3) 
+            of the required connection type to the SMS entitity. This 
+            function is used if MM receives a RR_RELEASE_IND primitive
+            for SAPI 3.
+
+*/
+
+GLOBAL void mm_mmsms_rel_ind (USHORT cause, UBYTE conn_typ)
+{
+  GET_INSTANCE_DATA;
+  UBYTE ti;
+
+  TRACE_FUNCTION ("mm_mmsms_rel_ind ()");
+    
+  for (ti = 0; ti < NUM_OF_CONN_PER_CM_ENT; ti++)
+  {
+    switch (conn_typ)
+    {
+      case CM_PENDING:
+      case CM_ACTIVE:
+      case CM_REEST_PENDING:
+        if (mm_data->conn_state[SMS_COMP][ti] NEQ conn_typ)
+          continue;
+        /*FALLTHROUGH*/
+        //lint -fallthrough
+      default: /* all connections */
+        if (mm_data->conn_state[SMS_COMP][ti] EQ CM_IDLE)
+          continue;
+        CM_SET_STATE (SMS_COMP, ti, CM_IDLE);
+        mm_mmxx_release_ind (SMS_COMP, ti, cause);
+        mm_delete_entry (SMS_COMP, ti);
+        break;
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmxx_err_ind            |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is called if a radio link error occurs, 
+            this means, the RR_ABORT_IND primitive was received 
+            while active connections existed. Upper layers are 
+            notificated about the failure. The function returns the 
+            number of active connections found (CM_ACTIVE).
+
+*/
+
+GLOBAL SHORT mm_mmxx_err_ind (USHORT cause)
+{
+  GET_INSTANCE_DATA;
+  UBYTE count = 0;
+  UBYTE cm;
+  UBYTE ti;
+
+  TRACE_FUNCTION ("mm_mmxx_err_ind ()");
+  for (cm = 0; cm < NUM_OF_CM_ENT; cm++)
+  {
+    for ( ti = 0; ti < NUM_OF_CONN_PER_CM_ENT; ti++)
+    {
+      if (CMSTATE(cm, ti) EQ CM_ACTIVE)
+      {
+        count++;
+        switch (cm)
+        {
+          case CC_COMP:
+          {
+            PALLOC (mmcm_error_ind, MMCM_ERROR_IND);
+            mmcm_error_ind->ti    = ti;
+            mmcm_error_ind->cause = cause;
+            PSENDX (CC, mmcm_error_ind);
+            break;
+          }
+          case SS_COMP:
+          {
+            PALLOC (mmss_error_ind, MMSS_ERROR_IND);
+            mmss_error_ind->ti    = ti;
+            mmss_error_ind->cause = cause;
+            PSENDX (SS, mmss_error_ind);
+            break;
+          }
+          case SMS_COMP:
+          {
+            PALLOC (mmsms_error_ind, MMSMS_ERROR_IND);
+            mmsms_error_ind->ti    = ti;
+            mmsms_error_ind->cause = cause;
+            PSENDX (SMS, mmsms_error_ind);
+            break;
+          }
+          default:
+            TRACE_ERROR ("Illegal cm comp");
+            break;
+        }
+      }
+    }
+  }
+  return (count);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmxx_est_cnf            |
++--------------------------------------------------------------------+
+
+  PURPOSE : Handle CM SERVICE ACCEPT / completion of ciphering mode
+            setting for connections requested by CM entities. 
+            Two different cases, call establishment and
+            call reestablishment are handled here.
+
+*/
+
+GLOBAL void mm_mmxx_est_cnf (void)
+{
+  GET_INSTANCE_DATA;
+  UBYTE ti;
+
+  TRACE_FUNCTION ("mm_mmxx_est_cnf ()");
+  {
+    if (mm_count_connections (CM_REEST_PENDING) EQ 0)
+    {
+      /* 
+       * No connections waiting for reestablishment. The establishment
+       * was confirmed for a pending connection. Set the state of the 
+       * pending connection to CM_ACTIVE as it is now not pending anymore.
+       * Notify the CM entitity which requested the connection
+       * about the successful establishment. 
+       * (There can only be one pending connection at a given time).
+       */
+
+      CM_SET_STATE (mm_data->pend_conn.comp,
+                    mm_data->pend_conn.ti, CM_ACTIVE);
+
+      switch (mm_data->pend_conn.comp)
+      {
+        case CC_COMP:
+          {
+            PALLOC (mmcm_establish_cnf, MMCM_ESTABLISH_CNF);
+            mmcm_establish_cnf->ti = mm_data->pend_conn.ti;
+            PSENDX (CC, mmcm_establish_cnf);
+          }
+          break;
+        case SS_COMP:
+          {
+            PALLOC (mmss_establish_cnf, MMSS_ESTABLISH_CNF);
+            mmss_establish_cnf->ti = mm_data->pend_conn.ti;
+            PSENDX (SS, mmss_establish_cnf);
+          }
+          break;
+        case SMS_COMP:
+          {
+            PALLOC (mmsms_establish_cnf, MMSMS_ESTABLISH_CNF);
+            mmsms_establish_cnf->ti = mm_data->pend_conn.ti;
+            PSENDX (SMS, mmsms_establish_cnf);
+          }
+          break;
+        default:
+          TRACE_ERROR (UNEXPECTED_DEFAULT); /* Cannot happen */
+          break;
+      }
+    }
+    else
+    {
+      /* 
+       * Reestablishment pending. Only the CM entitiy CC can perform call
+       * reestablishment, so only CC needs to be treated here.
+       */
+      for (ti = 0; ti < NUM_OF_CONN_PER_CM_ENT; ti++)
+      {
+        if (mm_data->conn_state[CC_COMP][ti] EQ CM_REEST_PENDING)
+        {
+          PALLOC (mmcm_reestablish_cnf, MMCM_REESTABLISH_CNF);
+          CM_SET_STATE (CC_COMP, ti, CM_ACTIVE);
+          mmcm_reestablish_cnf->ti = ti;
+          PSENDX (CC, mmcm_reestablish_cnf);
+        }
+      }
+    }
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmxx_release_ind        |
++--------------------------------------------------------------------+
+
+  PURPOSE : Send either MMCM_RELEASE_IND, MMSS_RELEASE_IND or
+            MMSMS_RELEASE_IND, dependend of the CM component.
+
+*/
+
+GLOBAL void mm_mmxx_release_ind (UBYTE comp, UBYTE ti, USHORT relcs)
+{
+  TRACE_FUNCTION ("mm_mmxx_release_ind()");
+
+  switch (comp)
+  {
+    case CC_COMP:
+      {
+        PALLOC (mmcm_release_ind, MMCM_RELEASE_IND); /* T_MMCC_RELEASE_IND */
+        mmcm_release_ind->ti    = ti;
+        mmcm_release_ind->cause = relcs;
+        PSENDX (CC, mmcm_release_ind);
+      }
+      break;
+
+    case SS_COMP:
+      {
+        PALLOC (mmss_release_ind, MMSS_RELEASE_IND); /* T_MMSS_RELEASE_IND */
+        mmss_release_ind->ti    = ti;
+        mmss_release_ind->cause = relcs;
+        PSENDX (SS, mmss_release_ind);
+      }
+      break;
+
+    case SMS_COMP:
+      {
+        PALLOC (mmsms_release_ind, MMSMS_RELEASE_IND); /* T_MMSMS_RELEASE_IND */
+        mmsms_release_ind->ti    = ti;
+        mmsms_release_ind->cause = relcs;
+        PSENDX (SMS, mmsms_release_ind);
+      }
+      break;
+
+    default: 
+      TRACE_ERROR (UNEXPECTED_PARAMETER);
+      break;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmxx_rel_ind            |
++--------------------------------------------------------------------+
+
+  PURPOSE : The mm_mmxx_rel_ind() function releases all CM connections 
+            of a given ´given type. Type may be CM_PENDING, 
+            CM_ACTIVE, CM_REEST_PENDING and CM_NOT_IDLE.
+
+*/
+
+GLOBAL void mm_mmxx_rel_ind (USHORT cause, UBYTE conn_typ)
+{
+  GET_INSTANCE_DATA;
+  UBYTE comp;
+  UBYTE ti;
+
+  TRACE_FUNCTION ("mm_mmxx_rel_ind ()");
+
+  for (comp = 0; comp < NUM_OF_CM_ENT; comp++)
+  {
+    for (ti = 0; ti < NUM_OF_CONN_PER_CM_ENT; ti++)
+    {
+      switch (conn_typ)
+      {
+        case CM_PENDING:
+        case CM_ACTIVE:
+        case CM_REEST_PENDING:
+          if (CMSTATE(comp, ti) NEQ conn_typ)
+            continue;
+          /*FALLTHROUGH*/
+          //lint -fallthrough
+        default: /* CM_NOT_IDLE */
+          if (CMSTATE(comp, ti) EQ CM_IDLE)
+            continue;
+          CM_SET_STATE (comp, ti, CM_IDLE);
+          mm_mmxx_release_ind (comp, ti, cause);
+          mm_delete_entry (comp, ti);
+      }
+    }
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_power_off               |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function deactivates the lower layers 
+            and enters the MM NULL state.
+
+*/
+
+GLOBAL void mm_power_off (void)
+{
+  GET_INSTANCE_DATA;
+  USHORT index;
+
+  TRACE_FUNCTION ("mm_power_off ()");
+
+  /* Send RR_DEACTIVATE_REQ */
+  {
+    PALLOC (rr_deactivate_req, RR_DEACTIVATE_REQ);
+    PSENDX (RR, rr_deactivate_req);
+  }
+  
+  /* Invalidate the registration data temporary only without deleting it. */
+  mm_clear_reg_data ();
+
+  /* Stop all MM timers */
+  for (index = 0; index < NUM_OF_MM_TIMERS; index++)
+  {
+    TIMERSTOP (index);
+  }
+
+  mm_data->t3212_timeout = FALSE;
+
+  /* MM enters MM_NULL state, but the important MM data is still alive. */
+  SET_STATE (STATE_MM, MM_NULL);
+#ifdef GPRS
+  SET_STATE (STATE_REG_TYPE, REG_GPRS_INACTIVE);
+  SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EST_OK);
+#endif /* GPRS */
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_random                  |
++--------------------------------------------------------------------+
+
+  PURPOSE : A random number generator.
+
+*/
+
+GLOBAL USHORT mm_random (USHORT    n)
+{
+  GET_INSTANCE_DATA;
+  T_TIME actual_time;
+
+  TRACE_FUNCTION ("mm_random ()");
+
+  vsi_t_time (VSI_CALLER &actual_time);
+  mm_data->rand_base += actual_time;
+  return ((USHORT) mm_data->rand_base % n);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_read_entry              |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions reads the entries which are flagged as 
+            "USE" and executes them. This is done by:
+            - rebuilding the original primitives and sending them to 
+            the MM entitity in case of content_type "EVENT_ENTRY".
+            - calling the respective timeout handling routine for 
+            timers (content_type "EVENT_ENTRY"),
+            - resending the stored primitive (content_type "PRIMITIVE_ENTRY")
+
+*/
+
+GLOBAL void mm_read_entry (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_read_entry ()");
+                          
+  if (mm_data->store[0].use EQ USE)
+  {
+    USHORT i;
+    T_STORE current;
+
+    current = mm_data->store[0]; /* Struct copy */
+
+    for (i = 0; i < MAX_STORE_ENTRIES - 1; i++)
+    {
+      mm_data->store[i] = mm_data->store[i + 1]; /* Struct copy */
+    }
+    mm_data->store[MAX_STORE_ENTRIES - 1].use = ENTRY_FREE;
+    mm_data->store[MAX_STORE_ENTRIES - 1].content_type = NO_ENTRY;
+
+    TRACE_EVENT_P2 ("Read entry: comp=%d, ti=%d", current.content.event.comp, current.content.event.ti);
+
+    if (current.content_type EQ EVENT_ENTRY)
+    {
+      switch (current.content.event.comp)
+      {
+        case TIMEOUT:
+          switch (current.content.event.ti) /* TI used as timer index here */
+          {
+            case T3210:  tim_t3210 ();  break;
+            case T3211:  tim_t3211 ();  break;
+            case T3212:  tim_t3212 ();  break;
+            case T3213:  tim_t3213 ();  break;
+            case T3220:  tim_t3220 ();  break;
+            case T3230:  tim_t3230 ();  break;
+            case T3240:  tim_t3240 ();  break;
+#ifdef REL99
+            case T3241:  tim_t3241 ();  break;
+#endif
+            default: 
+              TRACE_EVENT (UNEXPECTED_DEFAULT);
+              break;
+          }
+          break;
+
+        case REG_COMP:
+          mm_func_mmgmm_net_req ();
+          break;
+
+        case SS_COMP:
+        case SMS_COMP:
+          current.content.event.estcs = 0; /* Override estcs */
+          /*FALLTHROUGH*/
+          //lint -fallthrough
+        case CC_COMP:
+          CM_SET_STATE (current.content.event.comp, current.content.event.ti, CM_IDLE);
+          mm_mmxx_establish_req (current.content.event.comp, current.content.event.ti, current.content.event.estcs, current.info);
+          break;
+
+        default:
+          TRACE_ERROR (UNEXPECTED_DEFAULT);
+          break;
+      } /* switch comp */
+    } /* if content_type */
+    else
+    {
+      /* the following code will be used if additional primitives
+       * will be stored this way or a generic handling for storage
+       * and retrieval of elements is requested.
+       */
+      switch (((T_PRIM_HEADER *)current.content.primitive)->opc)
+      {
+        case RR_ACTIVATE_IND:
+       mm_rr_activate_ind((T_RR_ACTIVATE_IND *) P2D(current.content.primitive));
+          break;
+
+        case RR_ABORT_IND:
+          mm_rr_abort_ind((T_RR_ABORT_IND *) P2D(current.content.primitive));
+          break;
+
+        default:
+          TRACE_ERROR (UNEXPECTED_DEFAULT);
+          break;
+      }
+    }/* if content_type */
+  } /* if use */
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_reest                   |
++--------------------------------------------------------------------+
+
+  PURPOSE : 
+
+*/
+
+GLOBAL void mm_reest (UBYTE ti)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_reest ()");
+  if (mm_data->reg.op.func EQ FUNC_LIM_SERV_ST_SRCH)
+  {
+    mm_mmxx_rel_ind (MMCS_NO_REGISTRATION, CM_NOT_IDLE);
+    mm_sim_set_imsi_marker( MSG_MM_REE);
+  }
+  else
+  {
+    mm_rr_est_req (ESTCS_CAL_REEST, CALL_SERVICE, ti);
+    SET_STATE (STATE_MM, MM_WAIT_FOR_RR_CONN_MM);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_release_rr_connection   |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions releases the RR connection after a 
+            CM connection / CM connection attempt or after a 
+            successfull location updating procedure.
+            It can be assumed that if this function is entered MM 
+            has better service than no service at all (no state 19.5). 
+            It can also be assumed that the mobile is not currently 
+            performing a network search, so the following IDLE state 
+            will not be one of the IDLE search states 19.7 and 19.8.
+
+*/
+
+GLOBAL void mm_release_rr_connection (UBYTE resumption)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_release_rr_connection ()");
+
+  /* 
+   * We are here after either an CM service (attempt) or 
+   * after a successfull location updating procedure.
+   * The possible remaining states from this point are:
+   * 
+   * - MM_IDLE_NORMAL_SERVICE, 19.1
+   * - MM_IDLE_ATTEMPT_TO_UPDATE, 19.2
+   * - MM_IDLE_LIMITED_SERVICE, 19.3
+   * - MM_IDLE_NO_IMSI, 19.4 
+   * - MM_IDLE_LUP_NEEDED, 19.6 (GPRS only)
+   */
+
+#ifdef GPRS
+  if (mm_data->gprs.reg_cnf_on_idle_entry AND
+      mm_count_connections (CM_NOT_IDLE) EQ 0)
+  {
+    /* Inform GMM about successful end of registration procedure */
+    mm_data->reg.full_service_indicated = FALSE; /* Force MMGMM_REG_CNF */
+    mm_mmgmm_reg_cnf ();
+  }
+
+  switch (GET_STATE (STATE_REG_TYPE))
+  {
+    case REG_GPRS_INACTIVE:
+      break; /* No further signalling for GMM needed. GPRS is off */
+
+    case REG_REMOTE_CONTROLLED:
+      if (mm_data->gprs.sim_physically_removed AND mm_normal_upd_needed())
+      {
+        /* 
+         * Indicate end of RC update to GMM after SIM removal while also
+         * engaged in a call, the MS is not updated in the location area.
+         */
+        mm_mmgmm_nreg_ind (NREG_LIMITED_SERVICE, 
+                           SEARCH_NOT_RUNNING,
+                           FORB_PLMN_NOT_INCLUDED);
+      }
+      break;
+
+    case REG_CELL_SEARCH_ONLY:
+      /* Inform GMM about release of last CM connection, if any */
+      mm_mmgmm_cm_release_ind (resumption);
+      break;
+
+    default:
+      TRACE_ERROR (UNEXPECTED_DEFAULT);
+      break;
+  }
+#endif /* GPRS */
+
+  if (mm_data->reg.op.sim_ins EQ SIM_NO_INSRT)
+  {
+    /* 
+     * The SIM is considered invalid or is not present at all.
+     */
+    if (mm_data->idle_substate NEQ MM_IDLE_NO_IMSI)
+    {
+      /* 
+       * The SIM has recently been invalidated,
+       * Indicate the new service to MMI 
+       */   
+      mm_mmgmm_nreg_ind (NREG_LIMITED_SERVICE, 
+                         SEARCH_NOT_RUNNING,
+                         FORB_PLMN_NOT_INCLUDED);
+    }
+    
+    // Find original place where MM entered MM_IDLE_NO_IMSI state >>>
+    if (mm_data->mm_idle_no_imsi_marker EQ 0)
+      mm_data->mm_idle_no_imsi_marker = 4;
+    // End of debugging patch <<<
+    SET_STATE (STATE_MM, MM_IDLE_NO_IMSI);
+    USE_STORED_ENTRIES();
+    return;
+  }
+
+  /* 
+   * If we are here the next state is not MM_IDLE_NO_IMSI.
+   */
+  
+  if (mm_data->idle_substate EQ MM_IDLE_LIMITED_SERVICE)
+  {
+    /* 
+     * If we are here we come from an emergency call (attempt) 
+     * and had previously limited service only. So we have to 
+     * re-enter limited service state here.
+     */
+    SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE);
+    USE_STORED_ENTRIES();
+    return;
+  }
+
+#ifdef GPRS 
+  if (!mm_lup_allowed_by_gmm () AND
+      (mm_normal_upd_needed () OR mm_attach_upd_needed ()))
+  {
+    /* 
+     * MM needs location updating, but is not allowed by GMM to start it.
+     */
+    if (mm_data->rej_cause EQ MMCS_IMSI_IN_VLR)
+    {
+      /* 
+       * Mobile has no registration in VLR. 
+       * Normal update after CM SERVICE REJECT with RC_IMSI_IN_VLR needed.
+       */
+
+      /* Throw out all calls to force sending of MMGMM_CM_RELEASE_IND. */
+      mm_mmxx_rel_ind (mm_data->rej_cause, CM_NOT_IDLE);
+      mm_mmgmm_cm_release_ind (resumption);
+
+      /* Reset the exceptional condition */
+      mm_data->rej_cause = 0;
+
+      /* Inform GMM about lost registration in network */
+      mm_mmgmm_lup_needed_ind (MMGMM_IMSI_IN_VLR);
+    }
+
+    SET_STATE (STATE_MM, MM_IDLE_LUP_NEEDED);
+    USE_STORED_ENTRIES();
+    return;
+  }
+#endif /* GPRS */
+
+  /* 
+   * Here the remaining possible states are:
+   * 
+   * - MM_IDLE_NORMAL_SERVICE, 19.1
+   * - MM_IDLE_ATTEMPT_TO_UPDATE, 19.2
+   * - MM_IDLE_LIMITED_SERVICE, 19.3 (?) // This is not possible
+   */
+
+  /* After CM connection (attempt), restart T3212 if necessary */
+  mm_start_t3212_bcch ();
+
+  /* 
+   * Find appropriate IDLE state:
+   * Updated anywhere => MM_IDLE_NORMAL_SERVICE 
+   * Updated nowhere  => MM_IDLE_ATTEMPT_TO_UPDATE
+   */
+  if (mm_data->reg.update_stat EQ MS_UPDATED)
+  {
+    SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE);
+  }
+  else
+  {
+    SET_STATE (STATE_MM, MM_IDLE_ATTEMPT_TO_UPDATE);
+  }
+
+  // There may be still some problems if we have a clash 
+  // RR_ESTABLISH_REQ -> RR_ACTIVATE_IND -> RR_ESTABLISH_CNF -> RR_RELEASE_IND
+  // It could be a good idea to repeat the RR_ACTIVATE_IND in this case at 
+  // exactly this place and return. To be checked...
+  
+  /* 
+   * Check whether T3211 or T3213 are running, if so, the updating
+   * will be delayed until the respective timer expires.
+   */
+  if (!TIMERACTIVE (T3211) AND !TIMERACTIVE(T3213))
+  {
+    mm_continue_running_update ();
+  }
+  USE_STORED_ENTRIES();
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_rr_act_req              |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function activates the RR sublayer
+
+*/
+
+GLOBAL void mm_rr_act_req (void)
+{
+  GET_INSTANCE_DATA;
+
+
+  PALLOC (rr_activate_req, RR_ACTIVATE_REQ); /* T_RR_ACTIVATE_REQ */
+
+  TRACE_FUNCTION ("mm_rr_act_req()");
+
+  TIMERSTOP (T3211);
+  TIMERSTOP (T3213);
+  mm_data->t3213_restart = 0;
+  
+  memcpy (&rr_activate_req->op, &mm_data->reg.op, sizeof (T_op));
+  rr_activate_req->op.service = 0;  /* not used */
+  rr_activate_req->cell_test  = mm_data->reg.cell_test;
+  rr_activate_req->check_hplmn = CHECK_PLMN_NOT_PRES;
+
+ 
+  switch (rr_activate_req->op.func)
+  {
+    case FUNC_LIM_SERV_ST_SRCH:
+      mm_data->loc_upd_type.lut = NOT_RUNNING;
+	      
+      //lint -fallthrough
+    case FUNC_ST_PWR_SCAN:
+    case FUNC_NET_SRCH_BY_MMI:
+      rr_activate_req->cksn = CKSN_RES;
+      rr_activate_req->accc = 0;
+      memset (&rr_activate_req->plmn, 0x0F,
+              sizeof (T_plmn));
+      rr_activate_req->plmn.v_plmn = V_PLMN_NOT_PRES;
+      memset (&rr_activate_req->kcv, 0,
+              sizeof (T_kcv));
+      memset (&rr_activate_req->imsi_struct, 0,
+              sizeof (T_imsi_struct));
+      memset (&rr_activate_req->tmsi_struct, 0,
+              sizeof (T_tmsi_struct));
+      memset (&rr_activate_req->bcch_info, 0,
+              sizeof (T_bcch_info));
+	  	  
+      break;
+
+    case FUNC_PLMN_SRCH:
+      rr_activate_req->cksn = mm_data->reg.cksn;
+      rr_activate_req->accc = mm_data->reg.acc_class;
+      memcpy (&rr_activate_req->plmn, &mm_data->reg.actual_plmn,
+              sizeof (T_plmn));
+      rr_activate_req->kcv.v_kc = V_KC_PRES;
+      memcpy (rr_activate_req->kcv.kc, mm_data->reg.kc, 8);
+      rr_activate_req->accc = mm_data->reg.acc_class;
+      memcpy (&rr_activate_req->imsi_struct, &mm_data->reg.imsi_struct,
+              sizeof (T_imsi_struct));
+      
+      memset (rr_activate_req->tmsi_struct.id, 0, 
+              sizeof (rr_activate_req->tmsi_struct.id));
+      if (mm_data->reg.tmsi EQ TMSI_INVALID_VALUE)
+      {
+        rr_activate_req->tmsi_struct.v_mid    = V_MID_NOT_PRES;
+        rr_activate_req->tmsi_struct.id_type  = TYPE_NO_ID;
+        rr_activate_req->tmsi_struct.tmsi_dig = 0;
+      }
+      else
+      {
+        rr_activate_req->tmsi_struct.v_mid    = V_MID_PRES;
+        rr_activate_req->tmsi_struct.id_type  = TYPE_TMSI;
+        rr_activate_req->tmsi_struct.tmsi_dig = mm_data->reg.tmsi;
+      }
+       	
+
+      // Question: Did these testcases fail only because there was a bug?
+      // This has still to be tested on the Anite! ...
+      // And bcch_encode is suspect here. Maybe the variable could be 
+      // eliminated and instead the expression 
+      // "(mm_data->reg.update_stat EQ MS_UPDATED AND 
+      //  !reg_plmn_empty (&last_plmn))" be used. ...
+
+      /*
+       * stored cell selection only in the field
+       * else 20.4 and 20.5 on the Anite will fail
+       * Exception: the boolean variable 'config_use_stored_bcch' is set to a 
+       * value of TRUE by the config command: CONFIG USE_STORED_BCCH
+       * or the AT command: AT%CPRIM="MM","CONFIG USE_STORED_BCCH"
+       */
+      if (mm_data->reg.bcch_encode AND
+          ((mm_data->reg.op.ts EQ TS_NO_AVAIL) OR 
+           (mm_data->config_use_stored_bcch)))
+      {
+        /*
+         * use SIM data only the first time.
+         */
+        mm_data->reg.bcch_encode = FALSE;
+
+        // Patch HM 14.03.01 >>>
+        // memcpy (&rr_activate_req->bcch_info, &mm_data->reg.bcch, 17);
+        // rr_activate_req->bcch_info.v_bcch = TRUE;
+        rr_activate_req->bcch_info.v_bcch = V_BCCH_PRES;
+        memcpy (rr_activate_req->bcch_info.bcch, mm_data->reg.bcch, SIZE_BCCH);
+        // Patch HM 14.03.01 <<<
+        
+        TRACE_EVENT ("with BCCH information");
+      }
+      else
+        memset (&rr_activate_req->bcch_info, 0, 
+                sizeof (T_bcch_info));
+
+      /* restart HPLMN timer for 6 min if we change to a PLMN not the HPLMN */
+      if (!reg_best_plmn_in_country(&rr_activate_req->plmn))
+      {
+        reg_check_hplmn_tim(1);
+      }
+      /* reg_stop_hplmn_tim (); */
+
+      /* Not Power ON Scenario AND Not a Test SIM */
+      if (mm_data->first_attach EQ FALSE)
+      {
+          /* set the hplmn flag to true only if MM is in substate 
+          Limited service or No cell available*/
+          if (((GET_STATE(STATE_MM)) EQ MM_IDLE_NO_CELL_AVAILABLE) OR
+              ((GET_STATE(STATE_MM)) EQ MM_IDLE_LIMITED_SERVICE))
+          {
+              /* check_hplmn set to true */
+              rr_activate_req->check_hplmn = CHECK_PLMN_PRES;
+          }
+      }
+      break;
+
+    default:
+      TRACE_ERROR (UNEXPECTED_DEFAULT);
+      break;
+  }
+
+  /* Tell RR whether we are interested in GPRS */
+  if (mm_gsm_alone())
+    rr_activate_req->gprs_indication = GPRS_NO;
+  else 
+    rr_activate_req->gprs_indication = GPRS_YES;
+
+  if (mm_data->reg.op.sim_ins EQ SIM_NO_INSRT) 
+  {
+    /* 
+     * Without valid SIM, some informations are not present.
+     * Ensure SIM specific data will be deleted from RR_ACTIVATE_REQ 
+     * if SIM data present, but not considered as valid by MM.
+     */
+    memset (&rr_activate_req->plmn, 0x0F, sizeof (T_plmn));
+    rr_activate_req->plmn.v_plmn = V_PLMN_NOT_PRES;
+    rr_activate_req->op.sim_ins = SIM_NO_INSRT;
+    rr_activate_req->op.ts      = TS_NO_AVAIL;
+    rr_activate_req->cksn       = CKSN_RES;
+    memset (&rr_activate_req->kcv, 0x00, sizeof (T_kcv));
+    rr_activate_req->accc       = 0x0000;
+    mm_clear_mob_ident (&rr_activate_req->imsi_struct);
+    mm_clear_mob_ident ((T_imsi_struct*) &rr_activate_req->tmsi_struct);
+    memset (&rr_activate_req->bcch_info, 0, sizeof (T_bcch_info));
+    rr_activate_req->cell_test  = CELL_TEST_DISABLE;
+    /* rr_activate_req->gprs_indic = GPRS_NO; */
+  }
+
+  /* Add Equiavlent PLMN list to the activation data */
+  memcpy (&rr_activate_req->eq_plmn_list, 
+             &mm_data->reg.eqv_plmns.eqv_plmn_list,
+              sizeof (EPLMNLIST_SIZE*UBYTES_PER_PLMN));
+  /*added by jennifer for 134 sim card issue */
+      if((rr_activate_req->plmn.mcc[0]==4)
+     && (rr_activate_req->plmn.mcc[1]==6)
+     &&(rr_activate_req->plmn.mcc[2]==0)
+     &&(rr_activate_req->plmn.mnc[0]==0)
+     &&(rr_activate_req->plmn.mnc[1]==2))
+     {
+     rr_activate_req->plmn.mnc[1]=0;
+     }
+  /*added by jennifer for 134 sim card issue*/
+
+  TRACE_EVENT_P7 ("RR_ACT_REQ (%d) MCC=%X%X%X MNC=%X%X%X",
+                  rr_activate_req->op.func,
+                  rr_activate_req->plmn.mcc[0],
+                  rr_activate_req->plmn.mcc[1],
+                  rr_activate_req->plmn.mcc[2],
+                  rr_activate_req->plmn.mnc[0],
+                  rr_activate_req->plmn.mnc[1],
+                  rr_activate_req->plmn.mnc[2]);
+
+  PSENDX (RR, rr_activate_req);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_rr_data_req             |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function sends the CM_SERVICE_REQUEST message to the 
+            network if a CM entity is requesting an additional connection.
+
+*/
+
+GLOBAL void mm_rr_data_req (USHORT est_cause, UBYTE service, UBYTE ti)
+{
+  GET_INSTANCE_DATA;
+  USHORT bit_size_message = 0;
+
+  TRACE_FUNCTION ("mm_rr_data_req ()");
+
+  mm_create_est_message (est_cause, 
+                         service, 
+                         ti,
+                         &bit_size_message);
+  for_data_req (bit_size_message);
+  mm_data->wait_for_accept = TRUE;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_rr_est_req              |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions creates and sends the RR_ESTABLISH_REQ 
+            primitive. A RR connection is requested.
+
+*/
+
+GLOBAL void mm_rr_est_req (USHORT    est_cause,
+                           UBYTE     service,
+                           UBYTE     ti)
+{
+  GET_INSTANCE_DATA;
+  USHORT bit_size_message = 0;
+  MCAST (loc_upd_req, U_LOC_UPD_REQ);
+
+  TRACE_FUNCTION ("mm_rr_est_req ()");
+
+  if (est_cause EQ ESTCS_SERV_REQ_BY_MM)
+  {
+    /* LOCATION UPDATING only, IMSI DETACH not handled here */
+    
+    mm_create_est_message (est_cause, service, ti,
+                           &bit_size_message);
+
+    if (mm_data->reg.update_stat EQ MS_NOT_UPDATED)
+      loc_upd_req->ciph_key_num.key_seq = CKSN_RES;
+
+    for_est_req (est_cause, bit_size_message);
+  }
+  else
+  {
+    /* All the CM stuff */
+
+#ifdef  GPRS
+    assert (GET_STATE (STATE_GPRS_CM_EST) EQ REG_GPRS_INACTIVE OR
+            GET_STATE (STATE_GPRS_CM_EST) EQ CM_GPRS_EST_OK);
+#endif
+
+    mm_create_est_message (est_cause, service, ti,
+                           &bit_size_message);
+    
+    for_est_req (est_cause, bit_size_message);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_start_loc_upd           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function starts a location update. 
+            The type of the location update will be given in 
+            loc_upd_type and is one of NORMAL_LUP, PERIODIC_LUP or 
+            IMSI_ATTACH_LUP.
+
+*/
+GLOBAL void mm_start_loc_upd (UBYTE loc_upd_type)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_start_loc_upd ()");
+
+  TRACE_EVENT_P1 ("attempt #%x", mm_data->attempt_cnt + 1);
+
+  /* Set the actual plmn to the PLMN selected by RR */
+  // Added here by HM 13.11.00
+  mm_data->reg.actual_plmn.v_plmn = V_PLMN_PRES;
+  memcpy (mm_data->reg.actual_plmn.mcc, mm_data->mm.lai.mcc, SIZE_MCC);
+  memcpy (mm_data->reg.actual_plmn.mnc, mm_data->mm.lai.mnc, SIZE_MNC);
+
+  mm_set_follow_on_request ();
+  // mm_data->t3212_timeout = FALSE;
+  mm_data->idle_entry  = RRCS_INT_NOT_PRESENT;
+  mm_data->loc_upd_type.lut = loc_upd_type;
+  mm_data->limited_cause = MMCS_INT_NOT_PRESENT;
+
+  EM_RR_CONECTION_REQUESTED;
+
+  /* 
+   * Remember the idle substate MM may have to enter afterwards. 
+   * 
+   * This implementation of MM lacks the implementation of MM_IDLE_LUP_NEEDED
+   * for the GSM only protocol stack.
+   * So, we have to use MM_IDLE_NORMAL_SERVICE and MM_IDLE_ATTEMPT_TO_UPDATE 
+   * not as foreseen by ETSI in some certain situations as replacement for 
+   * the missing state MM_IDLE_LUP_NEEDED.
+   */
+
+#if 0  /* Bodybag 2004-01-15; remove latest 2004-07-15 */
+  // The old code: 
+  // Problem: Remembers MM_IDLE_ATTEMPT_TO_UPDATE even if IMSI ATTACH.
+  // This is wrong, compare this with GSM 04.08 subclause 4.2.3.
+  // Problem 2.) Didn't handle GPRS.
+  switch (GET_STATE(STATE_MM))
+  {
+    case MM_IDLE_ATTEMPT_TO_UPDATE:
+    case MM_WAIT_FOR_RR_ACTIVE:
+      mm_data->idle_substate = MM_IDLE_ATTEMPT_TO_UPDATE;
+      break;
+
+    default:
+      mm_data->idle_substate = MM_IDLE_NORMAL_SERVICE;
+      break;
+  }
+#endif
+
+  if (mm_data->reg.update_stat EQ MS_UPDATED)
+    mm_data->idle_substate = MM_IDLE_NORMAL_SERVICE;
+  else
+    mm_data->idle_substate = MM_IDLE_ATTEMPT_TO_UPDATE;
+
+  if (mm_data->rej_cause NEQ RRCS_RND_ACC_FAIL)
+    mm_data->last_rej_cause = mm_data->rej_cause;
+
+  mm_rr_est_req (ESTCS_SERV_REQ_BY_MM, NO_CM_SERVICE, 0);
+  
+  TIMERSTOP (T3211);
+  TIMERSTOP (T3213);
+  mm_data->t3213_restart = 0;
+  
+  SET_STATE (STATE_MM, MM_WAIT_FOR_RR_CONN_LUP);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_continue_running_update |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function continues a running location update.
+
+*/
+GLOBAL void mm_continue_running_update (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_continue_running_update()");
+
+  switch (mm_data->loc_upd_type.lut)
+  {
+    case NORMAL_LUP:
+      mm_normal_loc_upd ();
+      break;
+    case PERIODIC_LUP:
+      mm_periodic_loc_upd ();
+      break;
+    case IMSI_ATTACH_LUP:
+      mm_attach_loc_upd ();
+      break;
+    default: /* No updating procedure in progress */
+      break;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_start_net_req           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function starts a network request.
+
+*/
+
+GLOBAL void mm_start_net_req (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_start_net_req ()");
+
+  mm_data->reg.op.func = FUNC_NET_SRCH_BY_MMI;
+  mm_rr_act_req ();
+
+  /* 
+   * 19.7 PLMN SEARCH 
+   * The mobile station is searching for PLMNs, and the conditions for 
+   * state 19.8 are not met. This state is ended when either a cell is 
+   * selected (the new state is 19.1, 19.3 or 19.6), 
+   * or when it is concluded that no cell is available for the moment 
+   * (the new state is 19.5). [GSM 04.08 subclause 4.1.2.1.2]
+   */
+  
+  /* 
+   * 19.8 PLMN SEARCH, NORMAL SERVICE
+   * Valid subscriber data are available, update status is U1, a cell is
+   * selected which belongs to the LA where the subscriber is registered,
+   * and the mobile station is searching for PLMNs. This state is ended
+   * when either a cell is selected (the new state is 19.1, 19.3 or 19.6),
+   * or when it is concluded that no cell is available for the moment 
+   * (the new state is 19.5). [GSM 04.08 subclause 4.1.2.1.2]
+   */
+ 
+  /* 
+   * MM will enter MM_PLMN_SEARCH_NORMAL_SERVICE in the current implementation 
+   * also if update state is different from U1 e.g. if MM is in state 
+   * MM_IDLE_ATTEMPT_TO_UPDATE. This makes sense, as the update state can be
+   * queried to find this condition.
+   */
+
+  switch (GET_STATE (STATE_MM))
+  {
+    case MM_IDLE_NORMAL_SERVICE:        /* 19.1 */
+    case MM_IDLE_ATTEMPT_TO_UPDATE:     /* 19.2 */
+#ifdef GPRS
+    case MM_IDLE_LUP_NEEDED:            /* 19.6 */
+#endif /* GPRS */
+      /* Remember the type of IDLE state MM had before network search */
+      mm_data->idle_substate = GET_STATE (STATE_MM);
+      SET_STATE (STATE_MM, MM_PLMN_SEARCH_NORMAL_SERVICE);
+      break;
+    
+    case MM_IDLE_PLMN_SEARCH:           /* 19.7 */
+      break; /* No state change */
+
+    case MM_PLMN_SEARCH_NORMAL_SERVICE: /* 19.8 */
+      break; /* No state change */
+    
+    case MM_IDLE_LIMITED_SERVICE:       /* 19.3 */
+    case MM_IDLE_NO_IMSI:               /* 19.4 */
+      /* Remember the type of IDLE state MM had before network search */
+      mm_data->idle_substate = GET_STATE (STATE_MM);
+      SET_STATE (STATE_MM, MM_IDLE_PLMN_SEARCH);
+      break; 
+
+    case MM_NULL:
+    case MM_WAIT_FOR_RR_ACTIVE:         /* 18 */
+    case MM_IDLE_NO_CELL_AVAILABLE:     /* 19.5 */
+      mm_data->idle_substate = MM_IDLE_NO_CELL_AVAILABLE;
+      SET_STATE (STATE_MM, MM_IDLE_PLMN_SEARCH);
+      break;
+    
+#ifdef GPRS
+    case MM_LOCATION_UPDATING_PENDING:
+    case MM_IMSI_DETACH_PENDING:
+      /* What is happening here? Re-think again about this ... */
+      TRACE_EVENT ("Interesting protocol sequence");
+      
+      /* Back to last IDLE substate */
+      SET_STATE (STATE_MM, mm_data->idle_substate);
+      
+      /* Repeat this in old IDLE state */
+      mm_start_net_req ();
+      return;
+#endif /* GPRS */
+    
+    default:
+      TRACE_EVENT ("No IDLE state at network search. Observe this"); // ...
+      mm_data->idle_substate = MM_IDLE_NO_CELL_AVAILABLE;
+      SET_STATE (STATE_MM, MM_IDLE_PLMN_SEARCH);
+      break; 
+  }    
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_start_t3212_bcch        |
++--------------------------------------------------------------------+
+
+  PURPOSE : Start the periodic location updating timer T3212 with the
+            broadcasted value. This is done in two situations: First, 
+            after power on and no IMSI ATTACH / NORMAL UPDATE is needed
+            and second at return to IDLE state after network contact.
+            The case where no periodic update timer exists is 
+            handled also, in this case T3212 is stopped.
+            If T3212 is running it is left alone and not restarted, 
+            so it is ensured that no periodic location updating is 
+            missed if a dedicated connection to the network is released 
+            in e.g. state MM_WAIT_FOR_NW_COMMAND, but the conditions in 
+            GSM 04.08 subclause 4.4.2 were not met to stop the timer (e.g.
+            no MM message received or emergeny call and the previous 
+            IDLE state was MM_IDLE_LIMITED_SERVICE.
+
+*/
+
+GLOBAL void mm_start_t3212_bcch (void)
+{
+  GET_INSTANCE_DATA;
+  T_TIME t3212_time;
+  
+  TRACE_FUNCTION ("mm_start_t3212_bcch()");
+
+#ifdef GPRS 
+  if ((mm_data->mm.mm_info.t3212 EQ 0) OR mm_data->gprs.combined_procedures)
+#else
+  if (mm_data->mm.mm_info.t3212 EQ 0)
+#endif /* GPRS */
+  {
+    /* 
+     * No periodic location updating timer
+     */
+    TIMERSTOP (T3212); 
+    mm_data->t3212_timeout = FALSE;
+  }
+  else
+  {
+    /*
+     * Start T3212 with broadcasted value only if not already running
+     */
+    if (!TIMERACTIVE (T3212))
+    {
+      TRACE_EVENT ("T3212 start BCCH");
+      if (mm_data->t3212_cfg_counter NEQ 0)
+        t3212_time = T_T3212_TIC_VALUE * mm_data->t3212_cfg_counter;
+      else
+        t3212_time = T_T3212_TIC_VALUE * 36 * mm_data->mm.mm_info.t3212;
+      TIMERSTART (T3212, t3212_time);
+    }
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_change_t3212            |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function starts/restarts the periodic updating timer
+            with a new value if a change of the broadcasted value 
+            was detected, either by receiving RR_ACTIVATE_CNF, 
+            RR_ACTIVATE_IND or RR_SYNC_IND.
+
+*/
+
+GLOBAL void mm_change_t3212 (void)
+{
+  GET_INSTANCE_DATA;
+  T_TIME t3212_time;
+ 
+  TRACE_FUNCTION ("mm_change_t3212 ()");
+
+#ifdef GPRS 
+  if ((mm_data->mm.mm_info.t3212 EQ 0) OR mm_data->gprs.combined_procedures)
+#else
+  if (mm_data->mm.mm_info.t3212 EQ 0)
+#endif /* GPRS */
+  {
+    /*
+     * No periodic location updating timer
+     */
+    TIMERSTOP (T3212);
+    mm_data->t3212_timeout = FALSE;
+  }
+  else
+  {
+    if (TIMERACTIVE(T3212) OR mm_data->t3212_timeout)
+    {
+      if (!mm_data->t3212_timeout)
+      {
+        T_TIME remaining_time;
+        /*
+         * T3212 is running and there maybe changes.
+         * Restart T3212 with remaining time modulo BCCH value.
+         * Nothing will happen here if the BCCH time is 
+         * greater or equal the remaining time (modulo operator), 
+         * so we avoid TIMERSTOP / TIMERSTART in this case also.
+         */
+  #if defined (NEW_FRAME)
+        TIMER_STATUS (mm_handle, T3212, &remaining_time);
+  #else
+        TIMER_STATUS (mm_handle, mm_data->t_handle[T3212], &remaining_time);
+  #endif
+        t3212_time = 
+          remaining_time % (mm_data->mm.mm_info.t3212 * 36 * T_T3212_TIC_VALUE);
+        if (t3212_time NEQ remaining_time)
+        {
+          TRACE_EVENT ("T3212 restart modulo");
+          TIMERSTOP (T3212); // Neccessary ?
+  #ifdef WIN32
+          vsi_o_ttrace(VSI_CALLER TC_EVENT,
+                       "Modulo time = %d", t3212_time);
+  #endif
+          TIMERSTART (T3212, t3212_time);
+        }
+      }
+    }
+    else
+    {
+      if (mm_data->first_attach) 
+      {
+        /* 
+         * First activation after power on and no IMSI ATTACH, 
+         * start T3212 with broadcasted value.
+         */
+        mm_start_t3212_bcch ();
+      }
+      else
+      {
+        /*
+         * changes detected, T3212 is not running and it is not the first
+         * activation. Restart T3212 with random value between 0 and BCCH.
+         */
+        TRACE_EVENT ("T3212 restart random");
+        if (mm_data->t3212_cfg_counter NEQ 0)
+        {
+          t3212_time = mm_data->t3212_cfg_counter;
+        }
+        else
+        {
+          t3212_time = 
+            T_T3212_TIC_VALUE * 
+              mm_random ((USHORT)(mm_data->mm.mm_info.t3212 * 36));
+        }
+        TIMERSTART (T3212, t3212_time);
+      }
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_use_entry               |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions marks all entries in the stored event table
+            which are marked as "STORED" as "USE". Then these events 
+            are processed by mm_read_entry(). mm_read_entry() will 
+            re-build the respective primitive for each event which
+            is marked as "USE" and sent it to MM, giving it a new 
+            chance to be processed by MM. For timers, the respective
+            handling function will be called.
+
+*/
+
+GLOBAL void mm_use_entry (void)
+{
+  GET_INSTANCE_DATA;
+  SHORT i;
+  
+  TRACE_FUNCTION ("mm_use_entry ()");
+
+  for (i = 0; i < MAX_STORE_ENTRIES; i++)
+  {
+    if (mm_data->store[i].use EQ STORED)
+      mm_data->store[i].use = USE;
+  }
+
+  while (mm_data->store[0].use EQ USE)
+    mm_read_entry ();
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_write_entry             |
++--------------------------------------------------------------------+
+
+  PURPOSE : SDL SAVE
+            This function saves a primitive which cannot be used
+            in the current state, but may be used after the next 
+            state transition. If content_type is given as EVENT_ENTRY
+            storing is done for the data component, TI and establ. cause.
+            If another primitive is to be stored, the pointer is set to 
+            the T_PRIM_HEADER and stored.
+*/
+
+GLOBAL void mm_write_entry (UBYTE     comp,
+                            UBYTE     ti,
+                            USHORT    estcs,
+                            U8        content_type,
+                            void      *primitive,
+                            U8        info)
+{
+  GET_INSTANCE_DATA;
+  USHORT i;
+  
+  TRACE_FUNCTION ("mm_write_entry ()");
+
+  for (i = 0; i < MAX_STORE_ENTRIES; i++)
+  {
+    if (mm_data->store[i].use EQ ENTRY_FREE)
+    {
+      TRACE_EVENT_P2 ("Write entry: comp=%d, ti=%d", comp, ti);
+      
+      mm_data->store[i].use                 = STORED;
+      mm_data->store[i].content_type        = content_type;
+      if (content_type EQ EVENT_ENTRY)
+      {
+        mm_data->store[i].content.event.ti    = ti;
+        mm_data->store[i].content.event.estcs = estcs;
+        mm_data->store[i].content.event.comp  = comp;
+        mm_data->store[i].info  = info;
+        if (comp < NUM_OF_CM_ENT)
+        {
+          CM_SET_STATE (comp, ti, CM_STORE);
+        }
+      }
+      else
+      {
+        mm_data->store[i].content.primitive   = D2P(primitive);
+      }
+      return;
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_check_lai               |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether two given location areas
+            identifications (MCC, MNC and LAC) are identical. 
+            Returns TRUE if LAIs are identical, otherwise FALSE.
+
+*/
+
+GLOBAL BOOL mm_check_lai (const T_loc_area_ident * lai1,
+                          const T_loc_area_ident * lai2)
+{
+  TRACE_FUNCTION ("mm_check_lai ()");
+
+  return ((memcmp (lai1->mcc, lai2->mcc, SIZE_MCC) EQ 0) AND
+          (memcmp (lai1->mnc, lai2->mnc, SIZE_MNC) EQ 0) AND
+          lai1->lac EQ lai2->lac);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_check_lai_from_RR       |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function compares the PLMN and location area in the 
+            form delivered by RR and in and T_plmn structure 
+            for equality. Returns TRUE if the PLMNs and location areas
+            are equal, otherwise FALSE.
+
+*/
+
+GLOBAL BOOL mm_check_lai_from_RR (const T_loc_area_ident * lai1,
+                                  const T_plmn           * plmn2,
+                                  USHORT             lac2)
+{
+  TRACE_FUNCTION ("mm_check_lai_from_RR ()");
+
+  return (memcmp (lai1->mcc, plmn2->mcc, SIZE_MCC) EQ 0 AND
+          memcmp (lai1->mnc, plmn2->mnc, SIZE_MNC) EQ 0 AND
+          lai1->lac EQ lac2);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_normal_upd_needed       |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function returns TRUE if a normal updating is needed.
+
+*/
+
+GLOBAL BOOL mm_normal_upd_needed (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_normal_upd_needed()");
+
+  if (mm_data->reg.update_stat EQ MS_UPDATED AND
+      mm_check_lai (&mm_data->reg.lai, &mm_data->mm.lai))
+    return FALSE;
+  return TRUE;
+}
+
+
+/* 
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_attach_upd_needed       |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function returns TRUE if an IMSI ATTACH is needed.
+
+*/
+
+GLOBAL BOOL mm_attach_upd_needed (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_attach_upd_needed()");
+
+  if (mm_data->mm.mm_info.att EQ ATT_ALLOW AND mm_data->first_attach) 
+    return TRUE;
+  return FALSE;
+}
+
+
+/* 
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_periodic_upd_needed     |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function returns TRUE if a periodic location update 
+            is immediately needed. This can happen if T3212 expired 
+            in a no coverage situation.
+
+*/
+
+GLOBAL BOOL mm_periodic_upd_needed (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_periodic_upd_needed()");
+
+  if (mm_data->t3212_timeout AND mm_data->mm.mm_info.t3212 NEQ 0)
+    return TRUE;
+  return FALSE;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_end_of_detach           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function performs all actions which are done 
+            at the end of a detach operation. This function may 
+            be called due reception of the primitives RR_RELEASE_IND or 
+            RR_ABORT_IND. In case the end of the IMSI DETACH procedure 
+            was caused by a timeout of T3220, the RR connection has been 
+            aborted normally and this function is called after the 
+            release has been acknowledged by RR_RELEASE_IND from RR.
+
+*/          
+
+GLOBAL void mm_end_of_detach (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_end_of_detach()");
+  
+  TIMERSTOP (T3220);
+  
+  switch (mm_data->nreg_cause)
+  {
+    case CS_SIM_REM:
+      /* Send RR_ABORT_REQ with ABCS_SIM_REM to invalidate SIM in RR */
+      mm_abort_connection (ABCS_SIM_REM);
+      
+      // This may be done instead RR_ABORT_REQ
+      // mm_build_rr_sync_req_cause (SYNCCS_TMSI_CKSN_KC_INVAL_NO_PAG);
+      
+      mm_clear_reg_data ();
+        
+      // Find original place where MM entered MM_IDLE_NO_IMSI state >>>
+      if (mm_data->mm_idle_no_imsi_marker EQ 0)
+        mm_data->mm_idle_no_imsi_marker = 5;
+      // End of debugging patch <<<
+      SET_STATE (STATE_MM, MM_IDLE_NO_IMSI);
+
+      reg_end_of_deregistration (mm_data->nreg_cause, LIMITED_SERVICE);
+      break;
+
+    case CS_POW_OFF:
+    case CS_SOFT_OFF:
+      mm_power_off ();
+      reg_end_of_deregistration (mm_data->nreg_cause, NO_SERVICE);
+      break;
+
+#ifdef GPRS 
+    case CS_DISABLE:
+      /* Remember MM may have to perform IMSI ATTACH if reactivated */
+      mm_data->first_attach = TRUE;
+        
+      /* 
+       * Find appropriate IDLE state after disabling of CS GSM.
+       * If there was really an IMSI DETACH before, the new state 
+       * will be MM_IDLE_LUP_NEEDED as the old state was 
+       * MM_IDLE_LIMITED_SERVICE and now at least an IMSI ATTACH 
+       * is needed again, but if not really a DETACH was performed, 
+       * also another IDLE state may be entered.
+       */
+      if (mm_data->reg.op.sim_ins EQ SIM_NO_INSRT)
+      {
+        SET_STATE (STATE_MM, MM_IDLE_NO_IMSI);
+      }
+      else if (mm_data->idle_substate EQ MM_IDLE_LIMITED_SERVICE)
+      {
+        SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE);
+      }
+      else if (mm_normal_upd_needed () OR mm_attach_upd_needed())
+      {
+        SET_STATE (STATE_MM, MM_IDLE_LUP_NEEDED);
+      }
+      else
+      {
+        SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE);
+      }
+
+      /* Confirm the requested deregistration */
+      mm_mmgmm_nreg_cnf (mm_data->nreg_cause);
+      break;
+#endif /* GPRS */    
+  
+    default: 
+      TRACE_ERROR (UNEXPECTED_DEFAULT);
+      break;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_get_service_state       |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is used to get the service state from 
+            the MM main state and/or the service state. 
+            The return value of this function is expected to be in the
+            range of states 19.1..19.6 for GPRS and 19.1..19.5 for GSM.
+            The function shall only be used if leaving idle state and
+            entering some sort of dedicated state.
+
+*/
+
+GLOBAL UBYTE mm_get_service_state (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_get_service_state()");
+  
+  switch (GET_STATE (STATE_MM))
+  {
+    case MM_NULL:                       /* 0 */
+      /*  
+       * In MM_NULL state, the mobile is switched off, so there is no cell.
+       */
+      return MM_IDLE_NO_CELL_AVAILABLE;
+    
+    case MM_WAIT_FOR_RR_CONN_LUP:       /* 13 */
+    case MM_WAIT_FOR_RR_ACTIVE:         /* 18 */
+      /* 
+       * MM has a cell which may be good for full service.
+       * MM has also a valid SIM (IMSI).
+       *
+       * This implementation of MM lacks the implementation of 
+       * state MM_IDLE_LUP_NEEDED for the GSM only protocol stack.
+       * MM_IDLE_LUP_NEEDED is only used in this implementation if MM needs
+       * an update with GPRS, but GPRS has not yet triggered the updating.
+       * So we have to use MM_IDLE_NORMAL_SERVICE and MM_IDLE_ATTEMPT_TO_UPDATE
+       * not as foreseen by ETSI in some certain situations as replacement for 
+       * the missing state MM_IDLE_LUP_NEEDED.
+       */
+      if (mm_data->reg.update_stat EQ MS_UPDATED) 
+        return MM_IDLE_NORMAL_SERVICE; 
+      else
+        return MM_IDLE_ATTEMPT_TO_UPDATE;
+
+    case MM_IDLE_NORMAL_SERVICE:        /* 19.1 */
+    case MM_IDLE_ATTEMPT_TO_UPDATE:     /* 19.2 */
+    case MM_IDLE_LIMITED_SERVICE:       /* 19.3 */
+    case MM_IDLE_NO_IMSI:               /* 19.4 */
+    case MM_IDLE_NO_CELL_AVAILABLE:     /* 19.5 */
+#ifdef GPRS
+    case MM_IDLE_LUP_NEEDED:            /* 19.6, not used by GSM only stack */
+#endif /* GPRS */
+      /* 
+       * In the cases of 19.1..19.5 (GSM only) or 19.1..19.6 (GPRS also)
+       * the service state is simply the appropriate MM IDLE state.
+       */
+      return GET_STATE (STATE_MM);
+            
+    case MM_IDLE_PLMN_SEARCH:           /* 19.7 */
+    case MM_PLMN_SEARCH_NORMAL_SERVICE: /* 19.8 */
+      /* 
+       * For the searching IDLE states, no respective service state exists.
+       * This is due to the fact that the information that RR is searching
+       * for a network can be obtained by reading the MM main state.
+       * It is more interesting if CM wants to perform a call to know the
+       * IDLE state before the mobile has started network search.
+       */
+      return mm_data->idle_substate;
+    
+    default:
+      /* 
+       * Some sort of dedicated state. This cannot/need not be used to 
+       * determine the service state.
+       */
+      return mm_data->idle_substate;
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                              |
+| STATE   : code                ROUTINE : mm_full_service_pplmn_scan         |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This states according to MM main state whether the PPLMN
+            rescan procedure could be applicable.
+
+
+*/
+
+GLOBAL BOOL mm_full_service_pplmn_scan (void)
+{
+  GET_INSTANCE_DATA;
+  switch (GET_STATE (STATE_MM))
+  {
+    /*
+     * The 'normal' cases : idle updated states
+     */
+    case MM_IDLE_NORMAL_SERVICE:
+    case MM_PLMN_SEARCH_NORMAL_SERVICE:
+    /* new introduced
+     * We also might be in full service but without a valid registration.
+     */
+    case MM_IDLE_ATTEMPT_TO_UPDATE:
+    /*
+     * RR connection active, which is either for a CM connection which imply
+     * that we are updated (unless it is an emergency call!) or for a MM
+     * procedure. If MM procedure fails consistently then we will lose the
+     * registration data and the timer will be stopped anyway.
+     */
+    case MM_WAIT_FOR_OUTG_MM_CONN:
+    case MM_CONN_ACTIVE:
+    case MM_PROCESS_PROMPT:
+    case MM_WAIT_FOR_NW_CMD:
+#ifdef REL99
+    case MM_RR_CONN_RELEASE_NOT_ALLOWED:
+#endif
+    case MM_WAIT_FOR_RR_CONN_MM:
+    case MM_WAIT_FOR_REESTABLISH:
+      
+    /*
+     * It is important not to stop the timer when in this state (check of 
+     * conditions can be done during LUP procedure!) 
+     */
+    case MM_LUP_INITIATED:
+      return TRUE;
+
+    /*
+     * If we currently have no or limited service then the standard PLMN 
+     * reselection procedure will apply if automatic mode.
+     */
+    case MM_NULL:
+    case MM_IDLE_LIMITED_SERVICE:
+    case MM_IDLE_NO_CELL_AVAILABLE:
+    case MM_IDLE_PLMN_SEARCH:
+    case MM_WAIT_FOR_RR_ACTIVE:
+
+    /*
+     * We also might be in full service but without a valid registration. No
+     * point to carry on as HPLMN timer would be started after succesfull GSM
+     * attach or LUP procedure.
+     */
+    case MM_WAIT_FOR_RR_CONN_LUP:
+    case MM_LUP_REJECTED:
+#if defined(GPRS)
+    case MM_LOCATION_UPDATING_PENDING:
+#endif
+
+    /*
+     * No IMSI, detached or in the process to do it. HPLMN rescan does not 
+     * make sense so disregard it.
+     */
+    case MM_IMSI_DETACH_INIT:
+#if defined(GPRS)
+    case MM_IMSI_DETACH_PENDING:
+#endif
+    case MM_IDLE_NO_IMSI:
+    case MM_WAIT_FOR_RR_CONN_DETACH:
+      return FALSE;
+
+    /* 
+     * 3GPP 23.122 clause 4.4.3.4 may apply here and makes life easy:
+     * "The investigation scan is restricted to automatic selection mode and 
+     *  shall only be performed by an MS that is capable of both voice and 
+     * packet data."
+     */
+#ifdef GPRS
+    case MM_IDLE_LUP_NEEDED:
+      return FALSE;
+#endif /* #ifdef GPRS */
+
+     default:
+      TRACE_ERROR (UNEXPECTED_DEFAULT);
+      return FALSE;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_read_ffs_init           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is the initial read of ffs by MM.
+*/
+
+const char eplmn_list_name[] = "/gsm/l3/eplmn";
+/* added by jennifer to write simloci to FFS */
+//int Writesimloci = 1;
+//if(Writesimloci)
+const char simloci_name[] = "/gsm/l3/simloci";
+T_loc_info                loc_info_ffs;
+/* added by jennifer to write simloci to FFS */
+
+const char imsi_name[] = "/gsm/l3/imsi";
+T_imsi_struct      imsi_in_ffs;
+
+
+GLOBAL void mm_read_ffs_init(void)
+{
+  GET_INSTANCE_DATA;
+
+  TRACE_FUNCTION ("mm_read_ffs_init()");
+
+  /* If MM has to create the directories for FFS, there is no point in carry on with the */
+  /* initialisation */
+  if(mm_check_ffs_dirs())
+    return;
+
+  if(mm_read_ffs())
+  {
+    /*Successful read*/
+
+    /*
+     * Compare IMSIs...
+     */
+    if(!(reg_imsi_equal(&mm_data->reg.eqv_plmns.eqv_plmn_imsi, 
+                        &mm_data->reg.imsi_struct)))
+    {
+      /*
+       * Remove old EPLMN list
+       */
+      memset (&mm_data->reg.eqv_plmns.eqv_plmn_list, 0xFF, EPLMNLIST_SIZE*UBYTES_PER_PLMN);
+
+      /*
+       * Write the new IMSI
+       */
+      mm_data->reg.eqv_plmns.eqv_plmn_imsi = mm_data->reg.imsi_struct; /*Struct Copy*/
+      mm_write_eplmn_to_ffs();
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_read_ffs                |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function reads the EPLMN from the ffs by MM.
+*/
+
+GLOBAL BOOL mm_read_ffs(void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_read_ffs()");
+
+  return (mm_handle_ffs_read_result(ffs_file_read (eplmn_list_name, 
+                              &mm_data->reg.eqv_plmns, 
+                               sizeof(T_ffs_eplmn_imsi))));
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_read_ffs                |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function resets the EPLMN data and writes the empty 
+            data to the FFS
+*/
+
+GLOBAL void mm_reset_ffs(void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_reset_ffs()");
+
+  memset (&mm_data->reg.eqv_plmns.eqv_plmn_list, 
+           0xFF, 
+           EPLMNLIST_SIZE*UBYTES_PER_PLMN);
+
+   mm_write_eplmn_to_ffs();
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_write_eplmn_to_ffs      |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function writes the current EPLMN list to the 
+            FFS
+*/
+
+GLOBAL void mm_write_eplmn_to_ffs(void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_write_eplmn_to_ffs()");
+ 
+  mm_check_ffs_dirs();
+  mm_handle_ffs_write_result(ffs_file_write (eplmn_list_name, 
+                                &mm_data->reg.eqv_plmns,
+                                 sizeof(T_ffs_eplmn_imsi),
+                                 FFS_O_CREATE | FFS_O_RDWR));
+}
+/*add by TISH 0418 to write imsi to FFS*/
+
+GLOBAL void mm_write_imsi_to_ffs(void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_write_imsi_to_ffs()");
+  mm_check_ffs_dirs();
+  mm_handle_ffs_write_result(ffs_file_write (imsi_name,
+  					&mm_data->reg.imsi_struct,
+  					sizeof(T_imsi_struct),
+            FFS_O_CREATE | FFS_O_RDWR));
+}
+
+GLOBAL BOOL mm_read_ffs_imsi(void)
+{
+
+  TRACE_FUNCTION ("mm_read_ffs_imsi");
+  
+  return (mm_handle_ffs_read_result(ffs_file_read (imsi_name, 
+                              &imsi_in_ffs, 
+                              sizeof(T_imsi_struct))));
+}
+/*add by TISH 0418 to write imsi to FFS*/
+
+
+/* added by TISH 0418 to write simloci to FFS */
+
+GLOBAL void mm_write_simloci_to_ffs(void)
+{
+  GET_INSTANCE_DATA;
+
+  ULONG tmsi_binary;
+
+  TRACE_FUNCTION ("mm_write_simloci_to_ffs()");
+  
+  tmsi_binary = mm_data->reg.tmsi;
+  loc_info_ffs.c_loc = SIZE_LOC_INFO;
+  loc_info_ffs.loc[0]  = (UBYTE)(tmsi_binary >> 24);
+  loc_info_ffs.loc[1]  = (UBYTE)(tmsi_binary >> 16);
+  loc_info_ffs.loc[2]  = (UBYTE)(tmsi_binary >> 8);
+  loc_info_ffs.loc[3]  = (UBYTE)tmsi_binary;
+  loc_info_ffs.loc[4]  = mm_data->reg.lai.mcc[1] << 4;
+  loc_info_ffs.loc[4] += mm_data->reg.lai.mcc[0];
+  loc_info_ffs.loc[5]  = mm_data->reg.lai.mnc[2] << 4;
+  loc_info_ffs.loc[5] += mm_data->reg.lai.mcc[2];  
+  loc_info_ffs.loc[6]  = mm_data->reg.lai.mnc[1] << 4;
+  loc_info_ffs.loc[6] += mm_data->reg.lai.mnc[0];
+  loc_info_ffs.loc[7]  = mm_data->reg.lai.lac >> 8;
+  loc_info_ffs.loc[8]  = mm_data->reg.lai.lac & 0xff;
+  loc_info_ffs.loc[9]  = 0;
+  loc_info_ffs.loc[10] = mm_data->reg.update_stat;
+
+TRACE_EVENT_P7("writelocinfo:%d,%d,%d,%d,%d,%d,%d", loc_info_ffs.loc[4], loc_info_ffs.loc[5], loc_info_ffs.loc[6], loc_info_ffs.loc[7], 
+						loc_info_ffs.loc[8], loc_info_ffs.loc[9], loc_info_ffs.loc[10]);
+  mm_check_ffs_dirs();
+  mm_handle_ffs_write_result(ffs_file_write (simloci_name, 
+                                &loc_info_ffs,
+                                 sizeof(T_loc_info),
+                                 FFS_O_CREATE | FFS_O_RDWR));
+  
+}
+
+GLOBAL BOOL mm_read_ffs_simloci(void)
+{
+
+  TRACE_FUNCTION ("mm_read_ffs_simloci");
+  
+  return (mm_handle_ffs_read_result(ffs_file_read (simloci_name, 
+                              &loc_info_ffs, 
+                                sizeof(T_loc_info))));
+}
+/* added by TISH 0418 to write simloci to FFS */
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_check_ffs_dirs          |
++--------------------------------------------------------------------+
+
+  PURPOSE : This routine creates the /gsm/l3 directory for the eplmn 
+            file in the FFS. The return result indicates whether either 
+            directories existed or not. There is no error handling.
+*/
+
+LOCAL BOOL mm_check_ffs_dirs( void )
+{
+  const char gsm_name[] = "/gsm";
+  const char gsm_l3_name[] = "/gsm/l3";
+  BOOL x, y;
+
+  x = mm_create_ffs_dirs(gsm_name);
+  y = mm_create_ffs_dirs(gsm_l3_name);
+  return(x&&y);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_create_ffs_dirs         |
++--------------------------------------------------------------------+
+
+  PURPOSE : This routine calls the ffs_mkdir() routine to create a 
+            specified directory. It returns whether the directory 
+            existed or not prior to creation.
+*/
+LOCAL BOOL mm_create_ffs_dirs(const char *dir_name)
+{
+  T_FFS_RET status;
+  BOOL dirs_present = FALSE;
+
+  status=ffs_mkdir(dir_name);
+  switch(status)
+  {
+    case EFFS_EXISTS:
+      dirs_present = TRUE;
+      break;
+
+    case EFFS_OK:
+      break;
+
+    default: /*Error*/
+      TRACE_EVENT_P1("Create Dir error - %x",status);
+      break;
+  }
+  return dirs_present;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_handle_ffs_read_result  |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function checks the status from FFS and returns
+            TRUE if there is no error and FALSE if there is
+*/
+LOCAL BOOL mm_handle_ffs_read_result(T_FFS_SIZE status_read)
+{
+  if(status_read)
+  {
+    TRACE_EVENT ("FFS Read OK");
+    return TRUE;
+  }
+  else
+  {
+    TRACE_EVENT_P1("EPLMN Read ERROR - %x", status_read);
+    return FALSE;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_handle_ffs_write_result |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function checks the status from FFS and returns
+            TRUE if there is no error and FALSE if there is
+*/
+LOCAL BOOL mm_handle_ffs_write_result(T_FFS_RET status_write)
+{
+  if(status_write >= EFFS_OK)
+  {
+    TRACE_EVENT("FFS Write OK");
+    if(status_write)
+      TRACE_EVENT_P1 ("Bytes written: %d",status_write);
+
+    return(TRUE);
+  }
+  else
+  {
+    TRACE_EVENT_P1 ("FFS Write Error - Status: %x",status_write);
+    return(FALSE);
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_display_eplmn           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function displays the current EPLMN list
+
+*/
+
+GLOBAL void mm_display_eplmn(void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_EVENT ("EPLMN List");
+  TRACE_EVENT_P3 ("%x, %x, %x", mm_data->reg.eqv_plmns.eqv_plmn_list[0],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[1],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[2]);
+  TRACE_EVENT_P3 ("%x, %x, %x", mm_data->reg.eqv_plmns.eqv_plmn_list[3],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[4],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[5]);
+  TRACE_EVENT_P3 ("%x, %x, %x", mm_data->reg.eqv_plmns.eqv_plmn_list[6],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[7],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[8]);
+  TRACE_EVENT_P3 ("%x, %x, %x", mm_data->reg.eqv_plmns.eqv_plmn_list[9],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[10],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[11]);
+  TRACE_EVENT_P3 ("%x, %x, %x", mm_data->reg.eqv_plmns.eqv_plmn_list[12],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[13],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[14]);
+  TRACE_EVENT_P3 ("%x, %x, %x", mm_data->reg.eqv_plmns.eqv_plmn_list[15],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[16],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[17]);
+
+  TRACE_EVENT_P3 ("%c, %c, %c", mm_data->reg.eqv_plmns.eqv_plmn_list[0],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[1],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[2]);
+  TRACE_EVENT_P3 ("%c, %c, %c", mm_data->reg.eqv_plmns.eqv_plmn_list[3],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[4],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[5]);
+  TRACE_EVENT_P3 ("%c, %c, %c", mm_data->reg.eqv_plmns.eqv_plmn_list[6],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[7],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[8]);
+  TRACE_EVENT_P3 ("%c, %c, %c", mm_data->reg.eqv_plmns.eqv_plmn_list[9],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[10],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[11]);
+  TRACE_EVENT_P3 ("%c, %c, %c", mm_data->reg.eqv_plmns.eqv_plmn_list[12],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[13],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[14]);
+  TRACE_EVENT_P3 ("%c, %c, %c", mm_data->reg.eqv_plmns.eqv_plmn_list[15],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[16],
+                                mm_data->reg.eqv_plmns.eqv_plmn_list[17]);
+
+}
+
+/* Implements Measure 29 and streamline encoding */
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_send_status             |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function builts and sends status
+
+*/
+GLOBAL void mm_send_status (UBYTE  cause)
+{
+  TRACE_FUNCTION ("mm_send_status ()");
+  
+  {
+    MSG_CAST (mm_status, T_B_MM_STATUS);
+    mm_build_mm_status (cause, mm_status);
+    for_data_req (BSIZE_B_MM_STATUS);
+  }
+}
+#endif