FreeCalypso > hg > fc-magnetite
diff src/g23m-gsm/mm/mm_mmp.c @ 104:27a4235405c6
src/g23m-gsm: import from LoCosto source
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 04 Oct 2016 18:24:05 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g23m-gsm/mm/mm_mmp.c Tue Oct 04 18:24:05 2016 +0000 @@ -0,0 +1,3630 @@ +/* ++----------------------------------------------------------------------------- +| 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