diff src/g23m-gsm/mm/mm_gmm.c @ 1:d393cd9bb723

src/g23m-*: initial import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 15 Jul 2018 04:40:46 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/g23m-gsm/mm/mm_gmm.c	Sun Jul 15 04:40:46 2018 +0000
@@ -0,0 +1,845 @@
+/* 
++----------------------------------------------------------------------------- 
+|  Project :  GSM-PS (8410)
+|  Modul   :  MM_GMM.C
++----------------------------------------------------------------------------- 
+|  Copyright 2002 Texas Instruments Berlin, AG 
+|                 All rights reserved. 
+| 
+|                 This file is confidential and a trade secret of Texas 
+|                 Instruments Berlin, AG 
+|                 The receipt of or possession of this file does not convey 
+|                 any rights to reproduce or disclose its contents or to 
+|                 manufacture, use, or sell anything it may describe, in 
+|                 whole, or in part, without the specific written consent of 
+|                 Texas Instruments Berlin, AG. 
++----------------------------------------------------------------------------- 
+|  Purpose :  This module defines the functions for the communication
+|             of MM with GMM. All communications from MM to GMM will 
+|             be through this file.
++----------------------------------------------------------------------------- 
+*/ 
+
+#ifndef MM_GMM_C
+#define MM_GMM_C
+
+#define ENTITY_MM
+
+/*==== INCLUDES ===================================================*/
+
+
+#include <string.h>
+#include "typedefs.h"
+#include "pconst.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"
+
+/*==== EXPORT =====================================================*/
+
+/*==== TEST =====================================================*/
+
+/*==== PRIVAT =====================================================*/
+
+/*==== VARIABLES ==================================================*/
+
+/*==== FUNCTIONS ==================================================*/
+
+#if defined(GPRS)
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_send_mmgmm_reg_cnf     |
++--------------------------------------------------------------------+
+
+  PURPOSE : sends the MMGMM_REG_CNF primitive
+
+*/
+
+GLOBAL void mm_send_mmgmm_reg_cnf (UBYTE bootup_cause)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_send_mmgmm_reg_cnf()");
+
+  {
+    PALLOC (mmgmm_reg_cnf, MMGMM_REG_CNF); /* T_MMGMM_REG_CNF */
+    if (bootup_cause NEQ PWR_SCAN_START)
+    {
+      mmgmm_reg_cnf->plmn.v_plmn = V_PLMN_PRES;
+      memcpy (mmgmm_reg_cnf->plmn.mcc, mm_data->mm.lai.mcc, SIZE_MCC);
+      memcpy (mmgmm_reg_cnf->plmn.mnc, mm_data->mm.lai.mnc, SIZE_MNC);
+    }
+    else
+    {
+      mmgmm_reg_cnf->plmn.v_plmn = V_PLMN_NOT_PRES;
+    }
+    mmgmm_reg_cnf->lac = mm_data->mm.lai.lac;
+    mmgmm_reg_cnf->cid = mm_data->mm.cid;
+    mmgmm_reg_cnf->resumption = mm_data->gprs.resumption;
+    mmgmm_reg_cnf->gprs_indicator = mm_data->mm.gprs_indication;  
+    mmgmm_reg_cnf->bootup_cause = bootup_cause;
+    PSENDX (GMM, mmgmm_reg_cnf);
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_reg_cnf           |
++--------------------------------------------------------------------+
+
+  PURPOSE : This function indicates change in service or change in PLMN 
+            to the GMREG SAP. This is suppressed if the 
+            registration type is REG_CELL_SEARCH_ONLY, in this
+            case GMM is not interested in the MM service information.
+
+*/
+
+GLOBAL void mm_mmgmm_reg_cnf (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_reg_cnf()");
+
+  if (GET_STATE (STATE_REG_TYPE) NEQ REG_CELL_SEARCH_ONLY)
+  {
+    /* Issue 20792 : Added condition mm_data->plmn_scan_mmi. If network search requested by user
+     is pending then after RR release MM should initiate network search and after getting
+     proper PLMN list it should inform GMM followed by successful Registration. Else there will be
+     collision in RR between network search and GPRS Attach resulting in abortion of network
+     search and hence empty list by RR will be returned.
+    */
+
+
+    if ( mm_data->plmn_scan_mmi ) 
+    {
+      mm_data->gprs.reg_cnf_on_idle_entry = TRUE;
+    }
+    else
+    {
+      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.
+         */
+        mm_send_mmgmm_reg_cnf (REG_END);
+
+        mm_data->reg.full_service_indicated = TRUE;
+        mm_data->reg.new_cell_ind = FALSE;	  
+      }
+
+      mm_data->gprs.reg_cnf_on_idle_entry = FALSE;
+
+      /* Disallow establishment for own location updating and CM services */
+      if (GET_STATE (STATE_REG_TYPE) EQ REG_REMOTE_CONTROLLED)
+      {
+        SET_STATE (STATE_REG_TYPE, REG_CELL_SEARCH_ONLY);
+        SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EST_IDLE);
+      }
+    } /* else */
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_send_mmgmm_nreg_ind     |
++--------------------------------------------------------------------+
+
+  PURPOSE : This procedure builds ans sends the MMGMM_NREG_IND
+            primitive without having any side effects.
+
+*/
+
+LOCAL void mm_send_mmgmm_nreg_ind (UBYTE service, 
+                                   UBYTE search_running,
+                                   UBYTE forb_ind)
+{
+  GET_INSTANCE_DATA;
+  PALLOC (mmgmm_nreg_ind, MMGMM_NREG_IND); /* T_MMGMM_NREG_IND */
+
+  TRACE_FUNCTION ("mm_send_mmgmm_nreg_ind()");
+
+  mmgmm_nreg_ind->service        = service; 
+  mmgmm_nreg_ind->search_running = search_running;
+
+  if (forb_ind EQ FORB_PLMN_INCLUDED)
+  {
+    mmgmm_nreg_ind->new_forb_plmn.v_plmn = V_PLMN_PRES;
+    memcpy (mmgmm_nreg_ind->new_forb_plmn.mcc, mm_data->mm.lai.mcc, SIZE_MCC);
+    memcpy (mmgmm_nreg_ind->new_forb_plmn.mnc, mm_data->mm.lai.mnc, SIZE_MNC);
+  }
+  else
+  {
+    mmgmm_nreg_ind->new_forb_plmn.v_plmn = V_PLMN_NOT_PRES;
+    memset (mmgmm_nreg_ind->new_forb_plmn.mcc, 0x0f, SIZE_MCC);
+    memset (mmgmm_nreg_ind->new_forb_plmn.mnc, 0x0f, SIZE_MNC);
+  }
+
+  mmgmm_nreg_ind->cause = mm_data->limited_cause;
+  /* No GPRS resumption field in MMGMM_NREG_IND as in MMGMM_REG_REJ */
+  PSENDX (GMM, mmgmm_nreg_ind);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_send_mmgmm_reg_rej      |
++--------------------------------------------------------------------+
+
+  PURPOSE : This procedure builds ans sends the MMGMM_REG_REJ
+            primitive without having any side effects.
+
+*/
+
+LOCAL void mm_send_mmgmm_reg_rej (UBYTE service,
+                                  UBYTE search_running,
+                                  UBYTE forb_ind)
+{
+  GET_INSTANCE_DATA;
+  PALLOC (mmgmm_reg_rej, MMGMM_REG_REJ); /* T_MMGMM_REG_REJ */
+
+  TRACE_FUNCTION ("mm_send_mmgmm_reg_rej()");
+
+  mmgmm_reg_rej->service        = service; 
+  mmgmm_reg_rej->search_running = search_running;
+
+  if (forb_ind EQ FORB_PLMN_INCLUDED)
+  {
+    mmgmm_reg_rej->new_forb_plmn.v_plmn = V_PLMN_PRES;
+    memcpy (mmgmm_reg_rej->new_forb_plmn.mcc, mm_data->mm.lai.mcc, SIZE_MCC);
+    memcpy (mmgmm_reg_rej->new_forb_plmn.mnc, mm_data->mm.lai.mnc, SIZE_MNC);
+  }
+  else
+  {
+    mmgmm_reg_rej->new_forb_plmn.v_plmn = V_PLMN_NOT_PRES;
+    memset (mmgmm_reg_rej->new_forb_plmn.mcc, 0x0f, SIZE_MCC);
+    memset (mmgmm_reg_rej->new_forb_plmn.mnc, 0x0f, SIZE_MNC);
+  }
+
+  mmgmm_reg_rej->cause      = mm_data->limited_cause;
+  mmgmm_reg_rej->resumption = mm_data->gprs.resumption;
+  PSENDX (GMM, mmgmm_reg_rej);
+}
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_nreg_ind          |
++--------------------------------------------------------------------+
+
+  PURPOSE : This is the common procedure for MMGMM_NREG_IND and
+            MMGMM_REG_REJ. MMGMM_REG_REJ is sent if the procedure 
+            war a remote controlled location updating procedure, 
+            otherwise MMGMM_NREG_IND is sent.
+
+*/
+
+GLOBAL void mm_mmgmm_nreg_ind (UBYTE service,
+                               UBYTE search_running,
+                               UBYTE forb_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_nreg_ind()");
+
+  if (GET_STATE (STATE_REG_TYPE) EQ REG_REMOTE_CONTROLLED)
+  {
+    mm_send_mmgmm_reg_rej  (service, search_running, forb_ind);
+  }
+  else
+  {
+    mm_send_mmgmm_nreg_ind (service, search_running, forb_ind);
+  }
+
+#ifdef WIN32
+  TRACE_EVENT_P1 ("  service=%d",        service);
+  TRACE_EVENT_P1 ("  search_running=%d", search_running);
+  TRACE_EVENT_P1 ("  limited_cause=%d",  mm_data->limited_cause);
+  TRACE_EVENT_P1 ("  resumption=%d",     mm_data->gprs.resumption);
+#endif /* #ifdef WIN32 */
+
+  /* 
+   * 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;
+  mm_data->gprs.reg_cnf_on_idle_entry = FALSE;
+
+  /* Disallow establishment for own location updating and CM services */
+  if (GET_STATE (STATE_REG_TYPE) EQ REG_REMOTE_CONTROLLED)
+  {
+    SET_STATE (STATE_REG_TYPE, REG_CELL_SEARCH_ONLY);
+    SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EST_IDLE);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_nreg_cnf          |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_NREG_CNF. 
+            Otherwise send MMR_NREG_CNF.
+
+*/
+
+GLOBAL void mm_mmgmm_nreg_cnf (UBYTE detach_cause)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_nreg_cnf()");
+
+  if (mm_data->nreg_request)
+  {
+    PALLOC (mmgmm_nreg_cnf, MMGMM_NREG_CNF); /* T_MMGMM_NREG_CNF */
+    mmgmm_nreg_cnf->detach_cause = detach_cause;
+    
+#ifdef WIN32
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  detach_cause=%d", mmgmm_nreg_cnf->detach_cause);
+#endif /* WIN32 */
+  
+    PSENDX (GMM, mmgmm_nreg_cnf);
+
+    mm_data->nreg_request = FALSE;
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_plmn_ind          |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_PLMN_IND. 
+            Otherwise send MMR_PLMN_IND.
+
+*/
+
+GLOBAL void mm_mmgmm_plmn_ind (USHORT cause,
+                         const T_RR_ABORT_IND *rr_abort_ind)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_plmn_ind()");
+
+  if (mm_data->plmn_scan_mmi)
+  {
+    USHORT i;
+    PALLOC (mmgmm_plmn_ind, MMGMM_PLMN_IND); /* T_MMGMM_PLMN_IND */
+
+    /* Issue 20792  : If there was any network search request pending during specific
+         prorcedure then on getting RR_RELEASE_IND that would be processed first and 
+         MMGMM_REG_CNF will be held till that is done. Once PLMN list is receieved by RR
+         MM should send MMGMM_PLMN_IND to GMM followed by MMGMM_REG_CNF .
+    */
+
+    if ( mm_data->gprs.reg_cnf_on_idle_entry )
+    {
+      mm_data->plmn_scan_mmi = FALSE;
+      mm_data->reg.full_service_indicated = FALSE;/* Force MMGMM_REG_CNF */
+      mm_mmgmm_reg_cnf();
+    }
+
+    /* Net Search Result */
+    mmgmm_plmn_ind->cause = cause;
+    
+    // See comment for MMR_PLMN_IND!!!
+    memset (mmgmm_plmn_ind->plmn, NOT_PRESENT_8BIT,
+            sizeof (mmgmm_plmn_ind->plmn));
+
+    /* Make testcases happy, initialize all unused data */
+    memset (mmgmm_plmn_ind->forb_ind, FORB_PLMN_NOT_INCLUDED, 
+            sizeof (mmgmm_plmn_ind->forb_ind));    
+    memset (mmgmm_plmn_ind->rxlevel, 0x00, 
+            sizeof (mmgmm_plmn_ind->rxlevel));    
+    memset (mmgmm_plmn_ind->gprs_status, MMGMM_GPRS_GSM, 
+            sizeof (mmgmm_plmn_ind->gprs_status));    
+
+    if (cause EQ MMCS_SUCCESS)
+    {  
+      /* Create the PLMN list for the MMI and sent it */
+      reg_create_plmn_list (rr_abort_ind, WITH_ALL_PLMNS);
+
+      for (i = 0; i < mm_data->reg.plmn_cnt; i++) 
+      {
+        /* Copy the PLMN information itself from registration data 
+         * This may be too complicated, one memcpy() may be sufficient */
+
+        reg_unpack_plmn (&mmgmm_plmn_ind->plmn[i], mm_data->reg.plmn, i);
+
+        /* Process forbidden PLMN information */
+        if (reg_plmn_in_list (mm_data->reg.forb_plmn,
+                              MAX_FORB_PLMN_ID,
+                              &mmgmm_plmn_ind->plmn[i]))
+        {
+          mmgmm_plmn_ind->forb_ind[i] = FORB_PLMN_INCLUDED;
+        }
+        else
+        {
+          /* 
+           * PLMN not member of forbidden list (cause #11), if GPRS is 
+           * active, consider GPRS forbidden list also (cause #14)
+           */ 
+          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,
+                                &mmgmm_plmn_ind->plmn[i]))
+          {
+            mmgmm_plmn_ind->forb_ind[i] = FORB_PLMN_INCLUDED;
+          }
+          else
+          {
+            mmgmm_plmn_ind->forb_ind[i] = FORB_PLMN_NOT_INCLUDED;
+          }
+        }
+
+        /* Copy the rx level from registration data */
+        mmgmm_plmn_ind->rxlevel[i] = mm_data->reg.plmn_rx [i];
+
+        mmgmm_plmn_ind->lac_list[i] = mm_data->reg.plmn_lac [i]; //LOL 02.01.2003: added for EONS support
+
+        /* Copy the GPRS capabilities from registration data */
+        mmgmm_plmn_ind->gprs_status[i] = mm_data->reg.gprs_status[i];
+      } /* for */
+
+      /* Do not consider the forbidden PLMNs for MM's internal operation */
+      reg_create_plmn_list (rr_abort_ind, WITH_OTHER_PLMNS);
+    } /* if */
+
+    PSENDX (GMM, mmgmm_plmn_ind);
+
+  }
+
+  reg_check_plmn_search (cause, rr_abort_ind);
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_auth_rej_ind      |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_AUTH_REJ_IND. 
+            Otherwise this is compiled to a dummy function and will 
+            return without further action.
+*/
+
+GLOBAL void mm_mmgmm_auth_rej_ind (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_auth_rej_ind()");
+  
+  {
+    PALLOC (mmgmm_auth_rej_ind, MMGMM_AUTH_REJ_IND);
+    PSENDX (GMM, mmgmm_auth_rej_ind);
+  }
+
+  mm_data->reg.full_service_indicated = FALSE;
+  mm_data->gprs.reg_cnf_on_idle_entry = FALSE;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_cm_establish_ind  |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_CM_ESTABLISH_IND if 
+            not already done. A GSM only protocol stack doesn't 
+            need this function.
+            By the primitive MMGMM_CM_ESTABLISH_IND GMM is informed 
+            that a circuit switched call has to be started.
+
+*/
+
+GLOBAL void mm_mmgmm_cm_establish_ind (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_establish_ind()");
+
+  switch (GET_STATE (STATE_GPRS_CM_EST))
+  {
+    case CM_GPRS_EST_IDLE:
+      {
+        PALLOC (mmgmm_establish_ind, MMGMM_CM_ESTABLISH_IND);
+        PSENDX (GMM, mmgmm_establish_ind);
+      }
+      SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EST_PEND);
+      break;
+
+    default: /* Maybe CM establishment is already allowed etc. */
+      break;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_cm_emergency_ind  |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_CM_EMERGENCY_IND. 
+            Otherwise this is compiled to a dummy function and will 
+            return without further action.
+            By this primitive GMM is informed that a circuit switched 
+            emergency call has to be started.
+
+*/
+
+GLOBAL void mm_mmgmm_cm_emergency_ind (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_emergency_ind()");
+
+  switch (GET_STATE (STATE_GPRS_CM_EST))
+  {
+    case CM_GPRS_EST_IDLE:
+    case CM_GPRS_EST_PEND:
+      {
+        PALLOC (mmgmm_emergency_ind, MMGMM_CM_EMERGENCY_IND);
+        PSENDX (GMM, mmgmm_emergency_ind);
+      }
+      SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EMERGE_PEND);
+      break;
+
+    default: /* MMGMM_CM_EMERGENCY_IND has already been sent */
+      break;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_cm_release_ind    |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_CM_RELEASE_IND if the 
+            conditions are met.
+            Otherwise this is compiled to a dummy function and will 
+            return without further action.
+*/
+
+GLOBAL void mm_mmgmm_cm_release_ind (UBYTE resumption)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_cm_release_ind()");
+
+  if (!mm_gsm_alone() AND 
+      (GET_STATE (STATE_GPRS_CM_EST) NEQ CM_GPRS_EST_IDLE) AND
+      (mm_count_connections (CM_NOT_IDLE) EQ 0))
+  {
+    PALLOC (mmgmm_cm_release_ind, MMGMM_CM_RELEASE_IND);
+    mmgmm_cm_release_ind->resumption = resumption;
+
+#ifdef WIN32
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  resumption=%d", mmgmm_cm_release_ind->resumption);
+#endif /* WIN32 */
+
+    PSENDX (GMM, mmgmm_cm_release_ind);
+
+    SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EST_IDLE);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_activate_ind      |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_ACTIVATE_IND. 
+            Otherwise this is compiled to a dummy function and will 
+            return without further action.
+            The t3212_val here is to be given in the same form as it 
+            is to be received from the network, this means in steps of
+            6 minutes, it will be scaled to milliseconds for GMM here.
+*/
+
+GLOBAL void mm_mmgmm_activate_ind (UBYTE status)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_activate_ind()");
+
+  if (!mm_gsm_alone())
+  {
+    PALLOC (mmgmm_activate_ind, MMGMM_ACTIVATE_IND); /* T_MMGMM_ACTIVATE_IND */
+    mmgmm_activate_ind->plmn.v_plmn = V_PLMN_PRES;
+    memcpy (mmgmm_activate_ind->plmn.mcc, mm_data->mm.lai.mcc, SIZE_MCC);
+    memcpy (mmgmm_activate_ind->plmn.mnc, mm_data->mm.lai.mnc, SIZE_MNC);
+    mmgmm_activate_ind->lac = mm_data->mm.lai.lac;
+    mmgmm_activate_ind->cid = mm_data->mm.cid;
+    if (mm_data->t3212_cfg_counter NEQ 0 AND 
+        mm_data->mm.mm_info.t3212 NEQ 0)
+      mmgmm_activate_ind->t3212_val = mm_data->t3212_cfg_counter * 10000;
+    else
+      mmgmm_activate_ind->t3212_val = mm_data->mm.mm_info.t3212 * 360000;
+    mmgmm_activate_ind->status = status;
+    mmgmm_activate_ind->gprs_indicator = mm_data->mm.gprs_indication;
+
+    if (status NEQ MMGMM_LIMITED_SERVICE)
+    {
+      mm_data->reg.actual_plmn = mmgmm_activate_ind->plmn; /* Struct copy */
+    }
+
+#ifdef WIN32
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  MCC=%x%x%x MNC=%x%x%x LAC=%04x",
+                  mmgmm_activate_ind->plmn.mcc[0],
+                  mmgmm_activate_ind->plmn.mcc[1],
+                  mmgmm_activate_ind->plmn.mcc[2],
+                  mmgmm_activate_ind->plmn.mnc[0],
+                  mmgmm_activate_ind->plmn.mnc[1],
+                  mmgmm_activate_ind->plmn.mnc[2],
+                  mmgmm_activate_ind->lac);
+     
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  t3212_val=%d", 
+                  mmgmm_activate_ind->t3212_val);
+
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  status=%d", 
+                  mmgmm_activate_ind->status);
+
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  gprs_indicator=%d", 
+                  mmgmm_activate_ind->gprs_indicator);
+#endif /* #ifdef WIN32 */
+
+    PSENDX (GMM, mmgmm_activate_ind);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_t3212_val_ind     |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_T3212_VAL_IND always T3212 
+            changes, but no cell selection by RR was performed.
+            For a GSM only protocol stack, this function doesn't exist.
+            The time to be sent to GMM is scaled in units of milliseconds.
+
+*/
+
+GLOBAL void mm_mmgmm_t3212_val_ind (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_t3212_val_ind()");
+
+  {
+    /* T_MMGMM_T3212_VAL_IND */
+    PALLOC (mmgmm_t3212_val_ind, MMGMM_T3212_VAL_IND);
+
+    if (mm_data->t3212_cfg_counter NEQ 0 AND 
+        mm_data->mm.mm_info.t3212 NEQ 0)
+    {
+      mmgmm_t3212_val_ind->t3212_val = mm_data->t3212_cfg_counter * 10000;
+    }
+    else
+    {
+      mmgmm_t3212_val_ind->t3212_val = mm_data->mm.mm_info.t3212 * 360000;
+    }
+
+#ifdef WIN32
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  t3212_val=%d", mmgmm_t3212_val_ind->t3212_val);
+#endif /* WIN32 */
+
+    PSENDX (GMM, mmgmm_t3212_val_ind);
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_lup_accept_ind    |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_LUP_ACCEPT_IND.
+            For a GSM only protocol stack, this function doesn't exist.
+            It is assumed that the networks sends a location updating 
+            accept message for the location area of the current serving
+            cell here, this assumption should be true always.
+
+*/
+
+GLOBAL void mm_mmgmm_lup_accept_ind (void)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_lup_accept_ind()");
+
+  if ((mm_data->reg.full_service_indicated EQ FALSE) OR
+      (mm_data->reg.new_cell_ind EQ TRUE))
+  {
+    /* T_MMGMM_LUP_ACCEPT_IND */
+    PALLOC (mmgmm_lup_accept_ind, MMGMM_LUP_ACCEPT_IND);
+    mmgmm_lup_accept_ind->plmn.v_plmn = V_PLMN_PRES;
+    memcpy (mmgmm_lup_accept_ind->plmn.mcc, mm_data->mm.lai.mcc, SIZE_MCC);
+    memcpy (mmgmm_lup_accept_ind->plmn.mnc, mm_data->mm.lai.mnc, SIZE_MNC);
+    mmgmm_lup_accept_ind->lac = mm_data->mm.lai.lac;
+    mmgmm_lup_accept_ind->cid = mm_data->mm.cid;
+
+#ifdef WIN32
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  MCC=%x%x%x MNC=%x%x%x LAC=%04x",
+                  mmgmm_lup_accept_ind->plmn.mcc[0],
+                  mmgmm_lup_accept_ind->plmn.mcc[1],
+                  mmgmm_lup_accept_ind->plmn.mcc[2],
+                  mmgmm_lup_accept_ind->plmn.mnc[0],
+                  mmgmm_lup_accept_ind->plmn.mnc[1],
+                  mmgmm_lup_accept_ind->plmn.mnc[2],
+                  mmgmm_lup_accept_ind->lac);
+#endif /* #ifdef WIN32 */
+
+    PSENDX (GMM, mmgmm_lup_accept_ind);
+
+    mm_data->reg.full_service_indicated = TRUE;
+    mm_data->reg.new_cell_ind = FALSE;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_lup_needed_ind    |
++--------------------------------------------------------------------+
+
+  PURPOSE : If GPRS is enabled, send MMGMM_LUP_NEEDED_IND.
+            For a GSM only protocol stack, this function doesn't exist.
+            This function is used if GMM has to be informed about the
+            fact that a location updating procedure is needed by MM, 
+            eg. a CM SERVICE REJECT message with the cause "IMSI unknown
+            in VLR" has been received or simply T3212 has expired. 
+            A cell selection was not the cause for the need to update.
+            If the location updating is neccessary due to an incoming 
+            establish request by the CM entities in state 
+            MM_IDLE_ATTEMPT_TO_UPDATE, this is indicated by 
+            MMGMM_CM_ESTABLISH_IND and should cause a registration by GMM
+            as GMM should know that MM needs an update in this situation.
+ 
+*/
+
+GLOBAL void mm_mmgmm_lup_needed_ind (UBYTE reason)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_lup_needed_ind()");
+
+  if (!mm_lup_allowed_by_gmm ())
+  {
+    /* T_MMGMM_LUP_NEEDED_IND */
+    PALLOC (mmgmm_lup_needed_ind, MMGMM_LUP_NEEDED_IND);
+    mmgmm_lup_needed_ind->reason = reason;
+
+#ifdef WIN32
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  reason=%d", mmgmm_lup_needed_ind->reason);
+#endif /* WIN32 */
+
+    PSENDX (GMM, mmgmm_lup_needed_ind);
+  }
+  else
+  {
+    /* This is an internal MM error, harmless, but should be fixed if seen */
+    TRACE_ERROR ("MMGMM_LUP_NEEDED_IND suppressed");
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_tmsi_ind          |
++--------------------------------------------------------------------+
+
+  PURPOSE : Send MMGMM_TMSI_IND with the new TMSI
+            whenever the TMSI changes after SIM insertion.
+
+*/
+
+GLOBAL void mm_mmgmm_tmsi_ind (ULONG tmsi)
+{
+  GET_INSTANCE_DATA;
+  TRACE_FUNCTION ("mm_mmgmm_tmsi_ind()");
+
+  if (tmsi NEQ mm_data->reg.indicated_tmsi)
+  {
+    PALLOC (mmgmm_tmsi_ind, MMGMM_TMSI_IND);  /* T_MMGMM_TMSI_IND */
+    mmgmm_tmsi_ind->tmsi = tmsi;
+    PSENDX (GMM, mmgmm_tmsi_ind);
+
+    mm_data->reg.indicated_tmsi = tmsi;
+  }
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : MM_MM                      |
+| STATE   : code                ROUTINE : mm_mmgmm_ahplmn_ind        |
++--------------------------------------------------------------------+
+
+  PURPOSE : Send MMGMM_AHPLMN_IND with the new AHPLMN
+            at poweron if valid AHPLMN and whenever the
+            AHPLMN changes.            
+*/
+
+GLOBAL void mm_mmgmm_ahplmn_ind (T_plmn  *acting_hplmn)
+{
+
+  TRACE_FUNCTION ("mm_mmgmm_ahplmn_ind()");
+  {
+    PALLOC(mmgmm_ahplmn_ind, MMGMM_AHPLMN_IND);  /*T_MMGMM_AHPLMN_IND*/
+
+    mmgmm_ahplmn_ind->ahplmn.v_plmn = acting_hplmn->v_plmn;
+    memcpy(mmgmm_ahplmn_ind->ahplmn.mcc, acting_hplmn->mcc, SIZE_MCC);
+    memcpy(mmgmm_ahplmn_ind->ahplmn.mnc, acting_hplmn->mnc, SIZE_MNC);
+
+     
+
+#ifdef WIN32
+    vsi_o_ttrace (VSI_CALLER TC_FUNC, 
+                  "  MCC=%x%x%x MNC=%x%x%x v_plmn=%x",
+                  mmgmm_ahplmn_ind->ahplmn.mcc[0],
+                  mmgmm_ahplmn_ind->ahplmn.mcc[1],
+                  mmgmm_ahplmn_ind->ahplmn.mcc[2],
+                  mmgmm_ahplmn_ind->ahplmn.mnc[0],
+                  mmgmm_ahplmn_ind->ahplmn.mnc[1],
+                  mmgmm_ahplmn_ind->ahplmn.mnc[2],
+                  mmgmm_ahplmn_ind->ahplmn.v_plmn);
+                  
+#endif /* #ifdef WIN32 */
+
+    PSENDX(GMM, mmgmm_ahplmn_ind);
+  }   
+
+}
+
+#endif /* defined(GPRS) */
+#endif /* MM_GMM_C */