/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under * the OAI Public License, Version 1.0 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://www.openairinterface.org/?page_id=698 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ /***************************************************************************** Source emm_main.c Version 0.1 Date 2012/10/10 Product NAS stack Subsystem EPS Mobility Management Author Frederic Maurel Description Defines the EPS Mobility Management procedure call manager, the main entry point for elementary EMM processing. *****************************************************************************/ #include "emm_main.h" #include "nas_log.h" #include "emmData.h" #include "MobileIdentity.h" #include "memory.h" #include "usim_api.h" #include "IdleMode.h" #include // memset, memcpy, strlen #include // sprintf #include // malloc, free /****************************************************************************/ /**************** E X T E R N A L D E F I N I T I O N S ****************/ /****************************************************************************/ extern uint8_t usim_test; /****************************************************************************/ /******************* L O C A L D E F I N I T I O N S *******************/ /****************************************************************************/ static int _emm_main_get_imei(imei_t *imei, const char *imei_str); static int _emm_main_imsi_cmp(imsi_t *imsi1, imsi_t *imsi2); static const char *_emm_main_get_plmn(emm_plmn_list_t *emm_plmn_list, const plmn_t *plmn, int index, int format, size_t *size); static int _emm_main_get_plmn_index(emm_plmn_list_t *emm_plmn_list, const char *plmn, int format); /* * USIM application data */ static usim_data_t _usim_data; /* * Callback executed whenever a change in the network has to be notified * to the user application */ static emm_indication_callback_t _emm_main_user_callback; static int _emm_main_callback(emm_data_t *emm_data, int); /****************************************************************************/ /****************** E X P O R T E D F U N C T I O N S ******************/ /****************************************************************************/ /**************************************************************************** ** ** ** Name: emm_main_initialize() ** ** ** ** Description: Initializes EMM internal data ** ** ** ** Inputs: cb: The user notification callback ** ** imei: The IMEI read from the UE's non-volatile ** ** memory ** ** Others: _usim_data ** ** ** ** Outputs: None ** ** Return: None ** ** Others: user->emm_data-> ** ** ** ***************************************************************************/ void emm_main_initialize(nas_user_t *user, emm_indication_callback_t cb, const char *imei) { LOG_FUNC_IN; user->emm_data = calloc(1, sizeof(emm_data_t)); if ( user->emm_data == NULL ) { LOG_TRACE(ERROR, "EMM-MAIN - Failed to get allocate emm_data"); // FIXME stop here } /* USIM validity indicator */ user->emm_data->usim_is_valid = FALSE; /* The IMEI read from the UE's non-volatile memory */ user->emm_data->imei = (imei_t *)malloc(sizeof(imei_t)); user->emm_data->imei->length = _emm_main_get_imei(user->emm_data->imei, imei); /* The IMSI, valid only if USIM is present */ user->emm_data->imsi = NULL; /* EPS location information */ user->emm_data->guti = NULL; user->emm_data->tai = NULL; user->emm_data->ltai.n_tais = 0; /* EPS Connection Management status */ user->emm_data->ecm_status = ECM_IDLE; /* Network selection mode of operation */ user->emm_data->plmn_mode = EMM_DATA_PLMN_AUTO; /* Index of the PLMN manually selected by the user */ user->emm_data->plmn_index = -1; /* Selected Radio Access Technology */ user->emm_data->plmn_rat = NET_ACCESS_UNAVAILABLE; /* Selected PLMN */ memset(&user->emm_data->splmn, 0xFF, sizeof(plmn_t)); user->emm_data->is_rplmn = FALSE; user->emm_data->is_eplmn = FALSE; /* Radio Access Technology of the serving cell */ user->emm_data->rat = NET_ACCESS_UNAVAILABLE; /* Network registration status */ user->emm_data->stat = NET_REG_STATE_OFF; user->emm_data->is_attached = FALSE; user->emm_data->is_emergency = FALSE; /* Location/Tracking area code */ user->emm_data->tac = 0; // two byte in hexadecimal format /* Identifier of the serving cell */ user->emm_data->ci = 0; // four byte in hexadecimal format /* List of operators present in the network */ memset(user->emm_data->plist.buffer, 0, EMM_DATA_BUFFER_SIZE + 1); /* Home PLMN */ memset(&user->emm_data->hplmn, 0xFF, sizeof(plmn_t)); /* List of Forbidden PLMNs */ user->emm_data->fplmn.n_plmns = 0; /* List of Forbidden PLMNs for GPRS service */ user->emm_data->fplmn_gprs.n_plmns = 0; /* List of Equivalent HPLMNs */ user->emm_data->ehplmn.n_plmns = 0; /* List of user controlled PLMNs */ user->emm_data->plmn.n_plmns = 0; /* List of operator controlled PLMNs */ user->emm_data->oplmn.n_plmns = 0; /* List of operator network name records */ user->emm_data->n_opnns = 0; /* List of Forbidden Tracking Areas */ user->emm_data->ftai.n_tais = 0; /* List of Forbidden Tracking Areas for roaming */ user->emm_data->ftai_roaming.n_tais = 0; /* * Get USIM application data */ _usim_data.usimtestmode = usim_test; if ( usim_api_read(&_usim_data) != RETURNok ) { /* The USIM application may not be present or not valid */ LOG_TRACE(WARNING, "EMM-MAIN - Failed to read USIM application data"); } else { int i; /* The USIM application is present and valid */ LOG_TRACE(INFO, "EMM-MAIN - USIM application data successfully read"); user->emm_data->usim_is_valid = TRUE; /* Get the Home PLMN derived from the IMSI */ user->emm_data->hplmn.MCCdigit1 = _usim_data.imsi.u.num.digit1; user->emm_data->hplmn.MCCdigit2 = _usim_data.imsi.u.num.digit2; user->emm_data->hplmn.MCCdigit3 = _usim_data.imsi.u.num.digit3; user->emm_data->hplmn.MNCdigit1 = _usim_data.imsi.u.num.digit4; user->emm_data->hplmn.MNCdigit2 = _usim_data.imsi.u.num.digit5; user->emm_data->hplmn.MNCdigit3 = _usim_data.imsi.u.num.digit6; /* Get the list of forbidden PLMNs */ for (i=0; (i < EMM_DATA_FPLMN_MAX) && (i < USIM_FPLMN_MAX); i++) { if ( PLMN_IS_VALID(_usim_data.fplmn[i]) ) { user->emm_data->fplmn.plmn[i] = _usim_data.fplmn[i]; user->emm_data->fplmn.n_plmns += 1; } } /* Get the list of Equivalent HPLMNs */ for (i=0; (i < EMM_DATA_EHPLMN_MAX) && (i < USIM_EHPLMN_MAX); i++) { if ( PLMN_IS_VALID(_usim_data.ehplmn[i]) ) { user->emm_data->ehplmn.plmn[i] = _usim_data.ehplmn[i]; user->emm_data->ehplmn.n_plmns += 1; } } /* Get the list of User controlled PLMN Selector */ for (i=0; (i < EMM_DATA_PLMN_MAX) && (i < USIM_PLMN_MAX); i++) { if ( PLMN_IS_VALID(_usim_data.plmn[i].plmn) ) { user->emm_data->plmn.plmn[i] = _usim_data.plmn[i].plmn; user->emm_data->userAcT[i] = _usim_data.plmn[i].AcT; user->emm_data->plmn.n_plmns += 1; } } /* Get the list of Operator controlled PLMN Selector */ for (i=0; (i < EMM_DATA_OPLMN_MAX) && (i < USIM_OPLMN_MAX); i++) { if ( PLMN_IS_VALID(_usim_data.oplmn[i].plmn) ) { user->emm_data->oplmn.plmn[i] = _usim_data.oplmn[i].plmn; user->emm_data->operAcT[i] = _usim_data.oplmn[i].AcT; user->emm_data->oplmn.n_plmns += 1; } } /* Get the list of Operator network name records */ for (i=0; (i < EMM_DATA_OPNN_MAX) && (i < USIM_OPL_MAX); i++) { if ( PLMN_IS_VALID(_usim_data.opl[i].plmn) ) { int pnn_id = _usim_data.opl[i].record_id; user->emm_data->opnn[i].plmn = &_usim_data.opl[i].plmn; user->emm_data->opnn[i].fullname = (char *)_usim_data.pnn[pnn_id].fullname.value; user->emm_data->opnn[i].shortname = (char *)_usim_data.pnn[pnn_id].shortname.value; user->emm_data->n_opnns += 1; } } /* TODO: Get the Higher Priority PLMN search period parameter */ /* Get the EPS location information */ if (PLMN_IS_VALID(_usim_data.epsloci.guti.gummei.plmn)) { user->emm_data->guti = &_usim_data.epsloci.guti; } if (TAI_IS_VALID(_usim_data.epsloci.tai)) { user->emm_data->tai = &_usim_data.epsloci.tai; } user->emm_data->status = _usim_data.epsloci.status; /* Get NAS configuration parameters */ user->emm_data->NAS_SignallingPriority = _usim_data.nasconfig.NAS_SignallingPriority.value[0]; user->emm_data->NMO_I_Behaviour = _usim_data.nasconfig.NMO_I_Behaviour.value[0]; user->emm_data->AttachWithImsi = _usim_data.nasconfig.AttachWithImsi.value[0]; user->emm_data->MinimumPeriodicSearchTimer = _usim_data.nasconfig.MinimumPeriodicSearchTimer.value[0]; user->emm_data->ExtendedAccessBarring = _usim_data.nasconfig.ExtendedAccessBarring.value[0]; user->emm_data->Timer_T3245_Behaviour = _usim_data.nasconfig.Timer_T3245_Behaviour.value[0]; /* * Get EPS NAS security context */ /* Create NAS security context */ user->emm_data->security = (emm_security_context_t *)malloc(sizeof(emm_security_context_t)); if (user->emm_data->security != NULL) { memset(user->emm_data->security, 0, sizeof(emm_security_context_t)); /* Type of security context */ if (_usim_data.securityctx.KSIasme.value[0] != USIM_KSI_NOT_AVAILABLE) { user->emm_data->security->type = EMM_KSI_NATIVE; } else { user->emm_data->security->type = EMM_KSI_NOT_AVAILABLE; } /* EPS key set identifier */ user->emm_data->security->eksi = _usim_data.securityctx.KSIasme.value[0]; /* ASME security key */ user->emm_data->security->kasme.length = _usim_data.securityctx.Kasme.length; user->emm_data->security->kasme.value = (uint8_t *)malloc(user->emm_data->security->kasme.length); if (user->emm_data->security->kasme.value) { memcpy(user->emm_data->security->kasme.value, _usim_data.securityctx.Kasme.value, user->emm_data->security->kasme.length); } /* Downlink count parameter */ if (_usim_data.securityctx.dlNAScount.length <= sizeof(uint32_t)) { memcpy(&user->emm_data->security->dl_count, _usim_data.securityctx.dlNAScount.value, _usim_data.securityctx.dlNAScount.length); } /* Uplink count parameter */ if (_usim_data.securityctx.ulNAScount.length <= sizeof(uint32_t)) { memcpy(&user->emm_data->security->ul_count, _usim_data.securityctx.ulNAScount.value, _usim_data.securityctx.ulNAScount.length); } /* Ciphering algorithm */ user->emm_data->security->capability.eps_encryption = ((_usim_data.securityctx.algorithmID.value[0] >> 4) & 0xf); /* Identity protection algorithm */ user->emm_data->security->capability.eps_integrity = (_usim_data.securityctx.algorithmID.value[0] & 0xf); /* NAS integrity and cyphering keys are not available */ } else { LOG_TRACE(WARNING, "EMM-PROC - Failed to create security context"); } /* * Get EMM data from the UE's non-volatile memory */ memset(&user->emm_data->nvdata.rplmn, 0xFF, sizeof(plmn_t)); user->emm_data->nvdata.eplmn.n_plmns = 0; /* Get EMM data pathname */ char *path = memory_get_path(EMM_NVRAM_DIRNAME, EMM_NVRAM_FILENAME); if (path == NULL) { LOG_TRACE(ERROR, "EMM-MAIN - Failed to get EMM data pathname"); } else { /* Get EMM data stored in the non-volatile memory device */ int rc = memory_read(path, &user->emm_data->nvdata, sizeof(emm_nvdata_t)); if (rc != RETURNok) { LOG_TRACE(ERROR, "EMM-MAIN - Failed to read %s", path); } else { /* Check the IMSI */ LOG_TRACE(INFO, "EMM-MAIN - EMM data successfully read"); user->emm_data->imsi = &_usim_data.imsi; int imsi_ok = _emm_main_imsi_cmp(&user->emm_data->nvdata.imsi, &_usim_data.imsi); if (!imsi_ok) { LOG_TRACE(WARNING, "EMM-MAIN - IMSI checking failed nvram: " "%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x, " "usim: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x", user->emm_data->nvdata.imsi.u.value[0], user->emm_data->nvdata.imsi.u.value[1], user->emm_data->nvdata.imsi.u.value[2], user->emm_data->nvdata.imsi.u.value[3], user->emm_data->nvdata.imsi.u.value[4], user->emm_data->nvdata.imsi.u.value[5], user->emm_data->nvdata.imsi.u.value[6], user->emm_data->nvdata.imsi.u.value[7], _usim_data.imsi.u.value[0], _usim_data.imsi.u.value[1], _usim_data.imsi.u.value[2], _usim_data.imsi.u.value[3], _usim_data.imsi.u.value[4], _usim_data.imsi.u.value[5], _usim_data.imsi.u.value[6], _usim_data.imsi.u.value[7]); memset(&user->emm_data->nvdata.rplmn, 0xFF, sizeof(plmn_t)); user->emm_data->nvdata.eplmn.n_plmns = 0; } } free(path); } } /* * Initialize EMM timers */ T3410.id = NAS_TIMER_INACTIVE_ID; T3410.sec = T3410_DEFAULT_VALUE; T3411.id = NAS_TIMER_INACTIVE_ID; T3411.sec = T3411_DEFAULT_VALUE; T3402.id = NAS_TIMER_INACTIVE_ID; T3402.sec = T3402_DEFAULT_VALUE; T3416.id = NAS_TIMER_INACTIVE_ID; T3416.sec = T3416_DEFAULT_VALUE; T3417.id = NAS_TIMER_INACTIVE_ID; T3417.sec = T3417_DEFAULT_VALUE; T3418.id = NAS_TIMER_INACTIVE_ID; T3418.sec = T3418_DEFAULT_VALUE; T3420.id = NAS_TIMER_INACTIVE_ID; T3420.sec = T3420_DEFAULT_VALUE; T3421.id = NAS_TIMER_INACTIVE_ID; T3421.sec = T3421_DEFAULT_VALUE; T3423.id = NAS_TIMER_INACTIVE_ID; T3423.sec = T3423_DEFAULT_VALUE; T3430.id = NAS_TIMER_INACTIVE_ID; T3430.sec = T3430_DEFAULT_VALUE; /* * Initialize the user notification callback */ _emm_main_user_callback = *cb; /* * Initialize EMM internal data used for UE in idle mode */ // FIXME REVIEW IdleMode_initialize(user, &_emm_main_callback); LOG_FUNC_OUT; } /**************************************************************************** ** ** ** Name: emm_main_cleanup() ** ** ** ** Description: Performs the EPS Mobility Management clean up procedure ** ** ** ** Inputs: None ** ** Others: None ** ** ** ** Outputs: None ** ** Return: None ** ** Others: None ** ** ** ***************************************************************************/ void emm_main_cleanup(emm_data_t *emm_data) { LOG_FUNC_IN; if (emm_data->usim_is_valid) { /* * TODO: Update USIM application data */ } /* * Store EMM data into the UE's non-volatile memory * - Registered PLMN * - List of equivalent PLMNs */ char *path = memory_get_path(EMM_NVRAM_DIRNAME, EMM_NVRAM_FILENAME); if (path == NULL) { LOG_TRACE(ERROR, "EMM-MAIN - Failed to get EMM data pathname"); } else { int rc = memory_write(path, &emm_data->nvdata, sizeof(emm_nvdata_t)); if (rc != RETURNok) { LOG_TRACE(ERROR, "EMM-MAIN - Failed to write %s", path); } } /* Release dynamically allocated memory */ if (emm_data->imei) { free(emm_data->imei); emm_data->imei = NULL; } if (emm_data->security) { emm_security_context_t *security = emm_data->security; if (security->kasme.value) { free(security->kasme.value); security->kasme.value = NULL; security->kasme.length = 0; } if (security->knas_enc.value) { free(security->knas_enc.value); security->knas_enc.value = NULL; security->knas_enc.length = 0; } if (security->knas_int.value) { free(security->knas_int.value); security->knas_int.value = NULL; security->knas_int.length = 0; } free(emm_data->security); emm_data->security = NULL; } LOG_FUNC_OUT; } /**************************************************************************** ** ** ** Name: emm_main_get_imsi() ** ** ** ** Description: Get the International Mobile Subscriber Identity number ** ** ** ** Inputs: None ** ** Others: user->emm_data-> ** ** ** ** Outputs: None ** ** Return: Pointer to the IMSI ** ** Others: None ** ** ** ***************************************************************************/ const imsi_t *emm_main_get_imsi(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (&emm_data->nvdata.imsi); } /**************************************************************************** ** ** ** Name: emm_main_get_msisdn() ** ** ** ** Description: Get the Mobile Subscriber Dialing Number from the USIM ** ** ** ** Inputs: None ** ** Others: _usim_data ** ** ** ** Outputs: None ** ** Return: Pointer to the subscriber dialing number ** ** Others: None ** ** ** ***************************************************************************/ const msisdn_t *emm_main_get_msisdn(void) { LOG_FUNC_IN; LOG_FUNC_RETURN (&_usim_data.msisdn.number); } /**************************************************************************** ** ** ** Name: emm_main_set_plmn_selection_mode() ** ** ** ** Description: Set the network selection mode of operation to the given ** ** mode and update the manually selected network selection ** ** data ** ** ** ** Inputs: mode: The specified network selection mode of ** ** operation ** ** format: The representation format of the PLMN ** ** identifier ** ** plmn: Identifier of the selected PLMN ** ** rat: The selected Radio Access Techonology ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: user->emm_data-> ** ** ** ***************************************************************************/ int emm_main_set_plmn_selection_mode(nas_user_t *user, int mode, int format, const network_plmn_t *plmn, int rat) { LOG_FUNC_IN; int index; emm_data_t *emm_data = user->emm_data; emm_plmn_list_t *emm_plmn_list = user->emm_plmn_list; LOG_TRACE(INFO, "EMM-MAIN - PLMN selection: mode=%d, format=%d, plmn=%s, " "rat=%d", mode, format, (const char *)&plmn->id, rat); emm_data->plmn_mode = mode; if (mode != EMM_DATA_PLMN_AUTO) { /* Get the index of the PLMN in the list of available PLMNs */ index = _emm_main_get_plmn_index(emm_plmn_list, (const char *)&plmn->id, format); if (index < 0) { LOG_TRACE(WARNING, "EMM-MAIN - PLMN %s not available", (const char *)&plmn->id); } else { /* Update the manually selected network selection data */ emm_data->plmn_index = index; emm_data->plmn_rat = rat; } } else { /* * Get the index of the last PLMN the UE already tried to automatically * register to when switched on; the equivalent PLMNs list shall not be * applied to the user reselection in Automatic Network Selection Mode. */ index = IdleMode_get_hplmn_index(emm_plmn_list); } LOG_FUNC_RETURN (index); } /**************************************************************************** ** ** ** Name: emm_main_get_plmn_selection_mode() ** ** ** ** Description: Get the current value of the network selection mode of ** ** operation ** ** ** ** Inputs: None ** ** Others: user->emm_data-> ** ** ** ** Outputs: None ** ** Return: The value of the network selection mode ** ** Others: None ** ** ** ***************************************************************************/ int emm_main_get_plmn_selection_mode(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (emm_data->plmn_mode); } /**************************************************************************** ** ** ** Name: emm_main_get_plmn_list() ** ** ** ** Description: Get the list of available PLMNs ** ** ** ** Inputs: None ** ** Others: user->emm_data-> ** ** ** ** Outputs: plist: Pointer to the list of available PLMNs ** ** Return: The size of the list in bytes ** ** Others: None ** ** ** ***************************************************************************/ int emm_main_get_plmn_list(emm_plmn_list_t *emm_plmn_list, emm_data_t *emm_data, const char **plist) { LOG_FUNC_IN; int size = IdleMode_update_plmn_list(emm_plmn_list, emm_data, 0); *plist = emm_data->plist.buffer; LOG_FUNC_RETURN (size); } /**************************************************************************** ** ** ** Name: emm_main_get_selected_plmn() ** ** ** ** Description: Get the identifier of the currently selected PLMN ** ** ** ** Inputs: format: The requested format of the string repre- ** ** sentation of the PLMN identifier ** ** ** ** Outputs: plmn: The selected PLMN identifier coded in the ** ** requested format ** ** Return: A pointer to the string representation of ** ** the selected PLMN ** ** Others: None ** ** ** ***************************************************************************/ const char *emm_main_get_selected_plmn(emm_plmn_list_t *emm_plmn_list, emm_data_t *emm_data, network_plmn_t *plmn, int format) { LOG_FUNC_IN; size_t size = 0; /* * Get the identifier of the selected PLMN in the list of available PLMNs */ int index = IdleMode_get_splmn_index(emm_plmn_list); if ( !(index < 0) ) { const char *name = _emm_main_get_plmn(emm_plmn_list, &emm_data->splmn, index, format, &size); if (size > 0) { LOG_FUNC_RETURN ((char *) memcpy(&plmn->id, name, size)); } } LOG_FUNC_RETURN (NULL); } /**************************************************************************** ** ** ** Name: emm_main_get_registered_plmn() ** ** ** ** Description: Get the identifier of the currently registered PLMN ** ** ** ** Inputs: format: The requested format of the string repre- ** ** sentation of the PLMN identifier ** ** ** ** Outputs: plmn: The registered PLMN identifier coded in ** ** the requested format ** ** Return: A pointer to the string representation of ** ** the registered PLMN ** ** Others: None ** ** ** ***************************************************************************/ const char *emm_main_get_registered_plmn(emm_plmn_list_t *emm_plmn_list, emm_data_t *emm_data, network_plmn_t *plmn, int format) { LOG_FUNC_IN; size_t size = 0; /* * Get the identifier of the registered PLMN in the list of available PLMNs */ int index = IdleMode_get_rplmn_index(emm_plmn_list); if ( !(index < 0) ) { const char *name = _emm_main_get_plmn(emm_plmn_list, &emm_data->nvdata.rplmn, index, format, &size); if (size > 0) { LOG_FUNC_RETURN ((char *) memcpy(&plmn->id, name, size)); } } LOG_FUNC_RETURN (NULL); } /**************************************************************************** ** ** ** Name: emm_main_get_plmn_status() ** ** ** ** Description: Get the value of the network registration status which ** ** shows whether the network has currently indicated the ** ** registration of the UE ** ** ** ** Inputs: None ** ** ** ** Outputs: None ** ** Return: The current network registration status ** ** Others: None ** ** ** ***************************************************************************/ Stat_t emm_main_get_plmn_status(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (emm_data->stat); } /**************************************************************************** ** ** ** Name: emm_main_get_plmn_tac() ** ** ** ** Description: Get the code of the Tracking area the registered PLMN ** ** belongs to ** ** ** ** Inputs: None ** ** ** ** Outputs: None ** ** Return: The Location/Tracking area code ** ** Others: None ** ** ** ***************************************************************************/ tac_t emm_main_get_plmn_tac(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (emm_data->tac); } /**************************************************************************** ** ** ** Name: emm_main_get_plmn_ci() ** ** ** ** Description: Get the identifier of the serving cell ** ** ** ** Inputs: None ** ** ** ** Outputs: None ** ** Return: The serving cell identifier ** ** Others: None ** ** ** ***************************************************************************/ ci_t emm_main_get_plmn_ci(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (emm_data->ci); } /**************************************************************************** ** ** ** Name: emm_main_get_plmn_rat() ** ** ** ** Description: Get the value of the Radio Access Technology of the ser- ** ** ving cell ** ** ** ** Inputs: None ** ** ** ** Outputs: None ** ** Return: The value of the Radio Access Technology ** ** of the serving cell ** ** Others: None ** ** ** ***************************************************************************/ AcT_t emm_main_get_plmn_rat(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (emm_data->rat); } /**************************************************************************** ** ** ** Name: emm_main_is_attached() ** ** ** ** Description: Indicates whether the UE is currently attached to the ** ** network for EPS services or emergency service only ** ** ** ** Inputs: None ** ** Others: user->emm_data-> ** ** ** ** Outputs: None ** ** Return: TRUE if the UE is currently attached to ** ** the network; FALSE otherwise. ** ** Others: None ** ** ** ***************************************************************************/ int emm_main_is_attached(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (emm_data->is_attached); } /**************************************************************************** ** ** ** Name: emm_main_get_plmn_rat() ** ** ** ** Description: Indicates whether the UE is currently attached to the ** ** network for emergency bearer services ** ** ** ** Inputs: None ** ** Others: user->emm_data-> ** ** ** ** Outputs: None ** ** Return: TRUE if the UE is currently attached or is ** ** attempting to attach to the network for ** ** emergency bearer services; FALSE otherwise ** ** Others: None ** ** ** ***************************************************************************/ int emm_main_is_emergency(emm_data_t *emm_data) { LOG_FUNC_IN; LOG_FUNC_RETURN (emm_data->is_attached && emm_data->is_emergency); } /****************************************************************************/ /********************* L O C A L F U N C T I O N S *********************/ /****************************************************************************/ /**************************************************************************** ** ** ** Name: _emm_main_callback() ** ** ** ** Description: Forwards the network indication to the upper control la- ** ** yer (user API) to notify that network registration and/or ** ** location information has changed. ** ** ** ** Inputs: size: Size in byte of the list of operators ** ** present in the network. The list has to be ** ** displayed to the user application when ** ** size > 0. ** ** Others: user->emm_data-> ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ static int _emm_main_callback(emm_data_t *emm_data, int size) { LOG_FUNC_IN; /* Forward the notification to the user API */ int rc = (*_emm_main_user_callback)(emm_data->stat, emm_data->tac, emm_data->ci, emm_data->rat, emm_data->plist.buffer, size); LOG_FUNC_RETURN (rc); } /**************************************************************************** ** ** ** Name: _emm_main_get_imei() ** ** ** ** Description: Returns the International Mobile Equipment Identity con- ** ** tained in the given string representation ** ** ** ** Inputs: imei: The string representation of the IMEI ** ** Others: None ** ** ** ** Outputs: imei: The IMEI of the UE ** ** Return: The number of digits in the IMEI ** ** Others: None ** ** ** ***************************************************************************/ static int _emm_main_get_imei(imei_t *imei, const char *imei_str) { int len = strlen(imei_str); if (len % 2) { imei->u.num.parity = IMEI_ODD_PARITY; } else { imei->u.num.parity = EVEN_PARITY; } imei->u.num.digit1 = imei_str[0] - '0'; imei->u.num.digit2 = imei_str[1] - '0'; imei->u.num.digit3 = imei_str[2] - '0'; imei->u.num.digit4 = imei_str[3] - '0'; imei->u.num.digit5 = imei_str[4] - '0'; imei->u.num.digit6 = imei_str[5] - '0'; imei->u.num.digit7 = imei_str[6] - '0'; imei->u.num.digit8 = imei_str[7] - '0'; imei->u.num.digit9 = imei_str[8] - '0'; imei->u.num.digit10 = imei_str[9] - '0'; imei->u.num.digit11 = imei_str[10] - '0'; imei->u.num.digit12 = imei_str[11] - '0'; imei->u.num.digit13 = imei_str[12] - '0'; imei->u.num.digit14 = imei_str[13] - '0'; imei->u.num.digit15 = imei_str[14] - '0'; return (len); } /**************************************************************************** ** ** ** Name: _emm_main_imsi_cmp() ** ** ** ** Description: Compares two International Mobile Subscriber Identifiers ** ** ** ** Inputs: imsi1: The first IMSI ** ** imsi2: The second IMSI to compare to ** ** Others: None ** ** ** ** Outputs: None ** ** Return: TRUE if the first IMSI is found to match ** ** the second; FALSE otherwise. ** ** Others: None ** ** ** ***************************************************************************/ static int _emm_main_imsi_cmp(imsi_t *imsi1, imsi_t *imsi2) { int i; if (imsi1->length != imsi2->length) { return FALSE; } for (i = 0; i < imsi1->length; i++) { if (imsi1->u.value[i] != imsi2->u.value[i]) { return FALSE; } } return TRUE; } /**************************************************************************** ** ** ** Name: _emm_main_get_plmn() ** ** ** ** Description: Get the identifier of the PLMN at the given index in the ** ** list of available PLMNs. ** ** ** ** Inputs: plmn: The PLMN to search for ** ** index: The index of the PLMN in the list of PLMNs ** ** format: The requested representation format of the ** ** PLMN identifier ** ** Others: None ** ** ** ** Outputs: size: The size in bytes of the PLMN identifier ** ** coded in the requested format ** ** Return: A pointer to the identifier of the PLMN ** ** Others: None ** ** ** ***************************************************************************/ static const char *_emm_main_get_plmn(emm_plmn_list_t *emm_plmn_list, const plmn_t *plmn, int index, int format, size_t *size) { if ( PLMN_IS_VALID(*plmn) ) { switch (format) { case NET_FORMAT_LONG: /* Get the long alpha-numeric representation of the PLMN */ return IdleMode_get_plmn_fullname(emm_plmn_list, plmn, index, size); break; case NET_FORMAT_SHORT: /* Get the short alpha-numeric representation of the PLMN */ return IdleMode_get_plmn_shortname(emm_plmn_list, plmn, index, size); break; case NET_FORMAT_NUM: /* Get the numeric representation of the PLMN */ return IdleMode_get_plmn_id(emm_plmn_list, plmn, index, size); break; default: LOG_TRACE(WARNING, "EMM-MAIN - Format is not valid (%d)", format); *size = 0; break; } } return (NULL); } /**************************************************************************** ** ** ** Name: _emm_main_get_plmn_index() ** ** ** ** Description: Get the index of the given PLMN in the ordered list of ** ** available PLMNs ** ** ** ** Inputs: plmn: Identifier of the PLMN ** ** format: The representation format of the PLMN ** ** identifier ** ** Others: None ** ** ** ** Outputs: None ** ** Return: The index of the selected PLMN in the list ** ** of available PLMNs; -1 if the PLMN is not ** ** found ** ** Others: None ** ** ** ***************************************************************************/ static int _emm_main_get_plmn_index(emm_plmn_list_t *emm_plmn_list, const char *plmn, int format) { int index = -1; switch (format) { case NET_FORMAT_LONG: /* Get the index of the long alpha-numeric PLMN identifier */ index = IdleMode_get_plmn_fullname_index(emm_plmn_list, plmn); break; case NET_FORMAT_SHORT: /* Get the index of the short alpha-numeric PLMN identifier */ index = IdleMode_get_plmn_shortname_index(emm_plmn_list, plmn); break; case NET_FORMAT_NUM: /* Get the index of the numeric PLMN identifier */ index = IdleMode_get_plmn_id_index(emm_plmn_list, plmn); break; default: LOG_TRACE(WARNING, "EMM-MAIN - Format is not valid (%d)", format); break; } return (index); }