diff gsm-fw/g23m-gsm/mm/mm_regf.c @ 673:2f7df7a314f8

gsm-fw/g23m-gsm subtree: initial import from LoCosto source
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 28 Sep 2014 23:20:04 +0000
parents
children 105ac33aa5a1
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gsm-fw/g23m-gsm/mm/mm_regf.c	Sun Sep 28 23:20:04 2014 +0000
@@ -0,0 +1,2990 @@
+/* 
++----------------------------------------------------------------------------- 
+|  Project :  GSM-PS (8410)
+|  Modul   :  MM_REGF
++----------------------------------------------------------------------------- 
+|  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 registration
+|             capability of the module Mobility Management.
++----------------------------------------------------------------------------- 
+*/ 
+
+#define MM_REGF_C
+#define ENTITY_MM
+
+/*==== INCLUDES ===================================================*/
+#if defined (NEW_FRAME)
+
+#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"
+
+#else
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include "stddefs.h"
+#include "pcm.h"
+#include "pconst.cdg"
+#include "mconst.cdg"
+#include "message.h"
+#include "ccdapi.h"
+#include "custom.h"
+#include "gsm.h"
+#include "prim.h"
+#include "cnf_mm.h"
+#include "mon_mm.h"
+#include "vsi.h"
+#include "pei.h"
+#include "tok.h"
+#include "mm.h"
+
+#endif
+
+/*==== EXPORT =====================================================*/
+
+/*==== PRIVAT =====================================================*/
+
+/*==== VARIABLES ==================================================*/
+/* added by TISH 0418 to write simloci to FFS */
+extern T_loc_info                loc_info_ffs;
+extern T_imsi_struct      imsi_in_ffs;
+/* added by TISH 0418 to write simloci to FFS */
+
+/*==== TEST =====================================================*/
+
+/*==== FUNCTIONS ==================================================*/
+
+LOCAL void reg_pack_plmn_fn            (USHORT                i,
+                                        const T_RR_ABORT_IND *rr_abort_ind);
+
+/*==== LOCALS ==================================================*/
+/* first and last colums are dummies to staisf T_plmn structure*/
+LOCAL const T_plmn cingular_plmn_list[]=
+{ 
+  { 0x1, {0x00, 0x00 ,0x00},  {0x01, 0x08 ,0x00}, 0x1},
+  { 0x1, {0x03, 0x01 ,0x00},  {0x01, 0x05 ,0x00}, 0x1},
+  { 0x1, {0x03, 0x01 ,0x00},  {0x01, 0x07 ,0x00}, 0x1},
+  { 0x1, {0x03, 0x01 ,0x00},  {0x03, 0x08 ,0x00}, 0x1},
+  { 0x1, {0x03, 0x01 ,0x00},  {0x04, 0x01 ,0x00}, 0x1},
+  { 0x1, {0x03, 0x01 ,0x00},  {0x09, 0x08 ,0x00}, 0x1},
+  { 0x1, {0x03, 0x04 ,0x02},  {0x08, 0x01 ,0x00}, 0x1},
+  { 0x1, {0x03, 0x04 ,0x04},  {0x09, 0x03 ,0x00}, 0x1},
+  { 0x1, {0x03, 0x05 ,0x00},  {0x01, 0x00 ,0x0F}, 0x1},
+  { 0x1, {0x03, 0x05 ,0x02},  {0x03, 0x00 ,0x0F}, 0x1},
+  { 0x1, {0x03, 0x05 ,0x08},  {0x03, 0x00 ,0x0F}, 0x1},
+  { 0x1, {0x03, 0x06 ,0x00},  {0x01, 0x00 ,0x0F}, 0x1},
+  { 0x1, {0x03, 0x06 ,0x06},  {0x02, 0x00 ,0x0F}, 0x1}
+};
+
+#if !defined(GPRS)
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_send_mmr_reg_cnf              |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function builds and sends a MMR_REG_CNF primitive to the MMR SAP. 
+            This is only done if G23 is compiled as a GSM only protocol stack 
+            without GPRS. Otherwise this function is deactivated.
+
+*/
+
+GLOBAL void reg_send_mmr_reg_cnf (UBYTE bootup_cause)
+{
+  GET_INSTANCE_DATA;
+  PALLOC (mmr_reg_cnf, MMR_REG_CNF); /* T_MMR_REG_CNF */
+  
+  TRACE_FUNCTION ("reg_send_mmr_reg_cnf()");
+
+  if (bootup_cause NEQ PWR_SCAN_START)
+  {
+    mmr_reg_cnf->plmn.v_plmn = V_PLMN_PRES;
+    memcpy (mmr_reg_cnf->plmn.mcc, mm_data->mm.lai.mcc, SIZE_MCC);
+    memcpy (mmr_reg_cnf->plmn.mnc, mm_data->mm.lai.mnc, SIZE_MNC);
+  }
+  else
+  {
+    mmr_reg_cnf->plmn.v_plmn = V_PLMN_NOT_PRES;
+  }
+  mmr_reg_cnf->lac = mm_data->mm.lai.lac;
+  mmr_reg_cnf->cid = mm_data->mm.cid;
+  mmr_reg_cnf->bootup_cause = bootup_cause;
+  PSENDX (MMI, mmr_reg_cnf);
+}
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_build_mmr_reg_cnf              |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function indicates change in service or change in PLMN to the MMR SAP. 
+            This is only done if G23 is compiled as a GSM only protocol stack 
+            without GPRS. Otherwise this function is deactivated.
+
+*/
+
+GLOBAL void reg_build_mmr_reg_cnf (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_build_mmr_reg_cnf()");
+
+  if ((mm_data->reg.full_service_indicated EQ FALSE) OR
+      (mm_data->reg.new_cell_ind EQ TRUE))
+  {
+    /* 
+     * Either no full service was indicated to the MMI, 
+     * or the PLMN has changed from that what was indicated before.
+     */
+    reg_send_mmr_reg_cnf (REG_END);
+
+    mm_data->reg.full_service_indicated = TRUE;
+    mm_data->reg.new_cell_ind = FALSE;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_build_mmr_nreg_ind     |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions sends an MMR_NREG_IND to the MMR SAP.
+            This is only done if G23 is compiled as a GSM only protocol stack 
+            without GPRS. Otherwise this function is deactivated.
+
+*/
+
+GLOBAL void reg_build_mmr_nreg_ind (UBYTE service, 
+                                    UBYTE search_running,
+                                    UBYTE forb_ind)
+{
+  GET_INSTANCE_DATA;
+  PALLOC (mmr_nreg_ind, MMR_NREG_IND); /* T_MMR_NREG_IND */
+
+  TRACE_FUNCTION ("reg_build_mmr_nreg_ind");
+
+  mmr_nreg_ind->service = service;
+  mmr_nreg_ind->search_running = search_running;
+
+  if (forb_ind EQ FORB_PLMN_INCLUDED)                  
+  {
+    mmr_nreg_ind->new_forb_plmn.v_plmn = V_PLMN_PRES;
+    memcpy (mmr_nreg_ind->new_forb_plmn.mcc, mm_data->mm.lai.mcc, SIZE_MCC);
+    memcpy (mmr_nreg_ind->new_forb_plmn.mnc, mm_data->mm.lai.mnc, SIZE_MNC);
+  }
+  else
+  {
+    mmr_nreg_ind->new_forb_plmn.v_plmn = V_PLMN_NOT_PRES;
+    memset (mmr_nreg_ind->new_forb_plmn.mcc, 0x0f, SIZE_MCC);
+    memset (mmr_nreg_ind->new_forb_plmn.mnc, 0x0f, SIZE_MNC);
+  }
+
+  mmr_nreg_ind->cause = mm_data->limited_cause;
+
+  PSENDX (MMI, mmr_nreg_ind);
+
+  /* 
+   * Delete the limited cause if it was not fatal, as 
+   * on the next cell selection the reason may be another than 
+   * the one now indicated.
+   */
+  if (mm_data->reg.op.sim_ins EQ SIM_INSRT)
+    mm_data->limited_cause = MMCS_INT_NOT_PRESENT;
+
+  mm_data->reg.full_service_indicated = FALSE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_build_mmr_nreg_cnf     |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions sends an MMR_NREG_CNF to the MMR SAP.
+            This is only done if G23 is compiled as a GSM only protocol stack 
+            without GPRS. Otherwise this function is deactivated.
+
+*/
+
+GLOBAL void reg_build_mmr_nreg_cnf (UBYTE cause)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_build_mmr_nreg_cnf()");
+
+  if (mm_data->nreg_request)
+  {
+    PALLOC (mmr_nreg_cnf, MMR_NREG_CNF); /* T_MMR_NREG_CNF */
+    mmr_nreg_cnf->detach_cause = cause;
+    PSENDX (MMI, mmr_nreg_cnf);
+
+    mm_data->nreg_request = FALSE;
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_build_mmr_plmn_ind             |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function send a MMR_PLMN_IND primitive to the MMR SAP.
+            This is only done if G23 is compiled as a GSM only protocol stack 
+            without GPRS. Otherwise this function is deactivated.
+
+*/
+
+GLOBAL void reg_build_mmr_plmn_ind (USHORT cause,
+                              const T_RR_ABORT_IND *rr_abort_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_build_mmr_plmn_ind()");
+
+  if (mm_data->plmn_scan_mmi)
+  {
+    USHORT i;
+    PALLOC (mmr_plmn_ind, MMR_PLMN_IND); /* T_MMR_PLMN_IND */
+
+    mmr_plmn_ind->cause = cause;
+  
+    // This memset() sets all plmn.v_plmn fields to 0xff. 
+    // For ACI, file PSA_MMF.C, function psaMM_CpyPLMNLst() 
+    // this indicates that the PLMN is *not* valid. 
+    // This convention is used at some places in MM, 
+    // but it is against all usual conventions for G23.
+    // By RR SAP definition 0xff is not a possible value in this field.
+    // RR SAP definition says: 
+    //   plmn.v_plmn = V_PLMN_PRES (0x01) PLMN valid
+    //   plmn.v_plmn = V_PLMN_NOT_PRES (0x00) PLMN not valid
+
+    memset (&mmr_plmn_ind->plmn, NOT_PRESENT_8BIT,
+            sizeof (mmr_plmn_ind->plmn));
+  
+    if (cause EQ MMCS_SUCCESS)
+    {
+      /* Create the PLMN list for the MMI and send it */
+      reg_create_plmn_list (rr_abort_ind, WITH_ALL_PLMNS);
+
+      for (i = 0 ; i < mm_data->reg.plmn_cnt; i++)
+      {
+        reg_unpack_plmn (&mmr_plmn_ind->plmn[i], mm_data->reg.plmn, i);
+        mmr_plmn_ind->forb_ind[i] = 
+          reg_plmn_in_list (mm_data->reg.forb_plmn,
+                            MAX_FORB_PLMN_ID,
+                            &mmr_plmn_ind->plmn[i]);
+        mmr_plmn_ind->rxlevel[i]  = mm_data->reg.plmn_rx [i];
+        mmr_plmn_ind->lac_list[i]  = mm_data->reg.plmn_lac [i];
+      }
+
+      /* Do not consider the forbidden PLMNs for MM's internal operation */
+      reg_create_plmn_list (rr_abort_ind, WITH_OTHER_PLMNS);
+    }
+    
+    PSENDX (MMI, mmr_plmn_ind);
+  
+  }
+   
+  reg_check_plmn_search (cause, rr_abort_ind);
+}
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_build_mmr_ahplmn_ind             |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function sends a MMR_AHPLMN_IND primitive to the MMR SAP.
+            At poweron if valid AHPLMN or if MM receives valid AHPLMN request
+            from SIM, MM should inform ACI of the changed AHPLMN.
+            This is only done if G23 is compiled as a GSM only protocol stack 
+            without GPRS. Otherwise this function is deactivated.
+*/
+
+GLOBAL void reg_build_mmr_ahplmn_ind (T_plmn   *acting_hplmn)
+{
+  TRACE_FUNCTION ("reg_build_mmr_ahplmn_ind()");
+  {
+    PALLOC(mmr_ahplmn_ind, MMR_AHPLMN_IND);  /* T_MMR_AHPLMN_IND */
+
+    mmr_ahplmn_ind->ahplmn.v_plmn = acting_hplmn->v_plmn;
+    memcpy (mmr_ahplmn_ind->ahplmn.mcc, acting_hplmn->mcc, SIZE_MCC); 
+    memcpy (mmr_ahplmn_ind->ahplmn.mnc, acting_hplmn->mnc, SIZE_MNC);
+
+    PSENDX(MMI, mmr_ahplmn_ind);	 
+  }
+
+}
+
+#endif /* !defined(GPRS) */
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_build_sim_update               |
++----------------------------------------------------------------------------+
+
+  PURPOSE :
+
+*/
+
+GLOBAL void reg_build_sim_update (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_build_sim_update()");
+
+  if (mm_data->reg.op.sim_ins EQ SIM_INSRT)
+  {
+    PALLOC (sim_mm_update_req, SIM_MM_UPDATE_REQ);
+
+    mm_write_eplmn_to_ffs();
+
+    reg_set_loc_info   (sim_mm_update_req);
+    reg_set_bcch_info  (sim_mm_update_req);
+    reg_set_forb_plmns (sim_mm_update_req);
+    reg_set_kc         (sim_mm_update_req);
+
+    /* Sending the final EF indicator Bit pattern to SIM */
+    sim_mm_update_req->ef_indicator = mm_data->ef_indicator;
+
+    PSENDX (SIM, sim_mm_update_req);
+    /* Resetting to 0 after its info is conveyed to SIM */
+    mm_data->ef_indicator = 0;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_copy_sim_data          |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function copies the registration data from the SIM
+            provided by the SIM_MM_INSERT_IND primitive into the 
+            registration data structures. A consistency check is 
+            made, if data is not consistent (e.g. TMSI present, 
+            but update state is different from U1 updated), this is
+            corrected.
+
+*/
+
+GLOBAL void reg_copy_sim_data (const T_SIM_MM_INSERT_IND *sim_mm_insert_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_copy_sim_data()");
+
+  mm_data->reg.op.ts          = TS_NO_AVAIL;
+  mm_data->reg.op.sim_ins     = SIM_INSRT;
+
+  /* Clear limited service cause for MMI information */
+  mm_data->limited_cause = MMCS_INT_NOT_PRESENT;
+
+#ifdef TM_SPECIAL
+  mm_data->reg.op.ts = TS_AVAIL;
+#else
+  if (sim_mm_insert_ind->ad[0] >= 0x80)
+    mm_data->reg.op.ts = TS_AVAIL;
+  if (sim_mm_insert_ind->ad[0] EQ 4)
+    mm_data->reg.cell_test = CELL_TEST_ENABLE;
+  else
+    mm_data->reg.cell_test = CELL_TEST_DISABLE;
+#endif
+
+  /* EF_AD in SIM has length of MNC as optional field. If the field
+   * is present then Length of MNC is present and hence read it.
+   */
+  if (sim_mm_insert_ind->c_ad EQ 4)
+  {
+    mm_data->reg.length_mnc = sim_mm_insert_ind->ad[3] &0x0f;
+  }
+
+  TRACE_EVENT_P1("Length of MNC = %x",
+                  sim_mm_insert_ind->c_ad);
+
+  /* 
+   * Copy the information of SIM_MM_INSERT_IND into the 
+   * data fields of the registration 
+   */
+  reg_read_imsi     (&mm_data->reg.imsi_struct, &sim_mm_insert_ind->imsi_field);
+  reg_read_loc_info (&sim_mm_insert_ind->loc_info);
+/*add by TISH 0418 to write imsi to FFS*/
+mm_read_ffs_imsi();
+if (reg_imsi_equal(&imsi_in_ffs, &mm_data->reg.imsi_struct))
+{
+
+/* added by TISH 0418 to write simloci to FFS */
+if( mm_data->reg.update_stat NEQ MS_UPDATED)//only use value in FFS in this case
+{
+ TRACE_EVENT("MS NOT UPDATED, readsimloci from FFS");
+  if(mm_read_ffs_simloci())
+  	{
+    /*Successful read*/
+TRACE_EVENT_P7("readlocinfo:%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]);
+  reg_read_loc_info (&loc_info_ffs);
+  	}
+}
+/* added by TISH 0418 to write simloci to FFS */
+}
+  mm_data->reg.acc_class = sim_mm_insert_ind->acc_ctrl.acc[0] * 256 +
+                           sim_mm_insert_ind->acc_ctrl.acc[1];
+  reg_read_bcch_info (sim_mm_insert_ind);
+  reg_read_kc_cksn   (sim_mm_insert_ind);
+
+  reg_read_forb_plmn (&sim_mm_insert_ind->forb_plmn);
+  reg_copy_sim_ahplmn (sim_mm_insert_ind);
+  
+  /* Delete the AHPLMN entry from the Forbidden list, if present*/
+  if ( mm_data->reg.acting_hplmn.v_plmn)
+  {
+    /* Remove from forbidden PLMN list if stored */
+    reg_plmn_bad_del (mm_data->reg.forb_plmn, 
+                          MAX_FORB_PLMN_ID,
+                          &mm_data->reg.acting_hplmn);
+  }
+
+#ifdef GPRS
+  reg_clear_plmn_list (mm_data->reg.gprs_forb_plmn, MAX_GPRS_FORB_PLMN_ID);
+#endif /* #ifdef GPRS */
+  // sim_mm_insert_ind->phase is not needed by MM
+  mm_data->reg.thplmn = sim_mm_insert_ind->hplmn;
+  if (mm_data->reg.thplmn > HPLMN_MAX_SEARCH_PERIOD)
+  {
+    /* 3GPP 22.011 subclause 3.2.2.5 requires to use the default value
+     * if the value delivered by the SIM exceeds the allowed limit. */
+    mm_data->reg.thplmn = HPLMN_DEF_SEARCH_PERIOD;
+  }
+
+  /*
+   * If file size is indicated in SIM MM insert indication, MM shall read files from SIM.
+   */
+  if(reg_sim_files_to_be_read(sim_mm_insert_ind))
+  {
+    /*
+    * Read indicated EFs in SIM_MM_INSERT_IND from SIM.
+    */
+    reg_read_next_sim_file();
+  }
+
+  /*Re-read any valid EPLMNs..*/
+  mm_read_ffs_init();
+
+  if (mm_data->reg.update_stat NEQ MS_UPDATED)
+  {
+    /* 
+     * According to GSM 04.08 subclause 4.1.2.2 the SIM does not contain
+     * any valid LAI, TMSI, ciphering key or ciphering key sequence number if 
+     * the update status on the SIM not equals to U1.
+     */
+  
+    /* Delete TMSI */
+    mm_data->reg.tmsi = TMSI_INVALID_VALUE;
+  
+    /* Inform GMM about the TMSI change */
+    mm_mmgmm_tmsi_ind (TMSI_INVALID_VALUE);
+
+    /* Delete LAI */
+    mm_data->reg.lai.lac = LAC_INVALID_VALUE;
+    /* EF Indicator for EF LOCI - bit 1 */
+    mm_data->ef_indicator|=0x01;
+  
+    /* Delete CKSN */
+    mm_data->reg.cksn    = CKSN_RES;
+  
+    /* Delete also KC */
+    memset (mm_data->reg.kc, 0xff, MAX_KC);
+    /* Set bit 4 in ef_indicator to indicate kc change to SIM for next SIM_MM_UPDATE_REQ */
+    mm_data->ef_indicator|=(0x01 << 3);
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_create_plmn_list       |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions creates the list of available PLMNs from
+            the information given by the RR_ABORT_IND primitive. 
+            The HPLMN is sorted to the top of the PLMN list, 
+            than the PLMNs follow in th order defined in the 
+            preferred PLMN list, than the PLMNs follow in the 
+            order as delivered by the RR_ABORT_IND primitive.
+              
+            The parameter hplmn_flag controls whether the forbidden
+            PLMNs are deleted from the list, this will be the case 
+            for MM's internal operation or wheter all PLMNs found shall
+            be present in the resulting list, this will be the case
+            if the list was requested by the MMI for informational 
+            purposes.
+            
+            hplmn_flag may also indicate whether the HPLMN shall be 
+            present in the list, this functionality may become
+            obsolete in the future.
+
+            In case MM received a location updating reject #13, 
+            we remember the PLMN where we received this cause. This 
+            PLMN is in this case a low priority PLMN and sorted to the 
+            end of the list.
+
+
+
+*/
+
+GLOBAL void reg_create_plmn_list (const T_RR_ABORT_IND *rr_abort_ind,
+                                        UBYTE           include_flag)
+{
+  GET_INSTANCE_DATA;
+  USHORT i;
+  USHORT j;
+  USHORT low_prio_index;
+  BOOL copy_plmn[MAX_PLMN_ID];
+  UBYTE plmn_avail;
+
+  TRACE_FUNCTION ("reg_create_plmn_list()");
+
+  reg_clear_plmn_list (mm_data->reg.plmn, MAX_PLMN_ID);
+  mm_data->reg.plmn_cnt   = 0;
+  mm_data->reg.plmn_index = 0;
+
+  plmn_avail = rr_abort_ind->plmn_avail;
+
+  if (plmn_avail > MAX_PLMN_ID)
+    plmn_avail = MAX_PLMN_ID; /* Garbage protection, not expected to catch */
+  
+  for (i = 0; i < MAX_PLMN_ID; i++)
+    copy_plmn[i] = TRUE;
+
+  if (include_flag NEQ WITH_ALL_PLMNS)
+  {
+    /*
+     * MS is in automatic mode and the list which shall be created is 
+     * not for a PLMN available request,then remove the forbidden PLMNs.
+     */
+    for (i = 0; i < rr_abort_ind->plmn_avail; i++)
+    {
+      if (reg_plmn_in_list (mm_data->reg.forb_plmn, 
+                            MAX_FORB_PLMN_ID,
+                            &rr_abort_ind->plmn[i]))
+      {
+        copy_plmn[i] = FALSE;
+      }
+
+#ifdef GPRS
+      /* 
+       * Consider also the "forbidden PLMNs for GPRS services" list,
+       * if GPRS is active.
+       */
+      if (!mm_gsm_alone () AND
+          (mm_data->gprs.mobile_class EQ MMGMM_CLASS_CG) AND 
+          reg_plmn_in_list (mm_data->reg.gprs_forb_plmn,
+                            MAX_GPRS_FORB_PLMN_ID,
+                            &rr_abort_ind->plmn[i]))
+      {
+        copy_plmn[i] = FALSE;
+      }
+#endif /* #ifdef GPRS */  
+    }
+  }
+
+  /* 
+   * In case RR delivered the PLMN where we recently received a location 
+   * updating reject with cause #13, this PLMN has low priority now only.
+   * This is a different handling than described in GSM 03.22 clause 4.4.3, 
+   * but needed in the field.
+   */
+  low_prio_index = NOT_PRESENT_16BIT;
+  if ((include_flag NEQ WITH_ALL_PLMNS) AND
+      (include_flag NEQ WITH_RPLMN) AND
+      !reg_plmn_empty (&mm_data->reg.low_prio_plmn))
+  {
+    for (i = 0; i < plmn_avail; i++)
+    {
+      if (copy_plmn[i] AND
+          reg_plmn_equal_sim (&rr_abort_ind->plmn[i], 
+                              &mm_data->reg.low_prio_plmn))
+      {
+        low_prio_index = i;
+        copy_plmn[i] = FALSE;
+      }
+    }
+    
+    /* Clear the low priority PLMN */
+    reg_clear_plmn (&mm_data->reg.low_prio_plmn);
+  }
+  
+  /* 
+   * In case RR delivered the actual PLMN, requested by FUNC_PLMN_SRCH, 
+   * as a member of the list, we filter it out, as in this case no cell
+   * of the PLMN has been recognized by RR as suitable for full service.
+   */
+  if ((include_flag NEQ WITH_ALL_PLMNS) AND
+      (include_flag NEQ WITH_RPLMN))
+  {
+    for (i = 0; i < plmn_avail; i++)
+    {
+      if (reg_plmn_equal_sim (&rr_abort_ind->plmn[i], 
+                              &mm_data->reg.actual_plmn))
+      {
+        /* 
+         * In case of cause #12 - Location Area Not Allowed, MS shall be able
+         * to select the same PLMN if suitable cell with other LAI is avaiable. 
+         * Hence while preparing PLMN list MM shall not discard that PLMN.
+         */
+        if (((mm_data->rej_cause EQ MMCS_LA_NOT_ALLOWED) 
+#ifdef GPRS
+              OR (mm_data->rej_cause EQ GMMCS_LA_NOT_ALLOWED)
+#endif
+          )
+          AND (GET_STATE(STATE_MM) EQ MM_IDLE_LIMITED_SERVICE))
+        {
+          TRACE_EVENT ("Don't ignore actual PLMN for cause #12");
+        }
+        else
+        {
+        TRACE_EVENT ("Ignore actual PLMN");
+        copy_plmn[i] = FALSE;
+      }
+    }
+  }
+  }
+
+  /* 
+   * GSM 03.22 subclause 4.4.3 gives some rules in which way the PLMN list 
+   * has to be sorted. These rules apply for manual and for automatic mode.
+   * For further details, see the mentioned recommendation.
+   */
+  
+  /* 
+   * Find HPLMN in the list of found PLMNs. If present, set it on top 
+   */
+  for (i = 0; i < plmn_avail; i++)
+  {
+    if (copy_plmn[i] AND
+        reg_plmn_equal_hplmn (&rr_abort_ind->plmn[i]))
+    {
+      reg_pack_plmn_fn (i, rr_abort_ind);
+      copy_plmn[i] = FALSE;
+      break;
+    }
+  }
+
+  /* 
+   * Add the found PLMNS into MMR_PLMN_IND according to their position in the
+   * preferred PLMN list
+   */
+  for (j = 0; j < MAX_PREF_PLMN_ID; j++)
+  {
+    T_plmn pref_plmn;
+    reg_unpack_plmn (&pref_plmn, mm_data->reg.pref_plmn, j);
+
+    if (! reg_plmn_empty (&pref_plmn))
+    {
+      for (i = 0; i < plmn_avail; i++)
+      {
+        /* 
+         * Use the comparison routines from GSM 03.22 Annex A (normative)
+         * Reason: Even if it is not the HPLMN, we were not able to 
+         * recognize a 3-digit NA MNC network as preferred if it would still
+         * broadcast only 2-digit MNC.
+         */
+        if (copy_plmn[i] AND
+            reg_plmn_equal_sim (&rr_abort_ind->plmn[i], &pref_plmn))
+        {
+          reg_pack_plmn_fn (i, rr_abort_ind);
+          copy_plmn[i] = FALSE;
+          break;
+        }
+      }
+    }
+  }
+
+  /* 
+   * Add the remaining PLMNS to MMR_PLMN_IND 
+   */
+  for (i = 0; i < plmn_avail; i++)
+  {
+    if (copy_plmn[i] AND
+        ! reg_plmn_empty (&rr_abort_ind->plmn[i]))
+    {
+      reg_pack_plmn_fn (i, rr_abort_ind);
+      copy_plmn[i] = FALSE;
+    }
+  }
+
+  /* 
+   * Add the low priority PLMN where we previously received LUP reject #13, 
+   * if present, at the end of the list.
+   */
+  if (low_prio_index NEQ NOT_PRESENT_16BIT)
+  {
+    reg_pack_plmn_fn (low_prio_index, rr_abort_ind);
+    copy_plmn[i] = FALSE;
+  }
+
+#ifndef NTRACE
+  TRACE_EVENT ("PLMN list");
+
+  for (i = 0; i < mm_data->reg.plmn_cnt; i++)
+  {
+    T_plmn plmn;
+
+    reg_unpack_plmn (&plmn, mm_data->reg.plmn, i);
+    TRACE_EVENT_P6 ("MCC=%x%x%x MNC=%x%x%x",
+                    plmn.mcc[0],
+                    plmn.mcc[1],
+                    plmn.mcc[2],
+                    plmn.mnc[0],
+                    plmn.mnc[1],
+                    plmn.mnc[2]);
+  }
+#endif /* #ifndef NTRACE */
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_extract_hplmn          |
++--------------------------------------------------------------------+
+
+  PURPOSE : Extracts the HPLMN out of the registration data.
+            If valid AHPLMN is present then HPLMN should be
+            read from the file, else it should be read from IMSI.
+
+*/
+
+GLOBAL void reg_extract_hplmn (T_plmn *plmn)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_extract_hplmn()");
+
+  if (mm_data->reg.acting_hplmn.v_plmn)
+  {
+    plmn->v_plmn = V_PLMN_PRES;
+    memcpy(plmn->mcc,mm_data->reg.acting_hplmn.mcc,SIZE_MCC);
+    memcpy(plmn->mnc,mm_data->reg.acting_hplmn.mnc,SIZE_MNC);	  
+  }
+  else
+  {
+  plmn->v_plmn = V_PLMN_PRES;
+  plmn->mcc[0] = mm_data->reg.imsi_struct.id[0];
+  plmn->mcc[1] = mm_data->reg.imsi_struct.id[1];
+  plmn->mcc[2] = mm_data->reg.imsi_struct.id[2];
+  plmn->mnc[0] = mm_data->reg.imsi_struct.id[3];
+  plmn->mnc[1] = mm_data->reg.imsi_struct.id[4];
+
+  /* 
+   * We cannot be sure that plmn->mnc[2] really belongs to the MNC, 
+   * but the comparison routines for the HPLMN are done in a way that 
+   * this doesn't matter anyway. See GSM 03.03 subclause 2.2, 
+   * which is far away from being clear and GSM 03.22 version 7.1.0 
+   * Release 1998 Annex A (normative). Figure A.2 in this annex makes 
+   * it obvious that 3-digit-MNC isn't only a NA issue!
+   */
+  plmn->mnc[2] = mm_data->reg.imsi_struct.id[5];
+  }/* end of mm_data->reg.acting_hplmn.v_plmn */
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_init                   |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function initializes the registration data structures.
+
+*/
+
+GLOBAL void reg_init (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_init()");
+
+  memset (&mm_data->reg, 0, sizeof (T_REG));
+
+  mm_data->reg.update_stat = MS_NOT_UPDATED;
+  mm_data->reg.cksn        = CKSN_RES;
+  mm_data->reg.full_service_indicated = FALSE;
+  mm_data->reg.sim_insert_info = NULL;
+  mm_data->reg.sim_sync_req_pending = FALSE;
+  mm_data->reg.quick_hplmn_search = TRUE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_add_bad           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function adds the given PLMN to the given list of 
+            forbidden PLMNs. 
+            In case the PLMN is already stored in this list, no action
+            will be taken, otherwise the PLMN will be stored at the 
+            first free entry of the list. If there is no free entry, 
+            the first entry in the list will be deleted and the list 
+            will be shifted so that the PLMN can be added at the end 
+            of the list.
+
+*/
+
+GLOBAL void reg_plmn_add_bad (UBYTE *forb_plmn_list, 
+                              USHORT list_size, 
+                              const T_plmn *plmn)
+{
+  T_plmn forb_plmn;
+  USHORT i;
+
+  TRACE_FUNCTION ("reg_plmn_add_bad()");
+
+  /* First look whether the PLMN is already stored */
+  for (i = 0; i < list_size; i++)
+  {
+    reg_unpack_plmn (&forb_plmn, forb_plmn_list, i);
+    if (reg_plmn_equal_sim (plmn, &forb_plmn))
+      return;
+  }
+
+  /* Else look for an empty location and store the PLMN */
+  for (i = 0; i < list_size; i++)
+  {
+    reg_unpack_plmn (&forb_plmn, forb_plmn_list, i);
+    if (reg_plmn_empty (&forb_plmn))
+    {
+      reg_pack_plmn (forb_plmn_list, i, plmn);
+      return;
+    }
+  }
+
+  /* Else shift the entries down add the PLMN at the end of the list */
+  memmove (&forb_plmn_list[0], 
+           &forb_plmn_list[UBYTES_PER_PLMN],
+           UBYTES_PER_PLMN * (list_size - 1)); /*lint !e807 This function is always called with constant 'list_size'*/
+  reg_pack_plmn (forb_plmn_list, (USHORT)(list_size - 1), plmn);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_in_list           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether the PLMN in question is a 
+            member of the PLMN list provided. The function returns 
+            TRUE if the PLMN can be found in the PLMN list, otherwise 
+            the function returns FALSE.
+*/
+
+GLOBAL BOOL reg_plmn_in_list(const UBYTE *plmn_list, 
+                                   USHORT list_size, 
+                             const T_plmn *plmn)
+{
+  T_plmn member_plmn;
+  USHORT i;
+
+  TRACE_FUNCTION ("reg_in_forb_plmn()");
+
+  for (i = 0; i < list_size; i++)
+  {
+    reg_unpack_plmn (&member_plmn, plmn_list, i);
+    if (reg_plmn_equal_sim (plmn, &member_plmn))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_bad_del           |
++--------------------------------------------------------------------+
+
+  PURPOSE : Remove the specified PLMN from the given list of forbidden
+            PLMNs. In case the specified PLMN is found in the list, 
+            it will be deleted from the list. 
+
+*/
+
+GLOBAL void reg_plmn_bad_del (UBYTE *forb_plmn_list, 
+                              USHORT list_size, 
+                              const T_plmn *plmn)
+{
+  GET_INSTANCE_DATA;
+  T_plmn forb_plmn;
+  USHORT i;
+  USHORT j;
+
+  TRACE_FUNCTION ("reg_plmn_bad_del()");
+
+  for (i = 0; i < list_size; i++)
+  {
+    reg_unpack_plmn (&forb_plmn, forb_plmn_list, i);
+    if (reg_plmn_equal_sim (&forb_plmn, plmn)) /* Argument order matters */
+    {
+      for (j = i; j < list_size - 1; j++)
+      {
+        memcpy (&forb_plmn_list[j * UBYTES_PER_PLMN],
+                &forb_plmn_list[(j + 1) * UBYTES_PER_PLMN],
+                UBYTES_PER_PLMN);
+      }
+      memset (&forb_plmn_list[(list_size - 1) * UBYTES_PER_PLMN], 
+              0xff, UBYTES_PER_PLMN);
+      /* Set bit 3 in ef_indicator to indicate forb_plmn change to SIM */
+      mm_data->ef_indicator|=(0x01 << 2);
+    }
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_empty             |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function tests whether plmn points to an empty PLMN.
+            TRUE will be returned if plmn points to an empty PLMN, 
+            otherwise FALSE.
+
+*/
+
+GLOBAL BOOL reg_plmn_empty (const T_plmn *plmn)
+{
+  /* TRACE_FUNCTION ("reg_plmn_empty ()"); */ /* Avoid too much output */
+
+  return ((plmn->mcc[0] & 0x0F) EQ 0x0F);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_sim_ef_plmn_field_empty|
++--------------------------------------------------------------------+
+
+  PURPOSE : This function tests whether plmn in EF points to an empty PLMN.
+            TRUE will be returned if plmn points to an empty PLMN, 
+            otherwise FALSE.
+
+*/
+GLOBAL BOOL reg_sim_ef_plmn_field_empty (UBYTE*     plmn)
+{
+  /*check if 1th digit of MCC is not present*/
+  return ((plmn[0] & 0x0F) EQ 0x0F);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_is_NA_plmn        |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function tests whether the PLMN is a NA (North America)
+            PLMN. The MCC code is checked to meet this decision.
+
+*/
+
+GLOBAL BOOL reg_plmn_is_NA_plmn (const T_plmn *plmn)
+{
+  /* TRACE_FUNCTION ("reg_plmn_is_NA_plmn()"); */ /* Avoid too much output */
+
+ /* return ((plmn->mcc[0] EQ 3) AND
+          (plmn->mcc[1] EQ 1) AND
+          (plmn->mcc[2] >= 0) AND (plmn->mcc[2] <= 6)); lint !e568 never
+                                                          less than zero*/
+      return ((plmn->mcc[0] EQ 3) AND
+          (plmn->mcc[1] EQ 1) AND
+          (plmn->mcc[2] <= 6)); /*lint !e568 never
+                                                          less than zero*/
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_equal_sim         |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function tests whether two PLMNs are contained in
+            Equivalent PLMN list or not
+
+*/
+
+GLOBAL BOOL reg_plmn_equal_eqv (const T_plmn        *bcch_plmn,
+                                const T_plmn        *req_plmn)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_plmn_equal_eqv()");  
+
+  if (reg_plmn_equal_sim (bcch_plmn, req_plmn))    
+    return TRUE; /* Equal without equivalent PLMN */  
+  if (reg_plmn_in_list (mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE, bcch_plmn) && 
+      reg_plmn_in_list (mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE, req_plmn))  
+  {    
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_equal_sim         |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function tests whether two PLMNs are equal.
+
+*/
+
+GLOBAL BOOL reg_plmn_equal_sim (const T_plmn        *bcch_plmn,
+                                const T_plmn        *sim_plmn)
+{
+  /* TRACE_FUNCTION ("reg_plmn_equal_sim()"); */ /* Avoid too much output */
+
+  /* Check MCC */
+  if (memcmp (sim_plmn->mcc, bcch_plmn->mcc, SIZE_MCC) NEQ 0)
+    return FALSE;
+
+  /* Check first 2 MNC digits */
+  if (memcmp (sim_plmn->mnc, bcch_plmn->mnc, 2) NEQ 0)
+    return FALSE;
+
+  /* Check for full match */
+  if (sim_plmn->mnc[2] EQ bcch_plmn->mnc[2])
+    return TRUE;
+  
+  /* The 3rd digit of the MNC differs. */
+  if (reg_plmn_is_NA_plmn (bcch_plmn))
+  {
+    return (((sim_plmn->mnc[2] EQ 0xf) AND (bcch_plmn->mnc[2] EQ 0x0)) OR
+            ((sim_plmn->mnc[2] EQ 0x0) AND (bcch_plmn->mnc[2] EQ 0xf)));
+  }
+  return (bcch_plmn->mnc[2] EQ 0xf) OR (sim_plmn->mnc[2] EQ 0xf);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_equal_hplmn       |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function tests whether the PLMN received on the 
+            BCCH equals the HPLMN. TRUE will be returned if bcch_plmn 
+            points to a PLMN description which describes the HPLMN,
+            otherwise FALSE will be returned.
+
+*/
+
+GLOBAL BOOL reg_plmn_equal_hplmn (const T_plmn *bcch_plmn)
+{
+  T_plmn hplmn;
+
+  TRACE_FUNCTION ("reg_plmn_equal_hplmn()");
+
+  reg_extract_hplmn (&hplmn);
+  return (reg_plmn_equal_sim (bcch_plmn, &hplmn));
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_equal_rplmn       |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function tests whether the PLMN equals the RPLMN. 
+            TRUE will be returned if PLMN points to a PLMN description 
+            which describes the RPLMN,otherwise FALSE will be returned.        
+*/
+
+GLOBAL BOOL reg_plmn_equal_rplmn (T_plmn    *plmn)
+{
+  GET_INSTANCE_DATA;
+
+  T_plmn last_plmn;
+
+  TRACE_FUNCTION ("reg_plmn_equal_rplmn()");
+
+  last_plmn.v_plmn = V_PLMN_PRES;
+  memcpy (last_plmn.mcc, mm_data->reg.lai.mcc, SIZE_MCC);
+  memcpy (last_plmn.mnc, mm_data->reg.lai.mnc, SIZE_MNC);
+
+  return (reg_plmn_equal_sim (plmn, &last_plmn));
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_imsi_equal             |
++--------------------------------------------------------------------+
+
+  PURPOSE : Checks whether two given IMSIs are identical
+
+*/
+
+GLOBAL BOOL reg_imsi_equal (const T_imsi_struct *imsi_struct1, const T_imsi_struct *imsi_struct2)
+{
+  USHORT length;
+  
+  TRACE_FUNCTION ("reg_imsi_equal()");
+
+  if (imsi_struct1->v_mid NEQ imsi_struct2->v_mid)
+    return FALSE;
+  
+  if (imsi_struct1->id_type NEQ imsi_struct2->id_type)
+    return FALSE;
+  
+  switch (imsi_struct1->id_type)
+  {
+    case TYPE_IMSI:
+      length = mm_calculate_digits (imsi_struct1->id);
+      if (length NEQ mm_calculate_digits (imsi_struct2->id))
+        return FALSE;
+      return (memcmp (imsi_struct1->id, imsi_struct2->id, length) EQ 0);
+    
+    case TYPE_TMSI:
+      return (imsi_struct1->tmsi_dig EQ imsi_struct2->tmsi_dig);
+
+    default:
+      return TRUE;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_plmn_select            |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function is called if there was either a RR failure
+            or a MM failure (e.g. LOCATION UPDATING reject).
+            MM is in state LIMITED_SERVICE.
+
+*/
+
+GLOBAL void reg_plmn_select (UBYTE forb_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_plmn_select ()");
+
+  if (mm_data->reg.plmn_cnt > mm_data->reg.plmn_index AND
+      mm_data->reg.op.m EQ MODE_AUTO AND
+      mm_data->reg.op.sim_ins EQ SIM_INSRT)
+  {
+    /*
+     * Another PLMN available, automatic mode and SIM considered as valid
+     */
+    mm_mmgmm_nreg_ind (NREG_LIMITED_SERVICE, 
+                       SEARCH_RUNNING,
+                       forb_ind);
+    reg_unpack_plmn (&mm_data->reg.actual_plmn,
+                     mm_data->reg.plmn, mm_data->reg.plmn_index++);
+    mm_data->attempt_cnt = 0;
+    mm_mmr_reg_req (FUNC_PLMN_SRCH);
+  }
+  else
+  {
+    mm_mmgmm_nreg_ind (NREG_LIMITED_SERVICE, 
+                       SEARCH_NOT_RUNNING,
+                       forb_ind);
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_read_bcch_info         |
++--------------------------------------------------------------------+
+
+  PURPOSE : Read the BCCH information delivered by the SIM into the 
+            registration data structures.
+
+*/
+
+GLOBAL void reg_read_bcch_info (const T_SIM_MM_INSERT_IND *sim_mm_insert_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_read_bcch_info ()");
+
+  if(memcmp(mm_data->reg.bcch, sim_mm_insert_ind->bcch_inf.bcch, SIZE_BCCH))
+  {
+    /* Set bit 2 in ef_indicator to indicate bcch_info change to SIM */
+    mm_data->ef_indicator|=(0x01 << 1);
+  }
+  memcpy (mm_data->reg.bcch, sim_mm_insert_ind->bcch_inf.bcch, SIZE_BCCH);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS              MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_sim_files_to_be_read   |
++--------------------------------------------------------------------+
+
+  PURPOSE : Read the EFs size (EFu=EFPLMNwAcT, EFo=EFOPLMNwAcT, EFs=EFPLMNSEL) information delivered 
+            by the SIM into the registration data structures.
+
+*/
+
+GLOBAL BOOL reg_sim_files_to_be_read (const T_SIM_MM_INSERT_IND *sim_mm_insert_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_sim_files_to_be_read ()");
+  mm_data->reg.sim_read_in_progress = FALSE;
+
+#ifdef REL99
+  /*
+   * If the SIM insert indication and file size is indicated, it MM shall read files from SIM.
+   */
+  if (sim_mm_insert_ind->u_ctl_plmn_sel_actech_list_sz >0)
+  {
+    mm_data->reg.upd_sim_ucps_at = SAT_READ_FILE;
+   /*Set indicatort sim reading is in progress to true*/
+    mm_data->reg.sim_read_in_progress = TRUE;
+    /*
+     * MM cant decide here how many PLMNs are supported GSM access Technology so 
+     * MM should read maximum number of plmn as much it can read.
+     * At present there is a limitation in SIM read req. It cant read more than 
+     * 256 bytes in one request. May be PLMN reading can be extended using more
+     * than one sim read req for the same EF in future. 
+     */
+    if (sim_mm_insert_ind->u_ctl_plmn_sel_actech_list_sz > 0xFF)
+    {
+      /*
+       * In SIM_READ_REQ FF represents length not present. SIM will read actual EF length
+       * and send it to MM. At present limitaion is SIM READ CNF can sent max 256 bytes data.
+       */
+      mm_data->reg.sim_ucps_at_len = 0xFF;
+    }
+    else
+    {
+      mm_data->reg.sim_ucps_at_len = sim_mm_insert_ind->u_ctl_plmn_sel_actech_list_sz;
+    }
+  }
+  if(sim_mm_insert_ind->o_ctl_plmn_sel_actech_list_sz > 0)
+  {
+    mm_data->reg.upd_sim_ocps_at = SAT_READ_FILE;
+    /*Set indicatort sim reading is in progress to true*/
+    mm_data->reg.sim_read_in_progress = TRUE;
+    /*
+     * MM cant decide here how many PLMNs are supported GSM access Technology so 
+     * MM should read maximum number of plmn as much it can read.
+     * At present there is a limitation in SIM read req. It cant read more than 
+     * 256 bytes in one request. May be PLMN reading can be extended using more
+     * than one sim read req for the same EF in future. 
+     */
+    if (sim_mm_insert_ind->o_ctl_plmn_sel_actech_list_sz > 0xFF)
+    {
+      /*
+       * In SIM_READ_REQ FF represents length not present. SIM will read actual EF length
+       * and send it to MM. At present limitaion is SIM READ CNF can sent max 256 bytes data.
+       */
+      mm_data->reg.sim_ocps_at_len = 0xFF;
+    }
+    else
+    {
+      mm_data->reg.sim_ocps_at_len = sim_mm_insert_ind->o_ctl_plmn_sel_actech_list_sz;
+    }
+  }
+#endif
+
+  if (sim_mm_insert_ind->pref_plmn_list_sz >0)
+  {
+    mm_data->reg.upd_sim_plmnsel = SAT_READ_FILE;
+    /*Set indicatort sim reading is in progress to true*/
+    mm_data->reg.sim_read_in_progress = TRUE;
+    /* MM should read MAX PREF PLMNs because this EF does not contain any Access Technology info.*/
+    if (sim_mm_insert_ind->pref_plmn_list_sz > MAX_PREF_PLMN)
+    {
+      mm_data->reg.sim_plmnsel_len = MAX_PREF_PLMN; /* Garbage protection */
+    }
+    else
+    {
+      mm_data->reg.sim_plmnsel_len = sim_mm_insert_ind->pref_plmn_list_sz;
+    }
+  }
+
+  return mm_data->reg.sim_read_in_progress;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_read_forb_plmn         |
++--------------------------------------------------------------------+
+
+  PURPOSE : Read the forbidden PLMN into registration data
+
+*/
+
+GLOBAL void reg_read_forb_plmn (const T_forb_plmn *forb_plmn)
+{
+  GET_INSTANCE_DATA;
+  T_plmn plmn;
+
+  TRACE_FUNCTION ("reg_read_forb_plmn ()");
+
+  reg_clear_plmn_list (mm_data->reg.forb_plmn, MAX_FORB_PLMN_ID);
+  memcpy (mm_data->reg.forb_plmn, forb_plmn->forb, 
+          MAX_SIM_FORB_PLMN_ID * UBYTES_PER_PLMN);
+
+  /* 
+   * If the HPLMN is a member of the forbidden list, delete it from the list.
+   */
+  reg_extract_hplmn (&plmn);
+  TRACE_EVENT_P6 ("HPLMN = %x%x%x %x%x%x",
+                  plmn.mcc[0],
+                  plmn.mcc[1],
+                  plmn.mcc[2],
+                  plmn.mnc[0],
+                  plmn.mnc[1],
+                  plmn.mnc[2]);
+
+  reg_plmn_bad_del (mm_data->reg.forb_plmn, MAX_SIM_FORB_PLMN_ID, &plmn);
+
+#ifndef NTRACE
+  {
+    USHORT i;
+
+    for (i = 0; i < MAX_SIM_FORB_PLMN_ID; i++)
+    {
+      reg_unpack_plmn (&plmn, mm_data->reg.forb_plmn, i);
+      TRACE_EVENT_P6 ("FORB = %x%x%x %x%x%x",
+                      plmn.mcc[0],
+                      plmn.mcc[1],
+                      plmn.mcc[2],
+                      plmn.mnc[0],
+                      plmn.mnc[1],
+                      plmn.mnc[2]);
+    }
+  }
+#endif /* #ifndef NTRACE */
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_copy_sim_ahplmn         |
++--------------------------------------------------------------------+
+
+  PURPOSE : Read the AHPLMN information delivered by the SIM at poweron
+            into the registration data structures.
+
+*/
+
+GLOBAL void reg_copy_sim_ahplmn (const T_SIM_MM_INSERT_IND *sim_mm_insert_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_copy_sim_ahplmn ()");
+
+  TRACE_EVENT_P1("v_act_hplmn = %x",
+                  sim_mm_insert_ind->v_act_hplmn);
+                   
+
+  if (!sim_mm_insert_ind->v_act_hplmn)
+  {
+    /*Do Nothing. AHPLMN Feature not supported by SIM. Hence, ignore*/
+  }
+  else 
+  {
+    reg_read_acting_hplmn(sim_mm_insert_ind->act_hplmn);
+    /* Inform ACI & RR of the AHPLMN present in SIM */
+    valid_acting_hplmn(&mm_data->reg.acting_hplmn);
+    mm_build_rr_sync_hplmn_req();
+    mm_mmgmm_ahplmn_ind(&mm_data->reg.acting_hplmn);
+  }
+  
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_read_imsi              |
++--------------------------------------------------------------------+
+
+  PURPOSE : Reads IMSI delivered by SIM into T_imsi data structure
+
+*/
+
+GLOBAL void reg_read_imsi (T_imsi_struct *imsi_struct, const T_imsi_field *imsi_field)
+{
+  USHORT i;
+  UBYTE  digit;
+  UBYTE  length;
+
+  TRACE_FUNCTION ("reg_read_imsi ()");
+  
+  imsi_struct->v_mid    = V_MID_PRES;
+  imsi_struct->id_type  = TYPE_IMSI;
+  imsi_struct->tmsi_dig = 0;
+
+  length = (imsi_field->c_field - 1) * 2;
+  if ((imsi_field->field[0] & 0x08) NEQ 0)
+    length++;
+  for (i = 0; i < length; i++)
+  {
+    digit = ((i & 1) NEQ 0) ?
+        imsi_field->field[(i + 1) / 2] & 0x0f :
+       (imsi_field->field[(i + 1) / 2] & 0xf0) >> 4;
+    imsi_struct->id[i] = digit;
+  }
+  imsi_struct->id[i] = 0xff;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_read_kc_cksn           |
++--------------------------------------------------------------------+
+
+  PURPOSE :
+
+*/
+
+GLOBAL void reg_read_kc_cksn (const T_SIM_MM_INSERT_IND *sim_mm_insert_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_read_kc_cksn ()");
+
+  if (mm_data->reg.update_stat EQ MS_NOT_UPDATED)
+  {
+    /*
+     * clear cipher key, Kc and location area code
+     */
+    mm_data->reg.cksn = CKSN_RES;
+    // mm_data->reg.lac  = 0xfffe; // Write-only variable, deleted HM 20.07.00
+    memset (mm_data->reg.kc, 0xFF, 8);
+    /* Set bit 4 in ef_indicator to indicate kc change to SIM for next SIM_MM_UPDATE_REQ */
+    mm_data->ef_indicator|=(0x01 << 3);
+  }
+  else
+  {
+    /*
+     * copy parameter from SIM card
+     */
+    if(memcmp(mm_data->reg.kc, sim_mm_insert_ind->kc_n.kc, MAX_KC))
+    {
+    /* Set bit 4 in ef_indicator to indicate kc change to SIM for next SIM_MM_UPDATE_REQ */
+    mm_data->ef_indicator|=(0x01 << 3);
+    }
+    memcpy (mm_data->reg.kc, sim_mm_insert_ind->kc_n.kc, MAX_KC);
+    mm_data->reg.cksn = sim_mm_insert_ind->kc_n.kc[8];
+  }
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_read_loc_info          |
++--------------------------------------------------------------------+
+
+  PURPOSE : Reads the location information delivered by the SIM card
+            into the registration memory structures.
+
+*/
+
+GLOBAL void reg_read_loc_info (const T_loc_info *loc_info)
+{
+  GET_INSTANCE_DATA;
+  ULONG tmsi_binary;
+
+  TRACE_FUNCTION ("reg_read_loc_info ()");
+  
+  tmsi_binary = (((ULONG)loc_info->loc[0]) << 24) +
+                (((ULONG)loc_info->loc[1]) << 16) +
+                (((ULONG)loc_info->loc[2]) <<  8) +
+                  (ULONG)loc_info->loc[3];
+
+#ifdef GPRS
+  mm_data->reg.indicated_tmsi = tmsi_binary;
+#endif /* #ifdef GPRS */
+
+  mm_data->reg.tmsi = tmsi_binary;
+  mm_data->reg.lai.mcc[0] = loc_info->loc[4] & 0x0f;
+  mm_data->reg.lai.mcc[1] = loc_info->loc[4] >> 4;
+  mm_data->reg.lai.mcc[2] = loc_info->loc[5] & 0x0f;
+  mm_data->reg.lai.mnc[2] = loc_info->loc[5] >> 4;
+  
+  mm_data->reg.lai.mnc[0] = loc_info->loc[6] & 0x0f;
+  mm_data->reg.lai.mnc[1] = loc_info->loc[6] >> 4;
+  mm_data->reg.lai.lac    = loc_info->loc[7] * 256 +
+                            loc_info->loc[8];
+
+  if (mm_data->reg.lai.mnc[2] EQ 0xF)
+    mm_data->reg.lai.c_mnc = 2; /* 2-digit-MNC */
+  else
+    mm_data->reg.lai.c_mnc = 3; /* 3-digit-MNC */
+  
+  if (mm_data->reg.lai.lac EQ 0xffffL)
+  {
+    mm_data->reg.lai.lac = 0;
+  }
+  mm_data->reg.update_stat     = loc_info->loc[10];
+  if (mm_data->reg.update_stat >= 0x07)
+  {
+    mm_data->reg.update_stat = MS_NOT_UPDATED;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_read_pref_plmn         |
++--------------------------------------------------------------------+
+
+  PURPOSE : Reads the preferred PLMN list delivered by the SIM card
+            into the registration memory structures.
+
+*/
+
+GLOBAL void reg_read_pref_plmn (UBYTE* data, USHORT length)
+{
+  GET_INSTANCE_DATA;
+  USHORT index;
+  USHORT plmnsel_plmn_count;
+  USHORT plmn_count = 0;
+
+  TRACE_FUNCTION ("reg_read_pref_plmn ()");
+/* 
+   * If any additional which does not give complete PLMN id(length MOD UBYTES_PER_PLMN > 0),
+   * ignore these additional bytes at the end
+   */
+  mm_data->reg.sim_plmnsel_len = length-length%UBYTES_PER_PLMN;
+
+  if (mm_data->reg.sim_plmnsel_len > MAX_PREF_PLMN_ID * UBYTES_PER_PLMN)
+  {
+    mm_data->reg.sim_plmnsel_len = MAX_PREF_PLMN_ID * UBYTES_PER_PLMN; /* Garbage protection */
+  }
+  plmnsel_plmn_count = mm_data->reg.sim_plmnsel_len/UBYTES_PER_PLMN;
+
+  reg_clear_plmn_list (mm_data->reg.pref_plmn, MAX_PREF_PLMN_ID);
+  
+  /*Dont copy PLMN entry is empty in the EF*/
+  for (index =0; index < plmnsel_plmn_count; index++)
+  {
+    /*Check if PLMN entry is empty in the EF*/
+    if(!reg_sim_ef_plmn_field_empty(&data[index*UBYTES_PER_PLMN]))
+    {
+      memcpy (&mm_data->reg.pref_plmn[plmn_count*UBYTES_PER_PLMN], 
+              &data[index*UBYTES_PER_PLMN], UBYTES_PER_PLMN);
+      plmn_count++;
+    }
+  }
+}
+
+
+#ifdef REL99
+
+/*
++-------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                          |
+| STATE   : code                ROUTINE : reg_read_ucps_acctec            |
++-------------------------------------------------------------------------+
+
+  PURPOSE : Reads the user controlled PLMN selector with access technology
+            list delivered by the SIM card. PLMN does not support GSM access 
+            are ignored in the pref_plmn list.
+*/
+GLOBAL void reg_read_ucps_acctec(UBYTE* data, USHORT length)
+{
+  GET_INSTANCE_DATA;
+  USHORT index;
+  USHORT plmn_count=0;
+  USHORT ucps_acctech_plmn_count;
+  TRACE_FUNCTION ("reg_read_ucps_acctec ()");
+
+  /* 
+   * If any additional bytes at the end which does not give a complete PLMN id(length 
+   * MOD UBYTES_PER_PLMN_WITH_ACC_TECH > 0), ignore these additional bytes at the end
+   */
+  mm_data->reg.sim_ucps_at_len = length-length%UBYTES_PER_PLMN_WITH_ACC_TECH;
+  ucps_acctech_plmn_count = mm_data->reg.sim_ucps_at_len/UBYTES_PER_PLMN_WITH_ACC_TECH;
+  reg_clear_plmn_list (mm_data->reg.pref_plmn, MAX_PREF_PLMN_ID);
+
+  for( index=0; index < ucps_acctech_plmn_count; index++)
+  {
+    if(reg_read_plmn_support_acctec(&data[index*UBYTES_PER_PLMN_WITH_ACC_TECH]))
+    {
+      /*Check if PLMN entry is empty in the EF*/
+      if(!reg_sim_ef_plmn_field_empty(&data[index*UBYTES_PER_PLMN_WITH_ACC_TECH]))
+      {
+        memcpy(&mm_data->reg.pref_plmn[plmn_count*UBYTES_PER_PLMN],
+               &data[index*UBYTES_PER_PLMN_WITH_ACC_TECH], UBYTES_PER_PLMN);
+        plmn_count++;
+      }
+    }
+    if(plmn_count >= MAX_PREF_PLMN_ID)
+    {
+      /*MAX_PREF_PLMN_ID PLMN in pref_plmn list will be copied*/
+      break;
+    }
+  }
+  /*
+   * Number of plmn copied in the pref_plmn list from the user 
+   * controlled PLMN selector with access technology list 
+   * delivered by the SIM card. This informaiont will be used during copy of 
+   * PLMN from Operator controlled PLMN selector with access technology list 
+   * delivered by the SIM card.
+   */
+   mm_data->reg.sim_ucps_at_len = plmn_count*UBYTES_PER_PLMN;
+}
+
+/*
++--------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                           |
+| STATE   : code                ROUTINE : reg_read_plmn_support_acctec    |
++--------------------------------------------------------------------------+
+
+  PURPOSE : This function tests whether plmn points to an access technology
+            which is supported by the MS. Return TRUE if GSM access technology 
+            is supported else FALSE.
+*/
+
+GLOBAL BOOL reg_read_plmn_support_acctec (UBYTE* plmn_bytes)
+{
+  /*
+   * Check if GSM access technology is supported by the PLMN. Return TRUE 
+   * if supported else FALSE
+   * Spec 11.11 v8.9.1 For each User/Operator controlled PLMN Selector with Access Technology
+   * Byte 5th: 8th bit = 1: GSM access technology selected;
+   * Byte 5th: 8th bit = 0: GSM access technology selected;
+   */
+  
+  return ((plmn_bytes[4] & 0x80) EQ 0x80);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_read_plmn_present    |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function tests whether plmn points to an PLMN already 
+            exists in the pref_plmn list. TRUE will be returned if plmn
+            already exists in the pref_plmn list, otherwise FALSE.
+*/
+
+GLOBAL BOOL reg_read_plmn_present (UBYTE* plmn_bytes)
+{
+  GET_INSTANCE_DATA;
+  USHORT index;
+  USHORT pref_plmn_count;
+  pref_plmn_count = mm_data->reg.sim_ucps_at_len/UBYTES_PER_PLMN;
+  for(index=0; index < pref_plmn_count; index++)
+  {
+    if(((mm_data->reg.pref_plmn[index*UBYTES_PER_PLMN] EQ plmn_bytes[0]) AND
+         (mm_data->reg.pref_plmn[index*UBYTES_PER_PLMN+1] EQ plmn_bytes[1]) AND
+         (mm_data->reg.pref_plmn[index*UBYTES_PER_PLMN+2] EQ plmn_bytes[2])))
+    {
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+
+/*
++------------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                               |
+| STATE   : code                ROUTINE : reg_read_ocps_acctec                 |
++------------------------------------------------------------------------------+
+
+  PURPOSE : Read Operator controlled PLMN selector with access technology list delivered by
+            the SIM card. This can happens only after SIM insert indication indicates to read
+            file from SIM.
+*/
+GLOBAL void reg_read_ocps_acctec(UBYTE* data, USHORT length)
+{
+  GET_INSTANCE_DATA;
+  USHORT index;
+  USHORT plmn_count;
+  USHORT ocps_acctech_plmn_count;
+  TRACE_FUNCTION ("reg_read_ocps_acctec ()");
+  /* 
+   * If any additional bytes at the end which does not give a complete PLMN id(length 
+   * MOD UBYTES_PER_PLMN_WITH_ACC_TECH > 0), ignore these additional bytes at the end
+   */
+  mm_data->reg.sim_ocps_at_len = length-length%UBYTES_PER_PLMN_WITH_ACC_TECH;
+  /*
+   * Remember Number of plmn already copied in the pref_plmn list from the user
+   * controlled PLMN selector with access technology list.
+   */
+  plmn_count = mm_data->reg.sim_ucps_at_len/UBYTES_PER_PLMN;
+  ocps_acctech_plmn_count = mm_data->reg.sim_ocps_at_len/UBYTES_PER_PLMN_WITH_ACC_TECH;
+
+  for( index=0; index < ocps_acctech_plmn_count; index++)
+  {
+    /*Check if the PLMN supports GSM access technology*/
+    if (reg_read_plmn_support_acctec(&data[index*UBYTES_PER_PLMN_WITH_ACC_TECH]))
+    { 
+      /*Check if PLMN entry is empty in the EF*/
+      if(!reg_sim_ef_plmn_field_empty(&data[index*UBYTES_PER_PLMN_WITH_ACC_TECH]))
+      {
+        /*Check if the PLMN is already present in the pref_plmn list*/
+        if(!reg_read_plmn_present(&data[index*UBYTES_PER_PLMN_WITH_ACC_TECH]))
+        {
+          memcpy(&mm_data->reg.pref_plmn[plmn_count*UBYTES_PER_PLMN],
+                 &data[index*UBYTES_PER_PLMN_WITH_ACC_TECH], UBYTES_PER_PLMN);
+          plmn_count++;
+        }
+      }
+      if(plmn_count >= MAX_PREF_PLMN_ID)
+      {
+        /*MAX_PREF_PLMN_ID PLMN in pref_plmn list will be copied*/
+        break;
+      }
+    }
+  }  
+}
+
+
+#endif
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_clear_plmn             |
++--------------------------------------------------------------------+
+
+  PURPOSE : Clears a given PLMN.
+
+*/
+
+GLOBAL void reg_clear_plmn (T_plmn *plmn)
+{
+  TRACE_FUNCTION ("reg_clear_plmn()");
+  
+  memset (plmn, 0x0F, sizeof (T_plmn));
+  plmn->v_plmn = FALSE;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_clear_plmn_list        |
++--------------------------------------------------------------------+
+
+  PURPOSE : Clears a given PLMN list. Returns TRUE if the function
+            actually had to change data.
+
+*/
+
+GLOBAL BOOL reg_clear_plmn_list (UBYTE *plmn_list, USHORT list_size)
+{
+  USHORT i;
+  USHORT byte_count;
+
+  TRACE_FUNCTION ("reg_clear_plmn_list()");
+
+  byte_count = UBYTES_PER_PLMN * list_size;
+
+  for (i = 0; i < byte_count; i++)
+  {
+    if (plmn_list[i] NEQ NOT_PRESENT_8BIT)
+    {
+      memset (plmn_list, NOT_PRESENT_8BIT, UBYTES_PER_PLMN * list_size);
+      TRACE_EVENT ("list actually deleted");
+      return TRUE; /* List has been changed */
+    }
+  }
+  return FALSE; /* Nothing changed */
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_unpack_plmn            |
++--------------------------------------------------------------------+
+
+  PURPOSE : Unpacks a PLMN from compressed form to uncompressed form.
+
+*/
+
+GLOBAL void reg_unpack_plmn (T_plmn *plmn, const UBYTE *packed, USHORT index)
+{
+  /* TRACE_FUNCTION ("reg_unpack_plmn()"); */ /* Avoid too much traces */
+
+  index *= UBYTES_PER_PLMN;
+  plmn->mcc[0] = packed[index] & 0x0f;
+  plmn->mcc[1] = packed[index] >> 4;
+  index++;
+  plmn->mcc[2] = packed[index] & 0x0f;
+  plmn->mnc[2] = packed[index] >> 4;
+  index++;
+  plmn->mnc[0] = packed[index] & 0x0f;
+  plmn->mnc[1] = packed[index] >> 4;
+  index++;
+  if ((plmn->mcc[0] & 0x0F) EQ 0x0F)
+    plmn->v_plmn = V_PLMN_NOT_PRES;
+  else
+    plmn->v_plmn = V_PLMN_PRES;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_pack_plmn              |
++--------------------------------------------------------------------+
+
+  PURPOSE : Packs a PLMN from uncompressed form to compressed form.
+
+*/
+
+GLOBAL void reg_pack_plmn (UBYTE *packed, USHORT index, const T_plmn *plmn)
+{
+  /* TRACE_FUNCTION ("reg_pack_plmn()"); */ /* Avoid too much traces */
+
+  index *= UBYTES_PER_PLMN;
+  packed[index]  = plmn->mcc[1] << 4;
+  packed[index] += plmn->mcc[0];
+  index++;
+  packed[index]  = plmn->mnc[2] << 4;
+  packed[index] += plmn->mcc[2];
+  index++;
+  packed[index]  = plmn->mnc[1] << 4;
+  packed[index] += plmn->mnc[0];
+  index++;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_set_bcch_info          |
++--------------------------------------------------------------------+
+
+  PURPOSE : Fill in the BCCH information in SIM_MM_UPDATE_REQ using 
+            the new data in the registration data structures.
+
+*/
+
+GLOBAL void reg_set_bcch_info (T_SIM_MM_UPDATE_REQ *sim_mm_update_req)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_set_bcch_info ()");
+
+  if (!mm_normal_upd_needed())
+  {
+    if(memcmp(mm_data->reg.bcch, mm_data->mm.bcch, SIZE_BCCH))
+    {
+      /* Set bit 2 in ef_indicator to indicate bcch_info change to SIM */
+    mm_data->ef_indicator|=(0x01 << 1);
+    }
+    memcpy (mm_data->reg.bcch, mm_data->mm.bcch, SIZE_BCCH);
+  }
+  sim_mm_update_req->bcch_inf.c_bcch = SIZE_BCCH;
+  memcpy (sim_mm_update_req->bcch_inf.bcch, mm_data->reg.bcch, SIZE_BCCH);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_set_forb_plmns         |
++--------------------------------------------------------------------+
+
+  PURPOSE : Fill the forbidden PLMN field in the SIM_MM_UPDATE_REQ 
+            primitive with the actual values in the MM data structures.
+
+*/
+
+GLOBAL void reg_set_forb_plmns (T_SIM_MM_UPDATE_REQ *sim_mm_update_req)
+{
+  GET_INSTANCE_DATA;
+  T_plmn forb_plmn;
+  UBYTE sim_forb_plmn_list[MAX_SIM_FORB_PLMN_ID * UBYTES_PER_PLMN];
+  USHORT i;
+
+  TRACE_FUNCTION ("reg_set_forb_plmns ()");
+
+  memcpy (sim_forb_plmn_list, 
+          mm_data->reg.forb_plmn, 
+          MAX_SIM_FORB_PLMN_ID * UBYTES_PER_PLMN);
+
+  for (i = MAX_SIM_FORB_PLMN_ID; i < MAX_FORB_PLMN_ID; i++)
+  {
+    reg_unpack_plmn (&forb_plmn, mm_data->reg.forb_plmn, i);
+    if (!reg_plmn_empty (&forb_plmn))
+    {
+      reg_plmn_add_bad (sim_forb_plmn_list, 
+                        MAX_SIM_FORB_PLMN_ID,
+                        &forb_plmn);
+    }
+  }
+
+  sim_mm_update_req->forb_plmn.c_forb = MAX_SIM_FORB_PLMN_ID * UBYTES_PER_PLMN;
+  memcpy (sim_mm_update_req->forb_plmn.forb, 
+          sim_forb_plmn_list,
+          MAX_SIM_FORB_PLMN_ID * UBYTES_PER_PLMN);
+
+#ifndef NTRACE
+  for (i = 0; i < MAX_SIM_FORB_PLMN_ID; i++)
+  {
+    reg_unpack_plmn (&forb_plmn, sim_mm_update_req->forb_plmn.forb, i);
+    TRACE_EVENT_P6 ("FORB = %x%x%x %x%x%x",
+                    forb_plmn.mcc[0],
+                    forb_plmn.mcc[1],
+                    forb_plmn.mcc[2],
+                    forb_plmn.mnc[0],
+                    forb_plmn.mnc[1],
+                    forb_plmn.mnc[2]);
+  }
+#endif /* #ifndef NTRACE */
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_set_kc                 |
++--------------------------------------------------------------------+
+
+  PURPOSE :
+
+*/
+
+GLOBAL void reg_set_kc (T_SIM_MM_UPDATE_REQ *sim_mm_update_req)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_set_kc ()");
+
+  sim_mm_update_req->cksn = mm_data->reg.cksn;
+  memcpy (sim_mm_update_req->kc, mm_data->reg.kc, MAX_KC);
+
+  TRACE_EVENT_P1 ("CKSN = %d", mm_data->reg.cksn);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_set_loc_info           |
++--------------------------------------------------------------------+
+
+  PURPOSE : Set the location information in the SIM_MM_UPDATE_REQ 
+            primitive to the actual values of the MM data structures.
+
+*/
+
+GLOBAL void reg_set_loc_info (T_SIM_MM_UPDATE_REQ *sim_mm_update_req)
+{
+  GET_INSTANCE_DATA;
+  ULONG tmsi_binary;
+ 
+  TRACE_FUNCTION ("reg_set_loc_info ()");
+  
+  sim_mm_update_req->loc_info.c_loc = SIZE_LOC_INFO;
+
+  tmsi_binary = mm_data->reg.tmsi;
+
+  mm_mmgmm_tmsi_ind (tmsi_binary);
+
+  sim_mm_update_req->loc_info.loc[0]  = (UBYTE)(tmsi_binary >> 24);
+  sim_mm_update_req->loc_info.loc[1]  = (UBYTE)(tmsi_binary >> 16);
+  sim_mm_update_req->loc_info.loc[2]  = (UBYTE)(tmsi_binary >> 8);
+  sim_mm_update_req->loc_info.loc[3]  = (UBYTE)tmsi_binary;
+  sim_mm_update_req->loc_info.loc[4]  = mm_data->reg.lai.mcc[1] << 4;
+  sim_mm_update_req->loc_info.loc[4] += mm_data->reg.lai.mcc[0];
+  sim_mm_update_req->loc_info.loc[5]  = mm_data->reg.lai.mnc[2] << 4;
+  sim_mm_update_req->loc_info.loc[5] += mm_data->reg.lai.mcc[2];  
+  sim_mm_update_req->loc_info.loc[6]  = mm_data->reg.lai.mnc[1] << 4;
+  sim_mm_update_req->loc_info.loc[6] += mm_data->reg.lai.mnc[0];
+  sim_mm_update_req->loc_info.loc[7]  = mm_data->reg.lai.lac >> 8;
+  sim_mm_update_req->loc_info.loc[8]  = mm_data->reg.lai.lac & 0xff;
+  sim_mm_update_req->loc_info.loc[9]  = 0;
+  sim_mm_update_req->loc_info.loc[10] = mm_data->reg.update_stat;
+  sim_mm_update_req->cell_identity    = mm_data->mm.cid;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_send_sim_read_req      |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions sends SIM_READ_REQ for the requested field
+            Currently only used by function reg_read_next_sim_file
+
+*/
+
+LOCAL void reg_send_sim_read_req ( USHORT datafield,
+                                   T_path_info *path_info_ptr,
+                                   UBYTE act_length,
+                                   UBYTE max_length )
+{
+  GET_INSTANCE_DATA;
+    PALLOC (read_req, SIM_READ_REQ);
+
+    TRACE_FUNCTION ("mm_send_sim_read_req()");
+
+    read_req->source = SRC_MM;
+  /* req_id can be set to 0 as MM sends a SIM_READ_REQ only 
+   * when it gets the SIM_READ_CNF to the previous request */
+    read_req->req_id = 0;              
+
+    read_req->offset = 0;
+
+    if(path_info_ptr NEQ NULL)
+    {
+      read_req->v_path_info = TRUE;
+      read_req->path_info = *path_info_ptr;
+    }
+    else
+    {
+      read_req->v_path_info = FALSE;
+    }
+
+    mm_data->sim_read_req_data_field = read_req->datafield = datafield;
+
+    read_req->length = act_length;
+    read_req->max_length = max_length;
+    PSENDX (SIM, read_req);
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_read_next_sim_file     |
++--------------------------------------------------------------------+
+
+  PURPOSE : This functions requests the next changed, unread SIM file
+
+  RETURN: TRUE if function call caused a pending SIM_READ_CNF
+          FALSE otherwise
+
+*/
+
+GLOBAL BOOL reg_read_next_sim_file (void)
+{
+  GET_INSTANCE_DATA;
+  /* Definition used to determine sizeof() */
+  T_SIM_MM_INSERT_IND *insert_ind;
+  
+  TRACE_FUNCTION ("reg_read_next_sim_file()");
+
+  if (mm_data->reg.upd_sim_fplmn EQ SAT_READ_FILE)
+  {
+    /* Change of forbidden PLMN indicated */
+
+    reg_send_sim_read_req (SIM_FPLMN, NULL, NOT_PRESENT_8BIT, sizeof (insert_ind->forb_plmn.forb));
+    mm_data->reg.upd_sim_fplmn = SAT_PEND_CNF;
+    return TRUE;
+  }
+
+  if (mm_data->reg.upd_sim_hplmn EQ SAT_READ_FILE)
+  {
+    /* Change of HPLMN search timer indicated */
+
+    reg_send_sim_read_req (SIM_HPLMN, NULL, NOT_PRESENT_8BIT, sizeof (insert_ind->hplmn));
+    mm_data->reg.upd_sim_hplmn = SAT_PEND_CNF;
+    return TRUE;
+  }
+
+  #ifdef REL99
+  /*updating status user controlled & operator controlled PLMN selection*/
+
+  if (mm_data->reg.upd_sim_ucps_at EQ SAT_READ_FILE)
+  {
+    /* 
+     * Change of user controlled PLMN selector with access technology list indicated.
+     * Max length in SIM READ REQ is sent to FF(255 which is a limitation in SIM READ REQ)instead
+     * of MAX_PREF_PLMN because MM does not know how many PLMN in the EF are supported GSM access
+     * technology.So MM will try to read as many as possible.
+     * In future if MM want to read more than 255 byte for the same EF, MM implementation can
+     * be extented to send more than one SIM READ REQ for same EF.
+     */
+    reg_send_sim_read_req (SIM_UCPS_ACTEC, NULL, (UBYTE)mm_data->reg.sim_ucps_at_len, 0xFF);
+    mm_data->reg.upd_sim_ucps_at = SAT_PEND_CNF;
+    return TRUE;
+  }
+
+
+  if (mm_data->reg.upd_sim_ocps_at EQ SAT_READ_FILE)
+  {
+    /*
+     * Read Operator controlled PLMN selector with access technology list.
+     * Max length in SIM READ REQ is sent to FF(255 which is a limitation in SIM READ REQ)instead
+     * of MAX_PREF_PLMN because MM does not know how many PLMN in the EF are supported GSM access
+     * technology.So MM will try to read as much as possible.
+     * In future if MM want to read more than 255 byte for the same EF, MM implementation can
+     * be extented to send more than one SIM READ REQ for same EF.
+     */
+    reg_send_sim_read_req (SIM_OCPS_ACTEC, NULL, (UBYTE)mm_data->reg.sim_ocps_at_len, 0xFF);
+    mm_data->reg.upd_sim_ocps_at = SAT_PEND_CNF;
+    return TRUE;
+  }
+#endif
+
+  if (mm_data->reg.upd_sim_acc EQ SAT_READ_FILE)
+  {
+    /* Change of access class indicated */
+
+    reg_send_sim_read_req (SIM_ACC,NULL, NOT_PRESENT_8BIT, sizeof (insert_ind->acc_ctrl.acc));
+    mm_data->reg.upd_sim_acc = SAT_PEND_CNF;
+    return TRUE;
+  }
+
+  if (mm_data->reg.upd_sim_act_hplmn EQ SAT_READ_FILE)
+  {
+    /* Change of AHPLMN indicated */
+
+    reg_send_sim_read_req (SIM_CING_AHPLMN,NULL,NOT_PRESENT_8BIT, sizeof (insert_ind->act_hplmn));
+    mm_data->reg.upd_sim_act_hplmn = SAT_PEND_CNF;
+    return TRUE;
+  }
+  if (mm_data->reg.upd_sim_plmnsel EQ SAT_READ_FILE)
+  {
+    /* Change of preferred PLMN list indicated */
+    /*
+     * EF PLMNsel will only be used if EFs EFPLMNwAcT & EFOPLMNwAcT are not used.
+     * mm_data->reg.sim_uocps_at_used will only be true after successful sim read
+     * cnf for EFs EFPLMNwAcT or EFOPLMNwAcT.
+     */
+#ifdef REL99
+    if(mm_data->reg.sim_uocps_at_used EQ FALSE)
+    {
+      reg_send_sim_read_req (SIM_PLMNSEL,NULL, (UBYTE)mm_data->reg.sim_plmnsel_len, MAX_PREF_PLMN);
+      mm_data->reg.upd_sim_plmnsel = SAT_PEND_CNF;
+      return TRUE;
+    }
+    else
+    {
+      /*
+       * No need to read EF PLMNsel because EFs EFPLMNwAcT and(or) EFOPLMNwAcT are being used.
+       */
+      mm_data->reg.upd_sim_plmnsel = SAT_UNCHANGED;
+    }
+#else
+
+    reg_send_sim_read_req (SIM_PLMNSEL, NULL,(UBYTE)mm_data->reg.sim_plmnsel_len, MAX_PREF_PLMN);
+    mm_data->reg.upd_sim_plmnsel = SAT_PEND_CNF;
+    return TRUE;
+
+#endif
+  }
+  return FALSE;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : reg_end_of_deregistration  |
++--------------------------------------------------------------------+
+
+  PURPOSE : Indicate or confirm negative registration to MMI/GMM. 
+            The MM restart procedure may be performed.
+
+*/
+
+GLOBAL void reg_end_of_deregistration (UBYTE nreg_cause, UBYTE service)
+{
+  GET_INSTANCE_DATA;
+  BOOL mm_restart;
+
+  TRACE_FUNCTION ("reg_end_of_deregistration()");
+
+  /* Remember the MM restart condition */
+  mm_restart = ((mm_data->reg.sim_insert_info NEQ NULL) AND
+                (mm_data->nreg_cause EQ CS_SIM_REM));
+
+  if (mm_data->reg.sim_insert_info NEQ NULL) 
+  {
+    /* Insert the new SIM data and free primive */
+    mm_clear_reg_data ();
+    reg_copy_sim_data (mm_data->reg.sim_insert_info);
+    PFREE (mm_data->reg.sim_insert_info);
+    mm_data->reg.sim_insert_info = NULL;
+  }
+
+  if (mm_restart)
+  {
+    /* 
+     * End of MM restart procedure, re-register
+     */
+    if (mm_data->reg.op.m EQ MODE_AUTO)
+    {
+      /* 
+       * Register in automatic mode 
+       */
+      mm_auto_net_reg ();
+    }
+    else
+    {
+      /* 
+       * Register in manual mode 
+       */
+      mm_data->reg.plmn_cnt = 0; /* Delete list of available PLMNs */
+      mm_data->attempt_cnt = 0;
+      mm_mmr_reg_req (FUNC_PLMN_SRCH);
+    }
+  }
+  else
+  {
+    /* 
+     * This was no MM RESTART
+     */
+    if (mm_data->nreg_request) 
+    {
+      /* 
+       * The deregistration was requested by the MMI 
+       */
+      
+      if (nreg_cause EQ CS_POW_OFF)
+      {
+        /* Hard switch off (AT+CFUN=0), delete SIM data physically */ 
+        reg_init ();
+        
+        mm_data->limited_cause = MMCS_SIM_REMOVED; /* MMCS_SIM_INVAL_NOSIM */
+      }
+
+      mm_mmgmm_nreg_cnf (nreg_cause);
+    }
+    else
+    {
+      /* 
+       * This was a real SIM remove, the SIM has been pulled
+       */
+      if (service EQ NO_SERVICE)
+      {
+        mm_mmgmm_nreg_ind (NREG_NO_SERVICE, 
+                           SEARCH_NOT_RUNNING,
+                           FORB_PLMN_NOT_INCLUDED);
+      }
+      else
+      {
+        mm_mmgmm_nreg_ind (NREG_LIMITED_SERVICE, 
+                           SEARCH_NOT_RUNNING,
+                           FORB_PLMN_NOT_INCLUDED);
+      }
+    }
+  }
+
+#ifdef GPRS
+  if (mm_data->gprs.sim_physically_removed)
+  {
+    mm_data->gprs.sim_physically_removed = FALSE;
+    
+    /* Delete registration data */
+    reg_init ();
+  }
+#endif /* GPRS */
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : reg_invalidate_upd_state   |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function invalidates the update state. 
+
+*/          
+
+#ifdef REL99
+GLOBAL void reg_invalidate_upd_state (UBYTE new_update_state, BOOL tmsi_cksn_kc_not_deleted)
+#else
+GLOBAL void reg_invalidate_upd_state (UBYTE new_update_state)
+#endif
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_invalidate_update_state()");
+
+  /* No IMSI ATTACH neccessary anymore */
+  if (mm_data->first_attach)
+  {
+    mm_data->first_attach_mem = mm_data->first_attach;
+    mm_data->first_attach = FALSE;
+  }
+
+  /* No periodic update needed anymore, needing normal update now */
+  mm_data->t3212_timeout = FALSE;
+
+  /* Set new update state */
+  mm_data->reg.update_stat = new_update_state;
+
+#ifdef REL99
+  if(tmsi_cksn_kc_not_deleted EQ TRUE)
+  {
+    /*Dont delete LAI CKSN CKSN KC*/
+  }
+  else
+#endif
+  {
+    /* Delete TMSI */
+    mm_data->reg.tmsi = TMSI_INVALID_VALUE;
+
+    /* Delete LAI */
+    mm_data->reg.lai.lac = LAC_INVALID_VALUE;
+
+    /* Delete CKSN */
+    mm_data->reg.cksn    = CKSN_RES;
+
+    /* Delete also KC */
+    memset (mm_data->reg.kc, 0xff, MAX_KC);
+  }
+
+  /* Delete BCCH information */
+  memset (mm_data->reg.bcch, 0, SIZE_BCCH);
+  
+  /* Update all EFs on SIM */
+  mm_data->ef_indicator = 0xFF;
+  /* Write changed data to SIM */
+  reg_build_sim_update ();
+/* added by TISH 0418 to write simloci to FFS */
+        mm_write_simloci_to_ffs();
+        mm_write_imsi_to_ffs();
+/* added by TISH 0418 to write simloci to FFS */
+
+  /* Check HPLMN timer state */
+  reg_check_hplmn_tim (mm_data->reg.thplmn);
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                              |
+| STATE   : code                ROUTINE : reg_select_network                 |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function starts the network registration for the given PLMN.
+
+*/
+
+GLOBAL void reg_select_network (const T_plmn *plmn)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_select_network()");
+  
+  mm_data->reg.actual_plmn = *plmn; /* Struct copy */
+
+  if (reg_plmn_empty(plmn))
+  {
+    if (mm_data->reg.update_stat EQ MS_UPDATED)
+    {
+      mm_data->reg.actual_plmn.v_plmn = TRUE;
+      memcpy(mm_data->reg.actual_plmn.mcc, mm_data->reg.lai.mcc, SIZE_MCC);
+      memcpy(mm_data->reg.actual_plmn.mnc, mm_data->reg.lai.mnc, SIZE_MNC);
+    }
+    else
+    {
+      /* If PLMN sent is 0xFF (PLMN not present in FFS) and MM Update Status
+       * is MS_NOT_UPDATED, We send a error message to ACI */
+      mm_mmgmm_nreg_ind(NREG_LIMITED_SERVICE, 
+                           SEARCH_NOT_RUNNING, 
+                           FORB_PLMN_NOT_INCLUDED);
+      return;
+    }
+  }
+  mm_data->attempt_cnt = 0;
+  mm_mmr_reg_req (FUNC_PLMN_SRCH);
+}
+
+
+/*
+
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_best_plmn_in_country           |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether the given PLMN is the best PLMN
+            in the country where the mobile is roaming.
+
+*/
+
+GLOBAL BOOL reg_best_plmn_in_country (const T_plmn *bcch_plmn)
+{
+  GET_INSTANCE_DATA;
+  T_plmn hplmn;
+  USHORT i;
+
+  TRACE_FUNCTION ("reg_best_plmn_in_country()");
+
+  reg_extract_hplmn (&hplmn);
+
+  /* fix for CT PTCRB- TC_26_7_4_5_4_6. HPLMN timer is not started only if 
+   bcch PLMN and HPLMN belong to same country and both are in equivalent PLMN list.
+   Detailed analysis present in OMAPS00150594*/
+if (reg_same_country_plmn (bcch_plmn, &hplmn))
+  {
+
+      if (reg_plmn_equal_eqv (bcch_plmn, &hplmn))
+        return TRUE; /* The PLMN is the HPLMN */
+      else
+        return FALSE; /* National roaming */
+}
+  /* International roaming: Check the preferred PLMN list */
+  for (i = 0; i < MAX_PREF_PLMN_ID; i++)
+  {
+    T_plmn pref_plmn;
+
+    reg_unpack_plmn (&pref_plmn, mm_data->reg.pref_plmn, i);
+
+    if (reg_same_country_plmn (bcch_plmn, &pref_plmn))
+      return reg_plmn_equal_eqv (bcch_plmn, &pref_plmn);
+  }
+
+  return TRUE; /* For this country no entry exists */
+}
+
+
+/*
+
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_check_hplmn_tim                |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether:
+            - the HPLMN timer has to be started (if not running) with the duration given as input parameter or 
+            - stopped. 
+            Time unit is decihour.
+*/
+
+GLOBAL void reg_check_hplmn_tim (UBYTE decihours)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_check_hplmn_tim()");
+
+  /*
+   * The HPLMN timer has to be started if all the conditions below are
+   * fulfilled and is not running already. Otherwise, it has to be
+   * stopped.
+   * - Registration state is updated
+   * - MS is roaming on a VPLMN
+   * - Registration mode is automatic
+   * - THPLMN Elementary File is not equal to zero
+   */
+
+  if (mm_full_service_pplmn_scan())
+  {
+    if (mm_data->reg.op.m EQ M_AUTO AND
+        mm_data->reg.thplmn NEQ 0 AND
+        mm_data->reg.update_stat NEQ MS_LA_NOT_ALLOWED AND
+        !reg_best_plmn_in_country (&mm_data->reg.actual_plmn))
+    {
+     /*
+      * Period of HPLMN is controlled by EF_HPLMN file of the SIM.
+      * According to TS 11.11 chapter 10.3.5 :
+      *  0- no search attempt
+      *  N- search attempts every N*6 min intervals (6 min to 8 hours)
+      * For phase 1 SIM wehereby this EF is not available, a default 
+      * value of 1 hour shall be used according to TS 22.011 
+      * chapter 3.2.2.5. In G23 this is managed by SIM entity that 
+      * will force this default value within SIM_INSERT_IND.
+      */
+      if (!TIMERACTIVE(T_HPLMN))
+      {
+        if (mm_data->first_attach_mem)
+        {
+          TRACE_EVENT_P1 ("Start initial HPLMN timer: %d min", 2);
+          TIMERSTART(T_HPLMN, HPLMN_INITIAL_DELAY);
+        }
+        else
+        {
+          TRACE_EVENT_P1 ("Start HPLMN timer: %d", decihours);
+          TIMERSTART(T_HPLMN, decihours * 360000);
+        }
+      }/* if timeractive*/
+    }/*end if mm_data->reg.op.m eq*/
+    else
+    {
+      reg_stop_hplmn_tim ();
+    mm_data->first_attach_mem = FALSE;
+  }
+    
+  }/* end if mm_full_service_pplmn,,,*/
+  else
+  {
+    reg_stop_hplmn_tim();
+  }
+  /* Issue 31179  This timer is started for foreign mcc only for cingular */
+  if( mm_data->reg.is_cingular_sim AND !mm_data->first_attach)
+  {   
+    T_plmn   hplmn;
+    reg_extract_hplmn (&hplmn);
+    if(!TIMERACTIVE(T_HPLMN))
+    {
+      if(memcmp(&(mm_data->reg.actual_plmn.mcc[0]), &(hplmn.mcc[0]), SIZE_MCC) NEQ 0)
+      {
+        TRACE_EVENT_P1 ("Start HPLMN timer: %d", decihours);
+        TIMERSTART(T_HPLMN, decihours * 360000);
+      }
+    }
+  }
+  return;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_stop_hplmn_tim                 |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function stops the HPLMN timer.
+*/
+
+GLOBAL void reg_stop_hplmn_tim (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_stop_hplmn_tim()");
+
+  TRACE_EVENT("Stop HPLMN timer");
+  TIMERSTOP(T_HPLMN);
+  mm_data->plmn_scan_mm = FALSE;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_plmn_in_pref_list              |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function returns TRUE if the PLMN belongs to the 
+            preferred list.
+*/
+
+GLOBAL BOOL reg_plmn_in_pref_list (const T_plmn *plmn)
+{
+  GET_INSTANCE_DATA;
+  USHORT i;
+  TRACE_FUNCTION ("reg_plmn_in_pref_list()");
+
+  for (i = 0; i < MAX_PREF_PLMN_ID; i++)
+  {
+    T_plmn pref_plmn;
+
+    reg_unpack_plmn (&pref_plmn, mm_data->reg.pref_plmn, i);
+    if (!reg_plmn_empty (&pref_plmn))
+    {
+      if (reg_plmn_equal_sim (plmn, &pref_plmn))
+        return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_same_country_plmn              |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function returns TRUE if both PLMN belongs to the 
+            same country, handling the special case of NA (several
+            MCC).
+*/
+
+GLOBAL BOOL reg_same_country_plmn (const T_plmn *plmn1,
+                                   const T_plmn *plmn2)
+{
+  /* TRACE_FUNCTION ("reg_same_country_plmn()"); */ /* Avoid too much traces */
+
+  if (reg_plmn_is_NA_plmn(plmn1))
+    return (reg_plmn_is_NA_plmn(plmn2));
+  else
+    return (memcmp(&(plmn1->mcc[0]), &(plmn2->mcc[0]), SIZE_MCC) EQ 0);
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_check_plmn_search              |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether a better PLMN has been found and, 
+            if so, starts automatic registration on this PLMN.
+            In case the search has to be aborted for some reason (eg. 
+            MM is not in IDLE mode), the HPLMN search timer is started 
+            using a small value.
+*/
+
+GLOBAL void reg_check_plmn_search (USHORT cause,
+                             const T_RR_ABORT_IND *rr_abort_ind)
+{
+  GET_INSTANCE_DATA;
+  T_plmn plmn;
+  BOOL success;
+
+  TRACE_FUNCTION ("reg_check_plmn_search()");
+  
+  if (mm_data->plmn_scan_mm)
+  {
+    /* 
+     * A MM search was ongoing
+     */
+    switch (cause)
+    {
+      case MMCS_PLMN_NOT_IDLE_MODE:
+        TRACE_EVENT ("PLMN scan aborted");
+
+        /* 
+         * PLMN scan has been aborted because not compatible with the 
+         * current activity of the MS. Restart timer with a small duration.
+         * Bufferize / postpone this in a later implementation (Maybe).
+         */
+        reg_check_hplmn_tim (HPLMN_REARM_DELAY);
+        break;
+
+      case MMCS_SUCCESS:
+        /* 
+         * First we need to create the list of available PLMNs. We 
+         * are not interested in the ones belonging to a forbidden list 
+         * but we are still interested in the current RPLMN.
+         * Criteria to start the PLMN selection will be:
+         * 1) First PLMN in the list (higher priority) is not the RPLMN
+         * 2) Either it is the HPLMN,
+         *    Or it is an other PLMN, which belongs to the same country 
+         *    than the current VPLMN, and it belongs to the preferred 
+         *    list ie it has not been inserted here to the randomization
+         *    of the PLMNs whose fieldstrength is higher than -85 dBm.
+         */
+
+        reg_create_plmn_list (rr_abort_ind, WITH_RPLMN);
+
+        success = FALSE;
+        
+        while (mm_data->reg.plmn_index < mm_data->reg.plmn_cnt)
+        {
+          reg_unpack_plmn (&plmn, mm_data->reg.plmn, mm_data->reg.plmn_index);
+          
+          if (reg_plmn_equal_sim (&plmn, &mm_data->reg.actual_plmn))
+          {
+            TRACE_EVENT ("VPLMN hit - cancel");
+            break;
+          }
+          else if (reg_plmn_equal_hplmn (&plmn))
+          {
+             /* fix for TC 26.7.4.5.4.4. Select a PLMN of Same country 
+                and not HPLMN if in International roaming only for Test sim.*/
+             if((mm_data->reg.op.ts EQ TS_NO_AVAIL) OR
+               reg_same_country_plmn (&plmn, &mm_data->reg.actual_plmn))
+            {
+              TRACE_EVENT ("HPLMN found - success");
+              success = TRUE;          
+              break;
+            }
+            else
+            {
+              mm_data->reg.plmn_index++;
+              continue;
+            }
+
+          }
+          else if (!reg_plmn_in_pref_list (&plmn))
+          {
+            TRACE_EVENT ("PPLMN list end - cancel");
+            break;
+          }
+          else if(mm_data->reg.is_cingular_sim)
+          {
+            TRACE_EVENT ("better PLMN from HPLMN list in Cingular - success");
+            success = TRUE;
+            break;
+          }
+          else if (reg_same_country_plmn (&plmn, &mm_data->reg.actual_plmn))
+          {
+            TRACE_EVENT ("better PLMN same country - success");
+            success = TRUE;
+            break;
+          }
+          else
+            mm_data->reg.plmn_index++;
+        }
+
+        if (success)
+        {
+          TRACE_EVENT ("PPLMN rescan pass");
+
+          /* 
+           * An alternate network candidate has been found, so try to camp
+           * on it. It the registration procedure fails, then the normal automatic 
+           * network selection procedure will apply.
+           */
+          reg_select_network (&plmn); /*lint !e772 conceivably not initialized */
+        }
+        else
+        {
+          TRACE_EVENT ("PPLMN rescan failed");
+
+          /* 
+           * PLMN rescan did not provide any interesting results, 
+           * so restart timer.
+           */
+          reg_check_hplmn_tim (mm_data->reg.thplmn);
+        }
+
+        /* 
+         * Do not consider the forbidden PLMNs for MM's internal operation
+         */
+        reg_create_plmn_list (rr_abort_ind, WITH_OTHER_PLMNS);
+        break;
+
+      case MMCS_SIM_REMOVED:
+        /* 
+         * Not relevant for MM initiated search.
+         */
+        break;
+
+      default: 
+        TRACE_ERROR (UNEXPECTED_DEFAULT);
+        break;
+    }
+  }
+
+  mm_data->plmn_scan_mm  = FALSE;
+  mm_data->plmn_scan_mmi = FALSE;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_store_eqv_plmns                |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether a received equivalent PLMN list
+            matches an already stored list. If no match then the new 
+            equivalent PLMN list overwrites the currently stored list.
+*/
+BOOL reg_store_eqv_plmns(T_eqv_plmn_list *rx_eplmn_list, T_plmn *plmn)
+{
+  GET_INSTANCE_DATA;
+  U8 i=0, j=0;
+  T_plmn local_plmn;
+  UBYTE local_store[EPLMNLIST_SIZE*UBYTES_PER_PLMN];
+  
+  TRACE_FUNCTION ("reg_store_eqv_plmns()");
+  
+  if (rx_eplmn_list->c_eqv_plmn > EPLMNLIST_SIZE)
+  {  
+    rx_eplmn_list->c_eqv_plmn = 0;
+    TRACE_ERROR ("count out of range");
+    return FALSE;
+  }
+
+  for (i=0; i < EPLMNLIST_SIZE - 1; i++)
+  {
+    /* Use 0xf as filler for 2 digit MNCs */
+    if (rx_eplmn_list->eqv_plmn[i].c_mnc EQ (SIZE_MNC-1))
+      rx_eplmn_list->eqv_plmn[i].mnc[SIZE_MNC-1] = 0xf;
+  }
+  
+  /*Convert the new list into a MM-friendly format*/
+  reg_pack_plmn(local_store, 0, plmn);
+
+  for(i=0;i<EPLMNLIST_SIZE-1;i++)
+  {
+    memcpy(&local_plmn.mcc, &rx_eplmn_list->eqv_plmn[i].mcc, SIZE_MCC);
+    memcpy(&local_plmn.mnc, &rx_eplmn_list->eqv_plmn[i].mnc, SIZE_MNC);
+
+    reg_pack_plmn(local_store, i+1, &local_plmn);
+  }
+
+  if(memcmp(local_store, mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE*UBYTES_PER_PLMN))
+  {
+    /* The Equivalent PLMN list has changed */
+
+    /*Initialise EPLMN storage*/
+    memset (&mm_data->reg.eqv_plmns.eqv_plmn_list, 0xFF, EPLMNLIST_SIZE*UBYTES_PER_PLMN);
+
+    /* Store Equivalent PLMNs */
+    for(i=0,j=0;i<EPLMNLIST_SIZE;i++)
+    {
+      T_plmn new_plmn;
+
+      reg_unpack_plmn(&new_plmn, local_store, i);
+
+      /* Remove any forbidden PLMNs from the new EPLMN list */
+      if(!reg_plmn_in_list(mm_data->reg.forb_plmn, MAX_FORB_PLMN_ID, &new_plmn))
+        reg_pack_plmn(mm_data->reg.eqv_plmns.eqv_plmn_list, j++, &new_plmn);
+    }
+    return(TRUE);
+  }
+  return(FALSE);
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_read_acting_hplmn                 |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function copies the AHPLMN value read from the SIM at poweron
+            or after REFRESH command from network.            
+*/
+GLOBAL void reg_read_acting_hplmn (const U8  acting_hplmn[])
+{
+  GET_INSTANCE_DATA;
+  mm_data->reg.acting_hplmn.mcc[0] = acting_hplmn[0] &0x0f;
+  mm_data->reg.acting_hplmn.mcc[1] = acting_hplmn[0] >> 4;
+  mm_data->reg.acting_hplmn.mcc[2] = acting_hplmn[1] &0x0f;
+  mm_data->reg.acting_hplmn.mnc[2] = acting_hplmn[1] >>4;
+  mm_data->reg.acting_hplmn.mnc[0] = acting_hplmn[2] &0x0f;
+  mm_data->reg.acting_hplmn.mnc[1] = acting_hplmn[2] >>4;
+}
+
+            
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : valid_acting_hplmn                 |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether a received AHPLMN has the
+            same MCC as the True-HPLMN and if yes then checks the
+            validity of the MNC digits. Thus it checks the validity
+            of AHPLMN received.
+*/
+
+BOOL valid_acting_hplmn(T_plmn   *acting_hplmn)
+{
+  GET_INSTANCE_DATA;
+  T_plmn   hplmn;
+
+  UINT  temp1=0x0F0F0F;
+
+  /*This will be set to TRUE if AHPLMN is FFFFFF*/
+  mm_data->reg.acting_hplmn_invalid = FALSE;
+ 
+  TRACE_FUNCTION ("valid_acting_hplmn()");
+
+  /* Extract HPLMN from IMSI and compare MCC of HPLMN and AHPLMN */
+  reg_extract_hplmn(&hplmn);
+
+  /* Check If the AHPLMN contains FFFFFF */
+
+  if (!(memcmp(acting_hplmn->mcc,&temp1,SIZE_MCC) AND
+        memcmp(acting_hplmn->mnc,&temp1,SIZE_MNC)))
+  {     
+     mm_data->reg.acting_hplmn.v_plmn = V_PLMN_NOT_PRES;     
+     mm_data->reg.acting_hplmn_invalid = TRUE;
+     return FALSE;
+  }
+  
+  /* If MCC of HPLMN and AHPLMN differs invalidate AHPLMN */
+  if ( memcmp(acting_hplmn->mcc,mm_data->reg.imsi_struct.id,3) )
+  {
+    mm_data->reg.acting_hplmn.v_plmn = V_PLMN_NOT_PRES;         
+    return FALSE;
+  }
+
+  if (acting_hplmn->mnc[0] EQ 0x0f OR
+      acting_hplmn->mnc[1] EQ 0x0f )
+  {
+    mm_data->reg.acting_hplmn.v_plmn = V_PLMN_NOT_PRES;         
+    return FALSE;
+  }
+  else
+  {
+    /* 1. If True HPLMN has only 2 mnc digits ignore 3rd digit of mnc in AHPLMN 
+          even if exists 
+       2. If True HPLMN has mnc as 3 digits but AHPLMN has only 2 OR if any
+          of the mnc digits are 0xff,invalidate the AHPLMN
+    */
+    if (mm_data->reg.length_mnc EQ 2 ) 
+    {
+      acting_hplmn->mnc[2] = 0x0F;
+    }
+    else if(acting_hplmn->mnc[2] EQ 0xFF)
+    {
+      mm_data->reg.acting_hplmn.v_plmn = V_PLMN_NOT_PRES;         
+      return FALSE;
+    }
+  }/* else acting_hplmn->mnc */
+
+  mm_data->reg.acting_hplmn.v_plmn = V_PLMN_PRES;
+  return TRUE;
+
+}/* end of valid_acting_hplmn */
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                             |
+| STATE   : code                ROUTINE : reg_pack_plmn_fn.....              |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function packs a PLMN.
+*/
+
+LOCAL void reg_pack_plmn_fn (USHORT               i,
+                             const T_RR_ABORT_IND *rr_abort_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("reg_pack_plmn_fn()");
+  reg_pack_plmn (mm_data->reg.plmn, mm_data->reg.plmn_cnt, 
+                 &rr_abort_ind->plmn[i]);
+  mm_data->reg.plmn_rx[mm_data->reg.plmn_cnt] = rr_abort_ind->rxlevel[i];
+  mm_data->reg.plmn_lac[mm_data->reg.plmn_cnt] = rr_abort_ind->lac_list[i]; /* LOL 02.01.2003: added for EONS support */
+  mm_data->reg.plmn_cnt++;
+}/*reg_pack_plmn_fn*/
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_REG                     |
+| STATE   : code                ROUTINE : check_if_cingular_sim      |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether inserted sim belong to 
+  Cingular Network.cingular_plmn_list contains the entire mcc and mnc of
+  Cingular Network. Issue 31179
+
+*/
+
+GLOBAL void check_if_cingular_sim(void)
+{
+  GET_INSTANCE_DATA;
+  USHORT plmn_index;
+  T_plmn   hplmn;
+  reg_extract_hplmn (&hplmn);
+  for(plmn_index = 0; plmn_index < MAX_CINGULAR_PLMN; plmn_index++)
+  {
+    if(reg_plmn_equal_sim (&hplmn, &cingular_plmn_list[plmn_index]))
+    {
+      mm_data->reg.is_cingular_sim = TRUE;
+      break;
+    }
+  }
+}
+