/** * * \section COPYRIGHT * * Copyright 2014-2015 Ben Wojtowicz * 2016-2020 Software Radio Systems Limited * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the distribution. * */ /******************************************************************************* INCLUDES *******************************************************************************/ #include "srsran/asn1/liblte_mme.h" #include "srsran/common/liblte_security.h" /******************************************************************************* DEFINES *******************************************************************************/ /******************************************************************************* TYPEDEFS *******************************************************************************/ /******************************************************************************* GLOBAL VARIABLES *******************************************************************************/ /******************************************************************************* INFORMATION ELEMENT FUNCTIONS *******************************************************************************/ /********************************************************************* IE Name: Additional Information Description: Provides additional information to upper layers in relation to the generic NAS message transport mechanism. Document Reference: 24.301 v10.2.0 Section 9.9.2.0 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_additional_information_ie(LIBLTE_MME_ADDITIONAL_INFORMATION_STRUCT* add_info, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (add_info != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = add_info->N_octets; for (i = 0; i < add_info->N_octets; i++) { (*ie_ptr)[1 + i] = add_info->info[i]; } *ie_ptr += add_info->N_octets + 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_additional_information_ie(uint8** ie_ptr, LIBLTE_MME_ADDITIONAL_INFORMATION_STRUCT* add_info) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && add_info != NULL) { add_info->N_octets = (*ie_ptr)[0]; for (i = 0; i < add_info->N_octets; i++) { add_info->info[i] = (*ie_ptr)[1 + i]; } *ie_ptr += add_info->N_octets + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Device Properties Description: Indicates if the UE is configured for NAS signalling low priority. Document Reference: 24.301 v10.2.0 Section 9.9.2.0A 24.008 v10.2.0 Section 10.5.7.8 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_device_properties_ie(LIBLTE_MME_DEVICE_PROPERTIES_ENUM device_props, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= device_props << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_device_properties_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_DEVICE_PROPERTIES_ENUM* device_props) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && device_props != NULL) { *device_props = (LIBLTE_MME_DEVICE_PROPERTIES_ENUM)((**ie_ptr >> bit_offset) & 0x01); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: EPS Bearer Context Status Description: Indicates the state of each EPS bearer context that can be identified by an EPS bearer identity. Document Reference: 24.301 v10.2.0 Section 9.9.2.1 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_bearer_context_status_ie(LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT* ebcs, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ebcs != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = 2; (*ie_ptr)[1] = (ebcs->ebi[7] << 7); (*ie_ptr)[1] |= (ebcs->ebi[6] << 6); (*ie_ptr)[1] |= (ebcs->ebi[5] << 5); (*ie_ptr)[2] = (ebcs->ebi[15] << 7); (*ie_ptr)[2] |= (ebcs->ebi[14] << 6); (*ie_ptr)[2] |= (ebcs->ebi[13] << 5); (*ie_ptr)[2] |= (ebcs->ebi[12] << 4); (*ie_ptr)[2] |= (ebcs->ebi[11] << 3); (*ie_ptr)[2] |= (ebcs->ebi[10] << 2); (*ie_ptr)[2] |= (ebcs->ebi[9] << 1); (*ie_ptr)[2] |= ebcs->ebi[8]; *ie_ptr += 3; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_bearer_context_status_ie(uint8** ie_ptr, LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT* ebcs) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && ebcs != NULL) { ebcs->ebi[5] = ((*ie_ptr)[1] >> 5) & 0x01; ebcs->ebi[6] = ((*ie_ptr)[1] >> 6) & 0x01; ebcs->ebi[7] = ((*ie_ptr)[1] >> 7) & 0x01; ebcs->ebi[8] = (*ie_ptr)[2] & 0x01; ebcs->ebi[9] = ((*ie_ptr)[2] >> 1) & 0x01; ebcs->ebi[10] = ((*ie_ptr)[2] >> 2) & 0x01; ebcs->ebi[11] = ((*ie_ptr)[2] >> 3) & 0x01; ebcs->ebi[12] = ((*ie_ptr)[2] >> 4) & 0x01; ebcs->ebi[13] = ((*ie_ptr)[2] >> 5) & 0x01; ebcs->ebi[14] = ((*ie_ptr)[2] >> 6) & 0x01; ebcs->ebi[15] = ((*ie_ptr)[2] >> 7) & 0x01; *ie_ptr += 3; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Location Area Identification Description: Provides an unambiguous identification of location areas within the area covered by the 3GPP system. Document Reference: 24.301 v10.2.0 Section 9.9.2.2 24.008 v10.2.0 Section 10.5.1.3 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_location_area_id_ie(LIBLTE_MME_LOCATION_AREA_ID_STRUCT* lai, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (lai != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = (((lai->mcc / 10) % 10) << 4) | ((lai->mcc / 100) % 10); if (lai->mnc < 100) { (*ie_ptr)[1] = 0xF0 | (lai->mcc % 10); (*ie_ptr)[2] = ((lai->mnc % 10) << 4) | ((lai->mnc / 10) % 10); } else { (*ie_ptr)[1] = ((lai->mnc % 10) << 4) | (lai->mcc % 10); (*ie_ptr)[2] = (((lai->mnc / 10) % 10) << 4) | ((lai->mnc / 100) % 10); } (*ie_ptr)[3] = (lai->lac >> 8) & 0xFF; (*ie_ptr)[4] = lai->lac & 0xFF; *ie_ptr += 5; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_location_area_id_ie(uint8** ie_ptr, LIBLTE_MME_LOCATION_AREA_ID_STRUCT* lai) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && lai != NULL) { lai->mcc = ((*ie_ptr)[0] & 0x0F) * 100; lai->mcc += (((*ie_ptr)[0] >> 4) & 0x0F) * 10; lai->mcc += (*ie_ptr)[1] & 0x0F; if ((((*ie_ptr)[1] >> 4) & 0x0F) == 0x0F) { lai->mnc = ((*ie_ptr)[2] & 0x0F) * 10; lai->mnc += ((*ie_ptr)[2] >> 4) & 0x0F; } else { lai->mnc = ((*ie_ptr)[1] >> 4) & 0x0F; lai->mnc += ((*ie_ptr)[2] & 0x0F) * 100; lai->mnc += (((*ie_ptr)[2] >> 4) & 0x0F) * 10; } lai->lac = (*ie_ptr)[3] << 8; lai->lac |= (*ie_ptr)[4]; *ie_ptr += 5; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Mobile Identity Description: Provides either the IMSI, TMSI/P-TMSI/M-TMSI, IMEI, IMEISV, or TMGI, associated with the optional MBMS session identity. Document Reference: 24.301 v10.2.0 Section 9.9.2.3 24.008 v10.2.0 Section 10.5.1.4 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT* mobile_id, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* id = NULL; uint32 id32 = 0; uint32 i; uint8 length = 0; bool odd = false; if (mobile_id != NULL && ie_ptr != NULL) { if (LIBLTE_MME_MOBILE_ID_TYPE_IMSI == mobile_id->type_of_id) { id = mobile_id->imsi; length = 8; odd = true; } else if (LIBLTE_MME_MOBILE_ID_TYPE_IMEI == mobile_id->type_of_id) { id = mobile_id->imei; length = 8; odd = true; } else if (LIBLTE_MME_MOBILE_ID_TYPE_IMEISV == mobile_id->type_of_id) { id = mobile_id->imeisv; length = 9; odd = false; } else if (LIBLTE_MME_MOBILE_ID_TYPE_TMSI == mobile_id->type_of_id) { id32 = mobile_id->tmsi; length = 5; odd = false; } } else { // TODO: Not handling these IDs return (err); } // Length **ie_ptr = length; *ie_ptr += 1; if (LIBLTE_MME_MOBILE_ID_TYPE_TMSI != mobile_id->type_of_id) { // | Identity digit 1 | odd/even | Id type | if (odd) { **ie_ptr = (id[0] << 4) | (1 << 3) | mobile_id->type_of_id; } else { **ie_ptr = (id[0] << 4) | (0 << 3) | mobile_id->type_of_id; } *ie_ptr += 1; // | Identity digit p+1 | Identity digit p | for (i = 0; i < 7; i++) { (*ie_ptr)[i] = (id[i * 2 + 2] << 4) | id[i * 2 + 1]; } *ie_ptr += 7; if (!odd) { **ie_ptr = 0xF0 | id[15]; *ie_ptr += 1; } err = LIBLTE_SUCCESS; } else { **ie_ptr = (0xFF << 4) | (0 << 3) | mobile_id->type_of_id; *ie_ptr += 1; // 4-Byte based ids **ie_ptr = (id32 >> 24) & 0xFF; *ie_ptr += 1; **ie_ptr = (id32 >> 16) & 0xFF; *ie_ptr += 1; **ie_ptr = (id32 >> 8) & 0xFF; *ie_ptr += 1; **ie_ptr = id32 & 0xFF; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_id_ie(uint8** ie_ptr, LIBLTE_MME_MOBILE_ID_STRUCT* mobile_id) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* id; uint32* id32; uint32 length; uint32 i; bool odd = false; if (ie_ptr != NULL && mobile_id != NULL) { length = **ie_ptr; *ie_ptr += 1; mobile_id->type_of_id = **ie_ptr & 0x07; if (LIBLTE_MME_MOBILE_ID_TYPE_IMSI == mobile_id->type_of_id) { id = mobile_id->imsi; odd = true; } else if (LIBLTE_MME_MOBILE_ID_TYPE_IMEI == mobile_id->type_of_id) { id = mobile_id->imei; odd = true; } else if (LIBLTE_MME_MOBILE_ID_TYPE_IMEISV == mobile_id->type_of_id) { id = mobile_id->imeisv; odd = false; } else if (LIBLTE_MME_MOBILE_ID_TYPE_TMSI == mobile_id->type_of_id) { id32 = &mobile_id->tmsi; odd = false; } else { // TODO: Not handling these IDs return (err); } if (mobile_id->type_of_id != LIBLTE_MME_MOBILE_ID_TYPE_TMSI) { id[0] = **ie_ptr >> 4; *ie_ptr += 1; for (i = 0; i < 7; i++) { id[i * 2 + 1] = (*ie_ptr)[i] & 0x0F; id[i * 2 + 2] = (*ie_ptr)[i] >> 4; } if (odd) { *ie_ptr += 7; } else { id[i * 2 + 1] = (*ie_ptr)[i] & 0xF; *ie_ptr += 8; } } else { *ie_ptr += 1; uint32 tmsi = 0; for (i = 0; i < 4; i++) { tmsi += ((*ie_ptr)[i] & 0xFF) << ((3 - i) * 8); } *id32 = tmsi; *ie_ptr += 4; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Mobile Station Classmark 2 Description: Provides the network with information concerning aspects of both high and low priority of the UE. Document Reference: 24.301 v10.2.0 Section 9.9.2.4 24.008 v10.2.0 Section 10.5.1.6 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_station_classmark_2_ie(LIBLTE_MME_MOBILE_STATION_CLASSMARK_2_STRUCT* ms_cm2, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ms_cm2 != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = 3; (*ie_ptr)[1] = (ms_cm2->rev_lev & 0x03) << 5; (*ie_ptr)[1] |= ms_cm2->es_ind << 4; (*ie_ptr)[1] |= ms_cm2->a5_1 << 3; (*ie_ptr)[1] |= ms_cm2->rf_power_cap & 0x07; (*ie_ptr)[2] = ms_cm2->ps_cap << 6; (*ie_ptr)[2] |= (ms_cm2->ss_screen_ind & 0x03) << 4; (*ie_ptr)[2] |= ms_cm2->sm_cap << 3; (*ie_ptr)[2] |= ms_cm2->vbs << 2; (*ie_ptr)[2] |= ms_cm2->vgcs << 1; (*ie_ptr)[2] |= ms_cm2->fc; (*ie_ptr)[3] = ms_cm2->cm3 << 7; (*ie_ptr)[3] |= ms_cm2->lcsva_cap << 5; (*ie_ptr)[3] |= ms_cm2->ucs2 << 4; (*ie_ptr)[3] |= ms_cm2->solsa << 3; (*ie_ptr)[3] |= ms_cm2->cmsp << 2; (*ie_ptr)[3] |= ms_cm2->a5_3 << 1; (*ie_ptr)[3] |= ms_cm2->a5_2; *ie_ptr += 4; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_station_classmark_2_ie(uint8** ie_ptr, LIBLTE_MME_MOBILE_STATION_CLASSMARK_2_STRUCT* ms_cm2) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && ms_cm2 != NULL) { ms_cm2->rev_lev = (LIBLTE_MME_REVISION_LEVEL_ENUM)(((*ie_ptr)[1] >> 5) & 0x03); ms_cm2->es_ind = ((*ie_ptr)[1] >> 4) & 0x01; ms_cm2->a5_1 = ((*ie_ptr)[1] >> 3) & 0x01; ms_cm2->rf_power_cap = (LIBLTE_MME_RF_POWER_CAPABILITY_ENUM)((*ie_ptr)[1] & 0x07); ms_cm2->ps_cap = ((*ie_ptr)[2] >> 6) & 0x01; ms_cm2->ss_screen_ind = (LIBLTE_MME_SS_SCREEN_INDICATOR_ENUM)(((*ie_ptr)[2] >> 4) & 0x03); ms_cm2->sm_cap = ((*ie_ptr)[2] >> 3) & 0x01; ms_cm2->vbs = ((*ie_ptr)[2] >> 2) & 0x01; ms_cm2->vgcs = ((*ie_ptr)[2] >> 1) & 0x01; ms_cm2->fc = (*ie_ptr)[2] & 0x01; ms_cm2->cm3 = ((*ie_ptr)[3] >> 7) & 0x01; ms_cm2->lcsva_cap = ((*ie_ptr)[3] >> 5) & 0x01; ms_cm2->ucs2 = ((*ie_ptr)[3] >> 4) & 0x01; ms_cm2->solsa = ((*ie_ptr)[3] >> 3) & 0x01; ms_cm2->cmsp = ((*ie_ptr)[3] >> 2) & 0x01; ms_cm2->a5_3 = ((*ie_ptr)[3] >> 1) & 0x01; ms_cm2->a5_2 = (*ie_ptr)[3] & 0x01; *ie_ptr += 4; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Mobile Station Classmark 3 Description: Provides the network with information concerning aspects of the UE. Document Reference: 24.301 v10.2.0 Section 9.9.2.5 24.008 v10.2.0 Section 10.5.1.7 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_station_classmark_3_ie(LIBLTE_MME_MOBILE_STATION_CLASSMARK_3_STRUCT* ms_cm3, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ms_cm3 != NULL && ie_ptr != NULL) { // TODO err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_station_classmark_3_ie(uint8** ie_ptr, LIBLTE_MME_MOBILE_STATION_CLASSMARK_3_STRUCT* ms_cm3) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && ms_cm3 != NULL) { // TODO err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: NAS Security Parameters From E-UTRA Description: Provides the UE with information that enables the UE to create a mapped UMTS security context. Document Reference: 24.301 v10.2.0 Section 9.9.2.6 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_nas_security_parameters_from_eutra_ie(uint8 dl_nas_count, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = dl_nas_count & 0x0F; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_security_parameters_from_eutra_ie(uint8** ie_ptr, uint8* dl_nas_count) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && dl_nas_count != NULL) { *dl_nas_count = (*ie_ptr)[0]; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: NAS Security Parameters To E-UTRA Description: Provides the UE with parameters that enables the UE to create a mapped EPS security context and take this context into use after inter-system handover to S1 mode. Document Reference: 24.301 v10.2.0 Section 9.9.2.7 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_nas_security_parameters_to_eutra_ie(LIBLTE_MME_NAS_SECURITY_PARAMETERS_TO_EUTRA_STRUCT* sec_params, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (sec_params != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = (sec_params->nonce_mme >> 24) & 0xFF; (*ie_ptr)[1] = (sec_params->nonce_mme >> 16) & 0xFF; (*ie_ptr)[2] = (sec_params->nonce_mme >> 8) & 0xFF; (*ie_ptr)[3] = sec_params->nonce_mme & 0xFF; (*ie_ptr)[4] = (sec_params->eea & 0x07) << 4; (*ie_ptr)[4] |= sec_params->eia & 0x07; (*ie_ptr)[5] = (sec_params->tsc_flag & 0x01) << 3; (*ie_ptr)[5] |= sec_params->nas_ksi & 0x07; *ie_ptr += 6; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_security_parameters_to_eutra_ie(uint8** ie_ptr, LIBLTE_MME_NAS_SECURITY_PARAMETERS_TO_EUTRA_STRUCT* sec_params) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && sec_params != NULL) { sec_params->nonce_mme = (*ie_ptr)[0] << 24; sec_params->nonce_mme |= (*ie_ptr)[1] << 16; sec_params->nonce_mme |= (*ie_ptr)[2] << 8; sec_params->nonce_mme |= (*ie_ptr)[3]; sec_params->eea = (LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_ENUM)(((*ie_ptr)[4] >> 4) & 0x07); sec_params->eia = (LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_ENUM)((*ie_ptr)[4] & 0x07); sec_params->tsc_flag = (LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_ENUM)(((*ie_ptr)[5] >> 3) & 0x01); sec_params->nas_ksi = (*ie_ptr)[5] & 0x07; *ie_ptr += 6; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: PLMN List Description: Provides a list of PLMN codes to the UE. Document Reference: 24.301 v10.2.0 Section 9.9.2.8 24.008 v10.2.0 Section 10.5.1.13 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_plmn_list_ie(LIBLTE_MME_PLMN_LIST_STRUCT* plmn_list, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (plmn_list != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = plmn_list->N_plmns * 3; for (i = 0; i < plmn_list->N_plmns; i++) { (*ie_ptr)[i * 3 + 0] = (((plmn_list->mcc[i] / 10) % 10) << 4) | ((plmn_list->mcc[i] / 100) % 10); if (plmn_list->mnc[i] < 100) { (*ie_ptr)[i * 3 + 1] = 0xF0 | (plmn_list->mcc[i] % 10); (*ie_ptr)[i * 3 + 2] = ((plmn_list->mnc[i] % 10) << 4) | ((plmn_list->mnc[i] / 10) % 10); } else { (*ie_ptr)[i * 3 + 1] = ((plmn_list->mnc[i] % 10) << 4) | (plmn_list->mcc[i] % 10); (*ie_ptr)[i * 3 + 2] = (((plmn_list->mnc[i] / 10) % 10) << 4) | ((plmn_list->mnc[i] / 100) % 10); } } *ie_ptr += (plmn_list->N_plmns * 3) + 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_plmn_list_ie(uint8** ie_ptr, LIBLTE_MME_PLMN_LIST_STRUCT* plmn_list) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && plmn_list != NULL) { plmn_list->N_plmns = (*ie_ptr)[0] / 3; for (i = 0; i < plmn_list->N_plmns; i++) { plmn_list->mcc[i] = ((*ie_ptr)[i * 3 + 0] & 0x0F) * 100; plmn_list->mcc[i] += (((*ie_ptr)[i * 3 + 0] >> 4) & 0x0F) * 10; plmn_list->mcc[i] += (*ie_ptr)[i * 3 + 1] & 0x0F; if ((((*ie_ptr)[i * 3 + 1] >> 4) & 0x0F) == 0x0F) { plmn_list->mnc[i] = ((*ie_ptr)[i * 3 + 2] & 0x0F) * 10; plmn_list->mnc[i] += ((*ie_ptr)[i * 3 + 2] >> 4) & 0x0F; } else { plmn_list->mnc[i] = ((*ie_ptr)[i * 3 + 1] >> 4) & 0x0F; plmn_list->mnc[i] += ((*ie_ptr)[i * 3 + 2] & 0x0F) * 100; plmn_list->mnc[i] += (((*ie_ptr)[i * 3 + 2] >> 4) & 0x0F) * 10; } } *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Spare Half Octet Description: Used in the description of EMM and ESM messages when an odd number of half octet type 1 information elements are used. Document Reference: 24.301 v10.2.0 Section 9.9.2.9 *********************************************************************/ /********************************************************************* IE Name: Supported Codec List Description: Provides the network with information about the speech codecs supported by the UE. Document Reference: 24.301 v10.2.0 Section 9.9.2.10 24.008 v10.2.0 Section 10.5.4.32 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_supported_codec_list_ie(LIBLTE_MME_SUPPORTED_CODEC_LIST_STRUCT* supported_codec_list, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (supported_codec_list != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = supported_codec_list->N_supported_codecs * 4; for (i = 0; i < supported_codec_list->N_supported_codecs; i++) { (*ie_ptr)[1 + i * 4 + 0] = supported_codec_list->supported_codec[i].sys_id; (*ie_ptr)[1 + i * 4 + 1] = 2; (*ie_ptr)[1 + i * 4 + 2] = (supported_codec_list->supported_codec[i].codec_bitmap >> 8) & 0xFF; (*ie_ptr)[1 + i * 4 + 3] = supported_codec_list->supported_codec[i].codec_bitmap & 0xFF; } *ie_ptr += (supported_codec_list->N_supported_codecs * 4) + 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_supported_codec_list_ie(uint8** ie_ptr, LIBLTE_MME_SUPPORTED_CODEC_LIST_STRUCT* supported_codec_list) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && supported_codec_list != NULL) { supported_codec_list->N_supported_codecs = ((*ie_ptr)[0] / 4); for (i = 0; i < supported_codec_list->N_supported_codecs; i++) { supported_codec_list->supported_codec[i].sys_id = (*ie_ptr)[1 + i * 4 + 0]; supported_codec_list->supported_codec[i].codec_bitmap = (*ie_ptr)[1 + i * 4 + 2] << 8; supported_codec_list->supported_codec[i].codec_bitmap |= (*ie_ptr)[1 + i * 4 + 3]; } *ie_ptr += (supported_codec_list->N_supported_codecs * 4) + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Additional Update Result Description: Provides additional information about the result of a combined attached procedure or a combined tracking area updating procedure. Document Reference: 24.301 v10.2.0 Section 9.9.3.0A *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_additional_update_result_ie(LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM result, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= result << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_additional_update_result_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM* result) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (result != NULL && ie_ptr != NULL) { *result = (LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM)((**ie_ptr >> bit_offset) & 0x03); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Additional Update Type Description: Provides additional information about the type of request for a combined attach or a combined tracking area updating procedure. Document Reference: 24.301 v10.2.0 Section 9.9.3.0B *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_additional_update_type_ie(LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM aut, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= aut << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_additional_update_type_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM* aut) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && aut != NULL) { *aut = (LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_ENUM)((**ie_ptr >> bit_offset) & 0x01); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Authentication Failure Parameter Description: Provides the network with the necessary information to begin a re-authentication procedure in the case of a 'Synch failure', following a UMTS or EPS authentication challenge. Document Reference: 24.301 v10.2.0 Section 9.9.3.1 24.008 v10.2.0 Section 10.5.3.2.2 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_failure_parameter_ie(uint8* auth_fail_param, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (auth_fail_param != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = 14; for (i = 0; i < 14; i++) { (*ie_ptr)[i + 1] = auth_fail_param[i]; } *ie_ptr += 15; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_failure_parameter_ie(uint8** ie_ptr, uint8* auth_fail_param) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && auth_fail_param != NULL) { for (i = 0; i < 14; i++) { auth_fail_param[i] = (*ie_ptr)[i + 1]; } *ie_ptr += 15; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Authentication Parameter AUTN Description: Provides the UE with a means of authenticating the network. Document Reference: 24.301 v10.2.0 Section 9.9.3.2 24.008 v10.2.0 Section 10.5.3.1.1 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_parameter_autn_ie(uint8* autn, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (autn != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = 16; for (i = 0; i < 16; i++) { (*ie_ptr)[i + 1] = autn[i]; } *ie_ptr += 17; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_parameter_autn_ie(uint8** ie_ptr, uint8* autn) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && autn != NULL) { for (i = 0; i < 16; i++) { autn[i] = (*ie_ptr)[i + 1]; } *ie_ptr += 17; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Authentication Parameter RAND Description: Provides the UE with a non-predictable number to be used to calculate the authentication signature SRES and the ciphering key Kc (for a GSM authentication challenge), or the response RES and both the ciphering key CK and the integrity key IK (for a UMTS authentication challenge). Document Reference: 24.301 v10.2.0 Section 9.9.3.3 24.008 v10.2.0 Section 10.5.3.1 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_parameter_rand_ie(uint8* rand_val, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (rand_val != NULL && ie_ptr != NULL) { for (i = 0; i < 16; i++) { (*ie_ptr)[i] = rand_val[i]; } *ie_ptr += 16; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_parameter_rand_ie(uint8** ie_ptr, uint8* rand_val) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && rand_val != NULL) { for (i = 0; i < 16; i++) { rand_val[i] = (*ie_ptr)[i]; } *ie_ptr += 16; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Authentication Response Parameter Description: Provides the network with the authentication response calculated in the USIM. Document Reference: 24.301 v10.2.0 Section 9.9.3.4 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_parameter_ie(uint8* res, int res_len, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (res != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = res_len; *ie_ptr += 1; for (i = 0; i < res_len; i++) { (*ie_ptr)[i] = res[i]; } *ie_ptr += res_len; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_response_parameter_ie(uint8** ie_ptr, uint8* res) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && res != NULL) { for (i = 0; i < (*ie_ptr)[0]; i++) { res[i] = (*ie_ptr)[i + 1]; } *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Ciphering Key Sequence Number Description: Makes it possible for the network to identify the ciphering key Kc which is stored in the UE without invoking the authentication procedure. Document Reference: 24.301 v10.2.0 Section 9.9.3.4A 24.008 v10.2.0 Section 10.5.1.2 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_ciphering_key_sequence_number_ie(uint8 key_seq, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] |= (key_seq & 0x07) << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_ciphering_key_sequence_number_ie(uint8** ie_ptr, uint8 bit_offset, uint8* key_seq) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && key_seq != NULL) { *key_seq = ((*ie_ptr)[0] >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: CSFB Response Description: Indicates whether the UE accepts or rejects a paging for CS fallback. Document Reference: 24.301 v10.2.0 Section 9.9.3.5 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_csfb_response_ie(uint8 csfb_resp, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] |= (csfb_resp & 0x07) << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_csfb_response_ie(uint8** ie_ptr, uint8 bit_offset, uint8* csfb_resp) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && csfb_resp != NULL) { *csfb_resp = ((*ie_ptr)[0] & 0x07) >> bit_offset; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Daylight Saving Time Description: Encodes the daylight saving time in steps of 1 hour. Document Reference: 24.301 v10.2.0 Section 9.9.3.6 24.008 v10.2.0 Section 10.5.3.12 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_daylight_saving_time_ie(LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM dst, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = 1; (*ie_ptr)[1] = dst & 0x03; *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_daylight_saving_time_ie(uint8** ie_ptr, LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM* dst) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && dst != NULL) { *dst = (LIBLTE_MME_DAYLIGHT_SAVING_TIME_ENUM)((*ie_ptr)[1] & 0x03); *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Detach Type Description: Indicates the type of detach. Document Reference: 24.301 v10.2.0 Section 9.9.3.7 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_detach_type_ie(LIBLTE_MME_DETACH_TYPE_STRUCT* detach_type, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (detach_type != NULL && ie_ptr != NULL) { (*ie_ptr)[0] |= (detach_type->switch_off & 0x01) << (3 + bit_offset); (*ie_ptr)[0] |= (detach_type->type_of_detach & 0x07) << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_detach_type_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_DETACH_TYPE_STRUCT* detach_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && detach_type != NULL) { detach_type->switch_off = ((*ie_ptr)[0] >> (3 + bit_offset)) & 0x01; detach_type->type_of_detach = ((*ie_ptr)[0] >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: DRX Parameter Description: Indicates whether the UE uses DRX mode or not. Document Reference: 24.301 v10.2.0 Section 9.9.3.8 24.008 v10.2.0 Section 10.5.5.6 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_drx_parameter_ie(LIBLTE_MME_DRX_PARAMETER_STRUCT* drx_param, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (drx_param != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = drx_param->split_pg_cycle_code; (*ie_ptr)[1] = (drx_param->drx_cycle_len_coeff_and_value & 0x0F) << 4; (*ie_ptr)[1] |= (drx_param->split_on_ccch & 0x01) << 3; (*ie_ptr)[1] |= drx_param->non_drx_timer & 0x07; *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_drx_parameter_ie(uint8** ie_ptr, LIBLTE_MME_DRX_PARAMETER_STRUCT* drx_param) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && drx_param != NULL) { drx_param->split_pg_cycle_code = (*ie_ptr)[0]; drx_param->drx_cycle_len_coeff_and_value = ((*ie_ptr)[1] >> 4) & 0x0F; drx_param->split_on_ccch = ((*ie_ptr)[1] >> 3) & 0x01; drx_param->non_drx_timer = (LIBLTE_MME_NON_DRX_TIMER_ENUM)((*ie_ptr)[1] & 0x07); *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: EMM Cause Description: Indicates the reason why an EMM request from the UE is rejected by the network. Document Reference: 24.301 v10.2.0 Section 9.9.3.9 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_emm_cause_ie(uint8 emm_cause, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr = emm_cause; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_cause_ie(uint8** ie_ptr, uint8* emm_cause) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && emm_cause != NULL) { *emm_cause = **ie_ptr; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: EPS Attach Result Description: Specifies the result of an attach procedure. Document Reference: 24.301 v10.2.0 Section 9.9.3.10 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_attach_result_ie(uint8 result, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= result << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_attach_result_ie(uint8** ie_ptr, uint8 bit_offset, uint8* result) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && result != NULL) { *result = (**ie_ptr >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: EPS Attach Type Description: Indicates the type of the requested attach. Document Reference: 24.301 v10.2.0 Section 9.9.3.11 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_attach_type_ie(uint8 attach_type, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= attach_type << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_attach_type_ie(uint8** ie_ptr, uint8 bit_offset, uint8* attach_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && attach_type != NULL) { *attach_type = (**ie_ptr >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: EPS Mobile Identity Description: Provides either the IMSI, the GUTI, or the IMEI. Document Reference: 24.301 v10.2.0 Section 9.9.3.12 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_mobile_id_ie(LIBLTE_MME_EPS_MOBILE_ID_STRUCT* eps_mobile_id, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* id; uint32 i; if (eps_mobile_id != NULL && ie_ptr != NULL) { if (LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI == eps_mobile_id->type_of_id) { **ie_ptr = 11; *ie_ptr += 1; **ie_ptr = 0xF0 | eps_mobile_id->type_of_id; *ie_ptr += 1; **ie_ptr = (((eps_mobile_id->guti.mcc / 10) % 10) << 4) | ((eps_mobile_id->guti.mcc / 100) % 10); *ie_ptr += 1; if (eps_mobile_id->guti.mnc < 100) { **ie_ptr = 0xF0 | (eps_mobile_id->guti.mcc % 10); *ie_ptr += 1; **ie_ptr = ((eps_mobile_id->guti.mnc % 10) << 4) | ((eps_mobile_id->guti.mnc / 10) % 10); *ie_ptr += 1; } else { **ie_ptr = ((eps_mobile_id->guti.mnc % 10) << 4) | (eps_mobile_id->guti.mcc % 10); *ie_ptr += 1; **ie_ptr = (((eps_mobile_id->guti.mnc / 10) % 10) << 4) | ((eps_mobile_id->guti.mnc / 100) % 10); *ie_ptr += 1; } **ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0xFF; *ie_ptr += 1; **ie_ptr = eps_mobile_id->guti.mme_group_id & 0xFF; *ie_ptr += 1; **ie_ptr = eps_mobile_id->guti.mme_code; *ie_ptr += 1; **ie_ptr = (eps_mobile_id->guti.m_tmsi >> 24) & 0xFF; *ie_ptr += 1; **ie_ptr = (eps_mobile_id->guti.m_tmsi >> 16) & 0xFF; *ie_ptr += 1; **ie_ptr = (eps_mobile_id->guti.m_tmsi >> 8) & 0xFF; *ie_ptr += 1; **ie_ptr = eps_mobile_id->guti.m_tmsi & 0xFF; *ie_ptr += 1; } else { if (LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI == eps_mobile_id->type_of_id) { id = eps_mobile_id->imsi; } else { id = eps_mobile_id->imei; } **ie_ptr = 8; *ie_ptr += 1; **ie_ptr = (id[0] << 4) | (1 << 3) | eps_mobile_id->type_of_id; *ie_ptr += 1; for (i = 0; i < 7; i++) { **ie_ptr = (id[i * 2 + 2] << 4) | id[i * 2 + 1]; *ie_ptr += 1; } } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_mobile_id_ie(uint8** ie_ptr, LIBLTE_MME_EPS_MOBILE_ID_STRUCT* eps_mobile_id) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* id; uint32 length; uint32 i; if (ie_ptr != NULL && eps_mobile_id != NULL) { length = **ie_ptr; *ie_ptr += 1; eps_mobile_id->type_of_id = **ie_ptr & 0x07; if (LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI == eps_mobile_id->type_of_id) { *ie_ptr += 1; eps_mobile_id->guti.mcc = (**ie_ptr & 0x0F) * 100; eps_mobile_id->guti.mcc += ((**ie_ptr >> 4) & 0x0F) * 10; *ie_ptr += 1; eps_mobile_id->guti.mcc += **ie_ptr & 0x0F; if (((**ie_ptr >> 4) & 0x0F) == 0x0F) { *ie_ptr += 1; eps_mobile_id->guti.mnc = (**ie_ptr & 0x0F) * 10; eps_mobile_id->guti.mnc += (**ie_ptr >> 4) & 0x0F; *ie_ptr += 1; } else { eps_mobile_id->guti.mnc = (**ie_ptr >> 4) & 0x0F; *ie_ptr += 1; eps_mobile_id->guti.mnc += (**ie_ptr & 0x0F) * 100; eps_mobile_id->guti.mnc += ((**ie_ptr >> 4) & 0x0F) * 10; *ie_ptr += 1; } eps_mobile_id->guti.mme_group_id = **ie_ptr << 8; *ie_ptr += 1; eps_mobile_id->guti.mme_group_id |= **ie_ptr; *ie_ptr += 1; eps_mobile_id->guti.mme_code = **ie_ptr; *ie_ptr += 1; eps_mobile_id->guti.m_tmsi = **ie_ptr << 24; *ie_ptr += 1; eps_mobile_id->guti.m_tmsi |= **ie_ptr << 16; *ie_ptr += 1; eps_mobile_id->guti.m_tmsi |= **ie_ptr << 8; *ie_ptr += 1; eps_mobile_id->guti.m_tmsi |= **ie_ptr; *ie_ptr += 1; } else { if (LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI == eps_mobile_id->type_of_id) { id = eps_mobile_id->imsi; } else { id = eps_mobile_id->imei; } id[0] = **ie_ptr >> 4; *ie_ptr += 1; for (i = 0; i < 7; i++) { id[i * 2 + 1] = **ie_ptr & 0x0F; id[i * 2 + 2] = **ie_ptr >> 4; *ie_ptr += 1; } } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: EPS Network Feature Support Description: Indicates whether certain features are supported by the network. Document Reference: 24.301 v10.2.0 Section 9.9.3.12A *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_network_feature_support_ie(LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT* eps_nfs, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (eps_nfs != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = 1; (*ie_ptr)[1] = eps_nfs->esrps << 5; (*ie_ptr)[1] |= (eps_nfs->cs_lcs & 0x03) << 3; (*ie_ptr)[1] |= eps_nfs->epc_lcs << 2; (*ie_ptr)[1] |= eps_nfs->emc_bs << 1; (*ie_ptr)[1] |= eps_nfs->ims_vops; *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_network_feature_support_ie(uint8** ie_ptr, LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT* eps_nfs) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && eps_nfs != NULL) { int ie_len = *ie_ptr[0]; eps_nfs->esrps = ((*ie_ptr)[1] >> 5) & 0x01; eps_nfs->cs_lcs = (LIBLTE_MME_CS_LCS_ENUM)(((*ie_ptr)[1] >> 3) & 0x03); eps_nfs->epc_lcs = ((*ie_ptr)[1] >> 2) & 0x01; eps_nfs->emc_bs = ((*ie_ptr)[1] >> 1) & 0x01; eps_nfs->ims_vops = (*ie_ptr)[1] & 0x01; *ie_ptr += (ie_len + 1); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: EPS Update Result Description: Specifies the result of the associated updating procedure. Document Reference: 24.301 v10.2.0 Section 9.9.3.13 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_update_result_ie(uint8 eps_update_res, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] |= (eps_update_res & 0x07) << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_update_result_ie(uint8** ie_ptr, uint8 bit_offset, uint8* eps_update_res) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && eps_update_res != NULL) { *eps_update_res = ((*ie_ptr)[0] >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: EPS Update Type Description: Specifies the area the updating procedure is associated with. Document Reference: 24.301 v10.2.0 Section 9.9.3.14 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_update_type_ie(LIBLTE_MME_EPS_UPDATE_TYPE_STRUCT* eps_update_type, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (eps_update_type != NULL && ie_ptr != NULL) { (*ie_ptr)[0] |= (eps_update_type->active_flag & 0x01) << (bit_offset + 3); (*ie_ptr)[0] |= (eps_update_type->type & 0x07) << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_update_type_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_EPS_UPDATE_TYPE_STRUCT* eps_update_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && eps_update_type != NULL) { eps_update_type->active_flag = ((*ie_ptr)[0] >> (bit_offset + 3)) & 0x01; eps_update_type->type = (LIBLTE_MME_EPS_UPDATE_TYPE_ENUM)(((*ie_ptr)[0] >> bit_offset) & 0x07); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: ESM Message Container Description: Enables piggybacked transfer of a single ESM message within an EMM message. Document Reference: 24.301 v10.2.0 Section 9.9.3.15 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_message_container_ie(LIBLTE_BYTE_MSG_STRUCT* esm_msg, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (esm_msg != NULL && ie_ptr != NULL && esm_msg->N_bytes <= LIBLTE_MAX_MSG_SIZE_BYTES) { (*ie_ptr)[0] = esm_msg->N_bytes >> 8; (*ie_ptr)[1] = esm_msg->N_bytes & 0xFF; for (i = 0; i < esm_msg->N_bytes; i++) { (*ie_ptr)[2 + i] = esm_msg->msg[i]; } *ie_ptr += esm_msg->N_bytes + 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_message_container_ie(uint8** ie_ptr, LIBLTE_BYTE_MSG_STRUCT* esm_msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && esm_msg != NULL) { esm_msg->N_bytes = (*ie_ptr)[0] << 8; esm_msg->N_bytes |= (*ie_ptr)[1]; if (esm_msg->N_bytes > LIBLTE_MAX_MSG_SIZE_BYTES) { return err; } for (i = 0; i < esm_msg->N_bytes; i++) { esm_msg->msg[i] = (*ie_ptr)[2 + i]; } *ie_ptr += esm_msg->N_bytes + 2; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: GPRS Timer Description: Specifies GPRS specific timer values. Document Reference: 24.301 v10.2.0 Section 9.9.3.16 24.008 v10.2.0 Section 10.5.7.3 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_gprs_timer_ie(LIBLTE_MME_GPRS_TIMER_STRUCT* timer, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (timer != NULL && ie_ptr != NULL) { **ie_ptr = ((timer->unit & 0x07) << 5) | (timer->value & 0x1F); *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_gprs_timer_ie(uint8** ie_ptr, LIBLTE_MME_GPRS_TIMER_STRUCT* timer) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && timer != NULL) { timer->unit = **ie_ptr >> 5; timer->value = **ie_ptr & 0x1F; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: GPRS Timer 2 Description: Specifies GPRS specific timer values. Document Reference: 24.301 v10.2.0 Section 9.9.3.16A 24.008 v10.2.0 Section 10.5.7.4 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_gprs_timer_2_ie(uint8 value, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr = 1; *ie_ptr += 1; **ie_ptr = value; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_gprs_timer_2_ie(uint8** ie_ptr, uint8* value) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && value != NULL) { *ie_ptr += 1; *value = **ie_ptr; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: GPRS Timer 3 Description: Specifies GPRS specific timer values. Document Reference: 24.301 v10.2.0 Section 9.9.3.16B 24.008 v10.2.0 Section 10.5.7.4A *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_gprs_timer_3_ie(LIBLTE_MME_GPRS_TIMER_3_STRUCT* timer, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (timer != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = 1; (*ie_ptr)[1] = ((timer->unit & 0x07) << 5) | (timer->value & 0x1F); *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_gprs_timer_3_ie(uint8** ie_ptr, LIBLTE_MME_GPRS_TIMER_3_STRUCT* timer) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && timer != NULL) { timer->unit = (*ie_ptr)[1] >> 5; timer->value = (*ie_ptr)[1] & 0x1F; *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Identity Type 2 Description: Specifies which identity is requested. Document Reference: 24.301 v10.2.0 Section 9.9.3.17 24.008 v10.2.0 Section 10.5.5.9 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_identity_type_2_ie(uint8 id_type, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= id_type << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_type_2_ie(uint8** ie_ptr, uint8 bit_offset, uint8* id_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && id_type != NULL) { *id_type = (**ie_ptr >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: IMEISV Request Description: Indicates that the IMEISV shall be included by the UE in the authentication and ciphering response message. Document Reference: 24.301 v10.2.0 Section 9.9.3.18 24.008 v10.2.0 Section 10.5.5.10 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_imeisv_request_ie(LIBLTE_MME_IMEISV_REQUEST_ENUM imeisv_req, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= imeisv_req << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_imeisv_request_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_IMEISV_REQUEST_ENUM* imeisv_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && imeisv_req != NULL) { *imeisv_req = (LIBLTE_MME_IMEISV_REQUEST_ENUM)((**ie_ptr >> bit_offset) & 0x07); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: KSI And Sequence Number Description: Provides the network with the key set identifier (KSI) value of the current EPS security context and the 5 least significant bits of the NAS COUNT value applicable for the message including this information element. Document Reference: 24.301 v10.2.0 Section 9.9.3.19 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_ksi_and_sequence_number_ie(LIBLTE_MME_KSI_AND_SEQUENCE_NUMBER_STRUCT* ksi_and_seq_num, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ksi_and_seq_num != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = (ksi_and_seq_num->ksi & 0x07) << 5; (*ie_ptr)[0] |= ksi_and_seq_num->seq_num & 0x1F; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_ksi_and_sequence_number_ie(uint8** ie_ptr, LIBLTE_MME_KSI_AND_SEQUENCE_NUMBER_STRUCT* ksi_and_seq_num) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && ksi_and_seq_num != NULL) { ksi_and_seq_num->ksi = ((*ie_ptr)[0] >> 5) & 0x07; ksi_and_seq_num->seq_num = (*ie_ptr)[0] & 0x1F; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: MS Network Capability Description: Provides the network with information concerning aspects of the UE related to GPRS. Document Reference: 24.301 v10.2.0 Section 9.9.3.20 24.008 v10.2.0 Section 10.5.5.12 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_ms_network_capability_ie(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT* ms_network_cap, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ms_network_cap != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = 3; (*ie_ptr)[1] = ms_network_cap->gea[1] << 7; (*ie_ptr)[1] |= ms_network_cap->sm_cap_ded << 6; (*ie_ptr)[1] |= ms_network_cap->sm_cap_gprs << 5; (*ie_ptr)[1] |= ms_network_cap->ucs2 << 4; (*ie_ptr)[1] |= (ms_network_cap->ss_screening & 0x03) << 2; (*ie_ptr)[1] |= ms_network_cap->solsa << 1; (*ie_ptr)[1] |= ms_network_cap->revision; (*ie_ptr)[2] = ms_network_cap->pfc << 7; (*ie_ptr)[2] |= ms_network_cap->gea[2] << 6; (*ie_ptr)[2] |= ms_network_cap->gea[3] << 5; (*ie_ptr)[2] |= ms_network_cap->gea[4] << 4; (*ie_ptr)[2] |= ms_network_cap->gea[5] << 3; (*ie_ptr)[2] |= ms_network_cap->gea[6] << 2; (*ie_ptr)[2] |= ms_network_cap->gea[7] << 1; (*ie_ptr)[2] |= ms_network_cap->lcsva; (*ie_ptr)[3] = ms_network_cap->ho_g2u_via_iu << 7; (*ie_ptr)[3] |= ms_network_cap->ho_g2e_via_s1 << 6; (*ie_ptr)[3] |= ms_network_cap->emm_comb << 5; (*ie_ptr)[3] |= ms_network_cap->isr << 4; (*ie_ptr)[3] |= ms_network_cap->srvcc << 3; (*ie_ptr)[3] |= ms_network_cap->epc << 2; (*ie_ptr)[3] |= ms_network_cap->nf << 1; *ie_ptr += 4; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_ms_network_capability_ie(uint8** ie_ptr, LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT* ms_network_cap) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && ms_network_cap != NULL) { ms_network_cap->gea[1] = ((*ie_ptr)[1] >> 7) & 0x01; ms_network_cap->sm_cap_ded = ((*ie_ptr)[1] >> 6) & 0x01; ms_network_cap->sm_cap_gprs = ((*ie_ptr)[1] >> 5) & 0x01; ms_network_cap->ucs2 = ((*ie_ptr)[1] >> 4) & 0x01; ms_network_cap->ss_screening = (LIBLTE_MME_SS_SCREENING_INDICATOR_ENUM)(((*ie_ptr)[1] >> 2) & 0x03); ms_network_cap->solsa = ((*ie_ptr)[1] >> 1) & 0x01; ms_network_cap->revision = (*ie_ptr)[1] & 0x01; ms_network_cap->pfc = ((*ie_ptr)[2] >> 7) & 0x01; ms_network_cap->gea[2] = ((*ie_ptr)[2] >> 6) & 0x01; ms_network_cap->gea[3] = ((*ie_ptr)[2] >> 5) & 0x01; ms_network_cap->gea[4] = ((*ie_ptr)[2] >> 4) & 0x01; ms_network_cap->gea[5] = ((*ie_ptr)[2] >> 3) & 0x01; ms_network_cap->gea[6] = ((*ie_ptr)[2] >> 2) & 0x01; ms_network_cap->gea[7] = ((*ie_ptr)[2] >> 1) & 0x01; ms_network_cap->lcsva = (*ie_ptr)[2] & 0x01; ms_network_cap->ho_g2u_via_iu = ((*ie_ptr)[3] >> 7) & 0x01; ms_network_cap->ho_g2e_via_s1 = ((*ie_ptr)[3] >> 6) & 0x01; ms_network_cap->emm_comb = ((*ie_ptr)[3] >> 5) & 0x01; ms_network_cap->isr = ((*ie_ptr)[3] >> 4) & 0x01; ms_network_cap->srvcc = ((*ie_ptr)[3] >> 3) & 0x01; ms_network_cap->epc = ((*ie_ptr)[3] >> 2) & 0x01; ms_network_cap->nf = ((*ie_ptr)[3] >> 1) & 0x01; *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: NAS Key Set Identifier Description: Provides the NAS key set identifier that is allocated by the network. Document Reference: 24.301 v10.2.0 Section 9.9.3.21 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_nas_key_set_id_ie(LIBLTE_MME_NAS_KEY_SET_ID_STRUCT* nas_ksi, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (nas_ksi != NULL && ie_ptr != NULL) { **ie_ptr |= nas_ksi->tsc_flag << (bit_offset + 3); **ie_ptr |= nas_ksi->nas_ksi << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_key_set_id_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_NAS_KEY_SET_ID_STRUCT* nas_ksi) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && nas_ksi != NULL) { nas_ksi->tsc_flag = (LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_ENUM)((**ie_ptr >> (bit_offset + 3)) & 0x01); nas_ksi->nas_ksi = (**ie_ptr >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: NAS Message Container Description: Encapsulates the SMS messages transferred between the UE and the network. Document Reference: 24.301 v10.2.0 Section 9.9.3.22 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_nas_message_container_ie(LIBLTE_BYTE_MSG_STRUCT* nas_msg, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (nas_msg != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = nas_msg->N_bytes & 0xFF; for (i = 0; i < nas_msg->N_bytes; i++) { (*ie_ptr)[1 + i] = nas_msg->msg[i]; } *ie_ptr += nas_msg->N_bytes + 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_message_container_ie(uint8** ie_ptr, LIBLTE_BYTE_MSG_STRUCT* nas_msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && nas_msg != NULL) { nas_msg->N_bytes = (*ie_ptr)[0]; for (i = 0; i < nas_msg->N_bytes; i++) { nas_msg->msg[i] = (*ie_ptr)[1 + i]; } *ie_ptr += nas_msg->N_bytes + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: NAS Security Algorithms Description: Indicates the algorithms to be used for ciphering and integrity protection. Document Reference: 24.301 v10.2.0 Section 9.9.3.23 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_nas_security_algorithms_ie(LIBLTE_MME_NAS_SECURITY_ALGORITHMS_STRUCT* nas_sec_algs, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (nas_sec_algs != NULL && ie_ptr != NULL) { **ie_ptr = (nas_sec_algs->type_of_eea << 4) | (nas_sec_algs->type_of_eia); *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_nas_security_algorithms_ie(uint8** ie_ptr, LIBLTE_MME_NAS_SECURITY_ALGORITHMS_STRUCT* nas_sec_algs) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && nas_sec_algs != NULL) { nas_sec_algs->type_of_eea = (LIBLTE_MME_TYPE_OF_CIPHERING_ALGORITHM_ENUM)((**ie_ptr >> 4) & 0x07); nas_sec_algs->type_of_eia = (LIBLTE_MME_TYPE_OF_INTEGRITY_ALGORITHM_ENUM)(**ie_ptr & 0x07); *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Network Name Description: Passes a text string to the UE. Document Reference: 24.301 v10.2.0 Section 9.9.3.24 24.008 v10.2.0 Section 10.5.3.5A *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_network_name_ie(LIBLTE_MME_NETWORK_NAME_STRUCT* net_name, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; uint32 bit_offset; uint32 byte_offset; const char* char_str = net_name->name; if (net_name != NULL && ie_ptr != NULL) { bit_offset = 0; byte_offset = 2; for (i = 0; i < strnlen(char_str, LIBLTE_STRING_LEN); i++) { if (char_str[i] == 0x0A || char_str[i] == 0x0D || (char_str[i] >= 0x20 && char_str[i] <= 0x3F) || (char_str[i] >= 0x41 && char_str[i] <= 0x5A) || (char_str[i] >= 0x61 && char_str[i] <= 0x7A)) { switch (bit_offset) { case 0: (*ie_ptr)[byte_offset] = char_str[i]; bit_offset = 7; break; case 1: (*ie_ptr)[byte_offset] |= (char_str[i] << 1); bit_offset = 0; byte_offset++; break; case 2: (*ie_ptr)[byte_offset] |= ((char_str[i] << 2) & 0xFC); byte_offset++; (*ie_ptr)[byte_offset] = ((char_str[i] >> 6) & 0x01); bit_offset = 1; break; case 3: (*ie_ptr)[byte_offset] |= ((char_str[i] << 3) & 0xF8); byte_offset++; (*ie_ptr)[byte_offset] = ((char_str[i] >> 5) & 0x03); bit_offset = 2; break; case 4: (*ie_ptr)[byte_offset] |= ((char_str[i] << 4) & 0xF0); byte_offset++; (*ie_ptr)[byte_offset] = ((char_str[i] >> 4) & 0x07); bit_offset = 3; break; case 5: (*ie_ptr)[byte_offset] |= ((char_str[i] << 5) & 0xE0); byte_offset++; (*ie_ptr)[byte_offset] = ((char_str[i] >> 3) & 0x0F); bit_offset = 4; break; case 6: (*ie_ptr)[byte_offset] |= ((char_str[i] << 6) & 0xC0); byte_offset++; (*ie_ptr)[byte_offset] = ((char_str[i] >> 2) & 0x1F); bit_offset = 5; break; case 7: (*ie_ptr)[byte_offset] |= ((char_str[i] << 7) & 0x80); byte_offset++; (*ie_ptr)[byte_offset] = ((char_str[i] >> 1) & 0x3F); bit_offset = 6; break; } } } if (0 == bit_offset) { (*ie_ptr)[0] = byte_offset - 1; (*ie_ptr)[1] = 0x80 | ((net_name->add_ci & 0x01) << 3); *ie_ptr += byte_offset; } else { (*ie_ptr)[0] = byte_offset; (*ie_ptr)[1] = 0x80 | ((net_name->add_ci & 0x01) << 3) | ((8 - bit_offset) & 0x07); *ie_ptr += byte_offset + 1; } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8** ie_ptr, LIBLTE_MME_NETWORK_NAME_STRUCT* net_name) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; uint32 bit_offset; uint32 byte_offset; uint32 N_bytes; uint8 spare_field; char tmp_char; uint32 str_cnt; if (ie_ptr != NULL && net_name != NULL) { net_name->add_ci = (LIBLTE_MME_ADD_CI_ENUM)(((*ie_ptr)[1] >> 3) & 0x01); spare_field = (*ie_ptr)[1] & 0x07; N_bytes = (*ie_ptr)[0]; bit_offset = 0; byte_offset = 2; str_cnt = 0; while (byte_offset < N_bytes && str_cnt < LIBLTE_STRING_LEN) { switch (bit_offset) { case 0: tmp_char = (*ie_ptr)[byte_offset] & 0x7F; bit_offset = 7; break; case 1: tmp_char = ((*ie_ptr)[byte_offset] >> 1) & 0x7F; bit_offset = 0; byte_offset++; break; case 2: tmp_char = ((*ie_ptr)[byte_offset] >> 2) & 0x3F; byte_offset++; tmp_char |= ((*ie_ptr)[byte_offset] << 6) & 0x40; bit_offset = 1; break; case 3: tmp_char = ((*ie_ptr)[byte_offset] >> 3) & 0x1F; byte_offset++; tmp_char |= ((*ie_ptr)[byte_offset] << 5) & 0x60; bit_offset = 2; break; case 4: tmp_char = ((*ie_ptr)[byte_offset] >> 4) & 0x0F; byte_offset++; tmp_char |= ((*ie_ptr)[byte_offset] << 4) & 0x70; bit_offset = 3; break; case 5: tmp_char = ((*ie_ptr)[byte_offset] >> 5) & 0x07; byte_offset++; tmp_char |= ((*ie_ptr)[byte_offset] << 3) & 0x78; bit_offset = 4; break; case 6: tmp_char = ((*ie_ptr)[byte_offset] >> 6) & 0x03; byte_offset++; tmp_char |= ((*ie_ptr)[byte_offset] << 2) & 0x7C; bit_offset = 5; break; case 7: tmp_char = ((*ie_ptr)[byte_offset] >> 7) & 0x01; byte_offset++; tmp_char |= ((*ie_ptr)[byte_offset] << 1) & 0x7E; bit_offset = 6; break; } if (tmp_char == 0x0A || tmp_char == 0x0D || (tmp_char >= 0x20 && tmp_char <= 0x3F) || (tmp_char >= 0x41 && tmp_char <= 0x5A) || (tmp_char >= 0x61 && tmp_char <= 0x7A)) { net_name->name[str_cnt] = tmp_char; str_cnt++; } } if (0 == bit_offset || (1 == bit_offset && 0 == spare_field)) { if (0 == bit_offset) { tmp_char = (*ie_ptr)[byte_offset] & 0x7F; } else { tmp_char = ((*ie_ptr)[byte_offset] >> 1) & 0x7F; } if (tmp_char == 0x0A || tmp_char == 0x0D || (tmp_char >= 0x20 && tmp_char <= 0x3F) || (tmp_char >= 0x41 && tmp_char <= 0x5A) || (tmp_char >= 0x61 && tmp_char <= 0x7A)) { if (str_cnt < LIBLTE_STRING_LEN) { net_name->name[str_cnt] = tmp_char; str_cnt++; } } } if (str_cnt < LIBLTE_STRING_LEN) { net_name->name[str_cnt] = '\0'; str_cnt++; } *ie_ptr += byte_offset + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Nonce Description: Transfers a 32-bit nonce value to support deriving a new mapped EPS security context. Document Reference: 24.301 v10.2.0 Section 9.9.3.25 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_nonce_ie(uint32 nonce, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = (nonce >> 24) & 0xFF; (*ie_ptr)[1] = (nonce >> 16) & 0xFF; (*ie_ptr)[2] = (nonce >> 8) & 0xFF; (*ie_ptr)[3] = nonce & 0xFF; *ie_ptr += 4; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_nonce_ie(uint8** ie_ptr, uint32* nonce) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && nonce != NULL) { *nonce = (*ie_ptr)[0] << 24; *nonce |= (*ie_ptr)[1] << 16; *nonce |= (*ie_ptr)[2] << 8; *nonce |= (*ie_ptr)[3]; *ie_ptr += 4; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Paging Identity Description: Indicates the identity used for paging for non-EPS services. Document Reference: 24.301 v10.2.0 Section 9.9.3.25A *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_paging_identity_ie(uint8 paging_id, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = paging_id & 0x01; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_paging_identity_ie(uint8** ie_ptr, uint8* paging_id) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && paging_id != NULL) { *paging_id = (*ie_ptr)[0] & 0x01; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: P-TMSI Signature Description: Identifies a GMM context of a UE. Document Reference: 24.301 v10.2.0 Section 9.9.3.26 24.008 v10.2.0 Section 10.5.5.8 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_p_tmsi_signature_ie(uint32 p_tmsi_signature, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = (p_tmsi_signature >> 24) & 0xFF; (*ie_ptr)[1] = (p_tmsi_signature >> 16) & 0xFF; (*ie_ptr)[2] = (p_tmsi_signature >> 8) & 0xFF; (*ie_ptr)[3] = p_tmsi_signature & 0xFF; *ie_ptr += 4; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_p_tmsi_signature_ie(uint8** ie_ptr, uint32* p_tmsi_signature) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && p_tmsi_signature != NULL) { *p_tmsi_signature = (*ie_ptr)[0] << 24; *p_tmsi_signature |= (*ie_ptr)[1] << 16; *p_tmsi_signature |= (*ie_ptr)[2] << 8; *p_tmsi_signature |= (*ie_ptr)[3]; *ie_ptr += 4; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Service Type Description: Specifies the purpose of the service request procedure. Document Reference: 24.301 v10.2.0 Section 9.9.3.27 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_service_type_ie(uint8 value, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] |= (value & 0x0F) << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_service_type_ie(uint8** ie_ptr, uint8 bit_offset, uint8* value) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && value != NULL) { *value = ((*ie_ptr)[0] >> bit_offset) & 0x0F; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Short MAC Description: Protects the integrity of a SERVICE REQUEST message. Document Reference: 24.301 v10.2.0 Section 9.9.3.28 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_short_mac_ie(uint16 short_mac, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = (short_mac >> 8) & 0xFF; (*ie_ptr)[1] = short_mac & 0xFF; *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_short_mac_ie(uint8** ie_ptr, uint16* short_mac) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && short_mac != NULL) { *short_mac = (*ie_ptr)[0] << 8; *short_mac |= (*ie_ptr)[1]; *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Time Zone Description: Encodes the offset between universal time and local time in steps of 15 minutes. Document Reference: 24.301 v10.2.0 Section 9.9.3.29 24.008 v10.2.0 Section 10.5.3.8 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_time_zone_ie(uint8 tz, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = tz; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_time_zone_ie(uint8** ie_ptr, uint8* tz) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && tz != NULL) { *tz = (*ie_ptr)[0]; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Time Zone And Time Description: Encodes the offset between universal time and local time in steps of 15 minutes and encodes the universal time at which the IE may have been sent by the network. Document Reference: 24.301 v10.2.0 Section 9.9.3.30 24.008 v10.2.0 Section 10.5.3.9 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_time_zone_and_time_ie(LIBLTE_MME_TIME_ZONE_AND_TIME_STRUCT* ttz, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ttz != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = ((ttz->year % 10) << 4) | ((ttz->year % 100) / 10); (*ie_ptr)[1] = ((ttz->month % 10) << 4) | (ttz->month / 10); (*ie_ptr)[2] = ((ttz->day % 10) << 4) | (ttz->day / 10); (*ie_ptr)[3] = ((ttz->hour % 10) << 4) | (ttz->hour / 10); (*ie_ptr)[4] = ((ttz->minute % 10) << 4) | (ttz->minute / 10); (*ie_ptr)[5] = ((ttz->second % 10) << 4) | (ttz->second / 10); (*ie_ptr)[6] = ttz->tz; *ie_ptr += 7; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_time_zone_and_time_ie(uint8** ie_ptr, LIBLTE_MME_TIME_ZONE_AND_TIME_STRUCT* ttz) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && ttz != NULL) { ttz->year = 2000 + (((*ie_ptr)[0] & 0x0F) * 10) + (((*ie_ptr)[0] >> 4) & 0x0F); ttz->month = (((*ie_ptr)[1] & 0x0F) * 10) + (((*ie_ptr)[1] >> 4) & 0x0F); ttz->day = (((*ie_ptr)[2] & 0x0F) * 10) + (((*ie_ptr)[2] >> 4) & 0x0F); ttz->hour = (((*ie_ptr)[3] & 0x0F) * 10) + (((*ie_ptr)[3] >> 4) & 0x0F); ttz->minute = (((*ie_ptr)[4] & 0x0F) * 10) + (((*ie_ptr)[4] >> 4) & 0x0F); ttz->second = (((*ie_ptr)[5] & 0x0F) * 10) + (((*ie_ptr)[5] >> 4) & 0x0F); ttz->tz = (*ie_ptr)[6]; *ie_ptr += 7; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: TMSI Status Description: Indicates whether a valid TMSI is available in the UE or not. Document Reference: 24.301 v10.2.0 Section 9.9.3.31 24.008 v10.2.0 Section 10.5.5.4 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_tmsi_status_ie(LIBLTE_MME_TMSI_STATUS_ENUM tmsi_status, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= tmsi_status << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_tmsi_status_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_TMSI_STATUS_ENUM* tmsi_status) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && tmsi_status != NULL) { *tmsi_status = (LIBLTE_MME_TMSI_STATUS_ENUM)((**ie_ptr >> bit_offset) & 0x01); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Tracking Area Identity Description: Provides an unambiguous identification of tracking areas within the area covered by the 3GPP system. Document Reference: 24.301 v10.2.0 Section 9.9.3.32 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_id_ie(LIBLTE_MME_TRACKING_AREA_ID_STRUCT* tai, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (tai != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = (((tai->mcc / 10) % 10) << 4) | ((tai->mcc / 100) % 10); if (tai->mnc < 100) { (*ie_ptr)[1] = 0xF0 | (tai->mcc % 10); (*ie_ptr)[2] = ((tai->mnc % 10) << 4) | ((tai->mnc / 10) % 10); } else { (*ie_ptr)[1] = ((tai->mnc % 10) << 4) | (tai->mcc % 10); (*ie_ptr)[2] = (((tai->mnc / 10) % 10) << 4) | ((tai->mnc / 100) % 10); } (*ie_ptr)[3] = (tai->tac >> 8) & 0xFF; (*ie_ptr)[4] = tai->tac & 0xFF; *ie_ptr += 5; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_id_ie(uint8** ie_ptr, LIBLTE_MME_TRACKING_AREA_ID_STRUCT* tai) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && tai != NULL) { tai->mcc = ((*ie_ptr)[0] & 0x0F) * 100; tai->mcc += (((*ie_ptr)[0] >> 4) & 0x0F) * 10; tai->mcc += (*ie_ptr)[1] & 0x0F; if ((((*ie_ptr)[1] >> 4) & 0x0F) == 0x0F) { tai->mnc = ((*ie_ptr)[2] & 0x0F) * 10; tai->mnc += ((*ie_ptr)[2] >> 4) & 0x0F; } else { tai->mnc = ((*ie_ptr)[1] >> 4) & 0x0F; tai->mnc += ((*ie_ptr)[2] & 0x0F) * 100; tai->mnc += (((*ie_ptr)[2] >> 4) & 0x0F) * 10; } tai->tac = (*ie_ptr)[3] << 8; tai->tac |= (*ie_ptr)[4]; *ie_ptr += 5; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Tracking Area Identity List Description: Transfers a list of tracking areas from the network to the UE. Document Reference: 24.301 v10.2.0 Section 9.9.3.33 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_identity_list_ie(LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT* tai_list, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (tai_list != NULL && ie_ptr != NULL) { (*ie_ptr)[0] = (tai_list->N_tais * 5) + 1; // TODO: Support all types if (1 == tai_list->N_tais) { (*ie_ptr)[1] = (LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ONE_PLMN_NON_CONSECUTIVE_TACS << 5) | ((tai_list->N_tais - 1) & 0x1F); } else { (*ie_ptr)[1] = (LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_DIFFERENT_PLMNS << 5) | ((tai_list->N_tais - 1) & 0x1F); } *ie_ptr += 2; for (i = 0; i < tai_list->N_tais; i++) { liblte_mme_pack_tracking_area_id_ie(&tai_list->tai[i], ie_ptr); } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_identity_list_ie(uint8** ie_ptr, LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT* tai_list) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ENUM type; uint32 sent_length; uint32 length; uint32 i; uint32 N_elems; uint16 mcc; uint16 mnc; uint16 tac; if (ie_ptr != NULL && tai_list != NULL) { sent_length = (*ie_ptr)[0] + 1; length = 1; tai_list->N_tais = 0; while (length < sent_length) { type = (LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ENUM)(((*ie_ptr)[length] >> 5) & 0x03); N_elems = (*ie_ptr)[length++] & 0x1F; if (LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ONE_PLMN_NON_CONSECUTIVE_TACS == type) { mcc = ((*ie_ptr)[length] & 0x0F) * 100; mcc += (((*ie_ptr)[length++] >> 4) & 0x0F) * 10; mcc += (*ie_ptr)[length] & 0x0F; if ((((*ie_ptr)[length] >> 4) & 0x0F) == 0x0F) { length++; mnc = ((*ie_ptr)[length] & 0x0F) * 10; mnc += ((*ie_ptr)[length++] >> 4) & 0x0F; } else { mnc = ((*ie_ptr)[length++] >> 4) & 0x0F; mnc += ((*ie_ptr)[length] & 0x0F) * 100; mnc += (((*ie_ptr)[length++] >> 4) & 0x0F) * 10; } for (i = 0; i < N_elems; i++) { tai_list->tai[tai_list->N_tais].mcc = mcc; tai_list->tai[tai_list->N_tais].mnc = mnc; tai_list->tai[tai_list->N_tais].tac = (*ie_ptr)[length++] << 8; tai_list->tai[tai_list->N_tais].tac |= (*ie_ptr)[length++]; tai_list->N_tais++; } } else if (LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_TYPE_ONE_PLMN_CONSECUTIVE_TACS == type) { mcc = ((*ie_ptr)[length] & 0x0F) * 100; mcc += (((*ie_ptr)[length++] >> 4) & 0x0F) * 10; mcc += (*ie_ptr)[length] & 0x0F; if ((((*ie_ptr)[length] >> 4) & 0x0F) == 0x0F) { length++; mnc = ((*ie_ptr)[length] & 0x0F) * 10; mnc += ((*ie_ptr)[length++] >> 4) & 0x0F; } else { mnc = ((*ie_ptr)[length++] >> 4) & 0x0F; mnc += ((*ie_ptr)[length] & 0x0F) * 100; mnc += (((*ie_ptr)[length++] >> 4) & 0x0F) * 10; } tac = (*ie_ptr)[length++] << 8; tac |= (*ie_ptr)[length++]; for (i = 0; i < N_elems; i++) { tai_list->tai[tai_list->N_tais].mcc = mcc; tai_list->tai[tai_list->N_tais].mnc = mnc; tai_list->tai[tai_list->N_tais].tac = tac + i; tai_list->N_tais++; } } else { for (i = 0; i < N_elems; i++) { tai_list->tai[tai_list->N_tais].mcc = ((*ie_ptr)[length] & 0x0F) * 100; tai_list->tai[tai_list->N_tais].mcc += (((*ie_ptr)[length++] >> 4) & 0x0F) * 10; tai_list->tai[tai_list->N_tais].mcc += (*ie_ptr)[length] & 0x0F; if ((((*ie_ptr)[length] >> 4) & 0x0F) == 0x0F) { length++; tai_list->tai[tai_list->N_tais].mnc = ((*ie_ptr)[length] & 0x0F) * 10; tai_list->tai[tai_list->N_tais].mnc += ((*ie_ptr)[length++] >> 4) & 0x0F; } else { tai_list->tai[tai_list->N_tais].mnc = ((*ie_ptr)[length++] >> 4) & 0x0F; tai_list->tai[tai_list->N_tais].mnc += ((*ie_ptr)[length] & 0x0F) * 100; tai_list->tai[tai_list->N_tais].mnc += (((*ie_ptr)[length++] >> 4) & 0x0F) * 10; } tai_list->tai[tai_list->N_tais].tac = (*ie_ptr)[length++] << 8; tai_list->tai[tai_list->N_tais].tac |= (*ie_ptr)[length++]; tai_list->N_tais++; } } } *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: UE Network Capability Description: Provides the network with information concerning aspects of the UE related to EPS or interworking with GPRS. Document Reference: 24.301 v10.2.0 Section 9.9.3.34 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_ue_network_capability_ie(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT* ue_network_cap, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ue_network_cap != NULL && ie_ptr != NULL) { if (ue_network_cap->dc_nr_present) { **ie_ptr = 7; } else { **ie_ptr = 2; } *ie_ptr += 1; **ie_ptr = ue_network_cap->eea[0] << 7; **ie_ptr |= ue_network_cap->eea[1] << 6; **ie_ptr |= ue_network_cap->eea[2] << 5; **ie_ptr |= ue_network_cap->eea[3] << 4; **ie_ptr |= ue_network_cap->eea[4] << 3; **ie_ptr |= ue_network_cap->eea[5] << 2; **ie_ptr |= ue_network_cap->eea[6] << 1; **ie_ptr |= ue_network_cap->eea[7]; *ie_ptr += 1; **ie_ptr = ue_network_cap->eia[0] << 7; **ie_ptr |= ue_network_cap->eia[1] << 6; **ie_ptr |= ue_network_cap->eia[2] << 5; **ie_ptr |= ue_network_cap->eia[3] << 4; **ie_ptr |= ue_network_cap->eia[4] << 3; **ie_ptr |= ue_network_cap->eia[5] << 2; **ie_ptr |= ue_network_cap->eia[6] << 1; **ie_ptr |= ue_network_cap->eia[7]; *ie_ptr += 1; if (ue_network_cap->dc_nr_present) { // skip empty caps for (int i = 0; i < 4; i++) { **ie_ptr = 0; *ie_ptr += 1; } // set dcnr bit **ie_ptr = ue_network_cap->dc_nr << 4; *ie_ptr += 1; } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_ue_network_capability_ie(uint8** ie_ptr, LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT* ue_network_cap) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 length; if (ie_ptr != NULL && ue_network_cap != NULL) { length = **ie_ptr; *ie_ptr += 1; ue_network_cap->eea[0] = (**ie_ptr >> 7) & 0x01; ue_network_cap->eea[1] = (**ie_ptr >> 6) & 0x01; ue_network_cap->eea[2] = (**ie_ptr >> 5) & 0x01; ue_network_cap->eea[3] = (**ie_ptr >> 4) & 0x01; ue_network_cap->eea[4] = (**ie_ptr >> 3) & 0x01; ue_network_cap->eea[5] = (**ie_ptr >> 2) & 0x01; ue_network_cap->eea[6] = (**ie_ptr >> 1) & 0x01; ue_network_cap->eea[7] = **ie_ptr & 0x01; *ie_ptr += 1; ue_network_cap->eia[0] = (**ie_ptr >> 7) & 0x01; ue_network_cap->eia[1] = (**ie_ptr >> 6) & 0x01; ue_network_cap->eia[2] = (**ie_ptr >> 5) & 0x01; ue_network_cap->eia[3] = (**ie_ptr >> 4) & 0x01; ue_network_cap->eia[4] = (**ie_ptr >> 3) & 0x01; ue_network_cap->eia[5] = (**ie_ptr >> 2) & 0x01; ue_network_cap->eia[6] = (**ie_ptr >> 1) & 0x01; ue_network_cap->eia[7] = **ie_ptr & 0x01; *ie_ptr += 1; if (length > 2) { ue_network_cap->uea[0] = (**ie_ptr >> 7) & 0x01; ue_network_cap->uea[1] = (**ie_ptr >> 6) & 0x01; ue_network_cap->uea[2] = (**ie_ptr >> 5) & 0x01; ue_network_cap->uea[3] = (**ie_ptr >> 4) & 0x01; ue_network_cap->uea[4] = (**ie_ptr >> 3) & 0x01; ue_network_cap->uea[5] = (**ie_ptr >> 2) & 0x01; ue_network_cap->uea[6] = (**ie_ptr >> 1) & 0x01; ue_network_cap->uea[7] = **ie_ptr & 0x01; ue_network_cap->uea_present = true; *ie_ptr += 1; } else { ue_network_cap->uea_present = false; } if (length > 3) { ue_network_cap->ucs2 = (**ie_ptr >> 7) & 0x01; ue_network_cap->ucs2_present = true; ue_network_cap->uia[1] = (**ie_ptr >> 6) & 0x01; ue_network_cap->uia[2] = (**ie_ptr >> 5) & 0x01; ue_network_cap->uia[3] = (**ie_ptr >> 4) & 0x01; ue_network_cap->uia[4] = (**ie_ptr >> 3) & 0x01; ue_network_cap->uia[5] = (**ie_ptr >> 2) & 0x01; ue_network_cap->uia[6] = (**ie_ptr >> 1) & 0x01; ue_network_cap->uia[7] = **ie_ptr & 0x01; ue_network_cap->uia_present = true; *ie_ptr += 1; } else { ue_network_cap->ucs2_present = false; ue_network_cap->uia_present = false; } if (length > 4) { ue_network_cap->lpp = (**ie_ptr >> 3) & 0x01; ue_network_cap->lpp_present = true; ue_network_cap->lcs = (**ie_ptr >> 2) & 0x01; ue_network_cap->lcs_present = true; ue_network_cap->onexsrvcc = (**ie_ptr >> 1) & 0x01; ue_network_cap->onexsrvcc_present = true; ue_network_cap->nf = **ie_ptr >> 1; ue_network_cap->nf_present = true; *ie_ptr += 1; } else { ue_network_cap->lpp_present = false; ue_network_cap->lcs_present = false; ue_network_cap->onexsrvcc_present = false; ue_network_cap->nf_present = false; } if (length > 5) { *ie_ptr += length - 5; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: UE Radio Capability Update Needed Description: Indicates whether the MME shall delete the stored UE radio capability information, if any. Document Reference: 24.301 v10.2.0 Section 9.9.3.35 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_ue_radio_capability_update_needed_ie(uint8 urc_update, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] |= (urc_update & 0x01) << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_ue_radio_capability_update_needed_ie(uint8** ie_ptr, uint8 bit_offset, uint8* urc_update) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && urc_update != NULL) { *urc_update = ((*ie_ptr)[0] >> bit_offset) & 0x01; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: UE Security Capability Description: Indicates which security algorithms are supported by the UE in S1 mode. Document Reference: 24.301 v10.2.0 Section 9.9.3.36 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_ue_security_capabilities_ie(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT* ue_sec_cap, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 idx; if (ue_sec_cap != NULL && ie_ptr != NULL) { if (ue_sec_cap->uea_present && ue_sec_cap->uia_present && ue_sec_cap->gea_present) { (*ie_ptr)[0] = 5; } else if (ue_sec_cap->uea_present && ue_sec_cap->uia_present) { (*ie_ptr)[0] = 4; } else if (ue_sec_cap->uea_present) { (*ie_ptr)[0] = 3; } else { (*ie_ptr)[0] = 2; } idx = 1; (*ie_ptr)[idx] = ue_sec_cap->eea[0] << 7; (*ie_ptr)[idx] |= ue_sec_cap->eea[1] << 6; (*ie_ptr)[idx] |= ue_sec_cap->eea[2] << 5; (*ie_ptr)[idx] |= ue_sec_cap->eea[3] << 4; (*ie_ptr)[idx] |= ue_sec_cap->eea[4] << 3; (*ie_ptr)[idx] |= ue_sec_cap->eea[5] << 2; (*ie_ptr)[idx] |= ue_sec_cap->eea[6] << 1; (*ie_ptr)[idx] |= ue_sec_cap->eea[7]; idx++; (*ie_ptr)[idx] = ue_sec_cap->eia[0] << 7; (*ie_ptr)[idx] |= ue_sec_cap->eia[1] << 6; (*ie_ptr)[idx] |= ue_sec_cap->eia[2] << 5; (*ie_ptr)[idx] |= ue_sec_cap->eia[3] << 4; (*ie_ptr)[idx] |= ue_sec_cap->eia[4] << 3; (*ie_ptr)[idx] |= ue_sec_cap->eia[5] << 2; (*ie_ptr)[idx] |= ue_sec_cap->eia[6] << 1; (*ie_ptr)[idx] |= ue_sec_cap->eia[7]; idx++; if (ue_sec_cap->uea_present) { (*ie_ptr)[idx] = ue_sec_cap->uea[0] << 7; (*ie_ptr)[idx] |= ue_sec_cap->uea[1] << 6; (*ie_ptr)[idx] |= ue_sec_cap->uea[2] << 5; (*ie_ptr)[idx] |= ue_sec_cap->uea[3] << 4; (*ie_ptr)[idx] |= ue_sec_cap->uea[4] << 3; (*ie_ptr)[idx] |= ue_sec_cap->uea[5] << 2; (*ie_ptr)[idx] |= ue_sec_cap->uea[6] << 1; (*ie_ptr)[idx] |= ue_sec_cap->uea[7]; idx++; } if (ue_sec_cap->uia_present) { (*ie_ptr)[idx] = ue_sec_cap->uia[1] << 6; (*ie_ptr)[idx] |= ue_sec_cap->uia[2] << 5; (*ie_ptr)[idx] |= ue_sec_cap->uia[3] << 4; (*ie_ptr)[idx] |= ue_sec_cap->uia[4] << 3; (*ie_ptr)[idx] |= ue_sec_cap->uia[5] << 2; (*ie_ptr)[idx] |= ue_sec_cap->uia[6] << 1; (*ie_ptr)[idx] |= ue_sec_cap->uia[7]; idx++; } if (ue_sec_cap->gea_present) { (*ie_ptr)[idx] = ue_sec_cap->gea[1] << 6; (*ie_ptr)[idx] |= ue_sec_cap->gea[2] << 5; (*ie_ptr)[idx] |= ue_sec_cap->gea[3] << 4; (*ie_ptr)[idx] |= ue_sec_cap->gea[4] << 3; (*ie_ptr)[idx] |= ue_sec_cap->gea[5] << 2; (*ie_ptr)[idx] |= ue_sec_cap->gea[6] << 1; (*ie_ptr)[idx] |= ue_sec_cap->gea[7]; idx++; } *ie_ptr += idx; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_ue_security_capabilities_ie(uint8** ie_ptr, LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT* ue_sec_cap) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 length; if (ie_ptr != NULL && ue_sec_cap != NULL) { length = (*ie_ptr)[0]; ue_sec_cap->eea[0] = ((*ie_ptr)[1] >> 7) & 0x01; ue_sec_cap->eea[1] = ((*ie_ptr)[1] >> 6) & 0x01; ue_sec_cap->eea[2] = ((*ie_ptr)[1] >> 5) & 0x01; ue_sec_cap->eea[3] = ((*ie_ptr)[1] >> 4) & 0x01; ue_sec_cap->eea[4] = ((*ie_ptr)[1] >> 3) & 0x01; ue_sec_cap->eea[5] = ((*ie_ptr)[1] >> 2) & 0x01; ue_sec_cap->eea[6] = ((*ie_ptr)[1] >> 1) & 0x01; ue_sec_cap->eea[7] = (*ie_ptr)[1] & 0x01; ue_sec_cap->eia[0] = ((*ie_ptr)[2] >> 7) & 0x01; ue_sec_cap->eia[1] = ((*ie_ptr)[2] >> 6) & 0x01; ue_sec_cap->eia[2] = ((*ie_ptr)[2] >> 5) & 0x01; ue_sec_cap->eia[3] = ((*ie_ptr)[2] >> 4) & 0x01; ue_sec_cap->eia[4] = ((*ie_ptr)[2] >> 3) & 0x01; ue_sec_cap->eia[5] = ((*ie_ptr)[2] >> 2) & 0x01; ue_sec_cap->eia[6] = ((*ie_ptr)[2] >> 1) & 0x01; ue_sec_cap->eia[7] = (*ie_ptr)[2] & 0x01; if (length > 2) { ue_sec_cap->uea[0] = ((*ie_ptr)[3] >> 7) & 0x01; ue_sec_cap->uea[1] = ((*ie_ptr)[3] >> 6) & 0x01; ue_sec_cap->uea[2] = ((*ie_ptr)[3] >> 5) & 0x01; ue_sec_cap->uea[3] = ((*ie_ptr)[3] >> 4) & 0x01; ue_sec_cap->uea[4] = ((*ie_ptr)[3] >> 3) & 0x01; ue_sec_cap->uea[5] = ((*ie_ptr)[3] >> 2) & 0x01; ue_sec_cap->uea[6] = ((*ie_ptr)[3] >> 1) & 0x01; ue_sec_cap->uea[7] = (*ie_ptr)[3] & 0x01; ue_sec_cap->uea_present = true; } else { ue_sec_cap->uea_present = false; } if (length > 3) { ue_sec_cap->uia[1] = ((*ie_ptr)[4] >> 6) & 0x01; ue_sec_cap->uia[2] = ((*ie_ptr)[4] >> 5) & 0x01; ue_sec_cap->uia[3] = ((*ie_ptr)[4] >> 4) & 0x01; ue_sec_cap->uia[4] = ((*ie_ptr)[4] >> 3) & 0x01; ue_sec_cap->uia[5] = ((*ie_ptr)[4] >> 2) & 0x01; ue_sec_cap->uia[6] = ((*ie_ptr)[4] >> 1) & 0x01; ue_sec_cap->uia[7] = (*ie_ptr)[4] & 0x01; ue_sec_cap->uia_present = true; } else { ue_sec_cap->uia_present = false; } if (length > 4) { ue_sec_cap->gea[1] = ((*ie_ptr)[5] >> 6) & 0x01; ue_sec_cap->gea[2] = ((*ie_ptr)[5] >> 5) & 0x01; ue_sec_cap->gea[3] = ((*ie_ptr)[5] >> 4) & 0x01; ue_sec_cap->gea[4] = ((*ie_ptr)[5] >> 3) & 0x01; ue_sec_cap->gea[5] = ((*ie_ptr)[5] >> 2) & 0x01; ue_sec_cap->gea[6] = ((*ie_ptr)[5] >> 1) & 0x01; ue_sec_cap->gea[7] = (*ie_ptr)[5] & 0x01; ue_sec_cap->gea_present = true; } else { ue_sec_cap->gea_present = false; } *ie_ptr += length + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Emergency Number List Description: Encodes emergency number(s) for use within the country (as indicated by MCC) where the IE is received. Document Reference: 24.301 v10.2.0 Section 9.9.3.37 24.008 v10.2.0 Section 10.5.3.13 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_emergency_number_list_ie(LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT* emerg_num_list, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; uint32 j; uint32 length; if (emerg_num_list != NULL && ie_ptr != NULL) { length = 1; for (i = 0; i < emerg_num_list->N_emerg_nums; i++) { if ((emerg_num_list->emerg_num[i].N_emerg_num_digits % 2) == 0) { (*ie_ptr)[length++] = (emerg_num_list->emerg_num[i].N_emerg_num_digits / 2) + 1; (*ie_ptr)[length++] = emerg_num_list->emerg_num[i].emerg_service_cat; if (emerg_num_list->emerg_num[i].N_emerg_num_digits / 2 > LIBLTE_MME_EMERGENCY_NUMBER_MAX_NUM_DIGITS) { return err; } for (j = 0; j < emerg_num_list->emerg_num[i].N_emerg_num_digits / 2; j++) { (*ie_ptr)[length] = emerg_num_list->emerg_num[i].emerg_num[j * 2 + 0]; (*ie_ptr)[length++] |= emerg_num_list->emerg_num[i].emerg_num[j * 2 + 1] << 4; } } else { (*ie_ptr)[length++] = (emerg_num_list->emerg_num[i].N_emerg_num_digits / 2) + 2; (*ie_ptr)[length++] = emerg_num_list->emerg_num[i].emerg_service_cat; for (j = 0; j < emerg_num_list->emerg_num[i].N_emerg_num_digits / 2; j++) { (*ie_ptr)[length] = emerg_num_list->emerg_num[i].emerg_num[j * 2 + 0]; (*ie_ptr)[length++] |= emerg_num_list->emerg_num[i].emerg_num[j * 2 + 1] << 4; } (*ie_ptr)[length++] = 0xF0 | emerg_num_list->emerg_num[i].emerg_num[j * 2]; } } (*ie_ptr)[0] = length - 2; *ie_ptr += length - 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_emergency_number_list_ie(uint8** ie_ptr, LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT* emerg_num_list) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 sent_length; uint32 length; uint32 idx; uint32 i; if (ie_ptr != NULL && emerg_num_list != NULL) { sent_length = (*ie_ptr)[0] + 1; length = 1; emerg_num_list->N_emerg_nums = 0; while (length < sent_length) { idx = emerg_num_list->N_emerg_nums; //add length check on emergency number list if (idx >= LIBLTE_MME_EMERGENCY_NUMBER_LIST_MAX_SIZE) { return (err); } emerg_num_list->emerg_num[idx].N_emerg_num_digits = ((*ie_ptr)[length++] - 1) * 2; if (emerg_num_list->emerg_num[idx].N_emerg_num_digits > LIBLTE_MME_EMERGENCY_NUMBER_MAX_NUM_DIGITS) { return (err); } emerg_num_list->emerg_num[idx].emerg_service_cat = (LIBLTE_MME_EMERGENCY_SERVICE_CATEGORY_ENUM)((*ie_ptr)[length++] & 0x1F); for (i = 0; i < emerg_num_list->emerg_num[idx].N_emerg_num_digits / 2; i++) { emerg_num_list->emerg_num[idx].emerg_num[i * 2 + 0] = (*ie_ptr)[length] & 0x0F; emerg_num_list->emerg_num[idx].emerg_num[i * 2 + 1] = (*ie_ptr)[length++] >> 4; } // Added by Ismael: if i==0 this is negative if (i > 0) { if (emerg_num_list->emerg_num[idx].emerg_num[i * 2 - 1] == 0x0F) { emerg_num_list->emerg_num[idx].N_emerg_num_digits--; } } emerg_num_list->N_emerg_nums++; } *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: CLI Description: Conveys information about the calling line for a terminated call to a CS fallback capable UE. Document Reference: 24.301 v10.2.0 Section 9.9.3.38 *********************************************************************/ // TODO /********************************************************************* IE Name: SS Code Description: Conveys information related to a network initiated supplementary service request to a CS fallback capable UE. Document Reference: 24.301 v10.2.0 Section 9.9.3.39 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_ss_code_ie(uint8 code, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = code; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_ss_code_ie(uint8** ie_ptr, uint8* code) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && code != NULL) { *code = (*ie_ptr)[0]; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: LCS Indicator Description: Indicates that the origin of the message is due to a LCS request and the type of this request to a CS fallback capable UE. Document Reference: 24.301 v10.2.0 Section 9.9.3.40 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_lcs_indicator_ie(uint8 lcs_ind, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = lcs_ind; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_lcs_indicator_ie(uint8** ie_ptr, uint8* lcs_ind) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && lcs_ind != NULL) { *lcs_ind = (*ie_ptr)[0]; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: LCS Client Identity Description: Conveys information related to the client of a LCS request for a CS fallback capable UE. Document Reference: 24.301 v10.2.0 Section 9.9.3.41 *********************************************************************/ // TODO /********************************************************************* IE Name: Generic Message Container Type Description: Specifies the type of message contained in the generic message container IE. Document Reference: 24.301 v10.2.0 Section 9.9.3.42 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_generic_message_container_type_ie(uint8 msg_cont_type, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = msg_cont_type; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_generic_message_container_type_ie(uint8** ie_ptr, uint8* msg_cont_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && msg_cont_type != NULL) { *msg_cont_type = (*ie_ptr)[0]; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Generic Message Container Description: Encapsulates the application message transferred between the UE and the network. Document Reference: 24.301 v10.2.0 Section 9.9.3.43 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_generic_message_container_ie(LIBLTE_BYTE_MSG_STRUCT* msg, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (msg != NULL && ie_ptr != NULL && msg->N_bytes <= LIBLTE_MAX_MSG_SIZE_BYTES) { (*ie_ptr)[0] = msg->N_bytes >> 8; (*ie_ptr)[1] = msg->N_bytes & 0xFF; for (i = 0; i < msg->N_bytes; i++) { (*ie_ptr)[2 + i] = msg->msg[i]; } *ie_ptr += msg->N_bytes + 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_generic_message_container_ie(uint8** ie_ptr, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && msg != NULL) { msg->N_bytes = (*ie_ptr)[0] << 8; msg->N_bytes |= (*ie_ptr)[1]; if (msg->N_bytes > LIBLTE_MAX_MSG_SIZE_BYTES) { return err; } for (i = 0; i < msg->N_bytes; i++) { msg->msg[i] = (*ie_ptr)[2 + i]; } *ie_ptr += msg->N_bytes + 2; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Voice Domain Preference and UE's Usage Setting Description: Provides the network with the UE's usage setting and the voice domain preference for the E-UTRAN. Document Reference: 24.301 v10.2.0 Section 9.9.3.44 24.008 v10.2.0 Section 10.5.5.28 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_voice_domain_pref_and_ue_usage_setting_ie( LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_STRUCT* voice_domain_pref_and_ue_usage_setting, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (voice_domain_pref_and_ue_usage_setting != NULL && ie_ptr != NULL) { **ie_ptr = 1; *ie_ptr += 1; **ie_ptr = voice_domain_pref_and_ue_usage_setting->ue_usage_setting << 2; **ie_ptr |= voice_domain_pref_and_ue_usage_setting->voice_domain_pref; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_voice_domain_pref_and_ue_usage_setting_ie( uint8** ie_ptr, LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_STRUCT* voice_domain_pref_and_ue_usage_setting) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && voice_domain_pref_and_ue_usage_setting != NULL) { *ie_ptr += 1; voice_domain_pref_and_ue_usage_setting->ue_usage_setting = (LIBLTE_MME_UE_USAGE_SETTING_ENUM)((**ie_ptr >> 2) & 0x01); voice_domain_pref_and_ue_usage_setting->voice_domain_pref = (LIBLTE_MME_VOICE_DOMAIN_PREF_ENUM)(**ie_ptr & 0x03); *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: GUTI Type Description: Indicates whether the GUTI included in the same message in an information element of type EPS mobility identity represents a native GUTI or a mapped GUTI. Document Reference: 24.301 v10.2.0 Section 9.9.3.45 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_guti_type_ie(LIBLTE_MME_GUTI_TYPE_ENUM guti_type, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= guti_type << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_type_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_GUTI_TYPE_ENUM* guti_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && guti_type != NULL) { *guti_type = (LIBLTE_MME_GUTI_TYPE_ENUM)((**ie_ptr >> bit_offset) & 0x01); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Access Point Name Description: Identifies the packet data network to which the GPRS user wishes to connect and notifies the access point of the packet data network that wishes to connect to the UE. Document Reference: 24.301 v10.2.0 Section 9.9.4.1 24.008 v10.2.0 Section 10.5.6.1 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_NAME_STRUCT* apn, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; const char* apn_str; uint32 i; uint32 len_idx; uint32 apn_idx; uint32 label_len; if (apn != NULL && ie_ptr != NULL) { apn_str = apn->apn; (*ie_ptr)[0] = strnlen(apn->apn, LIBLTE_STRING_LEN) + 1; len_idx = 0; apn_idx = 0; label_len = 0; while (strnlen(apn->apn, LIBLTE_STRING_LEN) > apn_idx) { (*ie_ptr)[1 + apn_idx + 1] = (uint8)apn_str[apn_idx]; apn_idx++; label_len++; if (apn_str[apn_idx] == '.') { (*ie_ptr)[1 + len_idx] = label_len; label_len = 0; len_idx = apn_idx + 1; apn_idx++; } } (*ie_ptr)[1 + len_idx] = label_len; *ie_ptr += strnlen(apn->apn, LIBLTE_STRING_LEN) + 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_access_point_name_ie(uint8** ie_ptr, LIBLTE_MME_ACCESS_POINT_NAME_STRUCT* apn) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; uint32 ie_idx; uint32 label_len; uint32 str_cnt; if (ie_ptr != NULL && apn != NULL) { ie_idx = 0; str_cnt = 0; while (ie_idx < (*ie_ptr)[0] && str_cnt < LIBLTE_STRING_LEN) { label_len = (*ie_ptr)[1 + ie_idx]; for (i = 0; i < label_len && str_cnt < LIBLTE_STRING_LEN; i++) { apn->apn[str_cnt] = (char)((*ie_ptr)[1 + ie_idx + i + 1]); str_cnt++; } ie_idx += label_len + 1; if (ie_idx < (*ie_ptr)[0] && str_cnt < LIBLTE_STRING_LEN) { apn->apn[str_cnt] = '.'; str_cnt++; } } if (str_cnt < LIBLTE_STRING_LEN) { apn->apn[str_cnt] = '\0'; } *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: APN Aggregate Maximum Bit Rate Description: Indicates the initial subscribed APN-AMBR when the UE establishes a PDN connection or indicates the new APN-AMBR if it is changed by the network. Document Reference: 24.301 v10.2.0 Section 9.9.4.2 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_apn_aggregate_maximum_bit_rate_ie(LIBLTE_MME_APN_AGGREGATE_MAXIMUM_BIT_RATE_STRUCT* apn_ambr, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (apn_ambr != NULL && ie_ptr != NULL) { if (apn_ambr->ext_present && apn_ambr->ext2_present) { (*ie_ptr)[0] = 6; } else if (apn_ambr->ext_present) { (*ie_ptr)[0] = 4; } else { (*ie_ptr)[0] = 2; } (*ie_ptr)[1] = apn_ambr->apn_ambr_dl; (*ie_ptr)[2] = apn_ambr->apn_ambr_ul; if (apn_ambr->ext_present) { (*ie_ptr)[3] = apn_ambr->apn_ambr_dl_ext; (*ie_ptr)[4] = apn_ambr->apn_ambr_ul_ext; } if (apn_ambr->ext2_present) { (*ie_ptr)[5] = apn_ambr->apn_ambr_dl_ext2; (*ie_ptr)[6] = apn_ambr->apn_ambr_ul_ext2; } if (apn_ambr->ext_present && apn_ambr->ext2_present) { *ie_ptr += 7; } else if (apn_ambr->ext_present) { *ie_ptr += 5; } else { *ie_ptr += 3; } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_apn_aggregate_maximum_bit_rate_ie(uint8** ie_ptr, LIBLTE_MME_APN_AGGREGATE_MAXIMUM_BIT_RATE_STRUCT* apn_ambr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && apn_ambr != NULL) { if (6 == (*ie_ptr)[0]) { apn_ambr->ext_present = true; apn_ambr->ext2_present = true; } else if (4 == (*ie_ptr)[0]) { apn_ambr->ext_present = true; apn_ambr->ext2_present = false; } else { apn_ambr->ext_present = false; apn_ambr->ext2_present = false; } apn_ambr->apn_ambr_dl = (*ie_ptr)[1]; apn_ambr->apn_ambr_ul = (*ie_ptr)[2]; if (apn_ambr->ext_present) { apn_ambr->apn_ambr_dl_ext = (*ie_ptr)[3]; apn_ambr->apn_ambr_ul_ext = (*ie_ptr)[4]; } if (apn_ambr->ext2_present) { apn_ambr->apn_ambr_dl_ext2 = (*ie_ptr)[5]; apn_ambr->apn_ambr_ul_ext2 = (*ie_ptr)[6]; } if (apn_ambr->ext_present && apn_ambr->ext2_present) { *ie_ptr += 7; } else if (apn_ambr->ext_present) { *ie_ptr += 5; } else { *ie_ptr += 3; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Connectivity Type Description: Specifies the type of connectivity selected by the network for the PDN connection. Document Reference: 24.301 v10.2.0 Section 9.9.4.2A 24.008 v10.2.0 Section 10.5.6.19 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_connectivity_type_ie(uint8 con_type, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] |= con_type << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_connectivity_type_ie(uint8** ie_ptr, uint8 bit_offset, uint8* con_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && con_type != NULL) { *con_type = ((*ie_ptr)[0] >> bit_offset) & 0x0F; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: EPS Quality Of Service Description: Specifies the QoS parameters for an EPS bearer context. Document Reference: 24.301 v10.2.0 Section 9.9.4.3 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_quality_of_service_ie(LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT* qos, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (qos != NULL && ie_ptr != NULL) { if (qos->br_present && qos->br_ext_present) { (*ie_ptr)[0] = 9; } else if (qos->br_present) { (*ie_ptr)[0] = 5; } else { (*ie_ptr)[0] = 1; } (*ie_ptr)[1] = qos->qci; if (qos->br_present) { (*ie_ptr)[2] = qos->mbr_ul; (*ie_ptr)[3] = qos->mbr_dl; (*ie_ptr)[4] = qos->gbr_ul; (*ie_ptr)[5] = qos->gbr_dl; } if (qos->br_ext_present) { (*ie_ptr)[6] = qos->mbr_ul_ext; (*ie_ptr)[7] = qos->mbr_dl_ext; (*ie_ptr)[8] = qos->gbr_ul_ext; (*ie_ptr)[9] = qos->gbr_dl_ext; } if (qos->br_present && qos->br_ext_present) { *ie_ptr += 10; } else if (qos->br_present) { *ie_ptr += 6; } else { *ie_ptr += 2; } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_eps_quality_of_service_ie(uint8** ie_ptr, LIBLTE_MME_EPS_QUALITY_OF_SERVICE_STRUCT* qos) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && qos != NULL) { if ((*ie_ptr)[0] == 1) { qos->br_present = false; qos->br_ext_present = false; } else if ((*ie_ptr)[0] == 5) { qos->br_present = true; qos->br_ext_present = false; } else { qos->br_present = true; qos->br_ext_present = true; } qos->qci = (*ie_ptr)[1]; if (qos->br_present) { qos->mbr_ul = (*ie_ptr)[2]; qos->mbr_dl = (*ie_ptr)[3]; qos->gbr_ul = (*ie_ptr)[4]; qos->gbr_dl = (*ie_ptr)[5]; } if (qos->br_ext_present) { qos->mbr_ul_ext = (*ie_ptr)[6]; qos->mbr_dl_ext = (*ie_ptr)[7]; qos->gbr_ul_ext = (*ie_ptr)[8]; qos->gbr_dl_ext = (*ie_ptr)[9]; } if (qos->br_present && qos->br_ext_present) { *ie_ptr += 10; } else if (qos->br_present) { *ie_ptr += 6; } else { *ie_ptr += 2; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: ESM Cause Description: Indicates the reason why a session management request is rejected. Document Reference: 24.301 v10.2.0 Section 9.9.4.4 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_cause_ie(uint8 cause, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = cause; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_cause_ie(uint8** ie_ptr, uint8* cause) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && cause != NULL) { *cause = (*ie_ptr)[0]; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: ESM Information Transfer Flag Description: Indicates whether ESM information, i.e. protocol configuration options or APN or both, is to be transferred security protected. Document Reference: 24.301 v10.2.0 Section 9.9.4.5 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_info_transfer_flag_ie(LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM esm_info_transfer_flag, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= esm_info_transfer_flag << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_info_transfer_flag_ie(uint8** ie_ptr, uint8 bit_offset, LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM* esm_info_transfer_flag) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && esm_info_transfer_flag != NULL) { *esm_info_transfer_flag = (LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_ENUM)((**ie_ptr >> bit_offset) & 0x01); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Linked EPS Bearer Identity Description: Identifies the default bearer that is associated with a dedicated EPS bearer or identifies the EPS bearer (default or dedicated) with which one or more packet filters specified in a traffic flow aggregate are associated. Document Reference: 24.301 v10.2.0 Section 9.9.4.6 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_linked_eps_bearer_identity_ie(uint8 bearer_id, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] |= (bearer_id & 0x0F) << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_linked_eps_bearer_identity_ie(uint8** ie_ptr, uint8 bit_offset, uint8* bearer_id) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && bearer_id != NULL) { *bearer_id = ((*ie_ptr)[0] >> bit_offset) & 0x0F; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: LLC Service Access Point Identifier Description: Identifies the service access point that is used for the GPRS data transfer at LLC layer. Document Reference: 24.301 v10.2.0 Section 9.9.4.7 24.008 v10.2.0 Section 10.5.6.9 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_llc_service_access_point_identifier_ie(uint8 llc_sapi, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = llc_sapi; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_llc_service_access_point_identifier_ie(uint8** ie_ptr, uint8* llc_sapi) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && llc_sapi != NULL) { *llc_sapi = (*ie_ptr)[0]; *ie_ptr += 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Notification Indicator Description: Informs the UE about an event which is relevant for the upper layer using an EPS bearer context or having requested a procedure transaction. Document Reference: 24.301 v10.2.0 Section 9.9.4.7A *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_notification_indicator_ie(uint8 notification_ind, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = 1; (*ie_ptr)[1] = notification_ind; *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_notification_indicator_ie(uint8** ie_ptr, uint8* notification_ind) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && notification_ind != NULL) { *notification_ind = (*ie_ptr)[1]; *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Packet Flow Identifier Description: Indicates the packet flow identifier for a packet flow context. Document Reference: 24.301 v10.2.0 Section 9.9.4.8 24.008 v10.2.0 Section 10.5.6.11 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_packet_flow_identifier_ie(uint8 packet_flow_id, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = 1; (*ie_ptr)[1] = packet_flow_id; *ie_ptr += 2; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_packet_flow_identifier_ie(uint8** ie_ptr, uint8* packet_flow_id) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && packet_flow_id != NULL) { *packet_flow_id = (*ie_ptr)[1]; *ie_ptr += (*ie_ptr)[0]; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: PDN Address Description: Assigns an IPv4 address to the UE associated with a packet data network and provides the UE with an interface identifier to be used to build the IPv6 link local address. Document Reference: 24.301 v10.2.0 Section 9.9.4.9 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_address_ie(LIBLTE_MME_PDN_ADDRESS_STRUCT* pdn_addr, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (pdn_addr != NULL && ie_ptr != NULL) { (*ie_ptr)[1] = 0x00 | (pdn_addr->pdn_type & 0x07); if (LIBLTE_MME_PDN_TYPE_IPV4 == pdn_addr->pdn_type) { for (i = 0; i < 4; i++) { (*ie_ptr)[2 + i] = pdn_addr->addr[i]; } (*ie_ptr)[0] = 5; *ie_ptr += 6; } else if (LIBLTE_MME_PDN_TYPE_IPV6 == pdn_addr->pdn_type) { for (i = 0; i < 8; i++) { (*ie_ptr)[2 + i] = pdn_addr->addr[i]; } (*ie_ptr)[0] = 9; *ie_ptr += 10; } else { for (i = 0; i < 12; i++) { (*ie_ptr)[2 + i] = pdn_addr->addr[i]; } (*ie_ptr)[0] = 13; *ie_ptr += 14; } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_address_ie(uint8** ie_ptr, LIBLTE_MME_PDN_ADDRESS_STRUCT* pdn_addr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 i; if (ie_ptr != NULL && pdn_addr != NULL) { pdn_addr->pdn_type = (*ie_ptr)[1] & 0x07; if (LIBLTE_MME_PDN_TYPE_IPV4 == pdn_addr->pdn_type) { for (i = 0; i < 4; i++) { pdn_addr->addr[i] = (*ie_ptr)[2 + i]; } } else if (LIBLTE_MME_PDN_TYPE_IPV6 == pdn_addr->pdn_type) { for (i = 0; i < 8; i++) { pdn_addr->addr[i] = (*ie_ptr)[2 + i]; } } else { for (i = 0; i < 12; i++) { pdn_addr->addr[i] = (*ie_ptr)[2 + i]; } } *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: PDN Type Description: Indicates the IP version capability of the IP stack associated with the UE. Document Reference: 24.301 v10.2.0 Section 9.9.4.10 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_type_ie(uint8 pdn_type, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= pdn_type << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_type_ie(uint8** ie_ptr, uint8 bit_offset, uint8* pdn_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && pdn_type != NULL) { *pdn_type = (**ie_ptr >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Protocol Configuration Options Description: Transfers external network protocol options associated with a PDP context activation and transfers additional (protocol) data (e.g. configuration parameters, error codes or messages/ events) associated with an external protocol or an application. Document Reference: 24.301 v10.2.0 Section 9.9.4.11 24.008 v10.2.0 Section 10.5.6.3 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_protocol_config_options_ie(LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT* protocol_cnfg_opts, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 idx; uint32 i; uint32 j; if (protocol_cnfg_opts != NULL && ie_ptr != NULL) { (*ie_ptr)[1] = 0x80; idx = 2; for (i = 0; i < protocol_cnfg_opts->N_opts; i++) { (*ie_ptr)[idx++] = protocol_cnfg_opts->opt[i].id >> 8; (*ie_ptr)[idx++] = protocol_cnfg_opts->opt[i].id & 0x00FF; (*ie_ptr)[idx++] = protocol_cnfg_opts->opt[i].len; for (j = 0; j < protocol_cnfg_opts->opt[i].len; j++) { (*ie_ptr)[idx++] = protocol_cnfg_opts->opt[i].contents[j]; } } (*ie_ptr)[0] = idx - 1; *ie_ptr += idx; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_protocol_config_options_ie(uint8** ie_ptr, LIBLTE_MME_PROTOCOL_CONFIG_OPTIONS_STRUCT* protocol_cnfg_opts) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 idx; uint32 i; if (ie_ptr != NULL && protocol_cnfg_opts != NULL) { idx = 2; protocol_cnfg_opts->N_opts = 0; while (idx < (*ie_ptr)[0]) { protocol_cnfg_opts->opt[protocol_cnfg_opts->N_opts].id = (*ie_ptr)[idx++] << 8; protocol_cnfg_opts->opt[protocol_cnfg_opts->N_opts].id |= (*ie_ptr)[idx++]; protocol_cnfg_opts->opt[protocol_cnfg_opts->N_opts].len = (*ie_ptr)[idx++]; for (i = 0; i < protocol_cnfg_opts->opt[protocol_cnfg_opts->N_opts].len; i++) { protocol_cnfg_opts->opt[protocol_cnfg_opts->N_opts].contents[i] = (*ie_ptr)[idx++]; } protocol_cnfg_opts->N_opts++; } *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Quality Of Service Description: Specifies the QoS parameters for a PDP context. Document Reference: 24.301 v10.2.0 Section 9.9.4.12 24.008 v10.2.0 Section 10.5.6.5 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_quality_of_service_ie(LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT* qos, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (qos != NULL && ie_ptr != NULL) { if (qos->dl_ext_present && qos->ul_ext_present) { (*ie_ptr)[0] = 16; } else if (qos->dl_ext_present) { (*ie_ptr)[0] = 14; } else { (*ie_ptr)[0] = 12; } (*ie_ptr)[1] = ((qos->delay_class & 0x07) << 3) | (qos->reliability_class & 0x07); (*ie_ptr)[2] = ((qos->peak_throughput & 0x0F) << 4) | (qos->precedence_class & 0x07); (*ie_ptr)[3] = qos->mean_throughput & 0x1F; (*ie_ptr)[4] = ((qos->traffic_class & 0x07) << 5) | ((qos->delivery_order & 0x03) << 3) | (qos->delivery_of_erroneous_sdu & 0x03); (*ie_ptr)[5] = qos->max_sdu_size; (*ie_ptr)[6] = qos->mbr_ul; (*ie_ptr)[7] = qos->mbr_dl; (*ie_ptr)[8] = ((qos->residual_ber & 0x0F) << 4) | (qos->sdu_error_ratio & 0x0F); (*ie_ptr)[9] = ((qos->transfer_delay & 0x3F) << 2) | (qos->traffic_handling_prio & 0x03); (*ie_ptr)[10] = qos->gbr_ul; (*ie_ptr)[11] = qos->gbr_dl; (*ie_ptr)[12] = ((qos->signalling_ind & 0x01) << 4) | (qos->source_stats_descriptor & 0x0F); if (qos->dl_ext_present) { (*ie_ptr)[13] = qos->mbr_dl_ext; (*ie_ptr)[14] = qos->gbr_dl_ext; } if (qos->ul_ext_present) { (*ie_ptr)[15] = qos->mbr_ul_ext; (*ie_ptr)[16] = qos->gbr_ul_ext; } if (qos->dl_ext_present && qos->ul_ext_present) { *ie_ptr += 17; } else if (qos->dl_ext_present) { *ie_ptr += 15; } else { *ie_ptr += 13; } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_quality_of_service_ie(uint8** ie_ptr, LIBLTE_MME_QUALITY_OF_SERVICE_STRUCT* qos) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && qos != NULL) { if (16 == (*ie_ptr)[0]) { qos->dl_ext_present = true; qos->ul_ext_present = true; } else if (14 == (*ie_ptr)[0]) { qos->dl_ext_present = true; qos->ul_ext_present = false; } else { qos->dl_ext_present = false; qos->ul_ext_present = false; } qos->delay_class = ((*ie_ptr)[1] >> 3) & 0x07; qos->reliability_class = (*ie_ptr)[1] & 0x07; qos->peak_throughput = (*ie_ptr)[2] >> 4; qos->precedence_class = (*ie_ptr)[2] & 0x07; qos->mean_throughput = (*ie_ptr)[3] & 0x1F; qos->traffic_class = ((*ie_ptr)[4] >> 5) & 0x07; qos->delivery_order = ((*ie_ptr)[4] >> 3) & 0x03; qos->delivery_of_erroneous_sdu = (*ie_ptr)[4] & 0x07; qos->max_sdu_size = (*ie_ptr)[5]; qos->mbr_ul = (*ie_ptr)[6]; qos->mbr_dl = (*ie_ptr)[7]; qos->residual_ber = ((*ie_ptr)[8] >> 4) & 0x0F; qos->sdu_error_ratio = (*ie_ptr)[8] & 0x0F; qos->transfer_delay = ((*ie_ptr)[9] >> 2) & 0x3F; qos->traffic_handling_prio = (*ie_ptr)[9] & 0x03; qos->gbr_ul = (*ie_ptr)[10]; qos->gbr_dl = (*ie_ptr)[11]; qos->signalling_ind = ((*ie_ptr)[12] >> 4) & 0x01; qos->source_stats_descriptor = (*ie_ptr)[12] & 0x0F; if (qos->dl_ext_present) { qos->mbr_dl_ext = (*ie_ptr)[13]; qos->gbr_dl_ext = (*ie_ptr)[14]; } if (qos->ul_ext_present) { qos->mbr_ul_ext = (*ie_ptr)[15]; qos->gbr_ul_ext = (*ie_ptr)[16]; } if (qos->dl_ext_present && qos->ul_ext_present) { *ie_ptr += 17; } else if (qos->dl_ext_present) { *ie_ptr += 15; } else { *ie_ptr += 13; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Radio Priority Description: Specifies the priority level the UE shall use at the lower layers for transmission of data related to a PDP context or for mobile originated SMS transmission. Document Reference: 24.301 v10.2.0 Section 9.9.4.13 24.008 v10.2.0 Section 10.5.7.2 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_radio_priority_ie(uint8 radio_prio, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { (*ie_ptr)[0] = radio_prio << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_radio_priority_ie(uint8** ie_ptr, uint8 bit_offset, uint8* radio_prio) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && radio_prio != NULL) { *radio_prio = ((*ie_ptr)[0] >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Request Type Description: Indicates whether the UE requests to establish a new connectivity to a PDN or keep the connection(s) to which it has connected via non-3GPP access. Document Reference: 24.301 v10.2.0 Section 9.9.4.14 24.008 v10.2.0 Section 10.5.6.17 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_request_type_ie(uint8 req_type, uint8 bit_offset, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL) { **ie_ptr |= req_type << bit_offset; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_request_type_ie(uint8** ie_ptr, uint8 bit_offset, uint8* req_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && req_type != NULL) { *req_type = (**ie_ptr >> bit_offset) & 0x07; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Traffic Flow Aggregate Description Description: Specifies the aggregate of one or more packet filters and their related parameters and operations. Document Reference: 24.301 v10.2.0 Section 9.9.4.15 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_traffic_flow_aggregate_description_ie(LIBLTE_MME_TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_STRUCT* tfad, uint8** ie_ptr) { return (liblte_mme_pack_traffic_flow_template_ie((LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT*)tfad, ie_ptr)); } LIBLTE_ERROR_ENUM liblte_mme_unpack_traffic_flow_aggregate_description_ie(uint8** ie_ptr, LIBLTE_MME_TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_STRUCT* tfad) { return (liblte_mme_unpack_traffic_flow_template_ie(ie_ptr, (LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT*)tfad)); } /********************************************************************* IE Name: Traffic Flow Template Description: Specifies the TFT parameters and operations for a PDP context. Document Reference: 24.301 v10.2.0 Section 9.9.4.16 24.008 v10.2.0 Section 10.5.6.12 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_traffic_flow_template_ie(LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 idx; uint32 i; uint32 j; if (tft != NULL && ie_ptr != NULL) { idx = 1; (*ie_ptr)[idx] = (tft->tft_op_code & 0x07) << 5; if (0 != tft->parameter_list_size) { (*ie_ptr)[idx] |= 0x10; } (*ie_ptr)[idx] |= tft->packet_filter_list_size & 0x0F; idx++; for (i = 0; i < tft->packet_filter_list_size; i++) { (*ie_ptr)[idx] = (tft->packet_filter_list[i].dir & 0x0F) << 4; (*ie_ptr)[idx] |= tft->packet_filter_list[i].id & 0x0F; idx++; if (LIBLTE_MME_TFT_OPERATION_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING_TFT != tft->tft_op_code) { (*ie_ptr)[idx] = tft->packet_filter_list[i].eval_precedence; idx++; (*ie_ptr)[idx] = tft->packet_filter_list[i].filter_size; idx++; for (j = 0; j < tft->packet_filter_list[i].filter_size; j++) { (*ie_ptr)[idx] = tft->packet_filter_list[i].filter[j]; idx++; } } } for (i = 0; i < tft->parameter_list_size; i++) { (*ie_ptr)[idx] = tft->parameter_list[i].id; idx++; (*ie_ptr)[idx] = tft->parameter_list[i].parameter_size; idx++; for (j = 0; j < tft->parameter_list[i].parameter_size; j++) { (*ie_ptr)[idx] = tft->parameter_list[i].parameter[j]; idx++; } } (*ie_ptr)[0] = idx - 1; *ie_ptr += idx; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_traffic_flow_template_ie(uint8** ie_ptr, LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint32 idx; uint32 i; uint32 j; bool param_list_present; if (ie_ptr != NULL && tft != NULL) { idx = 1; tft->tft_op_code = (LIBLTE_MME_TFT_OPERATION_CODE_ENUM)(((*ie_ptr)[idx] >> 5) & 0x07); param_list_present = ((*ie_ptr)[idx] >> 4) & 0x01; tft->packet_filter_list_size = (*ie_ptr)[idx] & 0x0F; idx++; for (i = 0; i < tft->packet_filter_list_size; i++) { tft->packet_filter_list[i].dir = (LIBLTE_MME_TFT_PACKET_FILTER_DIRECTION_ENUM)(((*ie_ptr)[idx] >> 4) & 0x0F); tft->packet_filter_list[i].id = (*ie_ptr)[idx] & 0x0F; idx++; if (LIBLTE_MME_TFT_OPERATION_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING_TFT != tft->tft_op_code) { tft->packet_filter_list[i].eval_precedence = (*ie_ptr)[idx]; idx++; tft->packet_filter_list[i].filter_size = (*ie_ptr)[idx]; idx++; for (j = 0; j < tft->packet_filter_list[i].filter_size; j++) { tft->packet_filter_list[i].filter[j] = (*ie_ptr)[idx]; idx++; } } } tft->parameter_list_size = 0; if (param_list_present) { while (idx < (*ie_ptr)[0]) { tft->parameter_list[tft->parameter_list_size].id = (*ie_ptr)[idx]; idx++; tft->parameter_list[tft->parameter_list_size].parameter_size = (*ie_ptr)[idx]; idx++; for (i = 0; i < tft->parameter_list[tft->parameter_list_size].parameter_size; i++) { tft->parameter_list[tft->parameter_list_size].parameter[i] = (*ie_ptr)[idx]; idx++; } tft->parameter_list_size++; } } *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* IE Name: Transaction Identifier Description: Represents the corresponding PDP context in A/Gb mode or Iu mode which is mapped from the EPS bearer context. Document Reference: 24.301 v10.2.0 Section 9.9.4.17 24.008 v10.2.0 Section 10.5.6.7 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_transaction_identifier_ie(LIBLTE_MME_TRANSACTION_IDENTIFIER_STRUCT* trans_id, uint8** ie_ptr) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (trans_id != NULL && ie_ptr != NULL) { if (LIBLTE_MME_TI_VALUE_IS_GIVEN_BY_TIE == trans_id->tio) { (*ie_ptr)[0] = 2; } else { (*ie_ptr)[0] = 1; } (*ie_ptr)[1] = ((trans_id->ti_flag & 0x01) << 7) | ((trans_id->tio & 0x07) << 4); if (LIBLTE_MME_TI_VALUE_IS_GIVEN_BY_TIE == trans_id->tio) { (*ie_ptr)[2] = 0x80 | (trans_id->tie & 0x7F); *ie_ptr += 3; } else { *ie_ptr += 2; } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_transaction_identifier_ie(uint8** ie_ptr, LIBLTE_MME_TRANSACTION_IDENTIFIER_STRUCT* trans_id) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && trans_id != NULL) { uint8_t len = (*ie_ptr)[0]; trans_id->ti_flag = (*ie_ptr)[1] >> 7; trans_id->tio = ((*ie_ptr)[1] >> 4) & 0x07; if (len > 2 || len == 0) { return err; } if (2 == len) { trans_id->tie = (*ie_ptr)[2] & 0x7F; } *ie_ptr += (*ie_ptr)[0] + 1; err = LIBLTE_SUCCESS; } return (err); } /******************************************************************************* MESSAGE FUNCTIONS *******************************************************************************/ /********************************************************************* Message Name: Security Message Header (Plain NAS Message) Description: Security header for NAS messages. Document Reference: 24.301 v10.2.0 Section 9.1 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_parse_msg_sec_header(LIBLTE_BYTE_MSG_STRUCT* msg, uint8* pd, uint8* sec_hdr_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (msg != NULL && pd != NULL && sec_hdr_type != NULL) { *sec_hdr_type = (uint8)((msg->msg[0] & 0xF0) >> 4); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Message Header (Plain NAS Message) Description: Message header for plain NAS messages. Document Reference: 24.301 v10.2.0 Section 9.1 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_parse_msg_header(LIBLTE_BYTE_MSG_STRUCT* msg, uint8* pd, uint8* msg_type) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8 sec_hdr_type; if (msg != NULL && pd != NULL && msg_type != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; // Protocol Discriminator *pd = msg->msg[0] & 0x0F; if (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST == sec_hdr_type) { *msg_type = LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST; } else { if (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT == *pd) { // Message Type *msg_type = msg->msg[2]; } else { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { // Message Type *msg_type = msg->msg[1]; } else { // Protocol Discriminator *pd = msg->msg[6] & 0x0F; if (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT == *pd) { *msg_type = msg->msg[8]; } else { *msg_type = msg->msg[7]; } } } } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_pack_security_protected_nas_msg(LIBLTE_BYTE_MSG_STRUCT* msg, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* sec_msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = sec_msg->msg; uint32 i; if (msg != NULL && sec_msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // NAS Message for (i = 0; i < msg->N_bytes; i++) { *msg_ptr = msg->msg[i]; msg_ptr++; } // Fill in the number of bytes used sec_msg->N_bytes = msg_ptr - sec_msg->msg; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Attach Accept Description: Sent by the network to the UE to indicate that the corresponding attach request has been accepted. Document Reference: 24.301 v10.2.0 Section 8.2.1 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_accept_msg(LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT* attach_accept, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (attach_accept != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT; msg_ptr++; // EPS Attach Result & Spare Half Octet *msg_ptr = 0; liblte_mme_pack_eps_attach_result_ie(attach_accept->eps_attach_result, 0, &msg_ptr); msg_ptr++; // T3412 Value liblte_mme_pack_gprs_timer_ie(&attach_accept->t3412, &msg_ptr); // TAI List liblte_mme_pack_tracking_area_identity_list_ie(&attach_accept->tai_list, &msg_ptr); // ESM Message Container liblte_mme_pack_esm_message_container_ie(&attach_accept->esm_msg, &msg_ptr); // GUTI if (attach_accept->guti_present) { *msg_ptr = LIBLTE_MME_GUTI_IEI; msg_ptr++; liblte_mme_pack_eps_mobile_id_ie(&attach_accept->guti, &msg_ptr); } // Location Area Identification if (attach_accept->lai_present) { *msg_ptr = LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI; msg_ptr++; liblte_mme_pack_location_area_id_ie(&attach_accept->lai, &msg_ptr); } // MS Identity if (attach_accept->ms_id_present) { *msg_ptr = LIBLTE_MME_MS_IDENTITY_IEI; msg_ptr++; liblte_mme_pack_mobile_id_ie(&attach_accept->ms_id, &msg_ptr); } // EMM Cause if (attach_accept->emm_cause_present) { *msg_ptr = LIBLTE_MME_EMM_CAUSE_IEI; msg_ptr++; liblte_mme_pack_emm_cause_ie(attach_accept->emm_cause, &msg_ptr); } // T3402 Value if (attach_accept->t3402_present) { *msg_ptr = LIBLTE_MME_T3402_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_ie(&attach_accept->t3402, &msg_ptr); } // T3423 Value if (attach_accept->t3423_present) { *msg_ptr = LIBLTE_MME_T3423_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_ie(&attach_accept->t3423, &msg_ptr); } // Equivalent PLMNs if (attach_accept->equivalent_plmns_present) { *msg_ptr = LIBLTE_MME_EQUIVALENT_PLMNS_IEI; msg_ptr++; liblte_mme_pack_plmn_list_ie(&attach_accept->equivalent_plmns, &msg_ptr); } // Emergency Number List if (attach_accept->emerg_num_list_present) { *msg_ptr = LIBLTE_MME_EMERGENCY_NUMBER_LIST_IEI; msg_ptr++; liblte_mme_pack_emergency_number_list_ie(&attach_accept->emerg_num_list, &msg_ptr); } // EPS Network Feature Support if (attach_accept->eps_network_feature_support_present) { *msg_ptr = LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI; msg_ptr++; liblte_mme_pack_eps_network_feature_support_ie(&attach_accept->eps_network_feature_support, &msg_ptr); } // Additional Update Result if (attach_accept->additional_update_result_present) { *msg_ptr = LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI << 4; liblte_mme_pack_additional_update_result_ie(attach_accept->additional_update_result, 0, &msg_ptr); msg_ptr++; } // T3412 Extended Value if (attach_accept->t3412_ext_present) { *msg_ptr = LIBLTE_MME_T3412_EXTENDED_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_3_ie(&attach_accept->t3412_ext, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_accept_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT* attach_accept) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && attach_accept != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // EPS Attach Result & Spare Half Octet liblte_mme_unpack_eps_attach_result_ie(&msg_ptr, 0, &attach_accept->eps_attach_result); msg_ptr++; // T3412 Value liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &attach_accept->t3412); // TAI List liblte_mme_unpack_tracking_area_identity_list_ie(&msg_ptr, &attach_accept->tai_list); // ESM Message Container liblte_mme_unpack_esm_message_container_ie(&msg_ptr, &attach_accept->esm_msg); // GUTI if (LIBLTE_MME_GUTI_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &attach_accept->guti); attach_accept->guti_present = true; } else { attach_accept->guti_present = false; } // Location Area Identification if (LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_location_area_id_ie(&msg_ptr, &attach_accept->lai); attach_accept->lai_present = true; } else { attach_accept->lai_present = false; } // MS Identity if (LIBLTE_MME_MS_IDENTITY_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_mobile_id_ie(&msg_ptr, &attach_accept->ms_id); attach_accept->ms_id_present = true; } else { attach_accept->ms_id_present = false; } // EMM Cause if (LIBLTE_MME_EMM_CAUSE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_emm_cause_ie(&msg_ptr, &attach_accept->emm_cause); attach_accept->emm_cause_present = true; } else { attach_accept->emm_cause_present = false; } // T3402 Value if (LIBLTE_MME_T3402_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &attach_accept->t3402); attach_accept->t3402_present = true; } else { attach_accept->t3402_present = false; } // T3423 Value if (LIBLTE_MME_T3423_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &attach_accept->t3423); attach_accept->t3423_present = true; } else { attach_accept->t3423_present = false; } // Equivalent PLMNs if (LIBLTE_MME_EQUIVALENT_PLMNS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_plmn_list_ie(&msg_ptr, &attach_accept->equivalent_plmns); attach_accept->equivalent_plmns_present = true; } else { attach_accept->equivalent_plmns_present = false; } // Emergency Number List if (LIBLTE_MME_EMERGENCY_NUMBER_LIST_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_emergency_number_list_ie(&msg_ptr, &attach_accept->emerg_num_list); attach_accept->emerg_num_list_present = true; } else { attach_accept->emerg_num_list_present = false; } // EPS Network Feature Support if (LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_eps_network_feature_support_ie(&msg_ptr, &attach_accept->eps_network_feature_support); attach_accept->eps_network_feature_support_present = true; } else { attach_accept->eps_network_feature_support_present = false; } // Additional Update Result if ((LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_additional_update_result_ie(&msg_ptr, 0, &attach_accept->additional_update_result); msg_ptr++; attach_accept->additional_update_result_present = true; } else { attach_accept->additional_update_result_present = false; } // T3412 Extended Value if (LIBLTE_MME_T3412_EXTENDED_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &attach_accept->t3412_ext); attach_accept->t3412_ext_present = true; } else { attach_accept->t3412_ext_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Attach Complete Description: Sent by the UE to the network in response to an ATTACH ACCEPT message. Document Reference: 24.301 v10.2.0 Section 8.2.2 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_complete_msg(LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT* attach_comp, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (attach_comp != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE; msg_ptr++; // ESM Message Container liblte_mme_pack_esm_message_container_ie(&attach_comp->esm_msg, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_complete_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT* attach_comp) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && attach_comp != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // ESM Message Container liblte_mme_unpack_esm_message_container_ie(&msg_ptr, &attach_comp->esm_msg); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Attach Reject Description: Sent by the network to the UE to indicate that the corresponding attach request has been rejected. Document Reference: 24.301 v10.2.0 Section 8.2.3 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_reject_msg(LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT* attach_rej, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (attach_rej != NULL && msg != NULL) { // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ATTACH_REJECT; msg_ptr++; // EMM Cause liblte_mme_pack_emm_cause_ie(attach_rej->emm_cause, &msg_ptr); // ESM Message Container if (attach_rej->esm_msg_present) { *msg_ptr = LIBLTE_MME_ESM_MSG_CONTAINER_IEI; msg_ptr++; liblte_mme_pack_esm_message_container_ie(&attach_rej->esm_msg, &msg_ptr); } // T3446 Value if (attach_rej->t3446_value_present) { *msg_ptr = LIBLTE_MME_T3446_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_2_ie(attach_rej->t3446_value, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_reject_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT* attach_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && attach_rej != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // EMM Cause liblte_mme_unpack_emm_cause_ie(&msg_ptr, &attach_rej->emm_cause); // ESM Message Container if (LIBLTE_MME_ESM_MSG_CONTAINER_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_esm_message_container_ie(&msg_ptr, &attach_rej->esm_msg); attach_rej->esm_msg_present = true; } else { attach_rej->esm_msg_present = false; } // T3446 Value if (LIBLTE_MME_T3446_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_2_ie(&msg_ptr, &attach_rej->t3446_value); attach_rej->t3446_value_present = true; } else { attach_rej->t3446_value_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Attach Request Description: Sent by the UE to the network to perform an attach procedure. Document Reference: 24.301 v10.2.0 Section 8.2.4 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT* attach_req, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); return liblte_mme_pack_attach_request_msg(attach_req, LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, 0, msg); } LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT* attach_req, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (attach_req != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST; msg_ptr++; // EPS Attach Type & NAS Key Set Identifier *msg_ptr = 0; liblte_mme_pack_eps_attach_type_ie(attach_req->eps_attach_type, 0, &msg_ptr); liblte_mme_pack_nas_key_set_id_ie(&attach_req->nas_ksi, 4, &msg_ptr); msg_ptr++; // EPS Mobile ID liblte_mme_pack_eps_mobile_id_ie(&attach_req->eps_mobile_id, &msg_ptr); // UE Network Capability liblte_mme_pack_ue_network_capability_ie(&attach_req->ue_network_cap, &msg_ptr); // ESM Message Container liblte_mme_pack_esm_message_container_ie(&attach_req->esm_msg, &msg_ptr); // Old P-TMSI Signature if (attach_req->old_p_tmsi_signature_present) { *msg_ptr = LIBLTE_MME_P_TMSI_SIGNATURE_IEI; msg_ptr++; liblte_mme_pack_p_tmsi_signature_ie(attach_req->old_p_tmsi_signature, &msg_ptr); } // Additional GUTI if (attach_req->additional_guti_present) { *msg_ptr = LIBLTE_MME_ADDITIONAL_GUTI_IEI; msg_ptr++; liblte_mme_pack_eps_mobile_id_ie(&attach_req->additional_guti, &msg_ptr); } // Last Visited Registered TAI if (attach_req->last_visited_registered_tai_present) { *msg_ptr = LIBLTE_MME_LAST_VISITED_REGISTERED_TAI_IEI; msg_ptr++; liblte_mme_pack_tracking_area_id_ie(&attach_req->last_visited_registered_tai, &msg_ptr); } // DRX Parameter if (attach_req->drx_param_present) { *msg_ptr = LIBLTE_MME_DRX_PARAMETER_IEI; msg_ptr++; liblte_mme_pack_drx_parameter_ie(&attach_req->drx_param, &msg_ptr); } // MS Network Capability if (attach_req->ms_network_cap_present) { *msg_ptr = LIBLTE_MME_MS_NETWORK_CAPABILITY_IEI; msg_ptr++; liblte_mme_pack_ms_network_capability_ie(&attach_req->ms_network_cap, &msg_ptr); } // Old Location Area ID if (attach_req->old_lai_present) { *msg_ptr = LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI; msg_ptr++; liblte_mme_pack_location_area_id_ie(&attach_req->old_lai, &msg_ptr); } // TMSI Status if (attach_req->tmsi_status_present) { *msg_ptr = LIBLTE_MME_TMSI_STATUS_IEI << 4; liblte_mme_pack_tmsi_status_ie(attach_req->tmsi_status, 0, &msg_ptr); msg_ptr++; } // Mobile Station Classmark 2 if (attach_req->ms_cm2_present) { *msg_ptr = LIBLTE_MME_MS_CLASSMARK_2_IEI; msg_ptr++; liblte_mme_pack_mobile_station_classmark_2_ie(&attach_req->ms_cm2, &msg_ptr); } // Mobile Station Classmark 3 if (attach_req->ms_cm3_present) { *msg_ptr = LIBLTE_MME_MS_CLASSMARK_3_IEI; msg_ptr++; } // Supported Codecs if (attach_req->supported_codecs_present) { *msg_ptr = LIBLTE_MME_SUPPORTED_CODEC_LIST_IEI; msg_ptr++; liblte_mme_pack_supported_codec_list_ie(&attach_req->supported_codecs, &msg_ptr); } // Additional Update Type if (attach_req->additional_update_type_present) { *msg_ptr = LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_IEI << 4; liblte_mme_pack_additional_update_type_ie(attach_req->additional_update_type, 0, &msg_ptr); msg_ptr++; } // Voice Domain Preference and UE's Usage Setting if (attach_req->voice_domain_pref_and_ue_usage_setting_present) { *msg_ptr = LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_IEI; msg_ptr++; liblte_mme_pack_voice_domain_pref_and_ue_usage_setting_ie(&attach_req->voice_domain_pref_and_ue_usage_setting, &msg_ptr); } // Device Properties if (attach_req->device_properties_present) { *msg_ptr = LIBLTE_MME_ATTACH_REQUEST_DEVICE_PROPERTIES_IEI << 4; liblte_mme_pack_device_properties_ie(attach_req->device_properties, 0, &msg_ptr); msg_ptr++; } // Old GUTI Type if (attach_req->old_guti_type_present) { *msg_ptr = LIBLTE_MME_GUTI_TYPE_IEI << 4; liblte_mme_pack_guti_type_ie(attach_req->old_guti_type, 0, &msg_ptr); msg_ptr++; } if (attach_req->additional_security_cap_present) { *msg_ptr = LIBLTE_MME_ADDITIONAL_SECURITY_CAP_IEI; msg_ptr++; *msg_ptr = 0x4; // Length msg_ptr++; // Pack same capabilities that are used for EUTRA *msg_ptr = attach_req->ue_network_cap.eea[0] << 7; *msg_ptr |= attach_req->ue_network_cap.eea[1] << 6; *msg_ptr |= attach_req->ue_network_cap.eea[2] << 5; *msg_ptr |= attach_req->ue_network_cap.eea[3] << 4; *msg_ptr |= attach_req->ue_network_cap.eea[4] << 3; *msg_ptr |= attach_req->ue_network_cap.eea[5] << 2; *msg_ptr |= attach_req->ue_network_cap.eea[6] << 1; *msg_ptr |= attach_req->ue_network_cap.eea[7]; msg_ptr++; // 0x00 (5G-EA8=0, 5G-EA9=0, 5G-EA10=0, 5G-EA11=0, 5G-EA12=0, 5G-EA13=0, 5G-EA14=0, 5G-EA15=0) *msg_ptr = 0x00; msg_ptr++; // Pack same integrity caps *msg_ptr = attach_req->ue_network_cap.eia[0] << 7; *msg_ptr |= attach_req->ue_network_cap.eia[1] << 6; *msg_ptr |= attach_req->ue_network_cap.eia[2] << 5; *msg_ptr |= attach_req->ue_network_cap.eia[3] << 4; *msg_ptr |= attach_req->ue_network_cap.eia[4] << 3; *msg_ptr |= attach_req->ue_network_cap.eia[5] << 2; *msg_ptr |= attach_req->ue_network_cap.eia[6] << 1; *msg_ptr |= attach_req->ue_network_cap.eia[7]; msg_ptr++; // 0x00 (5G-IA8=0, 5G-IA9=0, 5G-IA10=0, 5G-IA11=0, 5G-IA12=0, 5G-IA13=0, 5G-IA14=0, 5G-IA15=0) *msg_ptr = 0x00; msg_ptr++; } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_request_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT* attach_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && attach_req != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // EPS Attach Type & NAS Key Set Identifier liblte_mme_unpack_eps_attach_type_ie(&msg_ptr, 0, &attach_req->eps_attach_type); liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 4, &attach_req->nas_ksi); msg_ptr++; // EPS Mobile ID liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &attach_req->eps_mobile_id); // UE Network Capability liblte_mme_unpack_ue_network_capability_ie(&msg_ptr, &attach_req->ue_network_cap); // ESM Message Container liblte_mme_unpack_esm_message_container_ie(&msg_ptr, &attach_req->esm_msg); // Old P-TMSI Signature if (LIBLTE_MME_P_TMSI_SIGNATURE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_p_tmsi_signature_ie(&msg_ptr, &attach_req->old_p_tmsi_signature); attach_req->old_p_tmsi_signature_present = true; } else { attach_req->old_p_tmsi_signature_present = false; } // Additional GUTI if (LIBLTE_MME_ADDITIONAL_GUTI_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &attach_req->additional_guti); attach_req->additional_guti_present = true; } else { attach_req->additional_guti_present = false; } // Last Visited Registered TAI if (LIBLTE_MME_LAST_VISITED_REGISTERED_TAI_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_tracking_area_id_ie(&msg_ptr, &attach_req->last_visited_registered_tai); attach_req->last_visited_registered_tai_present = true; } else { attach_req->last_visited_registered_tai_present = false; } // DRX Parameter if (LIBLTE_MME_DRX_PARAMETER_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_drx_parameter_ie(&msg_ptr, &attach_req->drx_param); attach_req->drx_param_present = true; } else { attach_req->drx_param_present = false; } // MS Network Capability if (LIBLTE_MME_MS_NETWORK_CAPABILITY_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_ms_network_capability_ie(&msg_ptr, &attach_req->ms_network_cap); attach_req->ms_network_cap_present = true; } else { attach_req->ms_network_cap_present = false; } // Old Location Area ID if (LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_location_area_id_ie(&msg_ptr, &attach_req->old_lai); attach_req->old_lai_present = true; } else { attach_req->old_lai_present = false; } // TMSI Status if ((LIBLTE_MME_TMSI_STATUS_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_tmsi_status_ie(&msg_ptr, 0, &attach_req->tmsi_status); msg_ptr++; attach_req->tmsi_status_present = true; } else { attach_req->tmsi_status_present = false; } // Mobile Station Classmark 2 if (LIBLTE_MME_MS_CLASSMARK_2_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_mobile_station_classmark_2_ie(&msg_ptr, &attach_req->ms_cm2); attach_req->ms_cm2_present = true; } else { attach_req->ms_cm2_present = false; } // Mobile Station Classmark 3 if (LIBLTE_MME_MS_CLASSMARK_3_IEI == *msg_ptr) { msg_ptr++; attach_req->ms_cm3_present = true; } else { attach_req->ms_cm3_present = false; } // Supported Codecs if (LIBLTE_MME_SUPPORTED_CODEC_LIST_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_supported_codec_list_ie(&msg_ptr, &attach_req->supported_codecs); attach_req->supported_codecs_present = true; } else { attach_req->supported_codecs_present = false; } // Additional Update Type if ((LIBLTE_MME_ADDITIONAL_UPDATE_TYPE_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_additional_update_type_ie(&msg_ptr, 0, &attach_req->additional_update_type); msg_ptr++; attach_req->additional_update_type_present = true; } else { attach_req->additional_update_type_present = false; } // Voice Domain Preference and UE's Usage Setting if (LIBLTE_MME_VOICE_DOMAIN_PREF_AND_UE_USAGE_SETTING_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_voice_domain_pref_and_ue_usage_setting_ie(&msg_ptr, &attach_req->voice_domain_pref_and_ue_usage_setting); attach_req->voice_domain_pref_and_ue_usage_setting_present = true; } else { attach_req->voice_domain_pref_and_ue_usage_setting_present = false; } // Device Properties if ((LIBLTE_MME_ATTACH_REQUEST_DEVICE_PROPERTIES_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &attach_req->device_properties); msg_ptr++; attach_req->device_properties_present = true; } else { attach_req->device_properties_present = false; } // Old GUTI Type if ((LIBLTE_MME_GUTI_TYPE_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_guti_type_ie(&msg_ptr, 0, &attach_req->old_guti_type); msg_ptr++; attach_req->old_guti_type_present = true; } else { attach_req->old_guti_type_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Authentication Failure Description: Sent by the UE to the network to indicate that authentication of the network has failed. Document Reference: 24.301 v10.2.0 Section 8.2.5 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_failure_msg(LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT* auth_fail, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (auth_fail != NULL && msg != NULL) { // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE; msg_ptr++; // EMM Cause liblte_mme_pack_emm_cause_ie(auth_fail->emm_cause, &msg_ptr); // Authentication Failure Parameter if (auth_fail->auth_fail_param_present) { *msg_ptr = LIBLTE_MME_AUTHENTICATION_FAILURE_PARAMETER_IEI; msg_ptr++; liblte_mme_pack_authentication_failure_parameter_ie(auth_fail->auth_fail_param, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_failure_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_AUTHENTICATION_FAILURE_MSG_STRUCT* auth_fail) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && auth_fail != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // EMM Cause liblte_mme_unpack_emm_cause_ie(&msg_ptr, &auth_fail->emm_cause); // Authentication Failure Parameter if (LIBLTE_MME_AUTHENTICATION_FAILURE_PARAMETER_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_authentication_failure_parameter_ie(&msg_ptr, auth_fail->auth_fail_param); auth_fail->auth_fail_param_present = true; } else { auth_fail->auth_fail_param_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Authentication Reject Description: Sent by the network to the UE to indicate that the authentication procedure has failed and that the UE shall abort all activities. Document Reference: 24.301 v10.2.0 Section 8.2.6 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_reject_msg(LIBLTE_MME_AUTHENTICATION_REJECT_MSG_STRUCT* auth_reject, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (auth_reject != NULL && msg != NULL) { // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT; msg_ptr++; // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_reject_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_AUTHENTICATION_REJECT_MSG_STRUCT* auth_reject) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && auth_reject != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Authentication Request Description: Sent by the network to the UE to initiate authentication of the UE identity. Document Reference: 24.301 v10.2.0 Section 8.2.7 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_request_msg(LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT* auth_req, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (auth_req != NULL && msg != NULL) { // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST; msg_ptr++; // NAS Key Set Identifier & Spare Half Octet *msg_ptr = 0; liblte_mme_pack_nas_key_set_id_ie(&auth_req->nas_ksi, 0, &msg_ptr); msg_ptr++; // Authentication Parameter RAND liblte_mme_pack_authentication_parameter_rand_ie(auth_req->rand, &msg_ptr); // Authentication Parameter AUTN liblte_mme_pack_authentication_parameter_autn_ie(auth_req->autn, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_request_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT* auth_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && auth_req != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // NAS Key Set Identifier & Spare Half Octet liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 0, &auth_req->nas_ksi); msg_ptr++; // Authentication Parameter RAND liblte_mme_unpack_authentication_parameter_rand_ie(&msg_ptr, auth_req->rand); // Authentication Parameter AUTN liblte_mme_unpack_authentication_parameter_autn_ie(&msg_ptr, auth_req->autn); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Authentication Response Description: Sent by the UE to the network to deliver a calculated authentication response to the network. Document Reference: 24.301 v10.2.0 Section 8.2.8 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_authentication_response_msg(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT* auth_resp, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (auth_resp != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE; msg_ptr++; // Authentication Response Parameter (RES) liblte_mme_pack_authentication_response_parameter_ie(auth_resp->res, auth_resp->res_len, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_authentication_response_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT* auth_resp) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && auth_resp != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // Authentication Response Parameter (RES) liblte_mme_unpack_authentication_response_parameter_ie(&msg_ptr, auth_resp->res); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: CS Service Notification Description: Sent by the network when a paging request with CS call indicator was received via SGs for a UE, and a NAS signalling connection is already established for the UE. Document Reference: 24.301 v10.2.0 Section 8.2.9 *********************************************************************/ // TODO /********************************************************************* Message Name: Detach Accept Description: Sent by the network to indicate that the detach procedure has been completed. Document Reference: 24.301 v10.2.0 Section 8.2.10 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_detach_accept_msg(LIBLTE_MME_DETACH_ACCEPT_MSG_STRUCT* detach_accept, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (detach_accept != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_DETACH_ACCEPT; msg_ptr++; // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_detach_accept_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_DETACH_ACCEPT_MSG_STRUCT* detach_accept) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && detach_accept != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Detach Request Description: Sent by the UE to request the release of an EMM context. Document Reference: 24.301 v10.2.0 Section 8.2.11 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_detach_request_msg(LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT* detach_req, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (detach_req != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_DETACH_REQUEST; msg_ptr++; // Detach Type & NAS Key Set Identifier *msg_ptr = 0; liblte_mme_pack_detach_type_ie(&detach_req->detach_type, 0, &msg_ptr); liblte_mme_pack_nas_key_set_id_ie(&detach_req->nas_ksi, 4, &msg_ptr); msg_ptr++; // EPS Mobile ID liblte_mme_pack_eps_mobile_id_ie(&detach_req->eps_mobile_id, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_detach_request_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT* detach_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && detach_req != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // Detach Type & NAS Key Set Identifier liblte_mme_unpack_detach_type_ie(&msg_ptr, 0, &detach_req->detach_type); liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 4, &detach_req->nas_ksi); msg_ptr++; // EPS Mobile ID liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &detach_req->eps_mobile_id); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Downlink NAS Transport Description: Sent by the network to the UE in order to carry an SMS message in encapsulated format. Document Reference: 24.301 v10.2.0 Section 8.2.12 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_downlink_nas_transport_msg(LIBLTE_MME_DOWNLINK_NAS_TRANSPORT_MSG_STRUCT* dl_nas_transport, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (dl_nas_transport != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_DOWNLINK_NAS_TRANSPORT; msg_ptr++; // NAS Message Container liblte_mme_pack_nas_message_container_ie(&dl_nas_transport->nas_msg, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_downlink_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_DOWNLINK_NAS_TRANSPORT_MSG_STRUCT* dl_nas_transport) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && dl_nas_transport != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // NAS Message Container liblte_mme_unpack_nas_message_container_ie(&msg_ptr, &dl_nas_transport->nas_msg); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: EMM Information Description: Sent by the network at any time during EMM context is established to send certain information to the UE. Document Reference: 24.301 v10.2.0 Section 8.2.13 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_emm_information_msg(LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT* emm_info, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (emm_info != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_EMM_INFORMATION; msg_ptr++; // Full Name For Network if (emm_info->full_net_name_present) { *msg_ptr = LIBLTE_MME_FULL_NAME_FOR_NETWORK_IEI; msg_ptr++; liblte_mme_pack_network_name_ie(&emm_info->full_net_name, &msg_ptr); } // Short Name For Network if (emm_info->short_net_name_present) { *msg_ptr = LIBLTE_MME_SHORT_NAME_FOR_NETWORK_IEI; msg_ptr++; liblte_mme_pack_network_name_ie(&emm_info->short_net_name, &msg_ptr); } // Local Time Zone if (emm_info->local_time_zone_present) { *msg_ptr = LIBLTE_MME_LOCAL_TIME_ZONE_IEI; msg_ptr++; liblte_mme_pack_time_zone_ie(emm_info->local_time_zone, &msg_ptr); } // Universal Time And Local Time Zone if (emm_info->utc_and_local_time_zone_present) { *msg_ptr = LIBLTE_MME_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI; msg_ptr++; liblte_mme_pack_time_zone_and_time_ie(&emm_info->utc_and_local_time_zone, &msg_ptr); } // Network Daylight Saving Time if (emm_info->net_dst_present) { *msg_ptr = LIBLTE_MME_NETWORK_DAYLIGHT_SAVING_TIME_IEI; msg_ptr++; liblte_mme_pack_daylight_saving_time_ie(emm_info->net_dst, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_information_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT* emm_info) { if (!msg || !emm_info) { return LIBLTE_ERROR_INVALID_INPUTS; } uint8* msg_ptr = msg->msg; uint8* msg_end = msg->msg + msg->N_bytes; uint8 sec_hdr_type; // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // Full Name For Network if (LIBLTE_MME_FULL_NAME_FOR_NETWORK_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_network_name_ie(&msg_ptr, &emm_info->full_net_name); emm_info->full_net_name_present = true; } else { emm_info->full_net_name_present = false; } // Short Name For Network if (msg_ptr < msg_end && LIBLTE_MME_SHORT_NAME_FOR_NETWORK_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_network_name_ie(&msg_ptr, &emm_info->short_net_name); emm_info->short_net_name_present = true; } else { emm_info->short_net_name_present = false; } // Local Time Zone if (msg_ptr < msg_end && LIBLTE_MME_LOCAL_TIME_ZONE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_time_zone_ie(&msg_ptr, &emm_info->local_time_zone); emm_info->local_time_zone_present = true; } else { emm_info->local_time_zone_present = false; } // Universal Time And Local Time Zone if (msg_ptr < msg_end && LIBLTE_MME_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_time_zone_and_time_ie(&msg_ptr, &emm_info->utc_and_local_time_zone); emm_info->utc_and_local_time_zone_present = true; } else { emm_info->utc_and_local_time_zone_present = false; } // Network Daylight Saving Time if (msg_ptr < msg_end && LIBLTE_MME_NETWORK_DAYLIGHT_SAVING_TIME_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_daylight_saving_time_ie(&msg_ptr, &emm_info->net_dst); emm_info->net_dst_present = true; } else { emm_info->net_dst_present = false; } return LIBLTE_SUCCESS; } /********************************************************************* Message Name: EMM Status Description: Sent by the UE or by the network at any time to report certain error conditions. Document Reference: 24.301 v10.2.0 Section 8.2.14 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_emm_status_msg(LIBLTE_MME_EMM_STATUS_MSG_STRUCT* emm_status, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (emm_status != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_EMM_STATUS; msg_ptr++; // EMM Cause liblte_mme_pack_emm_cause_ie(emm_status->emm_cause, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_emm_status_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_EMM_STATUS_MSG_STRUCT* emm_status) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && emm_status != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // EMM Cause liblte_mme_unpack_emm_cause_ie(&msg_ptr, &emm_status->emm_cause); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Extended Service Request Description: Sent by the UE to the network to initiate a CS fallback or 1xCS fallback call or respond to a mobile terminated CS fallback or 1xCS fallback request from the network or to request the establishment of a NAS signalling connection and of the radio and S1 bearers for packet services, if the UE needs to provide additional information that cannot be provided via a SERVICE REQUEST message. Document Reference: 24.301 v10.2.0 Section 8.2.15 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_extended_service_request_msg(LIBLTE_MME_EXTENDED_SERVICE_REQUEST_MSG_STRUCT* ext_service_req, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (ext_service_req != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_EXTENDED_SERVICE_REQUEST; msg_ptr++; // Service Type & NAS Key Set Identifier *msg_ptr = 0; liblte_mme_pack_service_type_ie(ext_service_req->service_type, 0, &msg_ptr); liblte_mme_pack_nas_key_set_id_ie(&ext_service_req->nas_ksi, 4, &msg_ptr); msg_ptr++; // M-TMSI liblte_mme_pack_mobile_id_ie(&ext_service_req->m_tmsi, &msg_ptr); // CSFB Response if (ext_service_req->csfb_resp_present) { *msg_ptr = LIBLTE_MME_CSFB_RESPONSE_IEI << 4; liblte_mme_pack_csfb_response_ie(ext_service_req->csfb_resp, 0, &msg_ptr); msg_ptr++; } // EPS Bearer Context Status if (ext_service_req->eps_bearer_context_status_present) { *msg_ptr = LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_IEI; msg_ptr++; liblte_mme_pack_eps_bearer_context_status_ie(&ext_service_req->eps_bearer_context_status, &msg_ptr); } // Device Properties if (ext_service_req->device_props_present) { *msg_ptr = LIBLTE_MME_EXTENDED_SERVICE_REQUEST_DEVICE_PROPERTIES_IEI << 4; liblte_mme_pack_device_properties_ie(ext_service_req->device_props, 0, &msg_ptr); msg_ptr++; } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_extended_service_request_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_EXTENDED_SERVICE_REQUEST_MSG_STRUCT* ext_service_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && ext_service_req != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // Service Type & NAS Key Set Identifier liblte_mme_unpack_service_type_ie(&msg_ptr, 0, &ext_service_req->service_type); liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 4, &ext_service_req->nas_ksi); msg_ptr++; // M-TMSI liblte_mme_unpack_mobile_id_ie(&msg_ptr, &ext_service_req->m_tmsi); // CSFB Response if ((LIBLTE_MME_CSFB_RESPONSE_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_csfb_response_ie(&msg_ptr, 0, &ext_service_req->csfb_resp); msg_ptr++; ext_service_req->csfb_resp_present = true; } else { ext_service_req->csfb_resp_present = false; } // EPS Bearer Context Status if (LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_eps_bearer_context_status_ie(&msg_ptr, &ext_service_req->eps_bearer_context_status); ext_service_req->eps_bearer_context_status_present = true; } else { ext_service_req->eps_bearer_context_status_present = false; } // Device Properties if ((LIBLTE_MME_EXTENDED_SERVICE_REQUEST_DEVICE_PROPERTIES_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &ext_service_req->device_props); msg_ptr++; ext_service_req->device_props_present = true; } else { ext_service_req->device_props_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: GUTI Reallocation Command Description: Sent by the network to the UE to reallocate a GUTI and optionally provide a new TAI list. Document Reference: 24.301 v10.2.0 Section 8.2.16 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_guti_reallocation_command_msg(LIBLTE_MME_GUTI_REALLOCATION_COMMAND_MSG_STRUCT* guti_realloc_cmd, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (guti_realloc_cmd != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_GUTI_REALLOCATION_COMMAND; msg_ptr++; // GUTI liblte_mme_pack_eps_mobile_id_ie(&guti_realloc_cmd->guti, &msg_ptr); // TAI List if (guti_realloc_cmd->tai_list_present) { *msg_ptr = LIBLTE_MME_TAI_LIST_IEI; msg_ptr++; liblte_mme_pack_tracking_area_identity_list_ie(&guti_realloc_cmd->tai_list, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_reallocation_command_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_GUTI_REALLOCATION_COMMAND_MSG_STRUCT* guti_realloc_cmd) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && guti_realloc_cmd != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // GUTI liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &guti_realloc_cmd->guti); // TAI List if (LIBLTE_MME_TAI_LIST_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_tracking_area_identity_list_ie(&msg_ptr, &guti_realloc_cmd->tai_list); guti_realloc_cmd->tai_list_present = true; } else { guti_realloc_cmd->tai_list_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: GUTI Reallocation Complete Description: Sent by the UE to the network to indicate that reallocation of a GUTI has taken place. Document Reference: 24.301 v10.2.0 Section 8.2.17 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_guti_reallocation_complete_msg(LIBLTE_MME_GUTI_REALLOCATION_COMPLETE_MSG_STRUCT* guti_realloc_complete, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (guti_realloc_complete != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_GUTI_REALLOCATION_COMPLETE; msg_ptr++; // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_reallocation_complete_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_GUTI_REALLOCATION_COMPLETE_MSG_STRUCT* guti_realloc_complete) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && guti_realloc_complete != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Identity Request Description: Sent by the network to the UE to request the UE to provide the specified identity. Document Reference: 24.301 v10.2.0 Section 8.2.18 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_identity_request_msg(LIBLTE_MME_ID_REQUEST_MSG_STRUCT* id_req, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (id_req != NULL && msg != NULL) { // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST; msg_ptr++; // ID Type & Spare Half Octet *msg_ptr = 0; liblte_mme_pack_identity_type_2_ie(id_req->id_type, 0, &msg_ptr); msg_ptr++; // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_request_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ID_REQUEST_MSG_STRUCT* id_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && id_req != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // ID Type & Spare Half Offset liblte_mme_unpack_identity_type_2_ie(&msg_ptr, 0, &id_req->id_type); msg_ptr++; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Identity Response Description: Sent by the UE to the network in response to an IDENTITY REQUEST message and provides the requested identity. Document Reference: 24.301 v10.2.0 Section 8.2.19 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_identity_response_msg(LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (id_resp != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE; msg_ptr++; // Mobile Identity liblte_mme_pack_mobile_id_ie(&id_resp->mobile_id, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_response_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ID_RESPONSE_MSG_STRUCT* id_resp) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && id_resp != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // Mobile Identity liblte_mme_unpack_mobile_id_ie(&msg_ptr, &id_resp->mobile_id); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Security Mode Command Description: Sent by the network to the UE to establish NAS signalling security. Document Reference: 24.301 v10.2.0 Section 8.2.20 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_security_mode_command_msg(LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT* sec_mode_cmd, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (sec_mode_cmd != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND; msg_ptr++; // Selected NAS Security Algorithms liblte_mme_pack_nas_security_algorithms_ie(&sec_mode_cmd->selected_nas_sec_algs, &msg_ptr); // NAS Key Set Identifier & Spare Half Octet *msg_ptr = 0; liblte_mme_pack_nas_key_set_id_ie(&sec_mode_cmd->nas_ksi, 0, &msg_ptr); msg_ptr++; // Replayed UE Security Capabilities liblte_mme_pack_ue_security_capabilities_ie(&sec_mode_cmd->ue_security_cap, &msg_ptr); // IMEISV Request if (sec_mode_cmd->imeisv_req_present) { *msg_ptr = LIBLTE_MME_IMEISV_REQUEST_IEI << 4; liblte_mme_pack_imeisv_request_ie(sec_mode_cmd->imeisv_req, 0, &msg_ptr); msg_ptr++; } // Replayed NONCE_ue if (sec_mode_cmd->nonce_ue_present) { *msg_ptr = LIBLTE_MME_REPLAYED_NONCE_UE_IEI; msg_ptr++; liblte_mme_pack_nonce_ie(sec_mode_cmd->nonce_ue, &msg_ptr); } // NONCE_mme if (sec_mode_cmd->nonce_mme_present) { *msg_ptr = LIBLTE_MME_NONCE_MME_IEI; msg_ptr++; liblte_mme_pack_nonce_ie(sec_mode_cmd->nonce_mme, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_security_mode_command_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT* sec_mode_cmd) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && sec_mode_cmd != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // Selected NAS Security Algorithms liblte_mme_unpack_nas_security_algorithms_ie(&msg_ptr, &sec_mode_cmd->selected_nas_sec_algs); // NAS Key Set Identifier & Spare Half Octet liblte_mme_unpack_nas_key_set_id_ie(&msg_ptr, 0, &sec_mode_cmd->nas_ksi); msg_ptr++; // Replayed UE Security Capabilities liblte_mme_unpack_ue_security_capabilities_ie(&msg_ptr, &sec_mode_cmd->ue_security_cap); // IMEISV Request if ((LIBLTE_MME_IMEISV_REQUEST_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_imeisv_request_ie(&msg_ptr, 0, &sec_mode_cmd->imeisv_req); msg_ptr++; sec_mode_cmd->imeisv_req_present = true; } else { sec_mode_cmd->imeisv_req_present = false; } // Replayed NONCE_ue if (LIBLTE_MME_REPLAYED_NONCE_UE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_nonce_ie(&msg_ptr, &sec_mode_cmd->nonce_ue); sec_mode_cmd->nonce_ue_present = true; } else { sec_mode_cmd->nonce_ue_present = false; } // NONCE_mme if (LIBLTE_MME_NONCE_MME_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_nonce_ie(&msg_ptr, &sec_mode_cmd->nonce_mme); sec_mode_cmd->nonce_mme_present = true; } else { sec_mode_cmd->nonce_mme_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Security Mode Complete Description: Sent by the UE to the network in response to a SECURITY MODE COMMAND message. Document Reference: 24.301 v10.2.0 Section 8.2.21 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_security_mode_complete_msg(LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT* sec_mode_comp, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (sec_mode_comp != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE; msg_ptr++; // IMEISV if (sec_mode_comp->imeisv_present) { *msg_ptr = LIBLTE_MME_IMEISV_IEI; msg_ptr++; liblte_mme_pack_mobile_id_ie(&sec_mode_comp->imeisv, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_security_mode_complete_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT* sec_mode_comp) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && sec_mode_comp != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // IMEISV if (LIBLTE_MME_IMEISV_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_mobile_id_ie(&msg_ptr, &sec_mode_comp->imeisv); sec_mode_comp->imeisv_present = true; } else { sec_mode_comp->imeisv_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Security Mode Reject Description: Sent by the UE to the network to indicate that the corresponding security mode command has been rejected. Document Reference: 24.301 v10.2.0 Section 8.2.22 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_security_mode_reject_msg(LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT* sec_mode_rej, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (sec_mode_rej != NULL && msg != NULL) { // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_SECURITY_MODE_REJECT; msg_ptr++; // EMM Cause liblte_mme_pack_emm_cause_ie(sec_mode_rej->emm_cause, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_security_mode_reject_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT* sec_mode_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && sec_mode_rej != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // EMM Cause liblte_mme_unpack_emm_cause_ie(&msg_ptr, &sec_mode_rej->emm_cause); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Service Reject Description: Sent by the network to the UE in order to reject the service request procedure. Document Reference: 24.301 v10.2.0 Section 8.2.24 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_service_reject_msg(LIBLTE_MME_SERVICE_REJECT_MSG_STRUCT* service_rej, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (service_rej != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_SERVICE_REJECT; msg_ptr++; // EMM Cause liblte_mme_pack_emm_cause_ie(service_rej->emm_cause, &msg_ptr); // T3442 Value if (service_rej->t3442_present) { *msg_ptr = LIBLTE_MME_T3442_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_ie(&service_rej->t3442, &msg_ptr); } // T3446 Value if (service_rej->t3446_present) { *msg_ptr = LIBLTE_MME_T3446_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_2_ie(service_rej->t3446, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_service_reject_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_SERVICE_REJECT_MSG_STRUCT* service_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && service_rej != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // EMM Cause liblte_mme_unpack_emm_cause_ie(&msg_ptr, &service_rej->emm_cause); // T3442 Value if (LIBLTE_MME_T3442_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &service_rej->t3442); service_rej->t3442_present = true; } else { service_rej->t3442_present = false; } // T3446 Value if (LIBLTE_MME_T3446_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_2_ie(&msg_ptr, &service_rej->t3446); service_rej->t3446_present = true; } else { service_rej->t3446_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Service Request Description: Sent by the UE to the network to request the establishment of a NAS signalling connection and of the radio and S1 bearers. Document Reference: 24.301 v10.2.0 Section 8.2.25 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_service_request_msg(LIBLTE_MME_SERVICE_REQUEST_MSG_STRUCT* service_req, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (service_req != NULL && msg != NULL) { // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // KSI and Sequence Number liblte_mme_pack_ksi_and_sequence_number_ie(&service_req->ksi_and_seq_num, &msg_ptr); // Short MAC liblte_mme_pack_short_mac_ie(service_req->short_mac, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_service_request_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_SERVICE_REQUEST_MSG_STRUCT* service_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && service_req != NULL) { // Protocol Discriminator and Security Header Type msg_ptr++; // KSI and Sequence Number liblte_mme_unpack_ksi_and_sequence_number_ie(&msg_ptr, &service_req->ksi_and_seq_num); // Short MAC liblte_mme_unpack_short_mac_ie(&msg_ptr, &service_req->short_mac); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Tracking Area Update Accept Description: Sent by the network to the UE to provide the UE with EPS mobility management related data in response to a tracking area update request message. Document Reference: 24.301 v10.2.0 Section 8.2.26 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_update_accept_msg(LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT* ta_update_accept, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (ta_update_accept != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_ACCEPT; msg_ptr++; // EPS Update Result & Spare Half Octet *msg_ptr = 0; liblte_mme_pack_eps_update_result_ie(ta_update_accept->eps_update_result, 0, &msg_ptr); msg_ptr++; // T3412 Value if (ta_update_accept->t3412_present) { *msg_ptr = LIBLTE_MME_T3412_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_ie(&ta_update_accept->t3412, &msg_ptr); } // GUTI if (ta_update_accept->guti_present) { *msg_ptr = LIBLTE_MME_GUTI_IEI; msg_ptr++; liblte_mme_pack_eps_mobile_id_ie(&ta_update_accept->guti, &msg_ptr); } // TAI List if (ta_update_accept->tai_list_present) { *msg_ptr = LIBLTE_MME_TAI_LIST_IEI; msg_ptr++; liblte_mme_pack_tracking_area_identity_list_ie(&ta_update_accept->tai_list, &msg_ptr); } // EPS Bearer Context Status if (ta_update_accept->eps_bearer_context_status_present) { *msg_ptr = LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_IEI; msg_ptr++; liblte_mme_pack_eps_bearer_context_status_ie(&ta_update_accept->eps_bearer_context_status, &msg_ptr); } // Location Area Identification if (ta_update_accept->lai_present) { *msg_ptr = LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI; msg_ptr++; liblte_mme_pack_location_area_id_ie(&ta_update_accept->lai, &msg_ptr); } // MS Identity if (ta_update_accept->ms_id_present) { *msg_ptr = LIBLTE_MME_MS_IDENTITY_IEI; msg_ptr++; liblte_mme_pack_mobile_id_ie(&ta_update_accept->ms_id, &msg_ptr); } // EMM Cause if (ta_update_accept->emm_cause_present) { *msg_ptr = LIBLTE_MME_EMM_CAUSE_IEI; msg_ptr++; liblte_mme_pack_emm_cause_ie(ta_update_accept->emm_cause, &msg_ptr); } // T3402 Value if (ta_update_accept->t3402_present) { *msg_ptr = LIBLTE_MME_T3402_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_ie(&ta_update_accept->t3402, &msg_ptr); } // T3423 Value if (ta_update_accept->t3423_present) { *msg_ptr = LIBLTE_MME_T3423_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_ie(&ta_update_accept->t3423, &msg_ptr); } // Equivalent PLMNs if (ta_update_accept->equivalent_plmns_present) { *msg_ptr = LIBLTE_MME_EQUIVALENT_PLMNS_IEI; msg_ptr++; liblte_mme_pack_plmn_list_ie(&ta_update_accept->equivalent_plmns, &msg_ptr); } // Emergency Number List if (ta_update_accept->emerg_num_list_present) { *msg_ptr = LIBLTE_MME_EMERGENCY_NUMBER_LIST_IEI; msg_ptr++; liblte_mme_pack_emergency_number_list_ie(&ta_update_accept->emerg_num_list, &msg_ptr); } // EPS Network Feature Support if (ta_update_accept->eps_network_feature_support_present) { *msg_ptr = LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI; msg_ptr++; liblte_mme_pack_eps_network_feature_support_ie(&ta_update_accept->eps_network_feature_support, &msg_ptr); } // Additional Update Result if (ta_update_accept->additional_update_result_present) { *msg_ptr = LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI << 4; liblte_mme_pack_additional_update_result_ie(ta_update_accept->additional_update_result, 0, &msg_ptr); msg_ptr++; } // T3412 Extended Value if (ta_update_accept->t3412_ext_present) { *msg_ptr = LIBLTE_MME_T3412_EXTENDED_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_3_ie(&ta_update_accept->t3412_ext, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_update_accept_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT* ta_update_accept) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && ta_update_accept != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // EPS Update Result & Spare Half Octet liblte_mme_unpack_eps_update_result_ie(&msg_ptr, 0, &ta_update_accept->eps_update_result); msg_ptr++; // T3412 Value if (LIBLTE_MME_T3412_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &ta_update_accept->t3412); ta_update_accept->t3412_present = true; } else { ta_update_accept->t3412_present = false; } // GUTI if (LIBLTE_MME_GUTI_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_eps_mobile_id_ie(&msg_ptr, &ta_update_accept->guti); ta_update_accept->guti_present = true; } else { ta_update_accept->guti_present = false; } // TAI List if (LIBLTE_MME_TAI_LIST_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_tracking_area_identity_list_ie(&msg_ptr, &ta_update_accept->tai_list); ta_update_accept->tai_list_present = true; } else { ta_update_accept->tai_list_present = false; } // EPS Bearer Context Status if (LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_eps_bearer_context_status_ie(&msg_ptr, &ta_update_accept->eps_bearer_context_status); ta_update_accept->eps_bearer_context_status_present = true; } else { ta_update_accept->eps_bearer_context_status_present = false; } // Location Area Identification if (LIBLTE_MME_LOCATION_AREA_IDENTIFICATION_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_location_area_id_ie(&msg_ptr, &ta_update_accept->lai); ta_update_accept->lai_present = true; } else { ta_update_accept->lai_present = false; } // MS Identity if (LIBLTE_MME_MS_IDENTITY_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_mobile_id_ie(&msg_ptr, &ta_update_accept->ms_id); ta_update_accept->ms_id_present = true; } else { ta_update_accept->ms_id_present = false; } // EMM Cause if (LIBLTE_MME_EMM_CAUSE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_emm_cause_ie(&msg_ptr, &ta_update_accept->emm_cause); ta_update_accept->emm_cause_present = true; } else { ta_update_accept->emm_cause_present = false; } // T3402 Value if (LIBLTE_MME_T3402_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &ta_update_accept->t3402); ta_update_accept->t3402_present = true; } else { ta_update_accept->t3402_present = false; } // T3423 Value if (LIBLTE_MME_T3423_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_ie(&msg_ptr, &ta_update_accept->t3423); ta_update_accept->t3423_present = true; } else { ta_update_accept->t3423_present = false; } // Equivalent PLMNs if (LIBLTE_MME_EQUIVALENT_PLMNS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_plmn_list_ie(&msg_ptr, &ta_update_accept->equivalent_plmns); ta_update_accept->equivalent_plmns_present = true; } else { ta_update_accept->equivalent_plmns_present = false; } // Emergency Number List if (LIBLTE_MME_EMERGENCY_NUMBER_LIST_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_emergency_number_list_ie(&msg_ptr, &ta_update_accept->emerg_num_list); ta_update_accept->emerg_num_list_present = true; } else { ta_update_accept->emerg_num_list_present = false; } // EPS Network Feature Support if (LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_eps_network_feature_support_ie(&msg_ptr, &ta_update_accept->eps_network_feature_support); ta_update_accept->eps_network_feature_support_present = true; } else { ta_update_accept->eps_network_feature_support_present = false; } // Additional Update Result if ((LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_additional_update_result_ie(&msg_ptr, 0, &ta_update_accept->additional_update_result); msg_ptr++; ta_update_accept->additional_update_result_present = true; } else { ta_update_accept->additional_update_result_present = false; } // T3412 Extended Value if (LIBLTE_MME_T3412_EXTENDED_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &ta_update_accept->t3412_ext); ta_update_accept->t3412_ext_present = true; } else { ta_update_accept->t3412_ext_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Tracking Area Update Complete Description: Sent by the UE to the network in response to a tracking area update accept message if a GUTI has been changed or a new TMSI has been assigned. Document Reference: 24.301 v10.2.0 Section 8.2.27 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_update_complete_msg( LIBLTE_MME_TRACKING_AREA_UPDATE_COMPLETE_MSG_STRUCT* ta_update_complete, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (ta_update_complete != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_COMPLETE; msg_ptr++; // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_update_complete_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_TRACKING_AREA_UPDATE_COMPLETE_MSG_STRUCT* ta_update_complete) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && ta_update_complete != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Tracking Area Update Reject Description: Sent by the network to the UE in order to reject the tracking area updating procedure. Document Reference: 24.301 v10.2.0 Section 8.2.28 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_tracking_area_update_reject_msg(LIBLTE_MME_TRACKING_AREA_UPDATE_REJECT_MSG_STRUCT* ta_update_rej, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (ta_update_rej != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REJECT; msg_ptr++; // EMM Cause liblte_mme_pack_emm_cause_ie(ta_update_rej->emm_cause, &msg_ptr); // T3446 Value if (ta_update_rej->t3446_present) { *msg_ptr = LIBLTE_MME_T3446_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_2_ie(ta_update_rej->t3446, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_tracking_area_update_reject_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_TRACKING_AREA_UPDATE_REJECT_MSG_STRUCT* ta_update_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && ta_update_rej != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // EMM Cause liblte_mme_unpack_emm_cause_ie(&msg_ptr, &ta_update_rej->emm_cause); // T3446 Value if (LIBLTE_MME_T3446_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_2_ie(&msg_ptr, &ta_update_rej->t3446); ta_update_rej->t3446_present = true; } else { ta_update_rej->t3446_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Tracking Area Update Request Description: Sent by the UE to the network to initiate a tracking area updating procedure. Document Reference: 24.301 v10.2.0 Section 8.2.29 *********************************************************************/ // TODO /********************************************************************* Message Name: Uplink NAS Transport Description: Sent by the UE to the network in order to carry an SMS message in encapsulated format. Document Reference: 24.301 v10.2.0 Section 8.2.30 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_uplink_nas_transport_msg(LIBLTE_MME_UPLINK_NAS_TRANSPORT_MSG_STRUCT* ul_nas_transport, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (ul_nas_transport != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_UPLINK_NAS_TRANSPORT; msg_ptr++; // NAS Message Container liblte_mme_pack_nas_message_container_ie(&ul_nas_transport->nas_msg, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_uplink_nas_transport_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_UPLINK_NAS_TRANSPORT_MSG_STRUCT* ul_nas_transport) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && ul_nas_transport != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // NAS Message Container liblte_mme_unpack_nas_message_container_ie(&msg_ptr, &ul_nas_transport->nas_msg); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Downlink Generic NAS Transport Description: Sent by the network to the UE in order to carry an application message in encapsulated format. Document Reference: 24.301 v10.2.0 Section 8.2.31 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_downlink_generic_nas_transport_msg( LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT* dl_generic_nas_transport, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (dl_generic_nas_transport != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_DOWNLINK_GENERIC_NAS_TRANSPORT; msg_ptr++; // Generic Message Container Type liblte_mme_pack_generic_message_container_type_ie(dl_generic_nas_transport->generic_msg_cont_type, &msg_ptr); // Generic Message Container liblte_mme_pack_generic_message_container_ie(&dl_generic_nas_transport->generic_msg_cont, &msg_ptr); // Additional Information if (dl_generic_nas_transport->add_info_present) { *msg_ptr = LIBLTE_MME_ADDITIONAL_INFORMATION_IEI; msg_ptr++; liblte_mme_pack_additional_information_ie(&dl_generic_nas_transport->add_info, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_downlink_generic_nas_transport_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT* dl_generic_nas_transport) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && dl_generic_nas_transport != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // Generic Message Container Type liblte_mme_unpack_generic_message_container_type_ie(&msg_ptr, &dl_generic_nas_transport->generic_msg_cont_type); // Generic Message Container liblte_mme_unpack_generic_message_container_ie(&msg_ptr, &dl_generic_nas_transport->generic_msg_cont); // Additional Information if (LIBLTE_MME_ADDITIONAL_INFORMATION_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_additional_information_ie(&msg_ptr, &dl_generic_nas_transport->add_info); dl_generic_nas_transport->add_info_present = true; } else { dl_generic_nas_transport->add_info_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Uplink Generic NAS Transport Description: Sent by the UE to the network in order to carry an application protocol message in encapsulated format. Document Reference: 24.301 v10.2.0 Section 8.2.32 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_uplink_generic_nas_transport_msg( LIBLTE_MME_UPLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT* ul_generic_nas_transport, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (ul_generic_nas_transport != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_UPLINK_GENERIC_NAS_TRANSPORT; msg_ptr++; // Generic Message Container Type liblte_mme_pack_generic_message_container_type_ie(ul_generic_nas_transport->generic_msg_cont_type, &msg_ptr); // Generic Message Container liblte_mme_pack_generic_message_container_ie(&ul_generic_nas_transport->generic_msg_cont, &msg_ptr); // Additional Information liblte_mme_pack_additional_information_ie(&ul_generic_nas_transport->add_info, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_uplink_generic_nas_transport_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_UPLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT* ul_generic_nas_transport) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && ul_generic_nas_transport != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 7; } // Skip Message Type msg_ptr++; // Generic Message Container Type liblte_mme_unpack_generic_message_container_type_ie(&msg_ptr, &ul_generic_nas_transport->generic_msg_cont_type); // Generic Message Container liblte_mme_unpack_generic_message_container_ie(&msg_ptr, &ul_generic_nas_transport->generic_msg_cont); // Additional Information liblte_mme_unpack_additional_information_ie(&msg_ptr, &ul_generic_nas_transport->add_info); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Activate Dedicated EPS Bearer Context Accept Description: Sent by the UE to the network to acknowledge activation of a dedicated EPS bearer context associated with the same PDN address(es) and APN as an already active EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.1 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_activate_dedicated_eps_bearer_context_accept_msg( LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT* act_ded_eps_bearer_context_accept, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (act_ded_eps_bearer_context_accept != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and EPS Bearer ID *msg_ptr = (act_ded_eps_bearer_context_accept->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = act_ded_eps_bearer_context_accept->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT; msg_ptr++; // Protocol Configuration Options if (act_ded_eps_bearer_context_accept->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&act_ded_eps_bearer_context_accept->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_dedicated_eps_bearer_context_accept_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT* act_ded_eps_bearer_context_accept) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && act_ded_eps_bearer_context_accept != NULL) { // EPS Bearer ID act_ded_eps_bearer_context_accept->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID act_ded_eps_bearer_context_accept->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_ded_eps_bearer_context_accept->protocol_cnfg_opts); act_ded_eps_bearer_context_accept->protocol_cnfg_opts_present = true; } else { act_ded_eps_bearer_context_accept->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Activate Dedicated EPS Bearer Context Reject Description: Sent by the UE to the network to reject activation of a dedicated EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.2 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_activate_dedicated_eps_bearer_context_reject_msg( LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT* act_ded_eps_bearer_context_rej, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (act_ded_eps_bearer_context_rej != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (act_ded_eps_bearer_context_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = act_ded_eps_bearer_context_rej->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT; msg_ptr++; // ESM Cause liblte_mme_pack_esm_cause_ie(act_ded_eps_bearer_context_rej->esm_cause, &msg_ptr); // Protocol Configuration Options if (act_ded_eps_bearer_context_rej->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&act_ded_eps_bearer_context_rej->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_dedicated_eps_bearer_context_reject_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT* act_ded_eps_bearer_context_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && act_ded_eps_bearer_context_rej != NULL) { // EPS Bearer ID act_ded_eps_bearer_context_rej->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID act_ded_eps_bearer_context_rej->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // ESM Cause liblte_mme_unpack_esm_cause_ie(&msg_ptr, &act_ded_eps_bearer_context_rej->esm_cause); // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_ded_eps_bearer_context_rej->protocol_cnfg_opts); act_ded_eps_bearer_context_rej->protocol_cnfg_opts_present = true; } else { act_ded_eps_bearer_context_rej->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Activate Dedicated EPS Bearer Context Request Description: Sent by the network to the UE to request activation of a dedicated EPS bearer context associated with the same PDN address(es) and APN as an already active default EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.3 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_activate_dedicated_eps_bearer_context_request_msg( LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT* act_ded_eps_bearer_context_req, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (act_ded_eps_bearer_context_req != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (act_ded_eps_bearer_context_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = act_ded_eps_bearer_context_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST; msg_ptr++; // Linked EPS Bearer Identity & Spare Half Octet *msg_ptr = 0; liblte_mme_pack_linked_eps_bearer_identity_ie(act_ded_eps_bearer_context_req->linked_eps_bearer_id, 0, &msg_ptr); msg_ptr++; // EPS QoS liblte_mme_pack_eps_quality_of_service_ie(&act_ded_eps_bearer_context_req->eps_qos, &msg_ptr); // TFT liblte_mme_pack_traffic_flow_template_ie(&act_ded_eps_bearer_context_req->tft, &msg_ptr); // Transaction Identifier if (act_ded_eps_bearer_context_req->transaction_id_present) { *msg_ptr = LIBLTE_MME_TRANSACTION_IDENTIFIER_IEI; msg_ptr++; liblte_mme_pack_transaction_identifier_ie(&act_ded_eps_bearer_context_req->transaction_id, &msg_ptr); } // Negotiated QoS if (act_ded_eps_bearer_context_req->negotiated_qos_present) { *msg_ptr = LIBLTE_MME_QUALITY_OF_SERVICE_IEI; msg_ptr++; liblte_mme_pack_quality_of_service_ie(&act_ded_eps_bearer_context_req->negotiated_qos, &msg_ptr); } // Negotiated LLC SAPI if (act_ded_eps_bearer_context_req->llc_sapi_present) { *msg_ptr = LIBLTE_MME_LLC_SAPI_IEI; msg_ptr++; liblte_mme_pack_llc_service_access_point_identifier_ie(act_ded_eps_bearer_context_req->llc_sapi, &msg_ptr); } // Radio Priority if (act_ded_eps_bearer_context_req->radio_prio_present) { *msg_ptr = LIBLTE_MME_RADIO_PRIORITY_IEI << 4; liblte_mme_pack_radio_priority_ie(act_ded_eps_bearer_context_req->radio_prio, 0, &msg_ptr); msg_ptr++; } // Packet Flow Identifier if (act_ded_eps_bearer_context_req->packet_flow_id_present) { *msg_ptr = LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI; msg_ptr++; liblte_mme_pack_packet_flow_identifier_ie(act_ded_eps_bearer_context_req->packet_flow_id, &msg_ptr); } // Protocol Configuration Options if (act_ded_eps_bearer_context_req->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&act_ded_eps_bearer_context_req->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_dedicated_eps_bearer_context_request_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT* act_ded_eps_bearer_context_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && act_ded_eps_bearer_context_req != NULL) { // Security Header Type uint8_t sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 6; } // EPS Bearer ID act_ded_eps_bearer_context_req->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID act_ded_eps_bearer_context_req->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Linked Bearer Identity & Spare Half Octet liblte_mme_unpack_linked_eps_bearer_identity_ie(&msg_ptr, 0, &act_ded_eps_bearer_context_req->linked_eps_bearer_id); msg_ptr++; // EPS QoS liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &act_ded_eps_bearer_context_req->eps_qos); // TFT liblte_mme_unpack_traffic_flow_template_ie(&msg_ptr, &act_ded_eps_bearer_context_req->tft); // Transaction Identifier if (LIBLTE_MME_TRANSACTION_IDENTIFIER_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_transaction_identifier_ie(&msg_ptr, &act_ded_eps_bearer_context_req->transaction_id); act_ded_eps_bearer_context_req->transaction_id_present = true; } else { act_ded_eps_bearer_context_req->transaction_id_present = false; } // Negotiated QoS if (LIBLTE_MME_QUALITY_OF_SERVICE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_quality_of_service_ie(&msg_ptr, &act_ded_eps_bearer_context_req->negotiated_qos); act_ded_eps_bearer_context_req->negotiated_qos_present = true; } else { act_ded_eps_bearer_context_req->negotiated_qos_present = false; } // Negotiated LLC SAPI if (LIBLTE_MME_LLC_SAPI_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_llc_service_access_point_identifier_ie(&msg_ptr, &act_ded_eps_bearer_context_req->llc_sapi); act_ded_eps_bearer_context_req->llc_sapi_present = true; } else { act_ded_eps_bearer_context_req->llc_sapi_present = false; } // Radio Priority if ((LIBLTE_MME_RADIO_PRIORITY_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_radio_priority_ie(&msg_ptr, 0, &act_ded_eps_bearer_context_req->radio_prio); msg_ptr++; act_ded_eps_bearer_context_req->radio_prio_present = true; } else { act_ded_eps_bearer_context_req->radio_prio_present = false; } // Packet Flow Identifier if (LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_packet_flow_identifier_ie(&msg_ptr, &act_ded_eps_bearer_context_req->packet_flow_id); act_ded_eps_bearer_context_req->packet_flow_id_present = true; } else { act_ded_eps_bearer_context_req->packet_flow_id_present = false; } // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_ded_eps_bearer_context_req->protocol_cnfg_opts); act_ded_eps_bearer_context_req->protocol_cnfg_opts_present = true; } else { act_ded_eps_bearer_context_req->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Activate Default EPS Bearer Context Accept Description: Sent by the UE to the network to acknowledge activation of a default EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.4 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_activate_default_eps_bearer_context_accept_msg( LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT* act_def_eps_bearer_context_accept, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (act_def_eps_bearer_context_accept != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (act_def_eps_bearer_context_accept->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = act_def_eps_bearer_context_accept->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT; msg_ptr++; // Protocol Configuration Options if (act_def_eps_bearer_context_accept->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&act_def_eps_bearer_context_accept->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_default_eps_bearer_context_accept_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT* act_def_eps_bearer_context_accept) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && act_def_eps_bearer_context_accept != NULL) { // EPS Bearer ID act_def_eps_bearer_context_accept->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID act_def_eps_bearer_context_accept->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_def_eps_bearer_context_accept->protocol_cnfg_opts); act_def_eps_bearer_context_accept->protocol_cnfg_opts_present = true; } else { act_def_eps_bearer_context_accept->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Activate Default EPS Bearer Context Reject Description: Sent by the UE to the network to reject activation of a default EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.5 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_activate_default_eps_bearer_context_reject_msg( LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT* act_def_eps_bearer_context_rej, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (act_def_eps_bearer_context_rej != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (act_def_eps_bearer_context_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = act_def_eps_bearer_context_rej->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT; msg_ptr++; // ESM Cause liblte_mme_pack_esm_cause_ie(act_def_eps_bearer_context_rej->esm_cause, &msg_ptr); // Protocol Configuration Options if (act_def_eps_bearer_context_rej->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&act_def_eps_bearer_context_rej->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_default_eps_bearer_context_reject_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT* act_def_eps_bearer_context_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && act_def_eps_bearer_context_rej != NULL) { // EPS Bearer ID act_def_eps_bearer_context_rej->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID act_def_eps_bearer_context_rej->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // ESM Cause liblte_mme_unpack_esm_cause_ie(&msg_ptr, &act_def_eps_bearer_context_rej->esm_cause); // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_def_eps_bearer_context_rej->protocol_cnfg_opts); act_def_eps_bearer_context_rej->protocol_cnfg_opts_present = true; } else { act_def_eps_bearer_context_rej->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Activate Default EPS Bearer Context Request Description: Sent by the network to the UE to request activation of a default EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.6 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_activate_default_eps_bearer_context_request_msg( LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT* act_def_eps_bearer_context_req, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (act_def_eps_bearer_context_req != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (act_def_eps_bearer_context_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = act_def_eps_bearer_context_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST; msg_ptr++; // EPS QoS liblte_mme_pack_eps_quality_of_service_ie(&act_def_eps_bearer_context_req->eps_qos, &msg_ptr); // Access Point Name liblte_mme_pack_access_point_name_ie(&act_def_eps_bearer_context_req->apn, &msg_ptr); // PDN Address liblte_mme_pack_pdn_address_ie(&act_def_eps_bearer_context_req->pdn_addr, &msg_ptr); // Transaction Identifier if (act_def_eps_bearer_context_req->transaction_id_present) { *msg_ptr = LIBLTE_MME_TRANSACTION_IDENTIFIER_IEI; msg_ptr++; liblte_mme_pack_transaction_identifier_ie(&act_def_eps_bearer_context_req->transaction_id, &msg_ptr); } // Negotiated QoS if (act_def_eps_bearer_context_req->negotiated_qos_present) { *msg_ptr = LIBLTE_MME_QUALITY_OF_SERVICE_IEI; msg_ptr++; liblte_mme_pack_quality_of_service_ie(&act_def_eps_bearer_context_req->negotiated_qos, &msg_ptr); } // Negotiated LLC SAPI if (act_def_eps_bearer_context_req->llc_sapi_present) { *msg_ptr = LIBLTE_MME_LLC_SAPI_IEI; msg_ptr++; liblte_mme_pack_llc_service_access_point_identifier_ie(act_def_eps_bearer_context_req->llc_sapi, &msg_ptr); } // Radio Priority if (act_def_eps_bearer_context_req->radio_prio_present) { *msg_ptr = LIBLTE_MME_RADIO_PRIORITY_IEI << 4; liblte_mme_pack_radio_priority_ie(act_def_eps_bearer_context_req->radio_prio, 0, &msg_ptr); msg_ptr++; } // Packet Flow Identifier if (act_def_eps_bearer_context_req->packet_flow_id_present) { *msg_ptr = LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI; msg_ptr++; liblte_mme_pack_packet_flow_identifier_ie(act_def_eps_bearer_context_req->packet_flow_id, &msg_ptr); } // APN-AMBR if (act_def_eps_bearer_context_req->apn_ambr_present) { *msg_ptr = LIBLTE_MME_APN_AMBR_IEI; msg_ptr++; liblte_mme_pack_apn_aggregate_maximum_bit_rate_ie(&act_def_eps_bearer_context_req->apn_ambr, &msg_ptr); } // ESM Cause if (act_def_eps_bearer_context_req->esm_cause_present) { *msg_ptr = LIBLTE_MME_ESM_CAUSE_IEI; msg_ptr++; liblte_mme_pack_esm_cause_ie(act_def_eps_bearer_context_req->esm_cause, &msg_ptr); } // Protocol Configuration Options if (act_def_eps_bearer_context_req->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&act_def_eps_bearer_context_req->protocol_cnfg_opts, &msg_ptr); } // Connectivity Type if (act_def_eps_bearer_context_req->connectivity_type_present) { *msg_ptr = LIBLTE_MME_CONNECTIVITY_TYPE_IEI << 4; liblte_mme_pack_connectivity_type_ie(act_def_eps_bearer_context_req->connectivity_type, 0, &msg_ptr); msg_ptr++; } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_activate_default_eps_bearer_context_request_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT* act_def_eps_bearer_context_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && act_def_eps_bearer_context_req != NULL) { // EPS Bearer ID act_def_eps_bearer_context_req->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID act_def_eps_bearer_context_req->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // EPS QoS liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &act_def_eps_bearer_context_req->eps_qos); // Access Point Name liblte_mme_unpack_access_point_name_ie(&msg_ptr, &act_def_eps_bearer_context_req->apn); // PDN Address liblte_mme_unpack_pdn_address_ie(&msg_ptr, &act_def_eps_bearer_context_req->pdn_addr); // Transaction Identifier if (LIBLTE_MME_TRANSACTION_IDENTIFIER_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_transaction_identifier_ie(&msg_ptr, &act_def_eps_bearer_context_req->transaction_id); act_def_eps_bearer_context_req->transaction_id_present = true; } else { act_def_eps_bearer_context_req->transaction_id_present = false; } // Negotiated QoS if (LIBLTE_MME_QUALITY_OF_SERVICE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_quality_of_service_ie(&msg_ptr, &act_def_eps_bearer_context_req->negotiated_qos); act_def_eps_bearer_context_req->negotiated_qos_present = true; } else { act_def_eps_bearer_context_req->negotiated_qos_present = false; } // Negotiated LLC SAPI if (LIBLTE_MME_LLC_SAPI_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_llc_service_access_point_identifier_ie(&msg_ptr, &act_def_eps_bearer_context_req->llc_sapi); act_def_eps_bearer_context_req->llc_sapi_present = true; } else { act_def_eps_bearer_context_req->llc_sapi_present = false; } // Radio Priority if ((LIBLTE_MME_RADIO_PRIORITY_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_radio_priority_ie(&msg_ptr, 0, &act_def_eps_bearer_context_req->radio_prio); msg_ptr++; act_def_eps_bearer_context_req->radio_prio_present = true; } else { act_def_eps_bearer_context_req->radio_prio_present = false; } // Packet Flow Identifier if (LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_packet_flow_identifier_ie(&msg_ptr, &act_def_eps_bearer_context_req->packet_flow_id); act_def_eps_bearer_context_req->packet_flow_id_present = true; } else { act_def_eps_bearer_context_req->packet_flow_id_present = false; } // APN-AMBR if (LIBLTE_MME_APN_AMBR_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_apn_aggregate_maximum_bit_rate_ie(&msg_ptr, &act_def_eps_bearer_context_req->apn_ambr); act_def_eps_bearer_context_req->apn_ambr_present = true; } else { act_def_eps_bearer_context_req->apn_ambr_present = false; } // ESM Cause if (LIBLTE_MME_ESM_CAUSE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_esm_cause_ie(&msg_ptr, &act_def_eps_bearer_context_req->esm_cause); act_def_eps_bearer_context_req->esm_cause_present = true; } else { act_def_eps_bearer_context_req->esm_cause_present = false; } // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &act_def_eps_bearer_context_req->protocol_cnfg_opts); act_def_eps_bearer_context_req->protocol_cnfg_opts_present = true; } else { act_def_eps_bearer_context_req->protocol_cnfg_opts_present = false; } // Connectivity Type if ((LIBLTE_MME_CONNECTIVITY_TYPE_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_connectivity_type_ie(&msg_ptr, 0, &act_def_eps_bearer_context_req->connectivity_type); msg_ptr++; act_def_eps_bearer_context_req->connectivity_type_present = true; } else { act_def_eps_bearer_context_req->connectivity_type_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Bearer Resource Allocation Reject Description: Sent by the network to the UE to reject the allocation of a dedicated bearer resource. Document Reference: 24.301 v10.2.0 Section 8.3.7 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_allocation_reject_msg( LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REJECT_MSG_STRUCT* bearer_res_alloc_rej, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (bearer_res_alloc_rej != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (bearer_res_alloc_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = bearer_res_alloc_rej->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_ALLOCATION_REJECT; msg_ptr++; // ESM Cause liblte_mme_pack_esm_cause_ie(bearer_res_alloc_rej->esm_cause, &msg_ptr); // Protocol Configuration Options if (bearer_res_alloc_rej->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&bearer_res_alloc_rej->protocol_cnfg_opts, &msg_ptr); } // T3496 Value if (bearer_res_alloc_rej->t3496_present) { *msg_ptr = LIBLTE_MME_T3496_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_3_ie(&bearer_res_alloc_rej->t3496, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_allocation_reject_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REJECT_MSG_STRUCT* bearer_res_alloc_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && bearer_res_alloc_rej != NULL) { // EPS Bearer ID bearer_res_alloc_rej->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID bearer_res_alloc_rej->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // ESM Cause liblte_mme_unpack_esm_cause_ie(&msg_ptr, &bearer_res_alloc_rej->esm_cause); // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &bearer_res_alloc_rej->protocol_cnfg_opts); bearer_res_alloc_rej->protocol_cnfg_opts_present = true; } else { bearer_res_alloc_rej->protocol_cnfg_opts_present = false; } // T3496 Value if (LIBLTE_MME_T3496_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &bearer_res_alloc_rej->t3496); bearer_res_alloc_rej->t3496_present = true; } else { bearer_res_alloc_rej->t3496_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Bearer Resource Allocation Request Description: Sent by the UE to the network to request the allocation of a dedicated bearer resource. Document Reference: 24.301 v10.2.0 Section 8.3.8 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_allocation_request_msg( LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_MSG_STRUCT* bearer_res_alloc_req, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (bearer_res_alloc_req != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (bearer_res_alloc_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = bearer_res_alloc_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_ALLOCATION_REQUEST; msg_ptr++; // Linked EPS Bearer Identity & Spare Half Octet liblte_mme_pack_linked_eps_bearer_identity_ie(bearer_res_alloc_req->linked_eps_bearer_id, 0, &msg_ptr); // Traffic Flow Aggregate liblte_mme_pack_traffic_flow_aggregate_description_ie(&bearer_res_alloc_req->tfa, &msg_ptr); // Required Traffic Flow QoS liblte_mme_pack_eps_quality_of_service_ie(&bearer_res_alloc_req->req_tf_qos, &msg_ptr); // Protocol Configuration Options if (bearer_res_alloc_req->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&bearer_res_alloc_req->protocol_cnfg_opts, &msg_ptr); } // Device Properties if (bearer_res_alloc_req->device_properties_present) { *msg_ptr = LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_DEVICE_PROPERTIES_IEI << 4; liblte_mme_pack_device_properties_ie(bearer_res_alloc_req->device_properties, 0, &msg_ptr); msg_ptr++; } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_allocation_request_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_MSG_STRUCT* bearer_res_alloc_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && bearer_res_alloc_req != NULL) { // EPS Bearer ID bearer_res_alloc_req->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID bearer_res_alloc_req->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Linked EPS Bearer Identity & Spare Half Octet liblte_mme_unpack_linked_eps_bearer_identity_ie(&msg_ptr, 0, &bearer_res_alloc_req->linked_eps_bearer_id); // Traffic Flow Aggregate liblte_mme_unpack_traffic_flow_aggregate_description_ie(&msg_ptr, &bearer_res_alloc_req->tfa); // Required Traffic Flow QoS liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &bearer_res_alloc_req->req_tf_qos); // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &bearer_res_alloc_req->protocol_cnfg_opts); bearer_res_alloc_req->protocol_cnfg_opts_present = true; } else { bearer_res_alloc_req->protocol_cnfg_opts_present = false; } // Device Properties if ((LIBLTE_MME_BEARER_RESOURCE_ALLOCATION_REQUEST_DEVICE_PROPERTIES_IEI << 4) == *msg_ptr) { liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &bearer_res_alloc_req->device_properties); msg_ptr++; bearer_res_alloc_req->device_properties_present = true; } else { bearer_res_alloc_req->device_properties_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Bearer Resource Modification Reject Description: Sent by the network to the UE to reject the modification of a dedicated bearer resource. Document Reference: 24.301 v10.2.0 Section 8.3.9 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_modification_reject_msg( LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REJECT_MSG_STRUCT* bearer_res_mod_rej, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (bearer_res_mod_rej != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (bearer_res_mod_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = bearer_res_mod_rej->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_MODIFICATION_REJECT; msg_ptr++; // ESM Cause liblte_mme_pack_esm_cause_ie(bearer_res_mod_rej->esm_cause, &msg_ptr); // Protocol Configuration Options if (bearer_res_mod_rej->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&bearer_res_mod_rej->protocol_cnfg_opts, &msg_ptr); } // T3496 Value if (bearer_res_mod_rej->t3496_present) { *msg_ptr = LIBLTE_MME_T3496_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_3_ie(&bearer_res_mod_rej->t3496, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_modification_reject_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REJECT_MSG_STRUCT* bearer_res_mod_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && bearer_res_mod_rej != NULL) { // EPS Bearer ID bearer_res_mod_rej->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID bearer_res_mod_rej->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // ESM Cause liblte_mme_unpack_esm_cause_ie(&msg_ptr, &bearer_res_mod_rej->esm_cause); // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &bearer_res_mod_rej->protocol_cnfg_opts); bearer_res_mod_rej->protocol_cnfg_opts_present = true; } else { bearer_res_mod_rej->protocol_cnfg_opts_present = false; } // T3496 Value if (LIBLTE_MME_T3496_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &bearer_res_mod_rej->t3496); bearer_res_mod_rej->t3496_present = true; } else { bearer_res_mod_rej->t3496_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Bearer Resource Modification Request Description: Sent by the UE to the network to request the modification of a dedicated bearer resource. Document Reference: 24.301 v10.2.0 Section 8.3.10 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_bearer_resource_modification_request_msg( LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_MSG_STRUCT* bearer_res_mod_req, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (bearer_res_mod_req != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (bearer_res_mod_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = bearer_res_mod_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_MODIFICATION_REQUEST; msg_ptr++; // EPS Bearer Identity For Packet Filter & Spare Half Octet liblte_mme_pack_linked_eps_bearer_identity_ie(bearer_res_mod_req->eps_bearer_id_for_packet_filter, 0, &msg_ptr); // Traffic Flow Aggregate liblte_mme_pack_traffic_flow_aggregate_description_ie(&bearer_res_mod_req->tfa, &msg_ptr); // Required Traffic Flow QoS if (bearer_res_mod_req->req_tf_qos_present) { *msg_ptr = LIBLTE_MME_EPS_QUALITY_OF_SERVICE_IEI; msg_ptr++; liblte_mme_pack_eps_quality_of_service_ie(&bearer_res_mod_req->req_tf_qos, &msg_ptr); } // ESM Cause if (bearer_res_mod_req->esm_cause_present) { *msg_ptr = LIBLTE_MME_ESM_CAUSE_IEI; msg_ptr++; liblte_mme_pack_esm_cause_ie(bearer_res_mod_req->esm_cause, &msg_ptr); } // Protocol Configuration Options if (bearer_res_mod_req->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&bearer_res_mod_req->protocol_cnfg_opts, &msg_ptr); } // Device Properties if (bearer_res_mod_req->device_properties_present) { *msg_ptr = LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_DEVICE_PROPERTIES_IEI << 4; liblte_mme_pack_device_properties_ie(bearer_res_mod_req->device_properties, 0, &msg_ptr); msg_ptr++; } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_bearer_resource_modification_request_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_MSG_STRUCT* bearer_res_mod_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && bearer_res_mod_req != NULL) { // EPS Bearer ID bearer_res_mod_req->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID bearer_res_mod_req->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // EPS Bearer Identity For Packet Filter & Spare Half Octet liblte_mme_unpack_linked_eps_bearer_identity_ie(&msg_ptr, 0, &bearer_res_mod_req->eps_bearer_id_for_packet_filter); // Traffic Flow Aggregate liblte_mme_unpack_traffic_flow_aggregate_description_ie(&msg_ptr, &bearer_res_mod_req->tfa); // Required Traffic Flow QoS if (LIBLTE_MME_EPS_QUALITY_OF_SERVICE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &bearer_res_mod_req->req_tf_qos); bearer_res_mod_req->req_tf_qos_present = true; } else { bearer_res_mod_req->req_tf_qos_present = false; } // ESM Cause if (LIBLTE_MME_ESM_CAUSE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_esm_cause_ie(&msg_ptr, &bearer_res_mod_req->esm_cause); bearer_res_mod_req->esm_cause_present = true; } else { bearer_res_mod_req->esm_cause_present = false; } // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &bearer_res_mod_req->protocol_cnfg_opts); bearer_res_mod_req->protocol_cnfg_opts_present = true; } else { bearer_res_mod_req->protocol_cnfg_opts_present = false; } // Device Properties if ((LIBLTE_MME_BEARER_RESOURCE_MODIFICATION_REQUEST_DEVICE_PROPERTIES_IEI << 4) == *msg_ptr) { liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &bearer_res_mod_req->device_properties); msg_ptr++; bearer_res_mod_req->device_properties_present = true; } else { bearer_res_mod_req->device_properties_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Deactivate EPS Bearer Context Accept Description: Sent by the UE to acknowledge deactivation of the EPS bearer context requested in the corresponding deactivate EPS bearer context request message. Document Reference: 24.301 v10.2.0 Section 8.3.11 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_deactivate_eps_bearer_context_accept_msg( LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT* deact_eps_bearer_context_accept, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (deact_eps_bearer_context_accept != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and EPS Bearer ID *msg_ptr = (deact_eps_bearer_context_accept->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = deact_eps_bearer_context_accept->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT; msg_ptr++; // Protocol Configuration Options if (deact_eps_bearer_context_accept->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&deact_eps_bearer_context_accept->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_deactivate_eps_bearer_context_accept_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT* deact_eps_bearer_context_accept) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && deact_eps_bearer_context_accept != NULL) { // EPS Bearer ID deact_eps_bearer_context_accept->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID deact_eps_bearer_context_accept->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &deact_eps_bearer_context_accept->protocol_cnfg_opts); deact_eps_bearer_context_accept->protocol_cnfg_opts_present = true; } else { deact_eps_bearer_context_accept->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Deactivate EPS Bearer Context Request Description: Sent by the network to request deactivation of an EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.12 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_deactivate_eps_bearer_context_request_msg( LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT* deact_eps_bearer_context_req, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (deact_eps_bearer_context_req != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and EPS Bearer ID *msg_ptr = (deact_eps_bearer_context_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = deact_eps_bearer_context_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST; msg_ptr++; // ESM Cause liblte_mme_pack_esm_cause_ie(deact_eps_bearer_context_req->esm_cause, &msg_ptr); // Protocol Configuration Options if (deact_eps_bearer_context_req->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&deact_eps_bearer_context_req->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_deactivate_eps_bearer_context_request_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT* deact_eps_bearer_context_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && deact_eps_bearer_context_req != NULL) { // Security Header Type uint8_t sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 6; } // EPS Bearer ID deact_eps_bearer_context_req->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID deact_eps_bearer_context_req->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // ESM Cause liblte_mme_unpack_esm_cause_ie(&msg_ptr, &deact_eps_bearer_context_req->esm_cause); // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &deact_eps_bearer_context_req->protocol_cnfg_opts); deact_eps_bearer_context_req->protocol_cnfg_opts_present = true; } else { deact_eps_bearer_context_req->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: ESM Information Request Description: Sent by the network to the UE to request the UE to provide ESM information, i.e. protocol configuration options or APN or both. This function is being added to support encryption and integrety protection on ESM information transfer. Document Reference: 24.301 v10.2.0 Section 8.3.13 *********************************************************************/ LIBLTE_ERROR_ENUM srsran_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT* esm_info_req, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (esm_info_req != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and EPS Bearer ID *msg_ptr = (esm_info_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = esm_info_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST; msg_ptr++; // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: ESM Information Request Description: Sent by the network to the UE to request the UE to provide ESM information, i.e. protocol configuration options or APN or both. Document Reference: 24.301 v10.2.0 Section 8.3.13 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT* esm_info_req, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (esm_info_req != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (esm_info_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = esm_info_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST; msg_ptr++; // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT* esm_info_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && esm_info_req != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 6; } // EPS Bearer ID esm_info_req->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID esm_info_req->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: ESM Information Response Description: Sent by the UE to the network in response to an ESM INFORMATION REQUEST message and provides the requested ESM information. Document Reference: 24.301 v10.2.0 Section 8.3.14 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT* esm_info_resp, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (esm_info_resp != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and EPS Bearer ID *msg_ptr = (esm_info_resp->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = esm_info_resp->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE; msg_ptr++; // Access Point Name if (esm_info_resp->apn_present) { *msg_ptr = LIBLTE_MME_ACCESS_POINT_NAME_IEI; msg_ptr++; liblte_mme_pack_access_point_name_ie(&esm_info_resp->apn, &msg_ptr); } // Protocol Configuration Options if (esm_info_resp->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&esm_info_resp->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM srsran_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT* esm_info_resp) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; uint8 sec_hdr_type; if (msg != NULL && esm_info_resp != NULL) { // Security Header Type sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 6; } // EPS Bearer ID esm_info_resp->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID esm_info_resp->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Access Point Name if (LIBLTE_MME_ACCESS_POINT_NAME_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_access_point_name_ie(&msg_ptr, &esm_info_resp->apn); esm_info_resp->apn_present = true; } else { esm_info_resp->apn_present = false; } // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &esm_info_resp->protocol_cnfg_opts); esm_info_resp->protocol_cnfg_opts_present = true; } else { esm_info_resp->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT* esm_info_resp) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && esm_info_resp != NULL) { // EPS Bearer ID esm_info_resp->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID esm_info_resp->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Access Point Name if (LIBLTE_MME_ACCESS_POINT_NAME_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_access_point_name_ie(&msg_ptr, &esm_info_resp->apn); esm_info_resp->apn_present = true; } else { esm_info_resp->apn_present = false; } // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &esm_info_resp->protocol_cnfg_opts); esm_info_resp->protocol_cnfg_opts_present = true; } else { esm_info_resp->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: ESM Status Description: Sent by the network or the UE to pass information on the status of the indicated EPS bearer context and report certain error conditions. Document Reference: 24.301 v10.2.0 Section 8.3.15 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_status_msg(LIBLTE_MME_ESM_STATUS_MSG_STRUCT* esm_status, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (esm_status != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (esm_status->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = esm_status->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ESM_STATUS; msg_ptr++; // ESM Cause liblte_mme_pack_esm_cause_ie(esm_status->esm_cause, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_status_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_ESM_STATUS_MSG_STRUCT* esm_status) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && esm_status != NULL) { // EPS Bearer ID esm_status->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID esm_status->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // ESM Cause liblte_mme_unpack_esm_cause_ie(&msg_ptr, &esm_status->esm_cause); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Modify EPS Bearer Context Accept Description: Sent by the UE to the network to acknowledge the modification of an active EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.16 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_modify_eps_bearer_context_accept_msg( LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT* mod_eps_bearer_context_accept, uint8 sec_hdr_type, uint32 count, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (mod_eps_bearer_context_accept != NULL && msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and EPS Bearer ID *msg_ptr = (mod_eps_bearer_context_accept->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = mod_eps_bearer_context_accept->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_ACCEPT; msg_ptr++; // Protocol Configuration Options if (mod_eps_bearer_context_accept->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&mod_eps_bearer_context_accept->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_modify_eps_bearer_context_accept_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT* mod_eps_bearer_context_accept) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && mod_eps_bearer_context_accept != NULL) { // EPS Bearer ID mod_eps_bearer_context_accept->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID mod_eps_bearer_context_accept->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &mod_eps_bearer_context_accept->protocol_cnfg_opts); mod_eps_bearer_context_accept->protocol_cnfg_opts_present = true; } else { mod_eps_bearer_context_accept->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Modify EPS Bearer Context Reject Description: Sent by the UE or the network to reject a modification of an active EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.17 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_modify_eps_bearer_context_reject_msg( LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT* mod_eps_bearer_context_rej, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (mod_eps_bearer_context_rej != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (mod_eps_bearer_context_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = mod_eps_bearer_context_rej->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_REJECT; msg_ptr++; // ESM Cause liblte_mme_pack_esm_cause_ie(mod_eps_bearer_context_rej->esm_cause, &msg_ptr); // Protocol Configuration Options if (mod_eps_bearer_context_rej->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&mod_eps_bearer_context_rej->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_modify_eps_bearer_context_reject_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REJECT_MSG_STRUCT* mod_eps_bearer_context_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && mod_eps_bearer_context_rej != NULL) { // EPS Bearer ID mod_eps_bearer_context_rej->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID mod_eps_bearer_context_rej->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // ESM Cause liblte_mme_unpack_esm_cause_ie(&msg_ptr, &mod_eps_bearer_context_rej->esm_cause); // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &mod_eps_bearer_context_rej->protocol_cnfg_opts); mod_eps_bearer_context_rej->protocol_cnfg_opts_present = true; } else { mod_eps_bearer_context_rej->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Modify EPS Bearer Context Request Description: Sent by the network to the UE to request modification of an active EPS bearer context. Document Reference: 24.301 v10.2.0 Section 8.3.18 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_modify_eps_bearer_context_request_msg( LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT* mod_eps_bearer_context_req, LIBLTE_BYTE_MSG_STRUCT* msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (mod_eps_bearer_context_req != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (mod_eps_bearer_context_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = mod_eps_bearer_context_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_REQUEST; msg_ptr++; // New EPS QoS if (mod_eps_bearer_context_req->new_eps_qos_present) { *msg_ptr = LIBLTE_MME_EPS_QUALITY_OF_SERVICE_IEI; msg_ptr++; liblte_mme_pack_eps_quality_of_service_ie(&mod_eps_bearer_context_req->new_eps_qos, &msg_ptr); } // TFT if (mod_eps_bearer_context_req->tft_present) { *msg_ptr = LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_IEI; msg_ptr++; liblte_mme_pack_traffic_flow_template_ie(&mod_eps_bearer_context_req->tft, &msg_ptr); } // New QoS if (mod_eps_bearer_context_req->new_qos_present) { *msg_ptr = LIBLTE_MME_QUALITY_OF_SERVICE_IEI; msg_ptr++; liblte_mme_pack_quality_of_service_ie(&mod_eps_bearer_context_req->new_qos, &msg_ptr); } // Negotiated LLC SAPI if (mod_eps_bearer_context_req->negotiated_llc_sapi_present) { *msg_ptr = LIBLTE_MME_LLC_SAPI_IEI; msg_ptr++; liblte_mme_pack_llc_service_access_point_identifier_ie(mod_eps_bearer_context_req->negotiated_llc_sapi, &msg_ptr); } // Radio Priority if (mod_eps_bearer_context_req->radio_prio_present) { *msg_ptr = LIBLTE_MME_RADIO_PRIORITY_IEI << 4; liblte_mme_pack_radio_priority_ie(mod_eps_bearer_context_req->radio_prio, 0, &msg_ptr); msg_ptr++; } // Packet Flow Identifier if (mod_eps_bearer_context_req->packet_flow_id_present) { *msg_ptr = LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI; msg_ptr++; liblte_mme_pack_packet_flow_identifier_ie(mod_eps_bearer_context_req->packet_flow_id, &msg_ptr); } // APN-AMBR if (mod_eps_bearer_context_req->apn_ambr_present) { *msg_ptr = LIBLTE_MME_APN_AMBR_IEI; msg_ptr++; liblte_mme_pack_apn_aggregate_maximum_bit_rate_ie(&mod_eps_bearer_context_req->apn_ambr, &msg_ptr); } // Protocol Configuration Options if (mod_eps_bearer_context_req->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&mod_eps_bearer_context_req->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_modify_eps_bearer_context_request_msg( LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_MODIFY_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT* mod_eps_bearer_context_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && mod_eps_bearer_context_req != NULL) { // Security Header Type uint8_t sec_hdr_type = (msg->msg[0] & 0xF0) >> 4; if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type) { msg_ptr++; } else { msg_ptr += 6; } // EPS Bearer ID mod_eps_bearer_context_req->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID mod_eps_bearer_context_req->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // New EPS QoS if (LIBLTE_MME_EPS_QUALITY_OF_SERVICE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_eps_quality_of_service_ie(&msg_ptr, &mod_eps_bearer_context_req->new_eps_qos); mod_eps_bearer_context_req->new_eps_qos_present = true; } else { mod_eps_bearer_context_req->new_eps_qos_present = false; } // TFT if (LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_traffic_flow_template_ie(&msg_ptr, &mod_eps_bearer_context_req->tft); mod_eps_bearer_context_req->tft_present = true; } else { mod_eps_bearer_context_req->tft_present = false; } // New QoS if (LIBLTE_MME_QUALITY_OF_SERVICE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_quality_of_service_ie(&msg_ptr, &mod_eps_bearer_context_req->new_qos); mod_eps_bearer_context_req->new_qos_present = true; } else { mod_eps_bearer_context_req->new_qos_present = false; } // Negotiated LLC SAPI if (LIBLTE_MME_LLC_SAPI_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_llc_service_access_point_identifier_ie(&msg_ptr, &mod_eps_bearer_context_req->negotiated_llc_sapi); mod_eps_bearer_context_req->negotiated_llc_sapi_present = true; } else { mod_eps_bearer_context_req->negotiated_llc_sapi_present = false; } // Radio Priority if ((LIBLTE_MME_RADIO_PRIORITY_IEI << 4) == *msg_ptr) { liblte_mme_unpack_radio_priority_ie(&msg_ptr, 0, &mod_eps_bearer_context_req->radio_prio); msg_ptr++; mod_eps_bearer_context_req->radio_prio_present = true; } else { mod_eps_bearer_context_req->radio_prio_present = false; } // Packet Flow Identifier if (LIBLTE_MME_PACKET_FLOW_IDENTIFIER_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_packet_flow_identifier_ie(&msg_ptr, &mod_eps_bearer_context_req->packet_flow_id); mod_eps_bearer_context_req->packet_flow_id_present = true; } else { mod_eps_bearer_context_req->packet_flow_id_present = false; } // APN-AMBR if (LIBLTE_MME_APN_AMBR_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_apn_aggregate_maximum_bit_rate_ie(&msg_ptr, &mod_eps_bearer_context_req->apn_ambr); mod_eps_bearer_context_req->apn_ambr_present = true; } else { mod_eps_bearer_context_req->apn_ambr_present = false; } // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &mod_eps_bearer_context_req->protocol_cnfg_opts); mod_eps_bearer_context_req->protocol_cnfg_opts_present = true; } else { mod_eps_bearer_context_req->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: Notification Description: Sent by the network to inform the UE about events which are relevant for the upper layer using an EPS bearer context or having requested a procedure transaction. Document Reference: 24.301 v10.2.0 Section 8.3.18A *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_notification_msg(LIBLTE_MME_NOTIFICATION_MSG_STRUCT* notification, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (notification != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (notification->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = notification->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_NOTIFICATION; msg_ptr++; // Notification Indicator liblte_mme_pack_notification_indicator_ie(notification->notification_ind, &msg_ptr); // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_notification_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_NOTIFICATION_MSG_STRUCT* notification) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && notification != NULL) { // EPS Bearer ID notification->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID notification->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Notification Indicator liblte_mme_unpack_notification_indicator_ie(&msg_ptr, ¬ification->notification_ind); err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: PDN Connectivity Reject Description: Sent by the network to the UE to reject establishment of a PDN connection. Document Reference: 24.301 v10.2.0 Section 8.3.19 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_connectivity_reject_msg(LIBLTE_MME_PDN_CONNECTIVITY_REJECT_MSG_STRUCT* pdn_con_rej, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (pdn_con_rej != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (pdn_con_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = pdn_con_rej->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_PDN_CONNECTIVITY_REJECT; msg_ptr++; // ESM Cause liblte_mme_pack_esm_cause_ie(pdn_con_rej->esm_cause, &msg_ptr); // Protocol Configuration Options if (pdn_con_rej->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&pdn_con_rej->protocol_cnfg_opts, &msg_ptr); } // T3496 Value if (pdn_con_rej->t3496_present) { *msg_ptr = LIBLTE_MME_T3496_VALUE_IEI; msg_ptr++; liblte_mme_pack_gprs_timer_3_ie(&pdn_con_rej->t3496, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_connectivity_reject_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_PDN_CONNECTIVITY_REJECT_MSG_STRUCT* pdn_con_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && pdn_con_rej != NULL) { // EPS Bearer ID pdn_con_rej->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID pdn_con_rej->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // ESM Cause liblte_mme_unpack_esm_cause_ie(&msg_ptr, &pdn_con_rej->esm_cause); // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &pdn_con_rej->protocol_cnfg_opts); pdn_con_rej->protocol_cnfg_opts_present = true; } else { pdn_con_rej->protocol_cnfg_opts_present = false; } // T3496 Value if (LIBLTE_MME_T3496_VALUE_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_gprs_timer_3_ie(&msg_ptr, &pdn_con_rej->t3496); pdn_con_rej->t3496_present = true; } else { pdn_con_rej->t3496_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: PDN Connectivity Request Description: Sent by the UE to the network to initiate establishment of a PDN connection. Document Reference: 24.301 v10.2.0 Section 8.3.20 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_connectivity_request_msg(LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT* pdn_con_req, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (pdn_con_req != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (pdn_con_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = pdn_con_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_PDN_CONNECTIVITY_REQUEST; msg_ptr++; // Request Type & PDN Type *msg_ptr = 0; liblte_mme_pack_request_type_ie(pdn_con_req->request_type, 0, &msg_ptr); liblte_mme_pack_pdn_type_ie(pdn_con_req->pdn_type, 4, &msg_ptr); msg_ptr++; // ESM Information Transfer Flag if (pdn_con_req->esm_info_transfer_flag_present) { *msg_ptr = LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_IEI << 4; liblte_mme_pack_esm_info_transfer_flag_ie(pdn_con_req->esm_info_transfer_flag, 0, &msg_ptr); msg_ptr++; } // Access Point Name if (pdn_con_req->apn_present) { *msg_ptr = LIBLTE_MME_ACCESS_POINT_NAME_IEI; msg_ptr++; liblte_mme_pack_access_point_name_ie(&pdn_con_req->apn, &msg_ptr); } // Protocol Configuration Options if (pdn_con_req->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&pdn_con_req->protocol_cnfg_opts, &msg_ptr); } // Device Properties if (pdn_con_req->device_properties_present) { *msg_ptr = LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_DEVICE_PROPERTIES_IEI << 4; liblte_mme_pack_device_properties_ie(pdn_con_req->device_properties, 0, &msg_ptr); msg_ptr++; } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_connectivity_request_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT* pdn_con_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && pdn_con_req != NULL) { // EPS Bearer ID pdn_con_req->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID pdn_con_req->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Request Type & PDN Type liblte_mme_unpack_request_type_ie(&msg_ptr, 0, &pdn_con_req->request_type); liblte_mme_unpack_pdn_type_ie(&msg_ptr, 4, &pdn_con_req->pdn_type); msg_ptr++; // ESM Information Transfer Flag if ((LIBLTE_MME_ESM_INFO_TRANSFER_FLAG_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_esm_info_transfer_flag_ie(&msg_ptr, 0, &pdn_con_req->esm_info_transfer_flag); msg_ptr++; pdn_con_req->esm_info_transfer_flag_present = true; } else { pdn_con_req->esm_info_transfer_flag_present = false; } // Access Point Name if (LIBLTE_MME_ACCESS_POINT_NAME_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_access_point_name_ie(&msg_ptr, &pdn_con_req->apn); pdn_con_req->apn_present = true; } else { pdn_con_req->apn_present = false; } // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &pdn_con_req->protocol_cnfg_opts); pdn_con_req->protocol_cnfg_opts_present = true; } else { pdn_con_req->protocol_cnfg_opts_present = false; } // Device Properties if ((LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_DEVICE_PROPERTIES_IEI << 4) == (*msg_ptr & 0xF0)) { liblte_mme_unpack_device_properties_ie(&msg_ptr, 0, &pdn_con_req->device_properties); msg_ptr++; pdn_con_req->device_properties_present = true; } else { pdn_con_req->device_properties_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: PDN Disconnect Reject Description: Sent by the network to the UE to reject release of a PDN connection. Document Reference: 24.301 v10.2.0 Section 8.3.21 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_disconnect_reject_msg(LIBLTE_MME_PDN_DISCONNECT_REJECT_MSG_STRUCT* pdn_discon_rej, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (pdn_discon_rej != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (pdn_discon_rej->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = pdn_discon_rej->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_PDN_DISCONNECT_REJECT; msg_ptr++; // ESM Cause liblte_mme_pack_esm_cause_ie(pdn_discon_rej->esm_cause, &msg_ptr); // Protocol Configuration Options if (pdn_discon_rej->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&pdn_discon_rej->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_disconnect_reject_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_PDN_DISCONNECT_REJECT_MSG_STRUCT* pdn_discon_rej) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && pdn_discon_rej != NULL) { // EPS Bearer ID pdn_discon_rej->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID pdn_discon_rej->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // ESM Cause liblte_mme_unpack_esm_cause_ie(&msg_ptr, &pdn_discon_rej->esm_cause); // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &pdn_discon_rej->protocol_cnfg_opts); pdn_discon_rej->protocol_cnfg_opts_present = true; } else { pdn_discon_rej->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } /********************************************************************* Message Name: PDN Disconnect Request Description: Sent by the UE to the network to initiate release of a PDN connection. Document Reference: 24.301 v10.2.0 Section 8.3.22 *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_pdn_disconnect_request_msg(LIBLTE_MME_PDN_DISCONNECT_REQUEST_MSG_STRUCT* pdn_discon_req, LIBLTE_BYTE_MSG_STRUCT* msg) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (pdn_discon_req != NULL && msg != NULL) { // Protocol Discriminator and EPS Bearer ID *msg_ptr = (pdn_discon_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT); msg_ptr++; // Procedure Transaction ID *msg_ptr = pdn_discon_req->proc_transaction_id; msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_PDN_DISCONNECT_REQUEST; msg_ptr++; // Linked EPS Bearer Identity & Spare Half Octet *msg_ptr = 0; liblte_mme_pack_linked_eps_bearer_identity_ie(pdn_discon_req->linked_eps_bearer_id, 0, &msg_ptr); msg_ptr++; // Protocol Configuration Options if (pdn_discon_req->protocol_cnfg_opts_present) { *msg_ptr = LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI; msg_ptr++; liblte_mme_pack_protocol_config_options_ie(&pdn_discon_req->protocol_cnfg_opts, &msg_ptr); } // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_unpack_pdn_disconnect_request_msg(LIBLTE_BYTE_MSG_STRUCT* msg, LIBLTE_MME_PDN_DISCONNECT_REQUEST_MSG_STRUCT* pdn_discon_req) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL && pdn_discon_req != NULL) { // EPS Bearer ID pdn_discon_req->eps_bearer_id = (*msg_ptr >> 4); msg_ptr++; // Procedure Transaction ID pdn_discon_req->proc_transaction_id = *msg_ptr; msg_ptr++; // Skip Message Type msg_ptr++; // Linked EPS Bearer Identity & Spare Half Octet liblte_mme_unpack_linked_eps_bearer_identity_ie(&msg_ptr, 0, &pdn_discon_req->linked_eps_bearer_id); msg_ptr++; // Protocol Configuration Options if (LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr) { msg_ptr++; liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &pdn_discon_req->protocol_cnfg_opts); pdn_discon_req->protocol_cnfg_opts_present = true; } else { pdn_discon_req->protocol_cnfg_opts_present = false; } err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_pack_activate_test_mode_complete_msg(LIBLTE_BYTE_MSG_STRUCT* msg, uint8 sec_hdr_type, uint32 count) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and skip indicator (always 0x0F) *msg_ptr = (LIBLTE_MME_MSG_TYPE_TEST_MODE_SKIP_INDICATOR << 4) | (LIBLTE_MME_MSG_TYPE_TEST_MODE_PROTOCOL_DISCRIMINATOR); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_ACTIVATE_TEST_MODE_COMPLETE; msg_ptr++; // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } LIBLTE_ERROR_ENUM liblte_mme_pack_close_ue_test_loop_complete_msg(LIBLTE_BYTE_MSG_STRUCT* msg, uint8 sec_hdr_type, uint32 count) { bzero(msg, sizeof(LIBLTE_BYTE_MSG_STRUCT)); LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* msg_ptr = msg->msg; if (msg != NULL) { if (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) { // Protocol Discriminator and Security Header Type *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; // MAC will be filled in later msg_ptr += 4; // Sequence Number *msg_ptr = count & 0xFF; msg_ptr++; } // Protocol Discriminator and skip indicator (always 0x0F) *msg_ptr = (LIBLTE_MME_MSG_TYPE_TEST_MODE_SKIP_INDICATOR << 4) | (LIBLTE_MME_MSG_TYPE_TEST_MODE_PROTOCOL_DISCRIMINATOR); msg_ptr++; // Message Type *msg_ptr = LIBLTE_MME_MSG_TYPE_CLOSE_UE_TEST_LOOP_COMPLETE; msg_ptr++; // Fill in the number of bytes used msg->N_bytes = msg_ptr - msg->msg; err = LIBLTE_SUCCESS; } return (err); } /******************************************************************************* HELPER FUNCTIONS *******************************************************************************/ const char* liblte_nas_sec_hdr_type_to_string(int code) { switch (code) { LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS); LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY); LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED); LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT); LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT); LIBLTE_CASE_STR(LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST); default: return "NAS Message Type Unknown"; } } const char* liblte_nas_msg_type_to_string(int code) { switch (code) { LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ATTACH_ACCEPT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ATTACH_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_DETACH_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_DETACH_ACCEPT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_ACCEPT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_COMPLETE); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_EXTENDED_SERVICE_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_SERVICE_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_GUTI_REALLOCATION_COMMAND); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_GUTI_REALLOCATION_COMPLETE); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_AUTHENTICATION_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_IDENTITY_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMMAND); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_SECURITY_MODE_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_EMM_STATUS); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_EMM_INFORMATION); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_DOWNLINK_NAS_TRANSPORT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_UPLINK_NAS_TRANSPORT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_CS_SERVICE_NOTIFICATION); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_DOWNLINK_GENERIC_NAS_TRANSPORT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_UPLINK_GENERIC_NAS_TRANSPORT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_ACCEPT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_MODIFY_EPS_BEARER_CONTEXT_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_PDN_CONNECTIVITY_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_PDN_CONNECTIVITY_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_PDN_DISCONNECT_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_PDN_DISCONNECT_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_ALLOCATION_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_ALLOCATION_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_MODIFICATION_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_BEARER_RESOURCE_MODIFICATION_REJECT); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_NOTIFICATION); LIBLTE_CASE_STR(LIBLTE_MME_MSG_TYPE_ESM_STATUS); default: return "NAS Message Type Unknown"; } }