FreeCalypso > hg > fc-tourmaline
view src/g23m-gsm/mm/mm_mmp.c @ 303:f76436d19a7a default tip
!GPRS config: fix long-standing AT+COPS chance hanging bug
There has been a long-standing bug in FreeCalypso going back years:
sometimes in the AT command bring-up sequence of an ACI-only MS,
the AT+COPS command would produce only a power scan followed by
cessation of protocol stack activity (only L1 ADC traces), instead
of the expected network search sequence. This behaviour was seen
in different FC firmware versions going back to Citrine, and seemed
to follow some law of chance, not reliably repeatable.
This bug has been tracked down and found to be specific to !GPRS
configuration, stemming from our TCS2/TCS3 hybrid and reconstruction
of !GPRS support that was bitrotten in TCS3.2/LoCosto version.
ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3
version and had to be pulled from TCS2 - but as it turns out,
there is a new field in the MMR_REG_REQ primitive that needs to be
set correctly, and that psa_mms.c module is the place where this
initialization needed to be added.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 08 Jun 2023 08:23:37 +0000 |
parents | fa8dc04885d8 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : GSM-PS (8410) | Modul : MM_MMP +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : This Modul defines the functions for the mob. management | capability of the module Mobility Management. +----------------------------------------------------------------------------- */ #ifndef MM_MMP_C #define MM_MMP_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" #include "mm_em.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" #include "mm_em.h" #endif /*==== EXPORT =====================================================*/ /*==== PRIVAT =====================================================*/ /*==== TEST =====================================================*/ /*==== VARIABLES ==================================================*/ /*==== FUNCTIONS ==================================================*/ LOCAL void mm_rr_abort_cell_sel_fail (T_RR_ABORT_IND *rr_abort_ind); LOCAL void mm_mmcm_ss_sms_data_req (T_VOID_STRUCT *mm_data_req); LOCAL void mm_sim_insert_state (void); /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_est_rr_for_cm | +--------------------------------------------------------------------+ PURPOSE : Establish a RR connection for any CM entity. If this is possible, e.g. GPRS is not active/delivered or CM establishment is allowed by GPRS, the RR_ESTABLISH_REQ is sent and state MM_WAIT_FOR_RR_CONN_MM is entered. Otherwise GMM is informed about the CM connection request and the primitive is saved for later usage, but no state change is done. */ LOCAL void mm_est_rr_for_cm (UBYTE comp, UBYTE ti, USHORT estcs) { GET_INSTANCE_DATA; UBYTE service; TRACE_FUNCTION ("mm_est_rr_for_cm()"); #ifdef WIN32 TRACE_EVENT_P3 (" comp = %d, ti = %d, estcs = %x", comp, ti, estcs); #endif /* #ifdef WIN32 */ switch (comp) { case CC_COMP: if (estcs EQ MMCM_ESTCS_EMERGE) service = EMERGENCY_SERVICE; else service = CALL_SERVICE; break; case SS_COMP: estcs = ESTCS_MOB_ORIG_CAL_BY_SS_SMS; /* Override estcs */ service = SS_SERVICE; break; case SMS_COMP: estcs = ESTCS_MOB_ORIG_CAL_BY_SS_SMS; /* Override estcs */ service = SMS_SERVICE; break; default: TRACE_ERROR (UNEXPECTED_PARAMETER); return; } mm_data->act_retrans = INTERNAL_REDIAL; if (estcs EQ MMCM_ESTCS_EMERGE) { /* * Establish RR connection for emergency call */ #ifdef GPRS if (mm_cm_est_allowed()) { #endif mm_data->idle_substate = GET_STATE (STATE_MM); mm_rr_est_req (estcs, service, ti); SET_STATE (STATE_MM, MM_WAIT_FOR_RR_CONN_MM); #ifdef GPRS } else { mm_mmgmm_cm_emergency_ind (); mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, UNSPEC); } #endif } else { /* * Establish RR connection for normal call, SS or SMS */ #ifdef GPRS if (mm_cm_est_allowed()) { #endif mm_data->idle_substate = GET_STATE (STATE_MM); mm_rr_est_req (estcs, service, ti); SET_STATE (STATE_MM, MM_WAIT_FOR_RR_CONN_MM); #ifdef GPRS } else { mm_mmgmm_cm_establish_ind (); mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, UNSPEC); } #endif } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmxx_release_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitives MMCM_RELEASE_REQ, MMSS_RELEASE_REQ and MMSMS_RELEASE_REQ. */ LOCAL void mm_mmxx_release_req (UBYTE comp, UBYTE ti) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_mmxx_release_req()"); switch (GET_STATE (STATE_MM)) { case MM_LUP_INITIATED: case MM_IMSI_DETACH_INIT: case MM_WAIT_FOR_NW_CMD: case MM_LUP_REJECTED: case MM_WAIT_FOR_RR_CONN_LUP: case MM_WAIT_FOR_RR_CONN_DETACH: /* * RR connection requested/established. Only delete the request from CM, * but do not inform GMM now until connection released. */ mm_delete_entry (comp, ti); break; case MM_WAIT_FOR_RR_ACTIVE: case MM_IDLE_NORMAL_SERVICE: /* 19.1 */ case MM_IDLE_ATTEMPT_TO_UPDATE: /* 19.2 */ case MM_IDLE_LIMITED_SERVICE: /* 19.3 */ case MM_IDLE_NO_IMSI: /* 19.4 */ case MM_IDLE_NO_CELL_AVAILABLE: /* 19.5 */ case MM_IDLE_PLMN_SEARCH: /* 19.7 */ case MM_PLMN_SEARCH_NORMAL_SERVICE: /* 19.8 */ #ifdef GPRS case MM_IDLE_LUP_NEEDED: /* 19.6 */ case MM_LOCATION_UPDATING_PENDING: case MM_IMSI_DETACH_PENDING: #endif /* GPRS */ mm_delete_entry (comp, ti); mm_mmgmm_cm_release_ind (MMGMM_RESUMPTION_OK); break; case MM_WAIT_FOR_OUTG_MM_CONN: if ((mm_data->pend_conn.comp EQ comp) AND (mm_data->pend_conn.ti EQ ti)) { MCAST (cm_serv_abort, U_CM_SERV_ABORT); CM_SET_STATE (comp, mm_data->pend_conn.ti, CM_IDLE); cm_serv_abort->msg_type = U_CM_SERV_ABORT; for_data_req (BSIZE_U_CM_SERV_ABORT); EM_SERVICE_ABORTED; TIMERSTOP (T3230); #if defined (FF_EOTD) AND defined (REL99) /* * check the flag rrlp_lcs_started value. True if rrlp is running, False * if no rrlp is runnig. */ if(mm_data->rrlp_lcs_started EQ TRUE) { /* * Enter state MM_RR_CONN_RELEASE_NOT_ALLOWED only if the last * active MM connection has been released by the CM layer * and there is rrlp service on going. */ TIMERSTART (T3241, T_3241_VALUE); SET_STATE (STATE_MM, MM_RR_CONN_RELEASE_NOT_ALLOWED); } else #endif /* (FF_EOTD) AND defined (REL99) */ { TIMERSTART (T3240, T_3240_VALUE); mm_data->wait_for_accept = FALSE; SET_STATE (STATE_MM, MM_WAIT_FOR_NW_CMD); } } else { mm_delete_entry (comp, ti); } break; case MM_CONN_ACTIVE: switch (CM_GET_STATE (comp, ti)) { case CM_STORE: mm_delete_entry (comp, ti); break; case CM_PENDING: mm_data->wait_for_accept = FALSE; CM_SET_STATE (comp, ti, CM_IDLE); break; case CM_ACTIVE: CM_SET_STATE (comp, ti, CM_IDLE); if ((mm_count_connections (CM_ACTIVE) EQ 0) AND !TIMERACTIVE (T3230)) { #if defined (FF_EOTD) AND defined (REL99) /*check the flag rrlp_lcs_started value. True if rrlp is running, False if no rrlp is runnig.*/ if(mm_data->rrlp_lcs_started EQ TRUE) { /* * Enter state MM_RR_CONN_RELEASE_NOT_ALLOWED only if the last * active MM connection has been released by the CM layer * and there is rrlp service on going. */ TIMERSTART (T3241, T_3241_VALUE); SET_STATE (STATE_MM, MM_RR_CONN_RELEASE_NOT_ALLOWED); } else #endif /* (FF_EOTD) AND defined (REL99) */ { /* * Enter state MM_WAIT_FOR_NW_CMD only if the last * active MM connection has been released by the CM layer * and there is no pending connection. Otherwise keep state. */ TIMERSTART (T3240, T_3240_VALUE); SET_STATE (STATE_MM, MM_WAIT_FOR_NW_CMD); } } break; default: break; } break; case MM_PROCESS_PROMPT: switch (CM_GET_STATE (comp, ti)) { case CM_STORE: mm_delete_entry (comp, ti); break; case CM_PENDING: /* * In state MM_PROCESS_PROMPT there are never pending connections, * so these need not be handled here */ TRACE_ERROR ("CM_PENDING?"); break; case CM_ACTIVE: CM_SET_STATE (comp, ti, CM_IDLE); if (mm_count_connections (CM_ACTIVE) EQ 0) { /* * Last active connection released, but * PROMPT remains present. Only START T3240 */ TIMERSTART (T3240, T_3240_VALUE); } break; default: break; } break; case MM_WAIT_FOR_RR_CONN_MM: if (mm_data->pend_conn.comp EQ comp AND mm_data->pend_conn.ti EQ ti) { CM_SET_STATE (comp, mm_data->pend_conn.ti, CM_IDLE); mm_abort_connection (ABCS_NORM); TIMERSTOP (T3230); /* After RR_ABORT_REQ here, RR_RELEASE_IND is guaranteed by RR */ } else { mm_delete_entry (comp, ti); } break; case MM_WAIT_FOR_REESTABLISH: switch (CM_GET_STATE (comp, ti)) { case CM_IDLE: case CM_PENDING: break; case CM_STORE: mm_delete_entry (comp, ti); break; case CM_ACTIVE: /* CC will not start call reestablishment, * then clear connection status */ CM_SET_STATE (comp, ti, CM_IDLE); /* this was the last answer from MM */ if (mm_count_connections (CM_ACTIVE) EQ 0) { /* there was no connection requesting call reestablishment */ if ( mm_count_connections (CM_REEST_PENDING) EQ 0) { /* Find IDLE state after MM connection */ mm_release_rr_connection (MMGMM_RESUMPTION_FAILURE); } else { /* * RR has already signalled a cell which is * suitable for call reestablishment * This could be explained to me. Why is in the release * routine reestablishment performed. I never understood * the problem which was solved here. Implementation problem? ... */ if (mm_data->reest_cell_avail) mm_reest (mm_data->reest_ti); } } break; } break; default: break; } } /*==== VARIABLES ==================================================*/ GLOBAL UBYTE _decodedMsg [MAX_MSTRUCT_LEN_MM]; /*==== FUNCTIONS ==================================================*/ /* * ------------------------------------------------------------------- * PRIMITIVE Processing functions * ------------------------------------------------------------------- */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_init_mm_data | +--------------------------------------------------------------------+ PURPOSE : Initialize the MM data for the module mob. management. */ GLOBAL void mm_init_mm_data (void) { GET_INSTANCE_DATA; USHORT i; TRACE_FUNCTION ("mm_init_mm_data()"); #if defined (NEW_FRAME) for (i = 0; i < NUM_OF_MM_TIMERS; i++) mm_data->t_running[i] = FALSE; #else for (i = 0; i < NUM_OF_MM_TIMERS; i++) mm_data->t_handle[i] = VSI_ERROR; #endif mm_init (); reg_clear_plmn_list (mm_data->reg.eqv_plmns.eqv_plmn_list, EPLMNLIST_SIZE); mm_data->state[STATE_MM] = MM_NULL; #ifdef GPRS mm_data->state[STATE_REG_TYPE] = REG_GPRS_INACTIVE; mm_data->state[STATE_GPRS_CM_EST] = CM_GPRS_EST_OK; #endif /* GPRS */ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mdl_error_ind | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MDL_ERROR_IND. */ GLOBAL void mm_mdl_error_ind (T_MDL_ERROR_IND *mdl_error_ind) { TRACE_FUNCTION ("mm_mdl_error_ind()"); #if 0 /* * No MDL_RELEASE_REQ is needed in DL for fatal reasons, * as DL already automatically releases the DL connection if such * a fatal reason occurs. The opposite is true: This function * will disturb DL operation if it sends a MDL_RELEASE_REQ * after receiving MDL_ERROR_IND with cause CS_T200_EXP in case * of a switch back to the old channel on handover failure. * * The communication path between DL and MM may have been a * general misdecision in design, this has still to be discussed. */ switch (GET_STATE (STATE_MM)) { case MM_NULL: case MM_IDLE_NO_CELL_AVAILABLE: /* * no DL is active */ break; default: /* * Handling depending on the error cause */ switch (mdl_error_ind->cs) { case CS_T200_EXP: case CS_UNSOL_DM_RESP: case CS_UNSOL_DM_RESP_MULT_FRM: case CS_NR_SEQ_ERR: switch (mdl_error_ind->sapi) { case SAPI_0: mm_mdl_rel_req (); break; case SAPI_3: mm_mdl_rel_req_sapi_3 (); break; } break; } break; } #endif PFREE (mdl_error_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmcm_data_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMCM_DATA_REQ. */ GLOBAL void mm_mmcm_data_req (T_MMCM_DATA_REQ *mmcm_data_req) { TRACE_FUNCTION ("mm_mmcm_data_req()"); mm_mmcm_ss_sms_data_req ( (T_VOID_STRUCT*)mmcm_data_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmxx_establish_req | +--------------------------------------------------------------------+ PURPOSE : Process MMCM_ESTABLISH_REQ, MMSS_ESTABLISH_REQ and MMSMS_ESTABLISH_REQ finally. This is a generic function which handles the establishment for all CM entities. */ GLOBAL void mm_mmxx_establish_req (UBYTE comp, UBYTE ti, USHORT estcs, U8 info) { GET_INSTANCE_DATA; UBYTE service; restart_function: TRACE_FUNCTION ("mm_mmxx_establish_req()"); switch (comp) { case CC_COMP: if (estcs EQ MMCM_ESTCS_EMERGE) service = EMERGENCY_SERVICE; else service = CALL_SERVICE; break; case SS_COMP: service = SS_SERVICE; break; case SMS_COMP: service = SMS_SERVICE; break; default: TRACE_ERROR (UNEXPECTED_DEFAULT); /* Cannot happen */ return; /* No action which makes sense possible here */ } #ifdef GPRS if ((mm_data->gprs.mobile_class EQ MMGMM_CLASS_CG) OR (mm_data->gprs.sim_physically_removed AND (service NEQ EMERGENCY_SERVICE))) { /* * 1.) No CS services with a PS only mobile, * for MMGMM_CLASS_BG MM has to ask * 2.) SIM removal, GMM detaching and call request requiring SIM * => release the call */ mm_mmxx_release_ind (comp, ti, MMCS_NO_REGISTRATION); return; } #endif /* #ifdef GPRS */ switch (GET_STATE (STATE_MM)) { case MM_NULL: case MM_IDLE_NO_CELL_AVAILABLE: /* * without coverage no calls ! */ mm_mmxx_release_ind (comp, ti, MMCS_NO_REGISTRATION); break; case MM_LUP_INITIATED: case MM_WAIT_FOR_OUTG_MM_CONN: case MM_PROCESS_PROMPT: case MM_WAIT_FOR_NW_CMD: case MM_LUP_REJECTED: case MM_WAIT_FOR_RR_CONN_LUP: case MM_WAIT_FOR_RR_CONN_MM: case MM_WAIT_FOR_REESTABLISH: case MM_WAIT_FOR_RR_ACTIVE: #ifdef GPRS case MM_LOCATION_UPDATING_PENDING: #endif /* GPRS */ mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, UNSPEC); break; #ifdef REL99 case MM_RR_CONN_RELEASE_NOT_ALLOWED: /*Upon reception of CM establishment request, MM will stop the timer 3241 & *shall send mm_rr_data_request. Upon reception of cm service accept from *network MM enter in MM_CONN_ACTIVE state. */ TIMERSTOP (T3241); mm_rr_data_req (estcs, service, ti); TIMERSTART (T3230, T_3230_VALUE); SET_STATE (STATE_MM, MM_WAIT_FOR_OUTG_MM_CONN); break; #endif case MM_CONN_ACTIVE: if (mm_data->wait_for_accept) { mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, UNSPEC); } else { /* * There is a rare, unhandled case: * MM_CONN_ACTIVE and the service state is not full service, * we have an ongoing emergency call. In this case MM should * reject the establish request, but this is not critical here. */ mm_rr_data_req (estcs, service, ti); TIMERSTART (T3230, T_3230_VALUE); } break; case MM_IMSI_DETACH_INIT: case MM_WAIT_FOR_RR_CONN_DETACH: #ifdef GPRS case MM_IMSI_DETACH_PENDING: #endif /* GPRS */ if (mm_data->nreg_cause EQ CS_SIM_REM AND estcs EQ MMCM_ESTCS_EMERGE) { mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, UNSPEC); } else { mm_mmxx_release_ind (comp, ti, MMCS_NO_REGISTRATION); } break; case MM_IDLE_NORMAL_SERVICE: mm_est_rr_for_cm (comp, ti, estcs); break; #ifdef GPRS case MM_IDLE_LUP_NEEDED: /* * Inform GMM about the wish to establish a RR connection * for CM. Either GMM will accept this and bring MM into * IDLE updated state or GMM will refuse this. * The final decision is left to GMM here. */ if (estcs EQ MMCM_ESTCS_EMERGE) { /* * Emergency call */ mm_mmxx_rel_ind (MMCS_INT_PREEM, CM_NOT_IDLE); mm_est_rr_for_cm (comp, ti, estcs); } else { /* * Normal call */ if (mm_cm_est_allowed()) { mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, CM_LUP_TRIGGER); if (info EQ UNSPEC) { SET_STATE (STATE_REG_TYPE, REG_REMOTE_CONTROLLED); mm_normal_loc_upd (); } } else { mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, UNSPEC); mm_mmgmm_cm_establish_ind (); } } break; #endif /* GPRS */ case MM_IDLE_ATTEMPT_TO_UPDATE: if (info NEQ CM_LUP_TRIGGER) mm_data->attempt_cnt = 0; if (estcs EQ MMCM_ESTCS_EMERGE) { /* * Emergency call */ mm_mmxx_rel_ind (MMCS_INT_PREEM, CM_NOT_IDLE); mm_est_rr_for_cm (comp, ti, estcs); } else { /* * 'info' is used to check to see where this function was called. * If this function was called from 'mm_mmcm_establish_req()' then * this is the first pass for this function and 'mm_normal_loc_upd()' * must be called according to the Recs. * If the function was called from 'mm_use_entry()', then it means * an existing CM request is stored in the MM local stack and the current * MM procedure is running for that entry. Subsequent calls of 'mm_use_entry()' * must be ignored i.e. mm_normal_loc_upd()' must *not* be called. */ /* * Normal call */ if (mm_cm_est_allowed()) { mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, CM_LUP_TRIGGER); if (info EQ UNSPEC) { #ifdef GPRS if (!mm_lup_allowed_by_gmm()) { SET_STATE (STATE_REG_TYPE, REG_REMOTE_CONTROLLED); } #endif mm_normal_loc_upd (); } } else { mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, UNSPEC); mm_mmgmm_cm_establish_ind (); } } break; case MM_IDLE_LIMITED_SERVICE: case MM_IDLE_NO_IMSI: if (estcs EQ MMCM_ESTCS_EMERGE) { mm_est_rr_for_cm (comp, ti, estcs); } else { mm_mmxx_release_ind (comp, ti, MMCS_NO_REGISTRATION); } break; case MM_IDLE_PLMN_SEARCH: mm_write_entry (comp, ti, estcs, EVENT_ENTRY, NULL, UNSPEC); if (estcs EQ MMCM_ESTCS_EMERGE) { mm_mmgmm_plmn_ind (MMCS_PLMN_NOT_IDLE_MODE, NULL); mm_rr_act_req (); SET_STATE (STATE_MM, MM_WAIT_FOR_RR_ACTIVE); } break; case MM_PLMN_SEARCH_NORMAL_SERVICE: /* Indicate stop of search to the MMI */ mm_mmgmm_plmn_ind (MMCS_PLMN_NOT_IDLE_MODE, NULL); /* Back to IDLE state before network search was started, * as establishment will stop network search in RR */ SET_STATE (STATE_MM, mm_data->idle_substate); /* Repeat the establish attempt in new MM state */ /* -- mm_mmxx_establish_req (comp, ti, estcs,info); -- */ /* -- return; -- */ /* avoid recursion, stack usage, therefore the goto. */ goto restart_function; /*lint !e801 goto*/ default: TRACE_ERROR (UNEXPECTED_DEFAULT); /* All states caught */ break; } } /* mm_mmxx_establish_req() */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmcm_establish_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMCM_ESTABLISH_REQ. */ GLOBAL void mm_mmcm_establish_req (T_MMCM_ESTABLISH_REQ *mmcm_establish_req) { TRACE_FUNCTION ("mm_mmcm_establish_req()"); /* * And from this point MM is not interested in prio anymore. * To distinguish emergency calls from normal calls estcs is used. */ switch (mmcm_establish_req->org_entity) { case MMCM_ORG_ENTITY_CC: mm_mmxx_establish_req (CC_COMP, mmcm_establish_req->ti, mmcm_establish_req->estcs, UNSPEC); break; case MMCM_ORG_ENTITY_SS: mm_mmxx_establish_req (SS_COMP, mmcm_establish_req->ti, 0,UNSPEC); break; case MMCM_ORG_ENTITY_SMS: mm_mmxx_establish_req (SMS_COMP, mmcm_establish_req->ti, 0,UNSPEC); break; default: TRACE_ERROR ("org_entity trashed"); break; } PFREE (mmcm_establish_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mmcm_reestablish_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMCM_REESTABLISH_REQ. */ GLOBAL void mm_mmcm_reestablish_req (T_MMCM_REESTABLISH_REQ *mmcm_reestablish_req) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_mmcm_reestablish_req()"); switch (GET_STATE (STATE_MM)) { case MM_WAIT_FOR_REESTABLISH: /* set re-establishment transaction identifier if not already set */ if (mm_data->reest_ti EQ NOT_PRESENT_8BIT) mm_data->reest_ti = mmcm_reestablish_req->ti; /* set connection type to reestablishment pending */ CM_SET_STATE (CC_COMP, mmcm_reestablish_req->ti, CM_REEST_PENDING); /* all CM connection have answered and * RR has signalled a suitable cell for call reestablishment */ if (mm_count_connections (CM_ACTIVE) EQ 0 AND mm_data->reest_cell_avail) mm_reest (mm_data->reest_ti); break; default: break; } PFREE (mmcm_reestablish_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmcm_release_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMCM_RELEASE_REQ. */ GLOBAL void mm_mmcm_release_req (T_MMCM_RELEASE_REQ *mmcm_release_req) { TRACE_FUNCTION ("mm_mmcm_release_req()"); mm_mmxx_release_req (CC_COMP, mmcm_release_req->ti); PFREE (mmcm_release_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmss_data_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMSS_DATA_REQ. */ GLOBAL void mm_mmss_data_req (T_MMSS_DATA_REQ *mmss_data_req) { TRACE_FUNCTION ("mm_mmss_data_req()"); mm_mmcm_ss_sms_data_req ( (T_VOID_STRUCT*)mmss_data_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmss_establish_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMSS_ESTABLISH_REQ. */ GLOBAL void mm_mmss_establish_req (T_MMSS_ESTABLISH_REQ *mmss_establish_req) { TRACE_FUNCTION ("mm_mmss_establish_req()"); mm_mmxx_establish_req (SS_COMP, mmss_establish_req->ti, 0, UNSPEC); PFREE (mmss_establish_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmss_release_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMSS_RELEASE_REQ. */ GLOBAL void mm_mmss_release_req (T_MMSS_RELEASE_REQ *mmss_release_req) { TRACE_FUNCTION ("mm_mmss_release_req()"); mm_mmxx_release_req (SS_COMP, mmss_release_req->ti); PFREE (mmss_release_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmsms_data_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMSMS_DATA_REQ. */ GLOBAL void mm_mmsms_data_req (T_MMSMS_DATA_REQ *mmsms_data_req) { TRACE_FUNCTION ("mm_mmsms_data_req()"); mm_mmcm_ss_sms_data_req ( (T_VOID_STRUCT*)mmsms_data_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmsms_establish_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMSMS_ESTABLISH_REQ. */ GLOBAL void mm_mmsms_establish_req (T_MMSMS_ESTABLISH_REQ *mmsms_establish_req) { TRACE_FUNCTION ("mm_mmsms_establish_req()"); mm_mmxx_establish_req (SMS_COMP, mmsms_establish_req->ti, 0, UNSPEC); PFREE (mmsms_establish_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmsms_release_req | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMSMS_RELEASE_REQ. */ GLOBAL void mm_mmsms_release_req (T_MMSMS_RELEASE_REQ *mmsms_release_req) { TRACE_FUNCTION ("mm_mmsms_release_req()"); mm_mmxx_release_req (SMS_COMP, mmsms_release_req->ti); PFREE (mmsms_release_req); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_abort_ind | +--------------------------------------------------------------------+ PURPOSE : Process the primitive RR_ABORT_IND. */ GLOBAL void mm_rr_abort_ind (T_RR_ABORT_IND *rr_abort_ind) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_rr_abort_ind()"); mm_data->t3213_restart = MAX_REST_T3213; /* * If MM is reading sim and waiting for the SIM_READ_CNF for the EF PLMNsel * /EF EFPLMNwAcT/EFOPLMNwAcT which are used to prepare pref_plmn list. * rr_abort_ind will be stored if plmn_avail is indicated and will be used * once sim_read_cnf is received. */ if (mm_data->reg.sim_read_in_progress AND rr_abort_ind->plmn_avail >0) { mm_write_entry(NO_ENTRY,NO_ENTRY,NO_ENTRY,PRIMITIVE_ENTRY,rr_abort_ind, UNSPEC); return; } #ifdef WIN32 /* Check for correct cause value */ switch (rr_abort_ind->cause) { case RRCS_ABORT_CEL_SEL_FAIL: case RRCS_ABORT_RAD_LNK_FAIL: case RRCS_DATA_LINK_FAIL: case RRCS_ABORT_PTM: break; default: TRACE_ERROR("Unexpected cause value"); assert (0); /* Stop the simulation */ break; } #endif /* #ifdef WIN32 */ EM_RESULT_PLMN_LIST; TRACE_EVENT_P1 ("SERVICE = %d", rr_abort_ind->op.service); /* This switch statement is used to catch the case where the RR_ABORT_IND sent in state */ /* MM_LUP_INITIATED triggers a second RR_ABORT_IND received in state MM_IDLE_NORMAL_SERVICE */ /* caused by a TABORT timeout. The second RR_ABORT_IND (containing zero plmns) is subsequently */ /* ignored. This situation occurs when running TC 26.7.4.3.4 */ switch(GET_STATE (STATE_MM)) { case MM_LUP_INITIATED: mm_data->rr_abort_prior_to_tabort = TRUE; break; case MM_IDLE_NORMAL_SERVICE: break; default: mm_data->rr_abort_prior_to_tabort = FALSE; break; } if (rr_abort_ind->op.service EQ LIMITED_SERVICE) mm_data->rf_power = rr_abort_ind->power; switch (GET_STATE (STATE_MM)) { case MM_NULL: break; case MM_LUP_INITIATED: TIMERSTOP (T3210); mm_mdl_rel_req (); mm_lup_restart (); break; case MM_WAIT_FOR_OUTG_MM_CONN: case MM_CONN_ACTIVE: case MM_PROCESS_PROMPT: case MM_WAIT_FOR_NW_CMD: #ifdef REL99 case MM_RR_CONN_RELEASE_NOT_ALLOWED: #endif mm_mdl_rel_req (); TIMERSTOP (T3230); TIMERSTOP (T3240); #ifdef REL99 TIMERSTOP (T3241); #endif mm_mmxx_rel_ind (rr_abort_ind->cause, CM_PENDING); if (mm_mmxx_err_ind (rr_abort_ind->cause) NEQ 0) { /* * Active connections exist (CM_ACTIVE), remember that * CC has not yet signalled a valid ti for call re-establishment and * RR has not yet indicated a cell which is able to process call * re-establishment. Enter MM state MM_WAIT_FOR_REESTABLISH. */ mm_data->reest_ti = NOT_PRESENT_8BIT; mm_data->reest_cell_avail = FALSE; SET_STATE (STATE_MM, MM_WAIT_FOR_REESTABLISH); } else { /* No active CM connection. Find IDLE state after MM connection. */ mm_release_rr_connection (MMGMM_RESUMPTION_FAILURE); } break; case MM_IMSI_DETACH_INIT: case MM_WAIT_FOR_RR_CONN_DETACH: mm_mdl_rel_req (); mm_mmgmm_cm_release_ind (MMGMM_RESUMPTION_FAILURE); mm_end_of_detach (); break; case MM_LUP_REJECTED: mm_mdl_rel_req (); TIMERSTOP (T3240); mm_loc_upd_rej (); break; case MM_WAIT_FOR_RR_CONN_LUP: if (rr_abort_ind->op.func EQ FUNC_NET_SRCH_BY_MMI) { /* * A running parallel search has been interrupted by a * location updating procedure. The sequence is * RR_ACTIVATE_REQ (MMI SEARCH) / RR_ACTIVATE_IND (new LA) * RR_ESTABLISH_REQ (LUP request) / RR_ABORT_IND (MMI SEARCH) * In this case we abort the pending search to the upper layers * and continue with our location updating procedure. */ mm_mmgmm_plmn_ind (MMCS_PLMN_NOT_IDLE_MODE, NULL); } else { /* * The RR_ABORT_IND is not indicating the end of a search for * available networks. */ TIMERSTOP (T3210); mm_mdl_rel_req (); if (rr_abort_ind->cause EQ RRCS_ABORT_CEL_SEL_FAIL) { TIMERSTOP (T3211); TIMERSTOP (T3213); mm_data->t3213_restart = 0; mm_mmxx_rel_ind (rr_abort_ind->cause, CM_NOT_IDLE); mm_mmgmm_cm_release_ind (MMGMM_RESUMPTION_FAILURE); switch (rr_abort_ind->op.service) { case NO_SERVICE: SET_STATE (STATE_MM, MM_IDLE_NO_CELL_AVAILABLE); break; case LIMITED_SERVICE: SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); break; default: /* eg. FULL_SERVICE and reg_rr_failure => nonsense */ TRACE_ERROR (UNEXPECTED_DEFAULT); break; } reg_rr_failure (rr_abort_ind); } else { mm_lup_restart (); } } break; case MM_WAIT_FOR_RR_CONN_MM: if (rr_abort_ind->op.func EQ FUNC_NET_SRCH_BY_MMI) { /* * Handle MMXXX_NET_REQ followed by MMGXXX_PLMN_RES during network * running search. MMXXX_NET_REQ is leading to establishment for MM's * location updating, this aborts the network search in RR. * Don't send probably partial or empty list to the MMI and avoid * MMXXX_NREG_IND in this situation, as this could be interpreted * by GMM as end of the procedure (which it is not). * Instead, send simply MMXXX_PLMN_IND (MMCS_PLMN_NOT_IDLE_MODE). */ mm_mmgmm_plmn_ind (MMCS_PLMN_NOT_IDLE_MODE, NULL); } else { mm_mdl_rel_req (); if (rr_abort_ind->cause EQ RRCS_ABORT_CEL_SEL_FAIL) { TIMERSTOP (T3211); TIMERSTOP (T3213); mm_data->t3213_restart = 0; if (rr_abort_ind->op.service EQ NO_SERVICE) { mm_mmxx_rel_ind (rr_abort_ind->cause, CM_NOT_IDLE); mm_mmgmm_cm_release_ind (MMGMM_RESUMPTION_FAILURE); SET_STATE (STATE_MM, MM_IDLE_NO_CELL_AVAILABLE); reg_rr_failure (rr_abort_ind); } else { if (mm_data->pend_conn.cause EQ MMCM_ESTCS_EMERGE) { /* * Clash RR_ESTABLISH_REQ (emergency call) / * RR_ABORT_IND (limited service). * RR dropped the RR_ESTABLISH_REQ. * Repeat the emergency call attempt. */ mm_rr_est_req (mm_data->pend_conn.cause, mm_data->pend_conn.service, mm_data->pend_conn.ti); /* Remain in state MM_WAIT_FOR_RR_CONN_MM */ } else { mm_mmxx_rel_ind (rr_abort_ind->cause, CM_NOT_IDLE); mm_mmgmm_cm_release_ind (MMGMM_RESUMPTION_FAILURE); SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); reg_rr_failure (rr_abort_ind); } } } else { /* * Is data link failure possible here? Release pending connection. */ mm_mmxx_rel_ind (rr_abort_ind->cause, CM_PENDING); mm_release_rr_connection (MMGMM_RESUMPTION_FAILURE); } } break; case MM_WAIT_FOR_REESTABLISH: case MM_IDLE_ATTEMPT_TO_UPDATE: case MM_IDLE_LIMITED_SERVICE: mm_mdl_rel_req (); mm_rr_abort_cell_sel_fail( rr_abort_ind); break; case MM_IDLE_NO_IMSI: /* * During limited service without SIM card * the no service condition is signalled by RR. */ mm_mdl_rel_req (); if (rr_abort_ind->cause EQ RRCS_ABORT_CEL_SEL_FAIL AND rr_abort_ind->op.service EQ NO_SERVICE) { TIMERSTOP (T3211); TIMERSTOP (T3213); mm_data->t3213_restart = 0; mm_mmxx_rel_ind (rr_abort_ind->cause, CM_NOT_IDLE); mm_mmgmm_cm_release_ind (MMGMM_RESUMPTION_FAILURE); SET_STATE (STATE_MM, MM_IDLE_NO_CELL_AVAILABLE); reg_rr_failure (rr_abort_ind); } break; case MM_IDLE_NORMAL_SERVICE: TIMERSTOP (T3213); mm_data->t3213_restart = 0; /*Check to see if this RR_ABORT_IND is caused by a RR TABORT timeout...*/ if((mm_data->rr_abort_prior_to_tabort EQ TRUE) && (rr_abort_ind->plmn_avail EQ 0)) { mm_data->rr_abort_prior_to_tabort = FALSE; PFREE (rr_abort_ind); return; } /*lint -fallthrough */ #ifdef GPRS case MM_IDLE_LUP_NEEDED: #endif /* GPRS */ mm_mdl_rel_req (); mm_rr_abort_cell_sel_fail( rr_abort_ind); break; case MM_IDLE_NO_CELL_AVAILABLE: if (rr_abort_ind->op.service NEQ NO_SERVICE) { mm_data->reg.bcch_encode = FALSE; SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); reg_rr_failure (rr_abort_ind); } break; case MM_WAIT_FOR_RR_ACTIVE: if (mm_data->reg.op.func EQ rr_abort_ind->op.func) { /* * answer to the request of MM */ mm_mdl_rel_req (); mm_data->reg.bcch_encode = FALSE; if (rr_abort_ind->op.service EQ NO_SERVICE) { SET_STATE (STATE_MM, MM_IDLE_NO_CELL_AVAILABLE); } else { SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); } reg_rr_failure (rr_abort_ind); USE_STORED_ENTRIES(); } #ifndef NTRACE else { /* This RR_ABORT_IND is to be ignored here, trace the func */ switch (rr_abort_ind->op.func) { case FUNC_LIM_SERV_ST_SRCH: TRACE_EVENT ("RR_ABORT_IND (FUNC_LIM_SERV_ST_SRCH)"); break; case FUNC_PLMN_SRCH: TRACE_EVENT ("RR_ABORT_IND (FUNC_PLMN_SRCH)"); break; case FUNC_NET_SRCH_BY_MMI: TRACE_EVENT ("RR_ABORT_IND (FUNC_NET_SRCH_BY_MMI)"); break; default: TRACE_ERROR (UNEXPECTED_PARAMETER); break; } } #endif /* of #ifndef NTRACE */ break; case MM_IDLE_PLMN_SEARCH: /* Find new MM IDLE state, not searching */ switch (rr_abort_ind->op.service) { case NO_SERVICE: SET_STATE (STATE_MM, MM_IDLE_NO_CELL_AVAILABLE); break; case LIMITED_SERVICE: mm_sim_insert_state(); break; case FULL_SERVICE: /* MM has to wait with full service in MM state machine * until it is known which cell was selected by RR. */ mm_sim_insert_state(); break; default: TRACE_ERROR (UNEXPECTED_DEFAULT); /* Something has been garbled */ break; } /* Build and send the list */ reg_net_list (rr_abort_ind); /* State change has occurred => use stored primitives */ USE_STORED_ENTRIES(); break; case MM_PLMN_SEARCH_NORMAL_SERVICE: /* This state implies that a SIM is present */ /* Find new MM IDLE state, not searching */ switch (rr_abort_ind->op.service) { case NO_SERVICE: SET_STATE (STATE_MM, MM_IDLE_NO_CELL_AVAILABLE); reg_net_list (rr_abort_ind); /* Build and send the list */ USE_STORED_ENTRIES(); break; case LIMITED_SERVICE: SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); reg_net_list (rr_abort_ind); /* Build and send the list */ USE_STORED_ENTRIES(); break; case FULL_SERVICE: /* * Back to old full service IDLE state, maybe either * MM_IDLE_NORMAL_SERVICE, MM_IDLE_ATTEMPT_TO_UPDATE, * or MM_IDLE_LUP_NEEDED. */ SET_STATE(STATE_MM,mm_data->idle_substate); if (rr_abort_ind->cause EQ RRCS_ABORT_PTM) { if(mm_data->net_search_count < 2) { /* Since GPRS is in PTM there seems to be no need to inform * ACI of the Network list * Also,MM should start with 10 secs timer and on the expiry of * this timer should initiate the plmn scan search again */ TIMERSTART(T_HPLMN,10000); mm_data->net_search_count++; } else { /* The user initiated network search should be repeated only twice * and empty PLMN list should be returned. But if the search was * other than user initiated network scan allow repetions till PLMN * search is a success. This should be tried every 2 mins. */ if ( mm_data->plmn_scan_mmi ) reg_net_list (rr_abort_ind); else TIMERSTART(T_HPLMN,120000); } } else { mm_data->net_search_count = 0;/*Network Scan successful,reset couter*/ reg_net_list (rr_abort_ind); /* Build and send the list */ } if (GET_STATE (STATE_MM) NEQ MM_WAIT_FOR_RR_ACTIVE) { /* * reg_net_list () didn't select a different PLMN. * Check whether MM needs a location update procedure. */ if (mm_data->t3212_timeout AND mm_data->loc_upd_type.lut EQ NOT_RUNNING) { /* * T3212 expired during MM_PLMN_SEARCH_NORMAL_SERVICE. * Repeat the timeout event now as we are back to IDLE. */ mm_data->t3212_timeout = FALSE; tim_t3212 (); } else { /* * Check whether T3211 and T3213 are inactive, if so, * continue an already running update now (if any). */ if (!TIMERACTIVE (T3211) AND !TIMERACTIVE (T3213)) { mm_continue_running_update (); } } } break; default: TRACE_ERROR (UNEXPECTED_DEFAULT); /* Something has been garbled */ break; } break; #ifdef GPRS case MM_LOCATION_UPDATING_PENDING: case MM_IMSI_DETACH_PENDING: /* * This state transitions here should be discussed with ANS, * maybe MM is doing the wrong thing here. */ if (rr_abort_ind->op.func NEQ FUNC_NET_SRCH_BY_MMI) { mm_mdl_rel_req (); /* Throw out all pending connections */ mm_mmxx_rel_ind (rr_abort_ind->cause, CM_NOT_IDLE); mm_mmgmm_cm_release_ind (MMGMM_RESUMPTION_FAILURE); TRACE_EVENT ("State transition may be subject of discussion"); /* Enter the appropriate IDLE state for the offered service */ if (rr_abort_ind->op.service EQ NO_SERVICE) { SET_STATE (STATE_MM, MM_IDLE_NO_CELL_AVAILABLE); } else { mm_sim_insert_state(); } reg_rr_failure (rr_abort_ind); } break; #endif /* GPRS */ default: /* All states caught by case statements, this is impossible */ TRACE_ERROR (UNEXPECTED_DEFAULT); break; } PFREE (rr_abort_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_limited_from_rr | +--------------------------------------------------------------------+ PURPOSE : This function takes the appropriate actions if a limited service cell is offered by RR. */ LOCAL void mm_limited_from_rr (T_RR_ACTIVATE_CNF *rr_activate_cnf) { TRACE_FUNCTION ("mm_limited_from_rr()"); mm_copy_rr_act_cnf_data (rr_activate_cnf); reg_mm_success (LIMITED_SERVICE); /* Inform GPRS about selected cell */ mm_mmgmm_activate_ind (MMGMM_LIMITED_SERVICE); mm_sim_insert_state(); } /* +----------------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_activate_cnf | +----------------------------------------------------------------------------+ PURPOSE : Process the primitive RR_ACTIVATE_CNF. */ GLOBAL void mm_rr_activate_cnf (T_RR_ACTIVATE_CNF *rr_activate_cnf) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_rr_activate_cnf()"); #ifdef WIN32 vsi_o_ttrace (VSI_CALLER TC_FUNC, " MCC=%x%x%x MNC=%x%x%x LAC=%04X CID=%04X POW=%d", rr_activate_cnf->plmn.mcc[0], rr_activate_cnf->plmn.mcc[1], rr_activate_cnf->plmn.mcc[2], rr_activate_cnf->plmn.mnc[0], rr_activate_cnf->plmn.mnc[1], rr_activate_cnf->plmn.mnc[2], rr_activate_cnf->lac, rr_activate_cnf->cid, rr_activate_cnf->power); #endif /* #ifdef WIN32 */ /* Changes for Boot Time Speedup. MM will get RR_ACTIVATE_CNF with op.func = FUNC_ST_PWR_SCAN. * No need to process it as this is response to dummy request. * MM need to send REG_CNF indicating PWR_SCAN_START */ if (mm_data->reg.op.func EQ FUNC_ST_PWR_SCAN) { if (rr_activate_cnf->op.func EQ FUNC_ST_PWR_SCAN) { mm_send_mmgmm_reg_cnf (PWR_SCAN_START); } else { TRACE_EVENT_P1 ("Expected function FUNC_ST_PWR_SCAN but received %x", rr_activate_cnf->op.func); } return ; } mm_data->rf_power = rr_activate_cnf->power; mm_data->reg.new_cell_ind = TRUE; if (reg_plmn_equal_eqv (&rr_activate_cnf->plmn, &mm_data->reg.actual_plmn)) { mm_data->reg.actual_plmn = rr_activate_cnf->plmn; /* Struct copy */ } switch (GET_STATE (STATE_MM)) { case MM_WAIT_FOR_RR_ACTIVE: if (mm_data->reg.op.func EQ rr_activate_cnf->op.func) { /* * this is the answer to the request of MM */ switch (rr_activate_cnf->op.service) { case LIMITED_SERVICE: mm_limited_from_rr (rr_activate_cnf); USE_STORED_ENTRIES(); break; case FULL_SERVICE: /* * full service is indicated by RR. */ mm_copy_rr_act_cnf_data (rr_activate_cnf); if (!mm_normal_upd_needed() AND !mm_attach_upd_needed() AND !mm_periodic_upd_needed()) { /* * No location updating needed */ TIMERSTOP (T3213); mm_data->t3213_restart = 0; /* Track possible change of T3212 */ mm_change_t3212 (); reg_mm_success (FULL_SERVICE); reg_build_sim_update (); /* Update cell id */ mm_mmgmm_activate_ind (MMGMM_FULL_SERVICE); /* Back to MM_IDLE_NORMAL_SERVICE */ mm_data->idle_entry = RRCS_INT_NOT_PRESENT; /* Remember MM doesn't need any IMSI ATTACH anymore */ if (mm_lup_allowed_by_gmm() AND mm_data->first_attach ) { mm_data->first_attach_mem = mm_data->first_attach; mm_data->first_attach = FALSE; } mm_data->t3212_timeout = FALSE; mm_data->loc_upd_type.lut = NOT_RUNNING; SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE); /* Check HPLMN timer state */ reg_check_hplmn_tim (mm_data->reg.thplmn); USE_STORED_ENTRIES(); } else { /* * Location updating needed */ reg_mm_cell_selected (); mm_data->attempt_cnt = 0; if (mm_normal_upd_needed()) { /* * If updating is allowed by GMM, start procedure, * otherwise enter state MM_IDLE_LUP_NEEDED. */ mm_normal_loc_upd (); } else if (mm_attach_upd_needed()) { /* * If updating is allowed by GMM, start procedure, * otherwise enter state MM_IDLE_LUP_NEEDED. */ mm_attach_loc_upd (); } else { /* * It must be a periodic location updating procedure. * If updating is allowed, start procedure, * otherwise enter state MM_IDLE_NORMAL_SERVICE. * Compare this with GSM 04.08 subclause 4.2.3 */ if (mm_lup_allowed_by_gmm()) /*lint !e774*/ { mm_periodic_loc_upd (); } else { SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE); } } /* * If GPRS is active, GMM will be informed about the * cell selection. In this case, MM has not tried * to establish a RR connection for location updating * and the state MM_IDLE_LUP_NEEDED has already been entered. */ mm_mmgmm_activate_ind (MMGMM_WAIT_FOR_UPDATE); } break; /* case FULL_SERVICE */ default: /* NO_SERVICE or other garbage */ TRACE_ERROR (UNEXPECTED_DEFAULT); break; } /* switch() */ } break; default: /* * Normally MM should not receive an unsolicited RR_ACTIVATE_CNF, * but if it happens, we keep MM up to date using considering the * RR_ACTIVATE_CNF as RR_ACTIVATE_IND. * It is theoretically possible that a clash * RR_ACTIVATE_REQ -> RR_ABORT_IND -> RR_ACTIVATE_CNF * happens, but in most of the cases the reception of RR_ACTIVATE_CNF * in another state than MM_WAIT_FOR_RR_ACTIVE is a strong hint that * something went wrong in RR which should be observed carefully. */ TRACE_ERROR ("RR_ACTIVATE_CNF => RR_ACTIVATE_IND"); mm_rr_activate_ind ((T_RR_ACTIVATE_IND*)rr_activate_cnf); return; /* Don't free primitive twice */ } PFREE (rr_activate_cnf); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_handled_forb_plmn_cell | +--------------------------------------------------------------------+ PURPOSE : This function checks whether RR selected a full service cell which is part of the forbidden PLMN list. If the cell is a member of a forbidden list, the appropriate actions are taken, but no change of the MM main state is performed. */ LOCAL BOOL mm_handled_forb_plmn_cell (T_RR_ACTIVATE_IND *rr_activate_ind) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_handled_forb_plmn_cell()"); if (reg_plmn_in_list (mm_data->reg.forb_plmn, MAX_FORB_PLMN_ID, &rr_activate_ind->plmn)) { TRACE_EVENT ("RR selected forbidden PLMN"); mm_copy_rr_act_cnf_data ((T_RR_ACTIVATE_CNF *)rr_activate_ind); reg_mm_success (LIMITED_SERVICE); mm_build_rr_sync_req_cause (SYNCCS_LIMITED_SERVICE); /* * GSM 04.08 subclause 4.4.4.7 doesn't say that a forbidden PLMN * for GSM shall also be considered as a forbidden PLMN for GPRS. * This means, we could have the situation that GSM has limited * service only, but GPRS has full network access. */ mm_mmgmm_activate_ind (MMGMM_LIMITED_SERVICE); return TRUE; /* Cell is in forbidden list */ } if (rr_activate_ind->mm_info.la EQ LA_IN_FRBD_LST_INCL) { mm_copy_rr_act_cnf_data ((T_RR_ACTIVATE_CNF *)rr_activate_ind); reg_mm_success (LIMITED_SERVICE); mm_mmgmm_activate_ind (MMGMM_LIMITED_SERVICE); return TRUE; /* Cell is in forbidden list */ } return FALSE; /* Cell is not in forbidden list */ } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_full_from_rr | +--------------------------------------------------------------------+ PURPOSE : This function takes the appropriate actions if a full service cell is offered by RR in some MM states. */ LOCAL void mm_full_from_rr (T_RR_ACTIVATE_IND *rr_activate_ind) { GET_INSTANCE_DATA; BOOL rr_changed_lai; TRACE_FUNCTION ("mm_full_from_rr()"); rr_changed_lai = !mm_check_lai_from_RR (&mm_data->mm.lai, &rr_activate_ind->plmn, rr_activate_ind->lac); mm_copy_rr_act_cnf_data ((T_RR_ACTIVATE_CNF *)rr_activate_ind); mm_data->idle_entry = RRCS_INT_NOT_PRESENT; if (mm_normal_upd_needed()) mm_data->loc_upd_type.lut = NORMAL_LUP; else if (mm_attach_upd_needed()) mm_data->loc_upd_type.lut = IMSI_ATTACH_LUP; else if (mm_periodic_upd_needed()) mm_data->loc_upd_type.lut = PERIODIC_LUP; else { if (memcmp(mm_data->reg.lai.mcc, mm_data->mm.lai.mcc, SIZE_MCC) OR memcmp(mm_data->reg.lai.mnc, mm_data->mm.lai.mnc, SIZE_MNC) OR (mm_data->reg.lai.lac NEQ mm_data->mm.lai.lac)) { /* EF LOCI value has changed, hence write it on SIM */ /* EF Indicator for EF LOCI - bit 1*/ mm_data->ef_indicator|=0x01; } mm_data->loc_upd_type.lut = NOT_RUNNING; } #ifdef GPRS if (rr_changed_lai AND (mm_data->loc_upd_type.lut NEQ NOT_RUNNING) AND (GET_STATE (STATE_REG_TYPE) EQ REG_REMOTE_CONTROLLED)) { /* * MM is in remote controlled operation with GPRS present and * the location area identifier has changed, MM has to set * its reg_type auxiliary state variable. The network mode * may have changed to network mode I. * Beware not to suppress an outstanding MMGMM_REG_CNF if * no update needed anymore for whatever reason. */ SET_STATE (STATE_REG_TYPE, REG_CELL_SEARCH_ONLY); } #endif /* GPRS */ switch (mm_data->loc_upd_type.lut) { case NOT_RUNNING: /* * No location updating needed */ /* Track possible change of T3212 */ mm_change_t3212 (); TIMERSTOP (T3211); TIMERSTOP (T3213); mm_data->t3213_restart = 0; mm_mmgmm_activate_ind (MMGMM_FULL_SERVICE); reg_mm_success (FULL_SERVICE); reg_build_sim_update (); /* Remember MM doesn't need any IMSI ATTACH anymore */ if (mm_lup_allowed_by_gmm() AND mm_data->first_attach) { mm_data->first_attach_mem = mm_data->first_attach; mm_data->first_attach = FALSE; } mm_data->t3212_timeout = FALSE; SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE); USE_STORED_ENTRIES(); break; case NORMAL_LUP: /* * If updating is allowed by GMM, start procedure, * otherwise enter appropriate IDLE state. */ if (mm_lup_allowed_by_gmm()) /*lint !e774*/ { mm_mmgmm_activate_ind (MMGMM_CELL_SELECTED); if (rr_changed_lai OR (!TIMERACTIVE (T3211) AND !TIMERACTIVE (T3213))) { mm_normal_loc_upd (); } else { /* Await timer expiry in appropriate IDLE state */ if (mm_data->reg.update_stat EQ MS_UPDATED) { SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE); } else { SET_STATE (STATE_MM, MM_IDLE_ATTEMPT_TO_UPDATE); } } } else { mm_mmgmm_activate_ind (MMGMM_WAIT_FOR_UPDATE); SET_STATE (STATE_MM, MM_IDLE_LUP_NEEDED); } break; case IMSI_ATTACH_LUP: /* * If updating is allowed, start procedure, * otherwise enter state MM_IDLE_LUP_NEEDED. */ if (mm_lup_allowed_by_gmm()) /*lint !e774*/ { mm_mmgmm_activate_ind (MMGMM_CELL_SELECTED); if (mm_gsm_alone ()) { mm_mmgmm_reg_cnf (); /* Early indication of full service */ } if (!TIMERACTIVE (T3211) AND !TIMERACTIVE (T3213)) { mm_attach_loc_upd (); } else { SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE); } } else { mm_mmgmm_activate_ind (MMGMM_WAIT_FOR_UPDATE); SET_STATE (STATE_MM, MM_IDLE_LUP_NEEDED); } break; case PERIODIC_LUP: /* * It is a periodic location updating procedure. * If updating is allowed, start procedure, * otherwise enter state MM_IDLE_NORMAL_SERVICE. * Compare this with GSM 04.08 subclause 4.2.3 */ if (mm_lup_allowed_by_gmm()) /*lint !e774*/ { mm_mmgmm_activate_ind (MMGMM_CELL_SELECTED); if (mm_gsm_alone ()) { mm_mmgmm_reg_cnf (); /* Early indication of full service */ } if (!TIMERACTIVE (T3211) AND !TIMERACTIVE (T3213)) { mm_periodic_loc_upd (); } else { SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE); } } else { mm_mmgmm_activate_ind (MMGMM_WAIT_FOR_UPDATE); SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE); } break; default: /* Cannot happen */ break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_activate_ind | +--------------------------------------------------------------------+ PURPOSE : Process the primitive RR_ACTIVATE_IND. MM is informed by RR about a cell selection without prior request by RR_ACTIVATE_REQ. */ GLOBAL void mm_rr_activate_ind (T_RR_ACTIVATE_IND *rr_activate_ind) { GET_INSTANCE_DATA; mm_data->t3213_restart = MAX_REST_T3213; restart_function: TRACE_FUNCTION ("mm_rr_activate_ind()"); #ifdef WIN32 vsi_o_ttrace (VSI_CALLER TC_FUNC, " MCC=%x%x%x MNC=%x%x%x LAC=%04X CID=%04X POW=%d", rr_activate_ind->plmn.mcc[0], rr_activate_ind->plmn.mcc[1], rr_activate_ind->plmn.mcc[2], rr_activate_ind->plmn.mnc[0], rr_activate_ind->plmn.mnc[1], rr_activate_ind->plmn.mnc[2], rr_activate_ind->lac, rr_activate_ind->cid, rr_activate_ind->power); #endif /* #ifdef WIN32 */ mm_data->rf_power = rr_activate_ind->power; mm_data->reg.new_cell_ind = TRUE; if(reg_plmn_equal_eqv (&rr_activate_ind->plmn, &mm_data->reg.actual_plmn)) { mm_data->reg.actual_plmn = rr_activate_ind->plmn; /* Struct copy */ } switch (GET_STATE (STATE_MM)) { case MM_WAIT_FOR_RR_CONN_MM: /* * If the unexpected incoming RR_ACTIVATE_IND in this state indicates * a new location area the rr_activation_indication is stored and a * rr_abort_req is sent. This should be answered by RR with a * RR_RELEASE_IND message triggering the MM to change the state to * MM_IDLE and to handle the outstanding RR_ACTIVATE_IND there. */ { T_loc_area_ident local_lai; memcpy (local_lai.mcc, rr_activate_ind->plmn.mcc, SIZE_MCC); memcpy (local_lai.mnc, rr_activate_ind->plmn.mnc, SIZE_MNC); local_lai.lac = rr_activate_ind->lac; if (!mm_check_lai (&mm_data->mm.lai, &local_lai)) { mm_write_entry(NO_ENTRY, NO_ENTRY, NO_ENTRY, PRIMITIVE_ENTRY, rr_activate_ind, UNSPEC); if (mm_data->pend_conn.cause NEQ ESTCS_EMRG_CAL) { TRACE_EVENT_P1 ("pend_conn.cause= %x", mm_data->pend_conn.cause); mm_abort_connection(ABCS_NORM); } return; } } /* FALLTHROUGH */ /*lint -fallthrough */ case MM_WAIT_FOR_RR_CONN_LUP: /* * case MM_WAIT_FOR_RR_CONN_MM: */ case MM_WAIT_FOR_RR_CONN_DETACH: /* * A dedicated connection to the network * has been requested, but has not yet been established. * As we are storing the cell data here only, * it may become necessary to perform a location * updating procedure if coming back to IDLE. */ mm_copy_rr_act_cnf_data ((T_RR_ACTIVATE_CNF*) rr_activate_ind); /* Inform GPRS about selected cell */ mm_mmgmm_activate_ind (MMGMM_CELL_SELECTED); if (mm_check_lai (&mm_data->mm.lai, &mm_data->reg.lai)) reg_build_sim_update (); /* Update cell id */ break; case MM_WAIT_FOR_REESTABLISH: /* RR indicates a suitable cell for call reestablishment */ if (rr_activate_ind->mm_info.re EQ 0) { /* What if call reestablishment and after call release of reestablished call in other LA LUP is necessary? The following line was obviously missing here (HM, 01.02.01) mm_copy_rr_act_cnf_data ((T_RR_ACTIVATE_CNF *) rr_activate_ind); Inform GPRS about selected cell mm_mmgmm_activate_ind (MMGMM_CELL_SELECTED); */ mm_data->reest_cell_avail = TRUE; /*at least one connection has requested call reestablishment */ if (mm_data->reest_ti NEQ NOT_PRESENT_8BIT) mm_reest (mm_data->reest_ti); /*if (mm_normal_upd_needed()) { */ mm_write_entry(NO_ENTRY, NO_ENTRY, NO_ENTRY, PRIMITIVE_ENTRY, rr_activate_ind, UNSPEC); return; /*} */ } else { /* * No support of call reestablishment */ mm_mmxx_rel_ind (MMCS_NO_REESTABLISH, CM_NOT_IDLE); /* Find IDLE state after MM connection */ mm_release_rr_connection (MMGMM_RESUMPTION_FAILURE); /* Restart the function in new state to perform location updating * if needed, avoid recursion for stack usage, therefore the goto */ goto restart_function; /*lint !e801 goto*/ } /* break is removed ,as case is returning before break so it is not needed */ case MM_WAIT_FOR_RR_ACTIVE: /* * Clash case. While MM required to perform a network selection in RR, * RR performed a cell selection. This maybe ignored, as RR stored the * RR_ACTIVATE_REQ primitive in this case and a RR_ACTIVATE_CNF or * RR_ABORT_IND primitive will follow within short time. */ break; #ifdef GPRS case MM_LOCATION_UPDATING_PENDING: case MM_IMSI_DETACH_PENDING: /* *What to do here?... */ assert (GET_STATE (STATE_REG_TYPE) EQ REG_CELL_SEARCH_ONLY); TRACE_EVENT ("This needs still discussion"); /*FALLTHROUGH*/ /* lint -fallthrough */ #endif /* GPRS */ case MM_IDLE_NORMAL_SERVICE: /* 19.1 */ switch (rr_activate_ind->op.service) { case LIMITED_SERVICE: mm_limited_from_rr ((T_RR_ACTIVATE_CNF*)rr_activate_ind); break; case FULL_SERVICE: if (mm_handled_forb_plmn_cell (rr_activate_ind)) { /* * The cell is a member of a forbidden list. */ SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); USE_STORED_ENTRIES(); } else { mm_full_from_rr (rr_activate_ind); } break; default: /* Either NO_SERVICE or other garbage */ TRACE_ERROR (UNEXPECTED_DEFAULT); break; } break; case MM_IDLE_ATTEMPT_TO_UPDATE: /* 19.2 */ if (mm_handled_forb_plmn_cell (rr_activate_ind)) { SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); } else { /* * RR selected a cell which may serve for full service. Behaviour * here is described in GSM 04.08 subclause 4.2.2.2, "Service State, * ATTEMPTING TO UPDATE". The idea behind this subclause for the * case "cell in old location area selected" seems to be very simple: * If the location updating problem has been caused by the BSS or the * cell itself, perform an updating attempt as soon as a new cell * has been selected by RR and don't consider the timers T3211 and * T3213. In case the location updating problem has been caused by the * NSS (core network), e.g. there was a "network failure", updating * if a new cell is entered makes no sense as the problem was under * no circumstances related to the previously selected cell. */ if (mm_check_lai_from_RR (&mm_data->mm.lai, &rr_activate_ind->plmn, rr_activate_ind->lac)) { /* * RR selected a cell which belongs to a location * area identical with the previously selected cell. * Don't reset the attempt counter. * Compare this with GSM 04.08 subclause 4.4.4.5. */ BOOL perform_lup; mm_copy_rr_act_cnf_data ((T_RR_ACTIVATE_CNF*) rr_activate_ind); /* Track possible change of T3212 */ mm_change_t3212 (); /* * Check reject cause category according to GSM 04.08 s * subclause 4.2.2.2 and decide whether a location updating * procedure shall be performed. */ switch (mm_data->rej_cause) { case RRCS_MM_ABORTED: /* GSM 04.08 4.4.4.9 e), T3210 */ case RRCS_ABNORM_UNSPEC: /* GSM 04.08 4.4.4.9 f), ABNORM */ /* * don´t start normal location updating if the state * has been entered after T3210 timeout or the network * released the RR connection with RR cause RRCS_ABNORM_UNSPEC. */ perform_lup = FALSE; break; case MMCS_RETRY_IN_NEW_CELL: /* GSM 04.08 4.4.4.8 g), RETRY */ perform_lup = TRUE; break; case RRCS_RND_ACC_FAIL: /* GSM 04.08 4.4.4.9 c) */ case RRCS_DL_EST_FAIL: /* GSM 04.08 4.4.4.9 d) */ perform_lup = (mm_data->attempt_cnt < 4); break; default: /* * Treated here: GSM 04.08 4.4.4.9 f) with causes different * from "abnormal release, unspecified and g) with causes * different from "retry upon entry into a new cell". */ perform_lup = GET_CAUSE_ORIGIN_ENTITY (mm_data->rej_cause) EQ RR_ORIGINATING_ENTITY; break; } /* switch (mm_data->rej_cause) */ if (perform_lup) { /* * Normal location update is necessary */ mm_normal_loc_upd (); /* Inform GPRS about selected cell */ if (mm_lup_allowed_by_gmm()) /*lint !e774*/ { mm_mmgmm_activate_ind (MMGMM_CELL_SELECTED); } else { mm_mmgmm_activate_ind (MMGMM_WAIT_FOR_UPDATE); } } else { /* * RR performed a cell selection which doesn't lead to a * location updating procedure in this state */ mm_mmgmm_activate_ind (MMGMM_CELL_SELECTED); } } else { /* * RR selected a cell which belongs to a location * area not identical with the previously selected cell. * See GSM 04.08, subclause 4.2.2.2, "Service State, * ATTEMPTING TO UPDATE". */ mm_copy_rr_act_cnf_data ((T_RR_ACTIVATE_CNF*) rr_activate_ind); /* Track possible change of T3212 */ mm_change_t3212 (); mm_data->attempt_cnt = 0; /* GSM 04.08 subclause 4.4.4.5 */ #ifdef GPRS TIMERSTOP (T3211); TIMERSTOP (T3213); mm_data->t3213_restart = 0; if (GET_STATE (STATE_REG_TYPE) EQ REG_REMOTE_CONTROLLED) { SET_STATE (STATE_REG_TYPE, REG_CELL_SEARCH_ONLY); } #endif /* GPRS */ mm_normal_loc_upd (); mm_mmgmm_activate_ind (MMGMM_WAIT_FOR_UPDATE); } } /* cell which may offer full service */ break; case MM_IDLE_LIMITED_SERVICE: /* 19.3 */ case MM_IDLE_NO_CELL_AVAILABLE: /* 19.5 */ switch (rr_activate_ind->op.service) { case LIMITED_SERVICE: mm_limited_from_rr ((T_RR_ACTIVATE_CNF*)rr_activate_ind); break; case FULL_SERVICE: if (mm_handled_forb_plmn_cell (rr_activate_ind)) { /* * The cell is a member of a forbidden list. */ SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); mm_use_entry (); } else { mm_full_from_rr (rr_activate_ind); } break; default: /* Either NO_SERVICE or other garbage */ TRACE_ERROR (UNEXPECTED_DEFAULT); break; } break; case MM_IDLE_PLMN_SEARCH: /* 19.7 */ if (!mm_handled_forb_plmn_cell (rr_activate_ind)) { /* * Cell is not in forbidden list, offering full service. */ mm_copy_rr_act_cnf_data ((T_RR_ACTIVATE_CNF*) rr_activate_ind); // Is it really for sure that an ACTIVATE IND in this state // cannot serve for more than limited service? Why?... /* Inform GPRS about selected cell */ mm_mmgmm_activate_ind (MMGMM_LIMITED_SERVICE); if (mm_check_lai (&mm_data->mm.lai, &mm_data->reg.lai)) reg_build_sim_update (); switch (mm_data->reg.op.func) { case FUNC_LIM_SERV_ST_SRCH: reg_mm_success (LIMITED_SERVICE); mm_sim_set_imsi_marker( MSG_RR_ACT); break; } } break; #ifdef GPRS case MM_IDLE_LUP_NEEDED: /* 19.6 */ if (mm_handled_forb_plmn_cell (rr_activate_ind)) { SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); } else { mm_copy_rr_act_cnf_data ((T_RR_ACTIVATE_CNF*) rr_activate_ind); /* * Cell maybe ok for full service, not forbidden PLMN */ if (!mm_normal_upd_needed() AND !mm_attach_upd_needed()) { /* * Back to old updated area, no IMSI ATTACH needed */ mm_mmgmm_activate_ind (MMGMM_FULL_SERVICE); SET_STATE (STATE_MM, MM_IDLE_NORMAL_SERVICE); } else { /* * Location updating procedure needed */ mm_mmgmm_activate_ind (MMGMM_WAIT_FOR_UPDATE); /* Remain in MM state MM_IDLE_LUP_NEEDED */ } } break; #endif /* GPRS */ case MM_IDLE_NO_IMSI: /* 19.4 */ /* * The mobile has no SIM and a cell change is indicated. * Service cannot be better than LIMITED_SERVICE without IMSI (SIM). */ mm_limited_from_rr ((T_RR_ACTIVATE_CNF*)rr_activate_ind); break; case MM_PLMN_SEARCH_NORMAL_SERVICE: /* 19.8 */ /* * RR_ACTIVATE_REQ -> RR_ACTIVATE_IND -> RR_ABORT_IND (search result) * Best thing (which is not perfect anyway) here is to abort the * search requested by the MMI and to handle this in the previous state. * The user may get an empty list, but the RR_ACTIVATE_IND maybe * more important. */ /* Abort the search for the MMI */ mm_data->reg.plmn_cnt = 0; mm_mmgmm_plmn_ind (MMCS_PLMN_NOT_IDLE_MODE, NULL); /* Back to previous IDLE state */ SET_STATE (STATE_MM, mm_data->idle_substate); /* Restart the function in new state, avoid recursion, stack usage, * therefore the goto. */ goto restart_function; /*lint !e801 goto*/ /* * Rare case: rr_activate_ind was received during call establishment for * emergency call and stored. * Stored rr_activate_ind shall remain stored until end of emergency call. */ case MM_CONN_ACTIVE: /* * Rare case: 16868 rr_activate indication follows to RR_ABORT during a call. * Reestablishment was rejected because of unknown TI. * Should trigger an LUP after RR connection release if a new LAI is contained. * Stored rr_activate_ind shall remain stored. */ case MM_WAIT_FOR_NW_CMD: mm_write_entry(NO_ENTRY, NO_ENTRY, NO_ENTRY, PRIMITIVE_ENTRY, rr_activate_ind, UNSPEC); return; default: /* * MM_LUP_INITIATED, MM_WAIT_FOR_OUTG_MM_CONN, * MM_IMSI_DETACH_INIT, MM_PROCESS_PROMPT, * MM_LUP_REJECTED => Not expected cell selection in dedicated mode */ TRACE_ERROR (UNEXPECTED_DEFAULT); break; } PFREE (rr_activate_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_establish_cnf | +--------------------------------------------------------------------+ PURPOSE : Process the primitive RR_ESTABLISH_CNF. */ GLOBAL void mm_rr_establish_cnf (T_RR_ESTABLISH_CNF *rr_establish_cnf) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mmrr_establish_cnf()"); switch (GET_STATE (STATE_MM)) { case MM_WAIT_FOR_RR_CONN_LUP: TIMERSTART (T3210, T_3210_VALUE); mm_data->ciphering_on = FALSE; SET_STATE (STATE_MM, MM_LUP_INITIATED); break; case MM_WAIT_FOR_RR_CONN_MM: mm_data->ciphering_on = FALSE; mm_data->wait_for_accept = TRUE; SET_STATE (STATE_MM, MM_WAIT_FOR_OUTG_MM_CONN); TIMERSTART (T3230, T_3230_VALUE); break; case MM_WAIT_FOR_REESTABLISH: mm_data->ciphering_on = FALSE; mm_data->wait_for_accept = TRUE; TIMERSTART (T3230, T_3230_VALUE); break; case MM_WAIT_FOR_RR_CONN_DETACH: /* * RR connection for IMSI Detach has been established */ TIMERSTART (T3220, T_3220_VALUE); /* * Wait for release by the infrastructure or timeout T3220 * if the SIM card is removed. */ SET_STATE (STATE_MM, MM_IMSI_DETACH_INIT); break; default: /* * A RR_ESTABLISH_CNF is somewhat unexpected here, but we can try to * handle it by aborting the RR connection. But it is at least also * worth a TRACE. */ mm_abort_connection (ABCS_NORM); TRACE_EVENT (UNEXPECTED_IN_STATE); break; } EM_RR_CONECTION_ESTABLISHED; PFREE (rr_establish_cnf); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_establish_ind | +--------------------------------------------------------------------+ PURPOSE : Process the primitive RR_ESTABLISH_IND. */ GLOBAL void mm_rr_establish_ind (T_RR_ESTABLISH_IND *rr_establish_ind) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_rr_establish_ind()"); TIMERSTOP (T3240); switch (GET_STATE (STATE_MM)) { case MM_IDLE_PLMN_SEARCH: case MM_PLMN_SEARCH_NORMAL_SERVICE: mm_mmgmm_plmn_ind (MMCS_PLMN_NOT_IDLE_MODE, NULL); /*FALLTHROUGH*/ //lint -fallthrough case MM_WAIT_FOR_RR_CONN_LUP: case MM_IDLE_NORMAL_SERVICE: case MM_IDLE_ATTEMPT_TO_UPDATE: case MM_IDLE_LIMITED_SERVICE: #ifdef GPRS case MM_IDLE_LUP_NEEDED: case MM_LOCATION_UPDATING_PENDING: mm_data->gprs.resumption = MMGMM_RESUMPTION_FAILURE; SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EST_OK); #endif /* GPRS */ mm_data->idle_substate = mm_get_service_state (); mm_data->ciphering_on = FALSE; mm_data->rej_cause = 0; SET_STATE (STATE_MM, MM_WAIT_FOR_NW_CMD); break; case MM_WAIT_FOR_RR_CONN_MM: /* * Clash. RR_ESTABLISH_IND was underway, in the * same moment RR_ESTABLISH_REQ was sent. * The RR_ESTABLISH_REQ is cancelled, the MT * establishment has the right of way. */ #ifdef GPRS mm_data->gprs.resumption = MMGMM_RESUMPTION_FAILURE; SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EST_OK); #endif /* GPRS */ if (mm_data->pend_conn.comp EQ SMS_COMP) { /* * In the clash a pending MO SMS is involved. Do not release the SMS * but store it until it can established again. * Note: This special treatment makes only sense for SMS. */ TRACE_EVENT ("MO SMS clashed with MT"); mm_write_entry (mm_data->pend_conn.comp, mm_data->pend_conn.ti, mm_data->pend_conn.cause, EVENT_ENTRY, NULL, UNSPEC); } else { /* Release all pending connections */ mm_mmxx_rel_ind (MMCS_INT_PREEM, CM_PENDING); } mm_data->idle_substate = mm_get_service_state (); mm_data->ciphering_on = FALSE; mm_data->rej_cause = 0; SET_STATE (STATE_MM, MM_WAIT_FOR_NW_CMD); break; /* case MM_WAIT_FOR_RR_CONN_MM: mm_abort_connection (ABCS_NORM); switch (mm_data->pend_conn.comp) { case CC_COMP: if (mm_data->pend_conn.prio EQ PRIO_NORM_CALL) { switch (mm_data->pend_conn.cause) { case ESTCS_MOB_ORIG_SPCH: case ESTCS_MOB_ORIG_DATA: case ESTCS_MOB_ORIG_DATA_HR_SUFF: mm_rr_est_req (mm_data->pend_conn.cause, CALL_SERVICE, mm_data->pend_conn.ti); break; } } else mm_rr_est_req (ESTCS_EMERGE, CALL_SERVICE, mm_data->pend_conn.ti); break; case SS_COMP: mm_rr_est_req (ESTCS_MOB_ORIG_CAL_BY_SS_SMS, SS_SERVICE, mm_data->pend_conn.ti); break; case SMS_COMP: mm_rr_est_req (ESTCS_MOB_ORIG_CAL_BY_SS_SMS, SMS_SERVICE, mm_data->pend_conn.ti); break; } break; */ case MM_WAIT_FOR_REESTABLISH: /* * Lost RR connection by a radio link failure and next thing which * happens is MT call establishment, just before the internal * communication after the radio link failure was completed. * This is not expected to happen, but if so, the MT call * has to be aborted. Maybe the incoming call ti is identical to a ti * for a call which has to be reestablished, this would lead to failure. */ mm_abort_connection (ABCS_NORM); break; default: break; } EM_RR_CONECTION_ESTABLISHED; PFREE (rr_establish_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_release_ind | +--------------------------------------------------------------------+ PURPOSE : Process the primitive RR_RELEASE_IND. */ GLOBAL void mm_rr_release_ind (T_RR_RELEASE_IND *rr_release_ind) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_rr_release_ind()"); /* Check for correct cause value */ assert (GET_CAUSE_ORIGIN_ENTITY (rr_release_ind->cause) EQ RR_ORIGINATING_ENTITY); #ifdef GPRS mm_data->gprs.resumption = rr_release_ind->gprs_resumption; #endif /* #ifdef GPRS */ switch (GET_STATE (STATE_MM)) { case MM_LUP_INITIATED: if (mm_data->rej_cause EQ 0) mm_data->rej_cause = rr_release_ind->cause; TIMERSTOP (T3210); mm_mdl_rel_req (); mm_lup_restart (); break; case MM_WAIT_FOR_OUTG_MM_CONN: case MM_WAIT_FOR_NW_CMD: #ifdef REL99 case MM_RR_CONN_RELEASE_NOT_ALLOWED: #endif case MM_WAIT_FOR_RR_CONN_MM: EM_RR_CONNECTION_ESTABLISHED_2; /*FALLTHROUGH*/ //lint -fallthrough case MM_WAIT_FOR_REESTABLISH: if (rr_release_ind->cause NEQ RRCS_MO_MT_COLL) mm_mdl_rel_req (); TIMERSTOP (T3230); TIMERSTOP (T3240); #ifdef REL99 /*Stop timer t3241 if it is ruuning. *As per the spec 24.008, Timer T3241 is stopped and reset (but not started) *when the MM state RR CONNECTION RELEASE NOT ALLOWED is left. */ TIMERSTOP(T3241); #endif if (rr_release_ind->cause EQ RRCS_RND_ACC_FAIL AND mm_data->reg.op.sim_ins EQ SIM_INSRT AND mm_data->reg.op.ts EQ TS_NO_AVAIL AND mm_data->act_retrans NEQ 0 AND (mm_count_connections (CM_PENDING) NEQ 0 OR mm_count_connections (CM_REEST_PENDING) NEQ 0)) { /* * start internal redial, if * - no TEST SIM * - SIM * - Cause <> random access failure * - retransmission counter <> 0 * - at least one CM connection is pending */ mm_data->act_retrans--; mm_rr_est_req (mm_data->pend_conn.cause, mm_data->pend_conn.service, mm_data->pend_conn.ti); SET_STATE (STATE_MM, MM_WAIT_FOR_RR_CONN_MM); } else { /* * other cases: no internal redial */ if (rr_release_ind->cause EQ RRCS_MO_MT_COLL) { if (mm_data->pend_conn.comp EQ SMS_COMP) { /* * Clash MO/MT, a pending MO SMS is involved. Do not release * the SMS but store it until it can be established again. * Note: This special treatment makes only sense for SMS. */ TRACE_EVENT ("MO SMS clashed with MT"); mm_write_entry (mm_data->pend_conn.comp, mm_data->pend_conn.ti, mm_data->pend_conn.cause, EVENT_ENTRY, NULL, UNSPEC); } else { /* * Clash MO/MT, no pending MO SMS is involved. Inform CM * about the release of the pending connection */ mm_mmxx_rel_ind (rr_release_ind->cause, CM_PENDING); mm_mmxx_rel_ind (rr_release_ind->cause, CM_REEST_PENDING); } /* Back to old Idle state without informing GMM about CM release */ SET_STATE (STATE_MM, mm_data->idle_substate); } else /* if release_ind->cause */ { /* Commenting the OMAPS00048777 changes as it was a incomplete workaround. Refer the analysis section of the defect 71208 for details */ /*#ifdef GPRS if (mm_data->gprs.sim_physically_removed) { mm_data->nreg_cause = CS_SIM_REM; mm_create_imsi_detach_message (); for_est_req (ESTCS_MOB_ORIG_CAL_BY_SS_SMS, BSIZE_U_IMSI_DETACH_IND); SET_STATE (STATE_MM, MM_WAIT_FOR_RR_CONN_DETACH); } else #endif {*/ /* * No MO/MT clash. Inform CM and also GMM about release. * Release all connections except the stored connections. */ mm_mmxx_rel_ind (rr_release_ind->cause, CM_PENDING); mm_mmxx_rel_ind (rr_release_ind->cause, CM_ACTIVE); mm_mmxx_rel_ind (rr_release_ind->cause, CM_REEST_PENDING); /* Find IDLE state */ mm_release_rr_connection (rr_release_ind->gprs_resumption); /* }*/ } /* release cause <> collision */ } break; case MM_CONN_ACTIVE: case MM_PROCESS_PROMPT: { if (rr_release_ind->sapi NEQ SAPI_3) { /* * Release of main signalling link, release all. */ /* Manager DL release, kill layer 2 */ mm_mdl_rel_req (); TIMERSTOP (T3230); TIMERSTOP (T3240); if ((rr_release_ind->cause EQ RRCS_NORM) AND (mm_count_connections (CM_PENDING) NEQ 0)) { /* * This is state MM WAIT FOR ADD OUTG MM CONN. * MM_PROCESS_PROMPT is incompatible with the requestion of a new * MM connection, so we are not in this state here. * The RR connection was released by the network normally. * Assume a clash case and repeat the CM_SERVICE_REQUEST message * for the pending connection. */ mm_mmxx_rel_ind (rr_release_ind->cause, CM_ACTIVE); mm_mmxx_rel_ind (rr_release_ind->cause, CM_REEST_PENDING); mm_rr_est_req (mm_data->pend_conn.cause, mm_data->pend_conn.service, mm_data->pend_conn.ti); SET_STATE (STATE_MM, MM_WAIT_FOR_RR_CONN_MM); } else { /* * Inform CM about release. */ mm_mmxx_rel_ind (rr_release_ind->cause, CM_PENDING); mm_mmxx_rel_ind (rr_release_ind->cause, CM_ACTIVE); mm_mmxx_rel_ind (rr_release_ind->cause, CM_REEST_PENDING); /* Find IDLE state after MM connection */ mm_release_rr_connection (rr_release_ind->gprs_resumption); } } else { /* * Only release of RR connection for SAPI = 3, * main signalling link not released. */ /* * Inform CM entity SMS about release. All SAPI 3 connections * are to be released to SMS (except the stored ones). */ mm_mmsms_rel_ind (rr_release_ind->cause, CM_PENDING); mm_mmsms_rel_ind (rr_release_ind->cause, CM_ACTIVE); mm_mmsms_rel_ind (rr_release_ind->cause, CM_REEST_PENDING); if (mm_count_connections (CM_ACTIVE) NEQ 0 OR mm_count_connections (CM_PENDING) NEQ 0) { /* * Some active or pending connections remaining for * SAPI NEQ 3, kill layer 2 only for SAPI = 3 */ mm_mdl_rel_req_sapi_3 (); } else { /* * No active or pending connections * remaining, manager release of layer 2. */ mm_mdl_rel_req (); TIMERSTOP (T3230); TIMERSTOP (T3240); /* Find IDLE state after MM connection */ mm_release_rr_connection (rr_release_ind->gprs_resumption); } } break; } case MM_IMSI_DETACH_INIT: case MM_WAIT_FOR_RR_CONN_DETACH: mm_mdl_rel_req (); mm_mmgmm_cm_release_ind (rr_release_ind->gprs_resumption); mm_end_of_detach (); break; case MM_LUP_REJECTED: mm_mdl_rel_req (); TIMERSTOP (T3240); mm_loc_upd_rej (); break; case MM_WAIT_FOR_RR_CONN_LUP: mm_data->rej_cause = rr_release_ind->cause; mm_mdl_rel_req (); TIMERSTOP (T3210); switch (rr_release_ind->cause) { case RRCS_DL_EST_FAIL: /* * GSM 04.08 subclause 4.4.4.9 case d) * RR connection failure. */ mm_data->rej_cause = RRCS_DL_EST_FAIL; mm_lup_restart (); break; case RRCS_RND_ACC_FAIL: /* * GSM 04.08 subclause 4.4.4.9 case c) * Random access failure. */ mm_data->rej_cause = RRCS_RND_ACC_FAIL; mm_data->idle_entry = RRCS_INT_NOT_PRESENT; #ifdef WIN32 TRACE_EVENT_P1 ("Last Rej Cause = %x", mm_data->last_rej_cause); #endif /* #ifdef WIN32 */ if (mm_data->last_rej_cause EQ RRCS_RND_ACC_FAIL) { mm_lup_restart (); } else { mm_data->last_rej_cause = RRCS_RND_ACC_FAIL; TIMERSTART (T3213, T_3213_VALUE); mm_data->t3213_restart = 0; /* * It can be safely assumed that idle_substate here is either * MM_IDLE_NORMAL_SERVICE or MM_IDLE_ATTEMPT_TO_UPDATE */ SET_STATE (STATE_MM, mm_data->idle_substate); } break; case RRCS_ACCESS_BARRED: case RRCS_RND_ACC_DELAY: /* * GSM 04.08 subclause 4.4.4.9 case a) * Access barred because of access class control. * GSM 04.08 subclause 4.4.4.9 case b) * The answer to random access is an * IMMEDIATE ASSIGNMENT REJECT message. */ mm_data->idle_entry = rr_release_ind->cause; /* * It can be safely assumed that idle_substate here is either * MM_IDLE_NORMAL_SERVICE or MM_IDLE_ATTEMPT_TO_UPDATE */ SET_STATE (STATE_MM, mm_data->idle_substate); break; default: /* eg. RRCS_ABNORM_UNSPEC, RRCS_INT_NOT_PRESENT */ mm_lup_restart (); break; } break; default: /* * 19.x, MM_LOCATION_UPDATING_PENDING, MM_IMSI_DETACH_PENDING, * and all remaining MM states. */ /* Local end release of layer 2 */ mm_mdl_rel_req (); #ifdef GPRS /* Assume GMM sent GMMRR_CS_PAGE_RES (GMMRR_CS_PAGE_CNF). * This means CS services are (were) allowed. */ SET_STATE (STATE_GPRS_CM_EST, CM_GPRS_EST_OK); /* Give CM control back to GMM */ mm_mmgmm_cm_release_ind (rr_release_ind->gprs_resumption); #endif /* #ifdef GPRS */ USE_STORED_ENTRIES(); break; } #ifdef GPRS mm_data->gprs.resumption = MMGMM_RESUMPTION_FAILURE; #endif /* #ifdef GPRS */ PFREE (rr_release_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_sync_ind | +--------------------------------------------------------------------+ PURPOSE : Process the primitive RR_SYNC_IND. */ GLOBAL void mm_rr_sync_ind (T_RR_SYNC_IND *rr_sync_ind) { GET_INSTANCE_DATA; BOOL t3212_changed; TRACE_FUNCTION ("mm_rr_sync_ind()"); /* prevent the T3213 from restarting when it runs first time, but don't forget, that it is restarted if so */ if (mm_data->t3213_restart EQ 0) { mm_data->t3213_restart = MAX_REST_T3213; } /* Remember wheter a change in broadcasted value for T3212 was detected */ t3212_changed = (rr_sync_ind->mm_info.valid EQ MM_INFO_PRES AND mm_data->mm.mm_info.t3212 NEQ rr_sync_ind->mm_info.t3212); /* * Forward new BCCH information to the SIM application */ if (rr_sync_ind->bcch_info.v_bcch EQ V_BCCH_PRES) { // Patch HM 14.03.01 >>> // memcpy (&mm_data->mm.bcch, &rr_sync_ind->bcch_info, SIZE_BCCH); memcpy (mm_data->mm.bcch, rr_sync_ind->bcch_info.bcch, SIZE_BCCH); // Patch HM 14.03.01 <<< if (memcmp(rr_sync_ind->bcch_info.bcch,mm_data->reg.bcch,SIZE_BCCH)) { /* Set bit 2 in ef_indicator to indicate bcch_info change to SIM */ mm_data->ef_indicator|=(0x01 << 1); } reg_build_sim_update (); PFREE (rr_sync_ind); // return; // } /* * forwarding of ciphering indicator */ if (rr_sync_ind->ciph NEQ CIPH_NOT_PRES) { if (rr_sync_ind->ciph NEQ mm_data->ciphering_on) { #ifdef GPRS /* GPRS supported, forward ciphering info for indicator to GMM */ PALLOC (ciphering_ind,MMGMM_CIPHERING_IND); ciphering_ind->ciph = rr_sync_ind->ciph; PSENDX (GMM, ciphering_ind); #else /* GSM only case, forward ciphering info for indicator to ACI directly */ PALLOC (ciphering_ind,MMR_CIPHERING_IND); ciphering_ind->ciph = rr_sync_ind->ciph; PSENDX (MMI, ciphering_ind); #endif /* GPRS */ } } switch (GET_STATE (STATE_MM)) { case MM_LUP_INITIATED: if (rr_sync_ind->ciph NEQ CIPH_NOT_PRES) { mm_data->ciphering_on = rr_sync_ind->ciph; } break; case MM_WAIT_FOR_OUTG_MM_CONN: if (rr_sync_ind->ciph NEQ CIPH_NOT_PRES) { mm_data->ciphering_on = rr_sync_ind->ciph; mm_data->error = FALSE; mm_cm_serv_accept (); } if (rr_sync_ind->chm.ch_mode NEQ NOT_PRESENT_8BIT) { PALLOC (mmcm_sync_ind, MMCM_SYNC_IND); /* T_MMCM_SYNC_IND */ mmcm_sync_ind->ti = 0; mmcm_sync_ind->sync_info.ch_info.ch_type = rr_sync_ind->chm.ch_type; mmcm_sync_ind->sync_info.ch_info.ch_mode = rr_sync_ind->chm.ch_mode; PSENDX (CC, mmcm_sync_ind); } break; case MM_CONN_ACTIVE: if (rr_sync_ind->chm.ch_mode NEQ NOT_PRESENT_8BIT) { PALLOC (mmcm_sync_ind, MMCM_SYNC_IND); /* T_MMCM_SYNC_IND */ mmcm_sync_ind->ti = 0; mmcm_sync_ind->sync_info.ch_info.ch_type = rr_sync_ind->chm.ch_type; mmcm_sync_ind->sync_info.ch_info.ch_mode = rr_sync_ind->chm.ch_mode; PSENDX (CC, mmcm_sync_ind); } if (rr_sync_ind->ciph NEQ NOT_PRESENT_8BIT) { mm_data->ciphering_on = rr_sync_ind->ciph; if (mm_data->wait_for_accept) { mm_mmxx_est_cnf (); TIMERSTOP (T3230); mm_data->wait_for_accept = FALSE; EM_CM_SERVICE_ACCEPTED(EM_COMMAND); USE_STORED_ENTRIES(); } } break; case MM_PROCESS_PROMPT: if (rr_sync_ind->chm.ch_mode NEQ NOT_PRESENT_8BIT) { /* Channel mode modification, MMCM_SYNC_IND to CC */ PALLOC (mmcm_sync_ind, MMCM_SYNC_IND); /* T_MMCM_SYNC_IND */ mmcm_sync_ind->ti = 0; mmcm_sync_ind->sync_info.ch_info.ch_type = rr_sync_ind->chm.ch_type; mmcm_sync_ind->sync_info.ch_info.ch_mode = rr_sync_ind->chm.ch_mode; PSENDX (CC, mmcm_sync_ind); } if (rr_sync_ind->ciph NEQ NOT_PRESENT_8BIT) { /* Ciphering changed, remember this is MM data */ mm_data->ciphering_on = rr_sync_ind->ciph; if (mm_count_connections (CM_ACTIVE) NEQ 0) { /* * In state MM_PROCESS PROMPT we cannot have * pending connections which are waiting * for CM SERVICE ACCEPT. This means, do nothing here. */ } else { /* * No connection exists, behaviour like in state * of MM_WAIT_FOR_NW_CMD, restart T3240 */ TIMERSTART (T3240, T_3240_VALUE); } } break; case MM_WAIT_FOR_NW_CMD: #ifdef REL99 case MM_RR_CONN_RELEASE_NOT_ALLOWED: #endif if (rr_sync_ind->chm.ch_mode NEQ NOT_PRESENT_8BIT) { PALLOC (mmcm_sync_ind, MMCM_SYNC_IND); /* T_MMCM_SYNC_IND */ mmcm_sync_ind->ti = 0; mmcm_sync_ind->sync_info.ch_info.ch_type = rr_sync_ind->chm.ch_type; mmcm_sync_ind->sync_info.ch_info.ch_mode = rr_sync_ind->chm.ch_mode; PSENDX (CC, mmcm_sync_ind); } if (rr_sync_ind->ciph NEQ NOT_PRESENT_8BIT) { mm_data->ciphering_on = rr_sync_ind->ciph; if (mm_get_service_state () NEQ MM_IDLE_LIMITED_SERVICE) { /* * T3212 is stopped if the first MM message is received, or * ciphering mode setting is completed in the case of MM * connection establishment, except when the most recent service * state is LIMITED SERVICE. [GSM 04.08 subclause 4.4.2] */ TIMERSTOP (T3212); mm_data->t3212_timeout = FALSE; } #ifdef REL99 if(TIMERACTIVE(T3241)) { /*Do nothing*/ } else #endif { /*restart timer T3240*/ TIMERSTART (T3240, T_3240_VALUE); } } break; case MM_IDLE_NO_IMSI: /* * Add traces to see last reject cause for location updating reject and * the place where MM entered the MM_IDLE_NO_IMSI state. */ TRACE_EVENT_P1 ("Last lup rej cause: %04x", mm_data->debug_last_rej_cause); TRACE_EVENT_P1 ("Entered state at %d", mm_data->mm_idle_no_imsi_marker); /*FALLTHROUGH*/ //lint -fallthrough case MM_WAIT_FOR_RR_CONN_LUP: case MM_WAIT_FOR_RR_CONN_MM: case MM_WAIT_FOR_RR_CONN_DETACH: case MM_IDLE_LIMITED_SERVICE: if ((rr_sync_ind->mm_info.valid EQ MM_INFO_PRES) AND (mm_data->reg.lai.lac NEQ LAC_INVALID_VALUE)) { mm_data->mm.mm_info = rr_sync_ind->mm_info; /* Structure copy */ if (t3212_changed) { // Maybe GMM is not interested either in T3212 if service state // is LIMITED SERVICE only, this should be checked... mm_mmgmm_t3212_val_ind (); } } break; case MM_IDLE_NORMAL_SERVICE: /* 19.1 */ if (rr_sync_ind->mm_info.valid EQ MM_INFO_PRES) { mm_data->mm.mm_info = rr_sync_ind->mm_info; /* Structure copy */ if (t3212_changed) { mm_mmgmm_t3212_val_ind (); mm_change_t3212 (); } } if ((rr_sync_ind->synccs EQ SYNCCS_ACC_CLS_CHA AND mm_data->idle_entry EQ RRCS_ACCESS_BARRED) OR (rr_sync_ind->synccs EQ SYNCCS_T3122_TIM_OUT AND mm_data->idle_entry EQ RRCS_RND_ACC_DELAY) OR (mm_data->t3213_restart > 0 AND mm_data->rej_cause EQ RRCS_RND_ACC_FAIL)) { mm_continue_running_update (); } break; case MM_IDLE_ATTEMPT_TO_UPDATE: if (rr_sync_ind->mm_info.valid EQ MM_INFO_PRES) { mm_data->mm.mm_info = rr_sync_ind->mm_info; /* Structure copy */ if (t3212_changed) { mm_mmgmm_t3212_val_ind (); mm_change_t3212 (); } } if ((rr_sync_ind->synccs EQ SYNCCS_ACC_CLS_CHA AND mm_data->idle_entry EQ RRCS_ACCESS_BARRED) OR (rr_sync_ind->synccs EQ SYNCCS_T3122_TIM_OUT AND mm_data->idle_entry EQ RRCS_RND_ACC_DELAY) OR (mm_data->t3213_restart > 0 AND mm_data->rej_cause EQ RRCS_RND_ACC_FAIL)) { mm_continue_running_update (); break; } #if 0 /* This code causes failure on ALCATEL test cases */ /* This registration attempt does not check the attempt counter*/ /* and so can cause the MS to attempt more than 4 LUs to the network */ if (rr_sync_ind->synccs EQ SYNCCS_LUP_RETRY) { if (mm_data->reg.op.sim_ins EQ SIM_INSRT AND mm_data->reg.op.ts EQ TS_NO_AVAIL) { /* * A SIM is inserted and it is no test SIM */ if (mm_lup_allowed_by_gmm()) /*lint !e774*/ { mm_normal_loc_upd (); } else { mm_mmgmm_lup_needed_ind (MMGMM_RXLEV_JUMP); /* No state change, MM remains in MM_IDLE_ATTEMPT_TO_UPDATE */ } } } #endif break; case MM_WAIT_FOR_REESTABLISH: if (rr_sync_ind->mm_info.re EQ RE_ALLOW) { /* * RR indicates a suitable cell for call reestablishment */ mm_data->reest_cell_avail = TRUE; // at least one connection has requested call reestablishment if (mm_data->reest_ti NEQ NOT_PRESENT_8BIT) mm_reest (mm_data->reest_ti); } else { /* * No support of call reestablishment */ mm_mmxx_rel_ind (MMCS_NO_REESTABLISH, CM_NOT_IDLE); /* Find IDLE state after MM connection */ mm_release_rr_connection(MMGMM_RESUMPTION_FAILURE); } break; #ifdef GPRS case MM_IDLE_LUP_NEEDED: /* 19.6 */ case MM_LOCATION_UPDATING_PENDING: /* 23 */ case MM_IMSI_DETACH_PENDING: /* 24 */ if (rr_sync_ind->mm_info.valid EQ MM_INFO_PRES) { mm_data->mm.mm_info = rr_sync_ind->mm_info; /* Structure copy */ if (t3212_changed) { mm_mmgmm_t3212_val_ind (); if (mm_get_service_state () NEQ MM_IDLE_LIMITED_SERVICE) mm_change_t3212 (); } } break; #endif /* GPRS */ default: TRACE_EVENT (PRIMITIVE_IGNORED); break; } PFREE (rr_sync_ind); } #if defined (FF_EOTD) AND defined (REL99) /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_rrlp_start_ind | +--------------------------------------------------------------------+ PURPOSE : Process the primitive mm_rr_rrlp_start_ind. */ GLOBAL void mm_rr_rrlp_start_ind (T_RR_RRLP_START_IND *rr_rrlp_start_ind) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_rr_rrlp_start_ind()"); /* *set rrlp_lcs_started flag to true */ mm_data->rrlp_lcs_started = TRUE; switch (GET_STATE (STATE_MM)) { case MM_WAIT_FOR_NW_CMD: TIMERSTOP(T3240); TIMERSTART(T3241, T_3241_VALUE); SET_STATE (STATE_MM, MM_RR_CONN_RELEASE_NOT_ALLOWED); break; case MM_RR_CONN_RELEASE_NOT_ALLOWED: TIMERSTOP(T3241); TIMERSTART(T3241, T_3241_VALUE); break; default : break; } PFREE (rr_rrlp_start_ind); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_rrlp_stop_ind | +--------------------------------------------------------------------+ PURPOSE : Process the primitive mm_rr_rrlp_stop_ind. */ GLOBAL void mm_rr_rrlp_stop_ind (T_RR_RRLP_STOP_IND *rr_rrlp_stop_ind) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_rr_rrlp_stop_ind()"); /* *set rrlp_lcs_started flag to false */ mm_data->rrlp_lcs_started = FALSE; switch (GET_STATE (STATE_MM)) { case MM_RR_CONN_RELEASE_NOT_ALLOWED: TIMERSTOP(T3241); TIMERSTART(T3240, T_3240_VALUE); SET_STATE (STATE_MM, MM_WAIT_FOR_NW_CMD); break; default : break; } PFREE (rr_rrlp_stop_ind); } #endif /* (FF_EOTD) AND defined (REL99) */ /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmcm_prompt_rej | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMCM_PROMPT_REJ. */ GLOBAL void mm_mmcm_prompt_rej (T_MMCM_PROMPT_REJ *prompt_rej) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_mmcm_prompt_rej()"); switch (GET_STATE (STATE_MM)) { case MM_PROCESS_PROMPT: /* Send MM STATUS with cause #34 */ { /* Implements Measure 29 and streamline encoding */ mm_send_status(RC_SERVICE_ORDER); } if ((mm_count_connections (CM_ACTIVE) NEQ 0) OR (mm_count_connections (CM_PENDING) NEQ 0)) { /* This is not standardized in GSM 4.08, but without returning to state MM_CONN_ACTIVE some MSCs in GSM 04.93 don't make sense. */ SET_STATE (STATE_MM, MM_CONN_ACTIVE); } else { #if defined (FF_EOTD) AND defined (REL99) if(mm_data->rrlp_lcs_started EQ TRUE) { TIMERSTART(T3241,T_3241_VALUE); SET_STATE(STATE_MM, MM_RR_CONN_RELEASE_NOT_ALLOWED); } else #endif /* (FF_EOTD) AND defined (REL99) */ { TIMERSTART (T3240, T_3240_VALUE); SET_STATE (STATE_MM, MM_WAIT_FOR_NW_CMD); } } break; default: break; } PFREE (prompt_rej); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmcm_prompt_res | +--------------------------------------------------------------------+ PURPOSE : Process the primitive MMCM_PROMPT_RES. */ GLOBAL void mm_mmcm_prompt_res (T_MMCM_PROMPT_RES *prompt_res) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_mmcm_prompt_res()"); switch (GET_STATE (STATE_MM)) { case MM_PROCESS_PROMPT: TIMERSTOP (T3240); CM_SET_STATE (CC_COMP, prompt_res->ti, CM_ACTIVE); SET_STATE (STATE_MM, MM_CONN_ACTIVE); break; default: /* MM cannot do anything (anymore) with the ti, send MMCM_RELEASE_IND */ mm_mmxx_release_ind (CC_COMP, prompt_res->ti, MMCS_INT_NOT_PRESENT); break; } PFREE (prompt_res); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_mmcm_ss_sms_data_req | +--------------------------------------------------------------------+ PURPOSE : This function unifies mm_mmcm_data_req(), mm_mmss_data_req() and mm_mmsms_data_req(). */ LOCAL void mm_mmcm_ss_sms_data_req (T_VOID_STRUCT *mm_data_req) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_mmcm_ss_sms_data_req()"); switch (GET_STATE (STATE_MM)) { case MM_WAIT_FOR_OUTG_MM_CONN: case MM_CONN_ACTIVE: case MM_PROCESS_PROMPT: case MM_WAIT_FOR_NW_CMD: { PPASS (mm_data_req, rr_data_req, RR_DATA_REQ); for_cm_message (rr_data_req); break; } default: PFREE (mm_data_req); break; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_sim_insrt_state | +--------------------------------------------------------------------+ PURPOSE : This function sets the parameter mm_idle_no_imsi_marker depending on the selector imsi_marker. */ GLOBAL void mm_sim_set_imsi_marker (T_MSG_TYPE imsi_marker) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_sim_set_imsi_marker()"); if (mm_data->reg.op.sim_ins EQ SIM_INSRT) { /* Valid SIM inserted */ SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); } else { /* Find original place where MM entered MM_IDLE_NO_IMSI state >>> */ if (mm_data->mm_idle_no_imsi_marker EQ 0) { if ( imsi_marker EQ MSG_RR_ACT) mm_data->mm_idle_no_imsi_marker = 13; else mm_data->mm_idle_no_imsi_marker = 3; } /* End of debugging patch <<< */ /* Invalid SIM inserted */ SET_STATE (STATE_MM, MM_IDLE_NO_IMSI); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_sim_insrt_state | +--------------------------------------------------------------------+ PURPOSE : This function sets the MM state depending on the SIM INSERT status. */ LOCAL void mm_sim_insert_state (void) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_sim_insert_state()"); if (mm_data->reg.op.sim_ins EQ SIM_INSRT) { /* SIM present */ SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); } else { /* SIM not present */ SET_STATE (STATE_MM, MM_IDLE_NO_IMSI); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-PS (6147) MODULE : MM_MM | | STATE : code ROUTINE : mm_rr_abort_cell_sel_fail | +--------------------------------------------------------------------+ PURPOSE : This function processes RR_ABORT_IND */ LOCAL void mm_rr_abort_cell_sel_fail (T_RR_ABORT_IND *rr_abort_ind) { GET_INSTANCE_DATA; TRACE_FUNCTION ("mm_rr_abort_cell_sel_fail()"); if (rr_abort_ind->cause EQ RRCS_ABORT_CEL_SEL_FAIL) { TIMERSTOP (T3211); TIMERSTOP (T3213); mm_data->t3213_restart = 0; mm_mmxx_rel_ind (rr_abort_ind->cause, CM_NOT_IDLE); mm_mmgmm_cm_release_ind (MMGMM_RESUMPTION_FAILURE); if (rr_abort_ind->op.service EQ NO_SERVICE) { SET_STATE (STATE_MM, MM_IDLE_NO_CELL_AVAILABLE); } else { SET_STATE (STATE_MM, MM_IDLE_LIMITED_SERVICE); } reg_rr_failure (rr_abort_ind); } } #endif